From b9b7bda3427d4021e08facc53a727a837806bd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Sun, 3 Nov 2019 23:18:09 +0100 Subject: [PATCH] Remove new resources when exception is thrown on creation --- .../shredzone/acme4j/mock/MockAcmeServer.java | 42 +++++++++++++++++++ .../acme4j/mock/connection/Repository.java | 30 +++++++++++++ .../acme4j/mock/model/MockAccount.java | 11 +++++ .../acme4j/mock/model/MockAuthorization.java | 10 +++++ .../acme4j/mock/model/MockChallenge.java | 10 +++++ .../acme4j/mock/model/MockOrder.java | 12 ++++++ .../acme4j/mock/MockAcmeServerTest.java | 26 ++++++++++++ .../acme4j/mock/model/MockAccountTest.java | 9 ++++ .../mock/model/MockAuthorizationTest.java | 7 ++++ .../acme4j/mock/model/MockChallengeTest.java | 7 ++++ .../acme4j/mock/model/MockOrderTest.java | 17 ++++++++ 11 files changed, 181 insertions(+) diff --git a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/MockAcmeServer.java b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/MockAcmeServer.java index f5872a5d..a2a76d33 100644 --- a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/MockAcmeServer.java +++ b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/MockAcmeServer.java @@ -247,6 +247,17 @@ public class MockAcmeServer { .findFirst(); } + /** + * Removes a {@link MockAccount}. + * + * @param account + * {@link MockAccount} to remove + */ + public void removeAccount(MockAccount account) { + account.detach(repository); + accounts.remove(account); + } + /** * Creates a new {@link MockAuthorization} for the given {@link Identifier}. If there * is already a {@link MockAuthorization} for that {@link Identifier}, it is returned @@ -272,6 +283,17 @@ public class MockAcmeServer { return Optional.ofNullable(authorizations.get(identifier)); } + /** + * Removes a {@link MockAuthorization}. + * + * @param authorization + * {@link MockAuthorization} to remove + */ + public void removeAuthorization(MockAuthorization authorization) { + authorization.detach(repository); + authorizations.remove(authorization.getIdentifier()); + } + /** * Creates a new {@link MockChallenge} instance of the given type. * @@ -284,6 +306,16 @@ public class MockAcmeServer { return MockChallenge.create(repository, type); } + /** + * Removes a {@link MockChallenge}. + * + * @param challenge + * {@link MockChallenge} to remove + */ + public void removeChallenge(MockChallenge challenge) { + challenge.detach(repository); + } + /** * Creates a new {@link MockOrder} for the given {@link Identifier}. *

@@ -343,6 +375,16 @@ public class MockAcmeServer { return MockOrder.create(repository, identifiers, authorizations, ca); } + /** + * Removes a {@link MockOrder}. + * + * @param order + * {@link MockOrder} to remove + */ + public void removeOrder(MockOrder order) { + order.detach(repository); + } + /** * Returns the {@link MockAccount} that corresponds to the given {@link Account}. * diff --git a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/connection/Repository.java b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/connection/Repository.java index 80dc99a3..45eb7f3d 100644 --- a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/connection/Repository.java +++ b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/connection/Repository.java @@ -87,6 +87,21 @@ public class Repository { resourceMap.put(uri, wrapperFactory.apply(receiver)); } + /** + * Removes a controller {@link URL}. + * + * @param url + * {@link URL} of the controller to be removed + */ + public void removeController(URL url) { + URI uri = safeToURI(url); + Controller receiver = resourceMap.get(uri); + if (receiver == null) { + throw new IllegalArgumentException("No controller is registered for " + url); + } + resourceMap.remove(uri); + } + /** * Adds a {@link MockResource} to this repository. * @@ -115,6 +130,21 @@ public class Repository { .map(type::cast); } + /** + * Removes a {@link MockResource} from this repository. Also removes the controller. + * + * @param resource + * {@link MockResource} to remove + */ + public void removeResource(MockResource resource) { + URI uri = safeToURI(resource.getLocation()); + if (!resources.containsKey(uri)) { + throw new IllegalArgumentException("Unknown resource " + resource.getLocation()); + } + removeController(resource.getLocation()); + resources.remove(uri); + } + /** * Safely converts an {@link URL} to an {@link URI}. * diff --git a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAccount.java b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAccount.java index b29af4ad..1ac1eff8 100644 --- a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAccount.java +++ b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAccount.java @@ -182,6 +182,17 @@ public class MockAccount extends MockResource { return buildUrl("account", getUniqueId(), "orders"); } + /** + * Detaches this {@link MockAccount} from the {@link Repository}. + * + * @param repository + * {@link Repository} to remove the account from. + */ + public void detach(Repository repository) { + repository.removeController(getOrdersLocation()); + repository.removeResource(this); + } + @Override public JSON toJSON() { JSONBuilder jb = new JSONBuilder(); diff --git a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAuthorization.java b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAuthorization.java index bb5d0f2e..295e2871 100644 --- a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAuthorization.java +++ b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockAuthorization.java @@ -164,6 +164,16 @@ public class MockAuthorization extends MockResource { return buildUrl("authz", getUniqueId()); } + /** + * Detaches this {@link MockAuthorization} from the {@link Repository}. + * + * @param repository + * {@link Repository} to remove the authorization from. + */ + public void detach(Repository repository) { + repository.removeResource(this); + } + @Override public JSON toJSON() { JSONBuilder jb = new JSONBuilder(); diff --git a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockChallenge.java b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockChallenge.java index 461f69dd..45b0d1cf 100644 --- a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockChallenge.java +++ b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockChallenge.java @@ -193,6 +193,16 @@ public class MockChallenge extends MockResource { return buildUrl("challenge", getUniqueId()); } + /** + * Detaches this {@link MockChallenge} from the {@link Repository}. + * + * @param repository + * {@link Repository} to remove the challenge from. + */ + public void detach(Repository repository) { + repository.removeResource(this); + } + @Override public JSON toJSON() { JSONBuilder jb = new JSONBuilder(); diff --git a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockOrder.java b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockOrder.java index 977eef8e..51c697da 100644 --- a/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockOrder.java +++ b/acme4j-mock/src/main/java/org/shredzone/acme4j/mock/model/MockOrder.java @@ -319,6 +319,18 @@ public class MockOrder extends MockResource { return buildUrl("certificate", getUniqueId()); } + /** + * Detaches this {@link MockOrder} from the {@link Repository}. + * + * @param repository + * {@link Repository} to remove the order from. + */ + public void detach(Repository repository) { + repository.removeController(getFinalizeLocation()); + repository.removeController(getCertificateLocation()); + repository.removeResource(this); + } + @Override public JSON toJSON() { JSONBuilder jb = new JSONBuilder(); diff --git a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/MockAcmeServerTest.java b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/MockAcmeServerTest.java index b2676063..b206c8f4 100644 --- a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/MockAcmeServerTest.java +++ b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/MockAcmeServerTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.fail; import java.net.URISyntaxException; import java.net.URL; import java.security.KeyPair; +import java.util.NoSuchElementException; import java.util.Optional; import org.junit.Test; @@ -184,6 +185,12 @@ public class MockAcmeServerTest { assertThat(server.getAccounts().size(), is(2)); assertThat(server.findAccount(keyPair1.getPublic()).isPresent(), is(false)); assertThat(server.findAccount(keyPair2.getPublic()).isPresent(), is(false)); + + server.removeAccount(account1); + assertThat(server.getAccounts().size(), is(1)); + + server.removeAccount(account2); + assertThat(server.getAccounts().size(), is(0)); } /** @@ -213,6 +220,9 @@ public class MockAcmeServerTest { Optional missingAuth = server.findAuthorization(Identifier.dns("example.com")); assertThat(missingAuth.isPresent(), is(false)); + + server.removeAuthorization(auth); + assertThat(server.findAuthorization(identifier).isPresent(), is(false)); } /** @@ -268,6 +278,14 @@ public class MockAcmeServerTest { MockChallenge mockChallenge = server.getMockOf(challenge); assertThat(mockChallenge, sameInstance(createdChallenge)); + + server.removeChallenge(createdChallenge); + try { + server.getMockOf(challenge); + fail("Challenge is still there"); + } catch (NoSuchElementException ex) { + // expected + } } /** @@ -284,6 +302,14 @@ public class MockAcmeServerTest { Order order = login.bindOrder(createdOrder.getLocation()); MockOrder mockOrder = server.getMockOf(order); assertThat(mockOrder, sameInstance(createdOrder)); + + server.removeOrder(createdOrder); + try { + server.getMockOf(order); + fail("Order is still there"); + } catch (NoSuchElementException ex) { + // expected + } } /** diff --git a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAccountTest.java b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAccountTest.java index f710e643..46bb75b9 100644 --- a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAccountTest.java +++ b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAccountTest.java @@ -68,6 +68,15 @@ public class MockAccountTest { assertThat(account.getPublicKey(), is(PUBLIC_KEY)); assertThat(account.getStatus(), is(Status.VALID)); assertThat(account.getTermsOfServiceAgreed(), is(nullValue())); + + // Detach from repository + account.detach(repository); + assertThat(repository.getController(account.getLocation()).isPresent(), + is(false)); + assertThat(repository.getController(account.getOrdersLocation()).isPresent(), + is(false)); + assertThat(repository.getResourceOfType(account.getLocation(), MockAccount.class).isPresent(), + is(false)); } /** diff --git a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAuthorizationTest.java b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAuthorizationTest.java index ba6063fc..d6a2d4e0 100644 --- a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAuthorizationTest.java +++ b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockAuthorizationTest.java @@ -59,6 +59,13 @@ public class MockAuthorizationTest { assertThat(auth.getIdentifier(), is(IDENTIFIER)); assertThat(auth.getStatus(), is(Status.PENDING)); assertThat(auth.getWildcard(), is(nullValue())); + + // Detach from repository + auth.detach(repository); + assertThat(repository.getController(auth.getLocation()).isPresent(), + is(false)); + assertThat(repository.getResourceOfType(auth.getLocation(), MockAuthorization.class).isPresent(), + is(false)); } /** diff --git a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockChallengeTest.java b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockChallengeTest.java index 585fcfb0..643c426c 100644 --- a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockChallengeTest.java +++ b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockChallengeTest.java @@ -59,6 +59,13 @@ public class MockChallengeTest { assertThat(challenge.getToken(), is(nullValue())); assertThat(challenge.getType(), is(Http01Challenge.TYPE)); assertThat(challenge.getValidated(), is(nullValue())); + + // Detach from repository + challenge.detach(repository); + assertThat(repository.getController(challenge.getLocation()).isPresent(), + is(false)); + assertThat(repository.getResourceOfType(challenge.getLocation(), MockChallenge.class).isPresent(), + is(false)); } /** diff --git a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockOrderTest.java b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockOrderTest.java index aa619c39..29e462b0 100644 --- a/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockOrderTest.java +++ b/acme4j-mock/src/test/java/org/shredzone/acme4j/mock/model/MockOrderTest.java @@ -32,6 +32,8 @@ import org.shredzone.acme4j.Status; import org.shredzone.acme4j.mock.connection.MockCertificateAuthority; import org.shredzone.acme4j.mock.connection.ProblemBuilder; import org.shredzone.acme4j.mock.connection.Repository; +import org.shredzone.acme4j.mock.controller.CertificateController; +import org.shredzone.acme4j.mock.controller.FinalizeController; import org.shredzone.acme4j.mock.controller.OrderController; import org.shredzone.acme4j.toolbox.JSONBuilder; @@ -64,6 +66,10 @@ public class MockOrderTest { // Controllers were added to the repository? assertThat(repository.getController(order.getLocation()).get(), is(instanceOf(OrderController.class))); + assertThat(repository.getController(order.getFinalizeLocation()).get(), + is(instanceOf(FinalizeController.class))); + assertThat(repository.getController(order.getCertificateLocation()).get(), + is(instanceOf(CertificateController.class))); assertThat(repository.getResourceOfType(order.getLocation(), MockOrder.class).get(), is(sameInstance(order))); @@ -76,6 +82,17 @@ public class MockOrderTest { assertThat(order.getNotBefore(), is(nullValue())); assertThat(order.getNotAfter(), is(nullValue())); assertThat(order.getStatus(), is(Status.PENDING)); + + // Detach from repository + order.detach(repository); + assertThat(repository.getController(order.getLocation()).isPresent(), + is(false)); + assertThat(repository.getController(order.getFinalizeLocation()).isPresent(), + is(false)); + assertThat(repository.getController(order.getCertificateLocation()).isPresent(), + is(false)); + assertThat(repository.getResourceOfType(order.getLocation(), MockOrder.class).isPresent(), + is(false)); } /**