mirror of https://github.com/shred/acme4j
Add unit tests for utils module
parent
7e07a0e2e4
commit
1d56065495
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.util;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.ASN1Encodable;
|
||||||
|
import org.bouncycastle.asn1.DERIA5String;
|
||||||
|
import org.bouncycastle.asn1.pkcs.Attribute;
|
||||||
|
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
||||||
|
import org.bouncycastle.asn1.x500.RDN;
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
|
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||||
|
import org.bouncycastle.asn1.x509.Extension;
|
||||||
|
import org.bouncycastle.asn1.x509.Extensions;
|
||||||
|
import org.bouncycastle.asn1.x509.GeneralName;
|
||||||
|
import org.bouncycastle.asn1.x509.GeneralNames;
|
||||||
|
import org.bouncycastle.openssl.PEMException;
|
||||||
|
import org.bouncycastle.openssl.PEMParser;
|
||||||
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
||||||
|
import org.hamcrest.BaseMatcher;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.jcabi.matchers.RegexMatchers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link CSRBuilder}.
|
||||||
|
*
|
||||||
|
* @author Richard "Shred" Körber
|
||||||
|
*/
|
||||||
|
public class CSRBuilderTest {
|
||||||
|
|
||||||
|
private static KeyPair testKey;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setup() {
|
||||||
|
testKey = KeyPairUtils.createKeyPair(512);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the generated CSR is plausible.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGenerate() throws IOException {
|
||||||
|
CSRBuilder builder = new CSRBuilder();
|
||||||
|
builder.addDomain("abc.de");
|
||||||
|
builder.addDomain("fg.hi");
|
||||||
|
builder.addDomains("jklm.no", "pqr.st");
|
||||||
|
builder.addDomains(Arrays.asList("uv.wx", "y.z"));
|
||||||
|
|
||||||
|
builder.setCountry("XX");
|
||||||
|
builder.setLocality("Testville");
|
||||||
|
builder.setOrganization("Testing Co");
|
||||||
|
builder.setOrganizationalUnit("Testunit");
|
||||||
|
builder.setState("ABC");
|
||||||
|
|
||||||
|
assertThat(builder.toString(), is("CN=abc.de,C=XX,L=Testville,O=Testing Co,"
|
||||||
|
+ "OU=Testunit,ST=ABC,"
|
||||||
|
+ "DNS=abc.de,DNS=fg.hi,DNS=jklm.no,DNS=pqr.st,DNS=uv.wx,DNS=y.z"));
|
||||||
|
|
||||||
|
builder.sign(testKey);
|
||||||
|
|
||||||
|
PKCS10CertificationRequest csr = builder.getCSR();
|
||||||
|
assertThat(csr, is(notNullValue()));
|
||||||
|
assertThat(csr.getEncoded(), is(equalTo(builder.getEncoded())));
|
||||||
|
|
||||||
|
csrTest(csr);
|
||||||
|
writerTest(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the CSR contains the right parameters.
|
||||||
|
* <p>
|
||||||
|
* This is not supposed to be a Bouncy Castle test. If the
|
||||||
|
* {@link PKCS10CertificationRequest} contains the right parameters, we assume that
|
||||||
|
* Bouncy Castle encodes it properly.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void csrTest(PKCS10CertificationRequest csr) {
|
||||||
|
X500Name name = csr.getSubject();
|
||||||
|
assertThat(name.getRDNs(BCStyle.CN), arrayContaining(new RDNMatcher("abc.de")));
|
||||||
|
assertThat(name.getRDNs(BCStyle.C), arrayContaining(new RDNMatcher("XX")));
|
||||||
|
assertThat(name.getRDNs(BCStyle.L), arrayContaining(new RDNMatcher("Testville")));
|
||||||
|
assertThat(name.getRDNs(BCStyle.O), arrayContaining(new RDNMatcher("Testing Co")));
|
||||||
|
assertThat(name.getRDNs(BCStyle.OU), arrayContaining(new RDNMatcher("Testunit")));
|
||||||
|
assertThat(name.getRDNs(BCStyle.ST), arrayContaining(new RDNMatcher("ABC")));
|
||||||
|
|
||||||
|
Attribute[] attr = csr.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
|
||||||
|
assertThat(attr.length, is(1));
|
||||||
|
ASN1Encodable[] extensions = attr[0].getAttrValues().toArray();
|
||||||
|
assertThat(extensions.length, is(1));
|
||||||
|
GeneralNames names = GeneralNames.fromExtensions((Extensions) extensions[0], Extension.subjectAlternativeName);
|
||||||
|
assertThat(names.getNames(), arrayContaining(new GeneralNameMatcher("abc.de"),
|
||||||
|
new GeneralNameMatcher("fg.hi"), new GeneralNameMatcher("jklm.no"),
|
||||||
|
new GeneralNameMatcher("pqr.st"), new GeneralNameMatcher("uv.wx"),
|
||||||
|
new GeneralNameMatcher("y.z")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the {@link CSRBuilder#write(java.io.Writer)} method generates a correct
|
||||||
|
* CSR PEM file.
|
||||||
|
*/
|
||||||
|
private void writerTest(CSRBuilder builder) throws IOException, PEMException {
|
||||||
|
// Write CSR to PEM
|
||||||
|
String pem;
|
||||||
|
try (StringWriter out = new StringWriter()) {
|
||||||
|
builder.write(out);
|
||||||
|
pem = out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure PEM file is properly formatted
|
||||||
|
assertThat(pem, RegexMatchers.matchesPattern(
|
||||||
|
"-----BEGIN CERTIFICATE REQUEST-----[\\r\\n]+"
|
||||||
|
+ "([a-zA-Z0-9/+=]+[\\r\\n]+)+"
|
||||||
|
+ "-----END CERTIFICATE REQUEST-----[\\r\\n]*"));
|
||||||
|
|
||||||
|
// Read CSR from PEM
|
||||||
|
PKCS10CertificationRequest readCsr;
|
||||||
|
try (PEMParser parser = new PEMParser(new StringReader(pem))) {
|
||||||
|
readCsr = (PKCS10CertificationRequest) parser.readObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that both keypairs are the same
|
||||||
|
assertThat(builder.getCSR(), not(sameInstance(readCsr)));
|
||||||
|
assertThat(builder.getEncoded(), is(equalTo(readCsr.getEncoded())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure an exception is thrown when no domain is set.
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testNoDomain() throws IOException {
|
||||||
|
CSRBuilder builder = new CSRBuilder();
|
||||||
|
builder.sign(testKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure all getters will fail if the CSR is not signed.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNoSign() throws IOException {
|
||||||
|
CSRBuilder builder = new CSRBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.getCSR();
|
||||||
|
fail("getCSR(): expected exception was not thrown");
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
builder.getEncoded();
|
||||||
|
fail("getEncoded(): expected exception was not thrown");
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try (StringWriter w = new StringWriter()) {
|
||||||
|
builder.write(w);
|
||||||
|
fail("write(): expected exception was not thrown");
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches {@link RDN} values.
|
||||||
|
*/
|
||||||
|
private static class RDNMatcher extends BaseMatcher<RDN> {
|
||||||
|
private final String expectedValue;
|
||||||
|
|
||||||
|
public RDNMatcher(String expectedValue) {
|
||||||
|
this.expectedValue = expectedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object item) {
|
||||||
|
if (!(item instanceof RDN)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return expectedValue.equals(((RDN) item).getFirst().getValue().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendValue(expectedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeMismatch(Object item, Description description) {
|
||||||
|
if (!(item instanceof RDN)) {
|
||||||
|
description.appendText("is a ").appendValue(item.getClass());
|
||||||
|
} else {
|
||||||
|
description.appendText("was ").appendValue(((RDN) item).getFirst().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches {@link GeneralName} DNS tagged values.
|
||||||
|
*/
|
||||||
|
private static class GeneralNameMatcher extends BaseMatcher<GeneralName> {
|
||||||
|
private final String expectedValue;
|
||||||
|
|
||||||
|
public GeneralNameMatcher(String expectedValue) {
|
||||||
|
this.expectedValue = expectedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object item) {
|
||||||
|
if (!(item instanceof GeneralName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralName gn = (GeneralName) item;
|
||||||
|
|
||||||
|
return gn.getTagNo() == GeneralName.dNSName
|
||||||
|
&& expectedValue.equals(DERIA5String.getInstance(gn.getName()).getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendValue(expectedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeMismatch(Object item, Description description) {
|
||||||
|
if (!(item instanceof GeneralName)) {
|
||||||
|
description.appendText("is a ").appendValue(item.getClass());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeneralName gn = (GeneralName) item;
|
||||||
|
if (gn.getTagNo() != GeneralName.dNSName) {
|
||||||
|
description.appendText("is not DNS");
|
||||||
|
} else {
|
||||||
|
description.appendText("was ").appendValue(DERIA5String.getInstance(gn.getName()).getString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.util;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.jcabi.matchers.RegexMatchers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link CertificateUtils}.
|
||||||
|
*
|
||||||
|
* @author Richard "Shred" Körber
|
||||||
|
*/
|
||||||
|
public class CertificateUtilsTest {
|
||||||
|
|
||||||
|
private CertificateFactory certificateFactory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws CertificateException {
|
||||||
|
certificateFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if {@link CertificateUtilsTest#writeX509CertificateTest()} writes a
|
||||||
|
* proper X.509 certificate.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testWriteX509Certificate() throws IOException, CertificateException {
|
||||||
|
// Read a demonstration certificate
|
||||||
|
X509Certificate original;
|
||||||
|
try (InputStream cert = getClass().getResourceAsStream("/cert.pem")) {
|
||||||
|
original = (X509Certificate) certificateFactory.generateCertificate(cert);
|
||||||
|
}
|
||||||
|
assertThat(original, is(notNullValue()));
|
||||||
|
|
||||||
|
// Write to StringWriter
|
||||||
|
String pem;
|
||||||
|
try (StringWriter out = new StringWriter()) {
|
||||||
|
CertificateUtils.writeX509Certificate(original, out);
|
||||||
|
pem = out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure it is a good PEM file
|
||||||
|
assertThat(pem, RegexMatchers.matchesPattern(
|
||||||
|
"-----BEGIN CERTIFICATE-----[\\r\\n]+"
|
||||||
|
+ "([a-zA-Z0-9/+=]+[\\r\\n]+)+"
|
||||||
|
+ "-----END CERTIFICATE-----[\\r\\n]*"));
|
||||||
|
|
||||||
|
// Read it back in
|
||||||
|
X509Certificate written;
|
||||||
|
try (InputStream cert = new ByteArrayInputStream(pem.getBytes("utf-8"))) {
|
||||||
|
written = (X509Certificate) certificateFactory.generateCertificate(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that both certificates are the same
|
||||||
|
assertThat(original.getEncoded(), is(equalTo(written.getEncoded())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* acme4j - Java ACME client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Richard "Shred" Körber
|
||||||
|
* http://acme4j.shredzone.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
package org.shredzone.acme4j.util;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.jcabi.matchers.RegexMatchers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link KeyPairUtils}.
|
||||||
|
*
|
||||||
|
* @author Richard "Shred" Körber
|
||||||
|
*/
|
||||||
|
public class KeyPairUtilsTest {
|
||||||
|
private static final int KEY_SIZE = 2048;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that RSA keypairs of the correct size are generated.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateKeyPair() {
|
||||||
|
KeyPair pair = KeyPairUtils.createKeyPair(KEY_SIZE);
|
||||||
|
assertThat(pair, is(notNullValue()));
|
||||||
|
assertThat(pair.getPublic(), is(instanceOf(RSAPublicKey.class)));
|
||||||
|
|
||||||
|
RSAPublicKey pub = (RSAPublicKey) pair.getPublic();
|
||||||
|
assertThat(pub.getModulus().bitLength(), is(KEY_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that reading and writing keypairs work correctly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testWriteAndRead() throws IOException {
|
||||||
|
// Generate a test keypair
|
||||||
|
KeyPair pair = KeyPairUtils.createKeyPair(KEY_SIZE);
|
||||||
|
|
||||||
|
// Write keypair to PEM
|
||||||
|
String pem;
|
||||||
|
try (StringWriter out = new StringWriter()) {
|
||||||
|
KeyPairUtils.writeKeyPair(pair, out);
|
||||||
|
pem = out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure PEM file is properly formatted
|
||||||
|
assertThat(pem, RegexMatchers.matchesPattern(
|
||||||
|
"-----BEGIN RSA PRIVATE KEY-----[\\r\\n]+"
|
||||||
|
+ "([a-zA-Z0-9/+=]+[\\r\\n]+)+"
|
||||||
|
+ "-----END RSA PRIVATE KEY-----[\\r\\n]*"));
|
||||||
|
|
||||||
|
// Read keypair from PEM
|
||||||
|
KeyPair readPair;
|
||||||
|
try (StringReader in = new StringReader(pem)) {
|
||||||
|
readPair = KeyPairUtils.readKeyPair(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that both keypairs are the same
|
||||||
|
assertThat(pair, not(sameInstance(readPair)));
|
||||||
|
assertThat(pair.getPrivate().getEncoded(), is(equalTo(readPair.getPrivate().getEncoded())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDVzCCAj+gAwIBAgIJAM4KDTzb0Y7NMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
|
||||||
|
BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
|
||||||
|
Q29tcGFueSBMdGQwHhcNMTUxMjEwMDAxMTA4WhcNMjUxMjA3MDAxMTA4WjBCMQsw
|
||||||
|
CQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh
|
||||||
|
dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||||
|
r0g3w4C8xbj/5lzJiDxk0HkEJeZeyruq+0AzOPMigJZ7zxZtX/KUxOIHrQ4qjcFh
|
||||||
|
l0DmQImoM0wESU+kcsjAHCx8E1lgRVlVsMfLAQPHkg5UybqfadzKT3ALcSD+9F9m
|
||||||
|
VIP6liC/6KzLTASmx6zM7j92KTl1ArObZr5mh0jvSNORrMhEC4Byn3+NTxjuHON1
|
||||||
|
rWppCMwpeNNhFzaAig3O8PY8IyaLXNP2Ac5pXn0iW16S+Im9by7751UeW5a7Dznm
|
||||||
|
uMEM+WY640ffJDQ4+I64H403uAgvvSu+BGw8SEEZGuBCxoCnG1g6y6OvJyN5TgqF
|
||||||
|
dGosAfm1u+/MP1seoPdpBQIDAQABo1AwTjAdBgNVHQ4EFgQUrie5ZLOrA/HuhW1b
|
||||||
|
/CHjzEvj34swHwYDVR0jBBgwFoAUrie5ZLOrA/HuhW1b/CHjzEvj34swDAYDVR0T
|
||||||
|
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkSOP0FUgIIUeJTObgXrenHzZpLAk
|
||||||
|
qXi37dgdYuPhNveo3agueP51N7yIoh6YGShiJ73Rvr+lVYTwFXStrLih1Wh3tWvk
|
||||||
|
sMxnvocgd7l6USRb5/AgH7eHeFK4DoCAak2hUAcCLDRJN3XMhNLpyJhw7GJxowVI
|
||||||
|
GUlxcW5Asrmh9qflfyMyjripTP3CdHobmNcNHyScjNncKj37m8vomel9acekTtDl
|
||||||
|
2Ci7nLdE+3VqQCXMIfLiF3PO0gGpKei0RuVCSOG6W83zVInCPd/l3aluSR+f/VZl
|
||||||
|
k8KGQ4As4uTQi89j+J1YepzG0ASMZpjVbXeIg5QBAywVxBh5XVTz37KN8A==
|
||||||
|
-----END CERTIFICATE-----
|
6
pom.xml
6
pom.xml
|
@ -158,6 +158,12 @@
|
||||||
<version>[1.3,)</version>
|
<version>[1.3,)</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcabi</groupId>
|
||||||
|
<artifactId>jcabi-matchers</artifactId>
|
||||||
|
<version>[1.3,)</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
|
|
Loading…
Reference in New Issue