From 558258e9fe8751ba51526d659951b12474296dbc Mon Sep 17 00:00:00 2001 From: Alex-Vol-Amz <83721736+Alex-Vol-Amz@users.noreply.github.com> Date: Fri, 17 May 2024 14:39:24 -0400 Subject: [PATCH] Fix Spotbugs issues with new Uluru checker (#63) * Fix Spotbugs issues with AWS::Transfer::Agreement * Fix Spotbugs issues with AWS::Transfer::Certificate * Fix Spotbugs issues with AWS::Transfer::Connector * Fix Spotbugs issues with AWS::Transfer::Profile * Fix Spotbugs issues with AWS::Transfer::Workflow * Fix Spotbugs issues with AWS::Transfer::(Server|User) Also added coverage improvement tests for BaseHandlerStd classes. This change is necessary due to the fact that Uluru is adding Spotbugs and specifically a new Spotbugs plugin designed to catch problems in handler implementations. Signed-off-by: Alex Volanis --- aws-transfer-agreement/spotbugs-exclude.xml | 15 ++ .../transfer/agreement/BaseHandlerStd.java | 40 +++++ .../transfer/agreement/CreateHandler.java | 15 +- .../transfer/agreement/DeleteHandler.java | 16 +- .../transfer/agreement/ListHandler.java | 16 +- .../agreement/MockableBaseHandler.java | 24 +++ .../transfer/agreement/ReadHandler.java | 16 +- .../transfer/agreement/UpdateHandler.java | 16 +- .../transfer/agreement/AbstractTestBase.java | 132 +++++++++++++--- .../agreement/BaseHandlerStdTest.java | 56 +++++++ .../transfer/agreement/CreateHandlerTest.java | 73 +++------ .../transfer/agreement/DeleteHandlerTest.java | 60 +++----- .../transfer/agreement/ListHandlerTest.java | 53 +++---- .../transfer/agreement/ReadHandlerTest.java | 63 +++----- .../transfer/agreement/UpdateHandlerTest.java | 81 ++++------ aws-transfer-certificate/spotbugs-exclude.xml | 15 ++ .../transfer/certificate/BaseHandlerStd.java | 40 +++++ .../transfer/certificate/CreateHandler.java | 16 +- .../transfer/certificate/DeleteHandler.java | 16 +- .../transfer/certificate/ListHandler.java | 16 +- .../certificate/MockableBaseHandler.java | 24 +++ .../transfer/certificate/ReadHandler.java | 16 +- .../transfer/certificate/UpdateHandler.java | 15 +- .../certificate/AbstractTestBase.java | 110 +++++++++++++- .../certificate/BaseHandlerStdTest.java | 56 +++++++ .../certificate/CreateHandlerTest.java | 80 +++------- .../certificate/DeleteHandlerTest.java | 62 +++----- .../transfer/certificate/ListHandlerTest.java | 54 +++---- .../transfer/certificate/ReadHandlerTest.java | 66 ++++---- .../certificate/UpdateHandlerTest.java | 82 ++++------ aws-transfer-connector/spotbugs-exclude.xml | 15 ++ .../transfer/connector/BaseHandlerStd.java | 40 +++++ .../transfer/connector/CreateHandler.java | 16 +- .../transfer/connector/DeleteHandler.java | 16 +- .../transfer/connector/ListHandler.java | 16 +- .../connector/MockableBaseHandler.java | 24 +++ .../transfer/connector/ReadHandler.java | 16 +- .../transfer/connector/UpdateHandler.java | 16 +- .../transfer/connector/AbstractTestBase.java | 143 +++++++++++++++--- .../connector/BaseHandlerStdTest.java | 56 +++++++ .../transfer/connector/CreateHandlerTest.java | 83 +++------- .../transfer/connector/DeleteHandlerTest.java | 70 +++------ .../transfer/connector/ListHandlerTest.java | 62 ++------ .../transfer/connector/ReadHandlerTest.java | 72 +++------ .../transfer/connector/UpdateHandlerTest.java | 82 ++++------ aws-transfer-profile/spotbugs-exclude.xml | 15 ++ .../transfer/profile/BaseHandlerStd.java | 40 +++++ .../transfer/profile/CreateHandler.java | 16 +- .../transfer/profile/DeleteHandler.java | 16 +- .../amazon/transfer/profile/ListHandler.java | 17 +-- .../transfer/profile/MockableBaseHandler.java | 24 +++ .../amazon/transfer/profile/ReadHandler.java | 16 +- .../transfer/profile/UpdateHandler.java | 16 +- .../transfer/profile/AbstractTestBase.java | 110 +++++++++++++- .../transfer/profile/BaseHandlerStdTest.java | 56 +++++++ .../transfer/profile/CreateHandlerTest.java | 69 +++------ .../transfer/profile/DeleteHandlerTest.java | 67 +++----- .../transfer/profile/ListHandlerTest.java | 67 +++----- .../transfer/profile/ReadHandlerTest.java | 67 +++----- .../transfer/profile/UpdateHandlerTest.java | 79 +++------- aws-transfer-server/spotbugs-exclude.xml | 15 ++ aws-transfer-user/docs/README.md | 2 + aws-transfer-user/spotbugs-exclude.xml | 15 ++ aws-transfer-workflow/spotbugs-exclude.xml | 15 ++ .../transfer/workflow/BaseHandlerStd.java | 40 +++++ .../transfer/workflow/CreateHandler.java | 16 +- .../transfer/workflow/DeleteHandler.java | 16 +- .../amazon/transfer/workflow/ListHandler.java | 16 +- .../workflow/MockableBaseHandler.java | 24 +++ .../amazon/transfer/workflow/ReadHandler.java | 16 +- .../transfer/workflow/UpdateHandler.java | 16 +- .../transfer/workflow/AbstractTestBase.java | 112 +++++++++++++- .../transfer/workflow/BaseHandlerStdTest.java | 56 +++++++ .../transfer/workflow/CreateHandlerTest.java | 86 +++-------- .../transfer/workflow/DeleteHandlerTest.java | 66 +++----- .../transfer/workflow/ListHandlerTest.java | 56 +++---- .../transfer/workflow/ReadHandlerTest.java | 65 +++----- .../transfer/workflow/UpdateHandlerTest.java | 75 +++------ 78 files changed, 1898 insertions(+), 1555 deletions(-) create mode 100644 aws-transfer-agreement/spotbugs-exclude.xml create mode 100644 aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/BaseHandlerStd.java create mode 100644 aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/MockableBaseHandler.java create mode 100644 aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/BaseHandlerStdTest.java create mode 100644 aws-transfer-certificate/spotbugs-exclude.xml create mode 100644 aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/BaseHandlerStd.java create mode 100644 aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/MockableBaseHandler.java create mode 100644 aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/BaseHandlerStdTest.java create mode 100644 aws-transfer-connector/spotbugs-exclude.xml create mode 100644 aws-transfer-connector/src/main/java/software/amazon/transfer/connector/BaseHandlerStd.java create mode 100644 aws-transfer-connector/src/main/java/software/amazon/transfer/connector/MockableBaseHandler.java create mode 100644 aws-transfer-connector/src/test/java/software/amazon/transfer/connector/BaseHandlerStdTest.java create mode 100644 aws-transfer-profile/spotbugs-exclude.xml create mode 100644 aws-transfer-profile/src/main/java/software/amazon/transfer/profile/BaseHandlerStd.java create mode 100644 aws-transfer-profile/src/main/java/software/amazon/transfer/profile/MockableBaseHandler.java create mode 100644 aws-transfer-profile/src/test/java/software/amazon/transfer/profile/BaseHandlerStdTest.java create mode 100644 aws-transfer-server/spotbugs-exclude.xml create mode 100644 aws-transfer-user/spotbugs-exclude.xml create mode 100644 aws-transfer-workflow/spotbugs-exclude.xml create mode 100644 aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/BaseHandlerStd.java create mode 100644 aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/MockableBaseHandler.java create mode 100644 aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/BaseHandlerStdTest.java diff --git a/aws-transfer-agreement/spotbugs-exclude.xml b/aws-transfer-agreement/spotbugs-exclude.xml new file mode 100644 index 0000000..7071a82 --- /dev/null +++ b/aws-transfer-agreement/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/BaseHandlerStd.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/BaseHandlerStd.java new file mode 100644 index 0000000..f5501fa --- /dev/null +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/BaseHandlerStd.java @@ -0,0 +1,40 @@ +package software.amazon.transfer.agreement; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * The purpose of this base class is to allow a simple calling pattern that + * makes testing Uluru handlers easier and avoids having to store context + * in class fields. The {@link MockableBaseHandler} interface is used to + * make isolation of the inner call such that in testing we guarantee that + * the caller will not pick the wrong method and avoid human error. + */ +public abstract class BaseHandlerStd extends BaseHandler + implements MockableBaseHandler { + @Override + public final ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final Logger logger) { + return handleRequest( + proxy, + request, + callbackContext != null ? callbackContext : new CallbackContext(), + proxy.newProxy(ClientBuilder::getClient), + logger); + } + + @Override + public abstract ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/CreateHandler.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/CreateHandler.java index 332e605..4468b97 100644 --- a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/CreateHandler.java +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/CreateHandler.java @@ -21,6 +21,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -28,24 +29,16 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class CreateHandler extends BaseHandler { - private TransferClient client; - - public CreateHandler(TransferClient client) { - this.client = client; - } +public class CreateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); Map allTags = new HashMap<>(); @@ -73,7 +66,7 @@ public ProgressEvent handleRequest( .collect(Collectors.toList())) .build(); - try { + try (TransferClient client = proxyClient.client()) { CreateAgreementResponse response = proxy.injectCredentialsAndInvokeV2(createAgreementRequest, client::createAgreement); model.setAgreementId(response.agreementId()); diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/DeleteHandler.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/DeleteHandler.java index 2f99c78..eef1b0b 100644 --- a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/DeleteHandler.java +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/DeleteHandler.java @@ -14,29 +14,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class DeleteHandler extends BaseHandler { - private TransferClient client; - - public DeleteHandler(TransferClient client) { - this.client = client; - } - +public class DeleteHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); DeleteAgreementRequest deleteAgreementRequest = DeleteAgreementRequest.builder() @@ -44,7 +36,7 @@ public ProgressEvent handleRequest( .serverId(model.getServerId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(deleteAgreementRequest, client::deleteAgreement); logger.log( String.format("%s %s deleted successfully", ResourceModel.TYPE_NAME, model.getPrimaryIdentifier())); diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ListHandler.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ListHandler.java index 2a6683f..356a37a 100644 --- a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ListHandler.java +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ListHandler.java @@ -16,29 +16,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class ListHandler extends BaseHandler { - private TransferClient client; - - public ListHandler(TransferClient client) { - this.client = client; - } - +public class ListHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel topModel = request.getDesiredResourceState(); final List models = new ArrayList<>(); @@ -48,7 +40,7 @@ public ProgressEvent handleRequest( .nextToken(request.getNextToken()) .build(); - try { + try (TransferClient client = proxyClient.client()) { ListAgreementsResponse response = proxy.injectCredentialsAndInvokeV2(listAgreementsRequest, client::listAgreements); diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/MockableBaseHandler.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/MockableBaseHandler.java new file mode 100644 index 0000000..1db10d0 --- /dev/null +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/MockableBaseHandler.java @@ -0,0 +1,24 @@ +package software.amazon.transfer.agreement; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * Interface exposing the only handler method that should be used when + * testing Uluru handlers. This provides a mechanism to feed the call chain + * a mock client as needed without complex static mocking of the ClientBuilder. + * + * @param + */ +interface MockableBaseHandler { + ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackT callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ReadHandler.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ReadHandler.java index abd6d71..ca72407 100644 --- a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ReadHandler.java +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/ReadHandler.java @@ -18,6 +18,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -25,30 +26,21 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class ReadHandler extends BaseHandler { - private TransferClient client; - - public ReadHandler(TransferClient client) { - this.client = client; - } - +public class ReadHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); DescribeAgreementRequest describeAgreementRequest = DescribeAgreementRequest.builder() .agreementId(model.getAgreementId()) .serverId(model.getServerId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { DescribeAgreementResponse response = proxy.injectCredentialsAndInvokeV2(describeAgreementRequest, client::describeAgreement); logger.log(String.format( diff --git a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/UpdateHandler.java b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/UpdateHandler.java index 33a900b..5d7aa84 100644 --- a/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/UpdateHandler.java +++ b/aws-transfer-agreement/src/main/java/software/amazon/transfer/agreement/UpdateHandler.java @@ -24,29 +24,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class UpdateHandler extends BaseHandler { - private TransferClient client; - - public UpdateHandler(TransferClient client) { - this.client = client; - } - +public class UpdateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); String arn = String.format( "arn:%s:transfer:%s:%s:agreement/%s/%s", @@ -82,7 +74,7 @@ public ProgressEvent handleRequest( Set tagsToAdd = Sets.difference(new HashSet<>(desiredTags), new HashSet<>(previousTags)); Set tagsToRemove = Sets.difference(new HashSet<>(previousTags), new HashSet<>(desiredTags)); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(updateAgreementRequest, client::updateAgreement); logger.log(String.format("%s updated successfully", ResourceModel.TYPE_NAME)); diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/AbstractTestBase.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/AbstractTestBase.java index 0b44013..2ba79a5 100644 --- a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/AbstractTestBase.java +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/AbstractTestBase.java @@ -1,39 +1,135 @@ package software.amazon.transfer.agreement; +import static org.mockito.Mockito.mock; + +import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -public class AbstractTestBase { - - public static String TEST_ARN = "arn:test-arn"; - public static String TEST_DESCRIPTION = "unit test"; - public static String TEST_DESCRIPTION_2 = "another unit test"; - public static String TEST_ACCESS_ROLE = "access-role"; - public static String TEST_BASE_DIRECTORY = "/"; - public static String TEST_LOCAL_PROFILE = "local-profile"; - public static String TEST_PARTNER_PROFILE = "partner-profile"; - public static String TEST_SERVER_ID = "test-server-id"; - public static String TEST_STATUS = "ACTIVE"; - public static String TEST_AGREEMENT_ID = "id"; - public static Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); - public static Map SYSTEM_TAG_MAP = +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; + +import software.amazon.awssdk.awscore.AwsRequest; +import software.amazon.awssdk.awscore.AwsResponse; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.pagination.sync.SdkIterable; +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Credentials; +import software.amazon.cloudformation.proxy.LoggerProxy; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +public abstract class AbstractTestBase { + + public static final String TEST_ARN = "arn:test-arn"; + public static final String TEST_DESCRIPTION = "unit test"; + public static final String TEST_DESCRIPTION_2 = "another unit test"; + public static final String TEST_ACCESS_ROLE = "access-role"; + public static final String TEST_BASE_DIRECTORY = "/"; + public static final String TEST_LOCAL_PROFILE = "local-profile"; + public static final String TEST_PARTNER_PROFILE = "partner-profile"; + public static final String TEST_SERVER_ID = "test-server-id"; + public static final String TEST_STATUS = "ACTIVE"; + public static final String TEST_AGREEMENT_ID = "id"; + public static final Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); + public static final Map SYSTEM_TAG_MAP = Collections.singletonMap("aws:cloudformation:stack-name", "StackName"); - public static Map TEST_TAG_MAP = + public static final Map TEST_TAG_MAP = ImmutableMap.of("key", "value", "aws:cloudformation:stack-name", "StackName"); - public static Set MODEL_TAGS = + public static final Set MODEL_TAGS = ImmutableSet.of(Tag.builder().key("key").value("value").build()); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("key") .value("value") .build(); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("aws:cloudformation:stack-name") .value("StackName") .build(); + + abstract MockableBaseHandler getHandler(); + + protected ProgressEvent callHandler(ResourceHandlerRequest request) { + return getHandler().handleRequest(proxy, request, null, proxyClient, logger); + } + + protected static final Credentials MOCK_CREDENTIALS; + protected static final LoggerProxy logger; + + static { + MOCK_CREDENTIALS = new Credentials("accessKey", "secretKey", "token"); + logger = new LoggerProxy(); + } + + protected AmazonWebServicesClientProxy proxy; + + protected ProxyClient proxyClient; + + @Mock + protected TransferClient client; + + @BeforeEach + public void setup() { + proxy = new AmazonWebServicesClientProxy( + logger, MOCK_CREDENTIALS, () -> Duration.ofSeconds(600).toMillis()); + client = mock(TransferClient.class); + proxyClient = MOCK_PROXY(proxy, client); + } + + static ProxyClient MOCK_PROXY(final AmazonWebServicesClientProxy proxy, final T sdkClient) { + return new ProxyClient() { + @Override + public ResponseT injectCredentialsAndInvokeV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeV2(request, requestFunction); + } + + @Override + public + CompletableFuture injectCredentialsAndInvokeV2Async( + RequestT request, Function> requestFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public < + RequestT extends AwsRequest, + ResponseT extends AwsResponse, + IterableT extends SdkIterable> + IterableT injectCredentialsAndInvokeIterableV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeIterableV2(request, requestFunction); + } + + @Override + public + ResponseInputStream injectCredentialsAndInvokeV2InputStream( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public + ResponseBytes injectCredentialsAndInvokeV2Bytes( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public T client() { + return sdkClient; + } + }; + } } diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/BaseHandlerStdTest.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/BaseHandlerStdTest.java new file mode 100644 index 0000000..654f0ca --- /dev/null +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/BaseHandlerStdTest.java @@ -0,0 +1,56 @@ +package software.amazon.transfer.agreement; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +@ExtendWith(MockitoExtension.class) +public class BaseHandlerStdTest { + @Mock + private AmazonWebServicesClientProxy proxy; + + static class MockTestHandler extends BaseHandlerStd { + @Override + public ProgressEvent handleRequest( + AmazonWebServicesClientProxy proxy, + ResourceHandlerRequest request, + CallbackContext callbackContext, + ProxyClient proxyClient, + Logger logger) { + assertNotNull(callbackContext); + return null; + } + } + + @Test + void justToCover3LinesOfCode() { + var uut = new MockTestHandler(); + + // Check with null CallbackContext + uut.handleRequest(proxy, null, null, null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + + // Check with non-null CallbackContext + uut.handleRequest(proxy, null, new CallbackContext(), null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + } +} diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/CreateHandlerTest.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/CreateHandlerTest.java index de512ed..c11ff18 100644 --- a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/CreateHandlerTest.java +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/CreateHandlerTest.java @@ -6,15 +6,13 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; -import static software.amazon.transfer.agreement.AbstractTestBase.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.CreateAgreementRequest; import software.amazon.awssdk.services.transfer.model.CreateAgreementResponse; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -27,27 +25,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; import software.amazon.cloudformation.exceptions.CfnThrottlingException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class CreateHandlerTest { - @Mock - private AmazonWebServicesClientProxy proxy; +public class CreateHandlerTest extends AbstractTestBase { - @Mock - private Logger logger; + private MockableBaseHandler handler; - @Mock - private TransferClient client; + @Override + MockableBaseHandler getHandler() { + return handler; + } + + @BeforeEach + public void setupTestData() { + handler = new CreateHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final CreateHandler handler = new CreateHandler(client); - final ResourceModel model = ResourceModel.builder() .accessRole(TEST_ACCESS_ROLE) .baseDirectory(TEST_BASE_DIRECTORY) @@ -67,10 +65,9 @@ public void handleRequest_SimpleSuccess() { CreateAgreementResponse createAgreementResponse = CreateAgreementResponse.builder().agreementId(TEST_AGREEMENT_ID).build(); - doReturn(createAgreementResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(createAgreementResponse).when(client).createAgreement(any(CreateAgreementRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -90,16 +87,14 @@ public void handleRequest_SimpleSuccess() { assertThat(testModel).hasFieldOrPropertyWithValue("status", TEST_STATUS); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CreateAgreementRequest.class); - verify(proxy).injectCredentialsAndInvokeV2(requestCaptor.capture(), any()); + verify(client).createAgreement(requestCaptor.capture()); CreateAgreementRequest actualRequest = requestCaptor.getValue(); assertThat(actualRequest.tags()).containsExactlyInAnyOrder(SDK_MODEL_TAG, SDK_SYSTEM_TAG); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).createAgreement(any(CreateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -107,16 +102,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class).when(client).createAgreement(any(CreateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -124,16 +115,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceExistsExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ResourceExistsException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(ResourceExistsException.class).when(client).createAgreement(any(CreateAgreementRequest.class)); ResourceModel model = ResourceModel.builder() .agreementId(TEST_AGREEMENT_ID) @@ -144,16 +131,12 @@ public void handleRequest_ResourceExistsExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnAlreadyExistsException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnAlreadyExistsException.class, () -> callHandler(request)); } @Test public void handleRequest_ThrottlingExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ThrottlingException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(ThrottlingException.class).when(client).createAgreement(any(CreateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -161,16 +144,12 @@ public void handleRequest_ThrottlingExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnThrottlingException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnThrottlingException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).createAgreement(any(CreateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -178,8 +157,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/DeleteHandlerTest.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/DeleteHandlerTest.java index 8eec9ac..50f879e 100644 --- a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/DeleteHandlerTest.java +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/DeleteHandlerTest.java @@ -6,12 +6,12 @@ import static org.mockito.Mockito.doThrow; import static software.amazon.transfer.agreement.AbstractTestBase.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.awssdk.services.transfer.model.DeleteAgreementRequest; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; @@ -20,28 +20,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class DeleteHandlerTest { +public class DeleteHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new DeleteHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final DeleteHandler handler = new DeleteHandler(client); - final ResourceModel model = ResourceModel.builder().agreementId(TEST_AGREEMENT_ID).build(); @@ -49,8 +48,7 @@ public void handleRequest_SimpleSuccess() { .desiredResourceState(model) .build(); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -64,9 +62,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).deleteAgreement(any(DeleteAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -74,16 +70,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class).when(client).deleteAgreement(any(DeleteAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -91,16 +83,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(ResourceNotFoundException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(ResourceNotFoundException.class).when(client).deleteAgreement(any(DeleteAgreementRequest.class)); ResourceModel model = ResourceModel.builder() .agreementId(TEST_AGREEMENT_ID) @@ -111,16 +99,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).deleteAgreement(any(DeleteAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -128,8 +112,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ListHandlerTest.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ListHandlerTest.java index 29c55b1..a54b2c9 100644 --- a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ListHandlerTest.java +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ListHandlerTest.java @@ -9,42 +9,41 @@ import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; +import software.amazon.awssdk.services.transfer.model.ListAgreementsRequest; import software.amazon.awssdk.services.transfer.model.ListAgreementsResponse; import software.amazon.awssdk.services.transfer.model.ListedAgreement; import software.amazon.awssdk.services.transfer.model.TransferException; import software.amazon.cloudformation.exceptions.CfnGeneralServiceException; import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ListHandlerTest { +public class ListHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new ListHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final ListHandler handler = new ListHandler(client); - ListedAgreement listedAgreement = ListedAgreement.builder() .arn(TEST_ARN) .agreementId(TEST_AGREEMENT_ID) @@ -64,9 +63,9 @@ public void handleRequest_SimpleSuccess() { ListAgreementsResponse listAgreementsResponse = ListAgreementsResponse.builder().agreements(listedAgreement).build(); - doReturn(listAgreementsResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(listAgreementsResponse).when(client).listAgreements(any(ListAgreementsRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); List testModels = response.getResourceModels(); @@ -92,9 +91,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).listAgreements(any(ListAgreementsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -102,16 +99,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class).when(client).listAgreements(any(ListAgreementsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -119,16 +112,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).listAgreements(any(ListAgreementsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -136,8 +125,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ReadHandlerTest.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ReadHandlerTest.java index ba77e03..bd0188a 100644 --- a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ReadHandlerTest.java +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/ReadHandlerTest.java @@ -7,12 +7,12 @@ import static org.mockito.Mockito.doThrow; import static software.amazon.transfer.agreement.AbstractTestBase.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.awssdk.services.transfer.model.DescribeAgreementRequest; import software.amazon.awssdk.services.transfer.model.DescribeAgreementResponse; import software.amazon.awssdk.services.transfer.model.DescribedAgreement; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -23,28 +23,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ReadHandlerTest { +public class ReadHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new ReadHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final ReadHandler handler = new ReadHandler(client); - ResourceModel model = ResourceModel.builder().agreementId(TEST_AGREEMENT_ID).build(); @@ -58,9 +57,9 @@ public void handleRequest_SimpleSuccess() { .status(TEST_STATUS) .build()) .build(); - doReturn(describeAgreementResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(describeAgreementResponse).when(client).describeAgreement(any(DescribeAgreementRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -75,9 +74,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).describeAgreement(any(DescribeAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -85,16 +82,14 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class) + .when(client) + .describeAgreement(any(DescribeAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -102,16 +97,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(ResourceNotFoundException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(ResourceNotFoundException.class).when(client).describeAgreement(any(DescribeAgreementRequest.class)); ResourceModel model = ResourceModel.builder() .agreementId(TEST_AGREEMENT_ID) @@ -122,16 +113,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).describeAgreement(any(DescribeAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -139,8 +126,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/UpdateHandlerTest.java b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/UpdateHandlerTest.java index 4fcf75c..999aae8 100644 --- a/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/UpdateHandlerTest.java +++ b/aws-transfer-agreement/src/test/java/software/amazon/transfer/agreement/UpdateHandlerTest.java @@ -12,18 +12,16 @@ import java.util.Set; import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; import software.amazon.awssdk.services.transfer.model.TagResourceRequest; import software.amazon.awssdk.services.transfer.model.TransferException; -import software.amazon.awssdk.services.transfer.model.TransferRequest; import software.amazon.awssdk.services.transfer.model.UntagResourceRequest; import software.amazon.awssdk.services.transfer.model.UpdateAgreementRequest; import software.amazon.awssdk.services.transfer.model.UpdateAgreementResponse; @@ -31,28 +29,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class UpdateHandlerTest { +public class UpdateHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new UpdateHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final UpdateHandler handler = new UpdateHandler(client); - ResourceModel model = ResourceModel.builder() .agreementId(TEST_AGREEMENT_ID) .description(TEST_DESCRIPTION_2) @@ -64,9 +61,9 @@ public void handleRequest_SimpleSuccess() { UpdateAgreementResponse updateAgreementRequest = UpdateAgreementResponse.builder().agreementId(TEST_AGREEMENT_ID).build(); - doReturn(updateAgreementRequest).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(updateAgreementRequest).when(client).updateAgreement(any(UpdateAgreementRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -78,12 +75,11 @@ public void handleRequest_SimpleSuccess() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(testModel).hasFieldOrPropertyWithValue("description", TEST_DESCRIPTION_2); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateAgreementRequest.class), any()); + verify(client, times(1)).updateAgreement(any(UpdateAgreementRequest.class)); } @Test public void handleRequest_AddTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set desiredTags = TEST_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -97,7 +93,7 @@ public void handleRequest_AddTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -108,13 +104,12 @@ public void handleRequest_AddTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(desiredTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(TagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateAgreementRequest.class), any()); + verify(client, times(1)).tagResource(any(TagResourceRequest.class)); + verify(client, times(1)).updateAgreement(any(UpdateAgreementRequest.class)); } @Test public void handleRequest_RemoveTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set systemTags = SYSTEM_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -128,7 +123,7 @@ public void handleRequest_RemoveTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -139,15 +134,13 @@ public void handleRequest_RemoveTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(systemTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UntagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateAgreementRequest.class), any()); + verify(client, times(1)).untagResource(any(UntagResourceRequest.class)); + verify(client, times(1)).updateAgreement(any(UpdateAgreementRequest.class)); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).updateAgreement(any(UpdateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -157,18 +150,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).updateAgreement(any(UpdateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -178,18 +165,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).updateAgreement(any(UpdateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -199,16 +180,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(TransferException.class).when(client).updateAgreement(any(UpdateAgreementRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -218,8 +195,6 @@ public void handleRequest_TransferExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-certificate/spotbugs-exclude.xml b/aws-transfer-certificate/spotbugs-exclude.xml new file mode 100644 index 0000000..46f154c --- /dev/null +++ b/aws-transfer-certificate/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/BaseHandlerStd.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/BaseHandlerStd.java new file mode 100644 index 0000000..7efd651 --- /dev/null +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/BaseHandlerStd.java @@ -0,0 +1,40 @@ +package software.amazon.transfer.certificate; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * The purpose of this base class is to allow a simple calling pattern that + * makes testing Uluru handlers easier and avoids having to store context + * in class fields. The {@link MockableBaseHandler} interface is used to + * make isolation of the inner call such that in testing we guarantee that + * the caller will not pick the wrong method and avoid human error. + */ +public abstract class BaseHandlerStd extends BaseHandler + implements MockableBaseHandler { + @Override + public final ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final Logger logger) { + return handleRequest( + proxy, + request, + callbackContext != null ? callbackContext : new CallbackContext(), + proxy.newProxy(ClientBuilder::getClient), + logger); + } + + @Override + public abstract ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/CreateHandler.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/CreateHandler.java index 1f23a75..86377f8 100644 --- a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/CreateHandler.java +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/CreateHandler.java @@ -22,6 +22,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -29,24 +30,15 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class CreateHandler extends BaseHandler { - private TransferClient client; - - public CreateHandler(TransferClient client) { - this.client = client; - } - +public class CreateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - ResourceModel model = request.getDesiredResourceState(); Map allTags = new HashMap<>(); @@ -79,7 +71,7 @@ public ProgressEvent handleRequest( .map(Converter.TagConverter::toSdk) .collect(Collectors.toList())) .build(); - try { + try (TransferClient client = proxyClient.client()) { ImportCertificateResponse response = proxy.injectCredentialsAndInvokeV2(importCertificateRequest, client::importCertificate); model.setCertificateId(response.certificateId()); diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/DeleteHandler.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/DeleteHandler.java index 0096d37..e0a3305 100644 --- a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/DeleteHandler.java +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/DeleteHandler.java @@ -14,35 +14,27 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class DeleteHandler extends BaseHandler { - private TransferClient client; - - public DeleteHandler(TransferClient client) { - this.client = client; - } - +public class DeleteHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); final DeleteCertificateRequest deleteCertificateRequest = DeleteCertificateRequest.builder() .certificateId(model.getCertificateId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(deleteCertificateRequest, client::deleteCertificate); logger.log( String.format("%s %s deleted successfully", ResourceModel.TYPE_NAME, model.getPrimaryIdentifier())); diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ListHandler.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ListHandler.java index 6f4315e..7b6dbbf 100644 --- a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ListHandler.java +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ListHandler.java @@ -16,29 +16,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class ListHandler extends BaseHandler { - private TransferClient client; - - public ListHandler(TransferClient client) { - this.client = client; - } - +public class ListHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - List models = new ArrayList<>(); ListCertificatesRequest listCertificatesRequest = ListCertificatesRequest.builder() @@ -46,7 +38,7 @@ public ProgressEvent handleRequest( .nextToken(request.getNextToken()) .build(); - try { + try (TransferClient client = proxyClient.client()) { ListCertificatesResponse response = proxy.injectCredentialsAndInvokeV2(listCertificatesRequest, client::listCertificates); diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/MockableBaseHandler.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/MockableBaseHandler.java new file mode 100644 index 0000000..26be8a4 --- /dev/null +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/MockableBaseHandler.java @@ -0,0 +1,24 @@ +package software.amazon.transfer.certificate; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * Interface exposing the only handler method that should be used when + * testing Uluru handlers. This provides a mechanism to feed the call chain + * a mock client as needed without complex static mocking of the ClientBuilder. + * + * @param + */ +interface MockableBaseHandler { + ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackT callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ReadHandler.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ReadHandler.java index a03c700..5b80228 100644 --- a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ReadHandler.java +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/ReadHandler.java @@ -18,6 +18,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -25,30 +26,21 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class ReadHandler extends BaseHandler { - private TransferClient client; - - public ReadHandler(TransferClient client) { - this.client = client; - } - +public class ReadHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); DescribeCertificateRequest describeCertificateRequest = DescribeCertificateRequest.builder() .certificateId(model.getCertificateId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { DescribeCertificateResponse response = proxy.injectCredentialsAndInvokeV2(describeCertificateRequest, client::describeCertificate); logger.log(String.format( diff --git a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/UpdateHandler.java b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/UpdateHandler.java index 660659d..5a34b7a 100644 --- a/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/UpdateHandler.java +++ b/aws-transfer-certificate/src/main/java/software/amazon/transfer/certificate/UpdateHandler.java @@ -25,28 +25,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class UpdateHandler extends BaseHandler { - private TransferClient client; - - public UpdateHandler(TransferClient client) { - this.client = client; - } - +public class UpdateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } final ResourceModel model = request.getDesiredResourceState(); UpdateCertificateRequest updateCertificateRequest = UpdateCertificateRequest.builder() @@ -75,7 +68,7 @@ public ProgressEvent handleRequest( Set tagsToAdd = Sets.difference(new HashSet<>(desiredTags), new HashSet<>(previousTags)); Set tagsToRemove = Sets.difference(new HashSet<>(previousTags), new HashSet<>(desiredTags)); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(updateCertificateRequest, client::updateCertificate); logger.log(String.format("%s created successfully", ResourceModel.TYPE_NAME)); diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/AbstractTestBase.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/AbstractTestBase.java index 7577f0d..7c56e88 100644 --- a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/AbstractTestBase.java +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/AbstractTestBase.java @@ -1,15 +1,34 @@ package software.amazon.transfer.certificate; +import static org.mockito.Mockito.mock; + +import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -public class AbstractTestBase { - private AbstractTestBase() {} +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; + +import software.amazon.awssdk.awscore.AwsRequest; +import software.amazon.awssdk.awscore.AwsResponse; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.pagination.sync.SdkIterable; +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Credentials; +import software.amazon.cloudformation.proxy.LoggerProxy; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; +public abstract class AbstractTestBase { public static final String TEST_CERTIFICATE_ID = "id"; public static final String TEST_ARN = "arn:certificate"; public static final String TEST_DESCRIPTION = "description"; @@ -20,21 +39,96 @@ private AbstractTestBase() {} public static final String TEST_PRIVATE_KEY = "private-key"; public static final String TEST_ACTIVE_DATE = "2022-07-17T09:59:51.312Z"; public static final String TEST_INACTIVE_DATE = "2069-07-17T09:59:51.312Z"; - public static Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); - public static Map SYSTEM_TAG_MAP = + public static final Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); + public static final Map SYSTEM_TAG_MAP = Collections.singletonMap("aws:cloudformation:stack-name", "StackName"); - public static Map TEST_TAG_MAP = + public static final Map TEST_TAG_MAP = ImmutableMap.of("key", "value", "aws:cloudformation:stack-name", "StackName"); - public static Set MODEL_TAGS = + public static final Set MODEL_TAGS = ImmutableSet.of(Tag.builder().key("key").value("value").build()); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("key") .value("value") .build(); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("aws:cloudformation:stack-name") .value("StackName") .build(); + + abstract MockableBaseHandler getHandler(); + + protected ProgressEvent callHandler(ResourceHandlerRequest request) { + return getHandler().handleRequest(proxy, request, null, proxyClient, logger); + } + + protected static final Credentials MOCK_CREDENTIALS; + protected static final LoggerProxy logger; + + static { + MOCK_CREDENTIALS = new Credentials("accessKey", "secretKey", "token"); + logger = new LoggerProxy(); + } + + protected AmazonWebServicesClientProxy proxy; + + protected ProxyClient proxyClient; + + @Mock + protected TransferClient client; + + @BeforeEach + public void setup() { + proxy = new AmazonWebServicesClientProxy( + logger, MOCK_CREDENTIALS, () -> Duration.ofSeconds(600).toMillis()); + client = mock(TransferClient.class); + proxyClient = MOCK_PROXY(proxy, client); + } + + static ProxyClient MOCK_PROXY(final AmazonWebServicesClientProxy proxy, final T sdkClient) { + return new ProxyClient() { + @Override + public ResponseT injectCredentialsAndInvokeV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeV2(request, requestFunction); + } + + @Override + public + CompletableFuture injectCredentialsAndInvokeV2Async( + RequestT request, Function> requestFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public < + RequestT extends AwsRequest, + ResponseT extends AwsResponse, + IterableT extends SdkIterable> + IterableT injectCredentialsAndInvokeIterableV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeIterableV2(request, requestFunction); + } + + @Override + public + ResponseInputStream injectCredentialsAndInvokeV2InputStream( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public + ResponseBytes injectCredentialsAndInvokeV2Bytes( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public T client() { + return sdkClient; + } + }; + } } diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/BaseHandlerStdTest.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/BaseHandlerStdTest.java new file mode 100644 index 0000000..ad36092 --- /dev/null +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/BaseHandlerStdTest.java @@ -0,0 +1,56 @@ +package software.amazon.transfer.certificate; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +@ExtendWith(MockitoExtension.class) +public class BaseHandlerStdTest { + @Mock + private AmazonWebServicesClientProxy proxy; + + static class MockTestHandler extends BaseHandlerStd { + @Override + public ProgressEvent handleRequest( + AmazonWebServicesClientProxy proxy, + ResourceHandlerRequest request, + CallbackContext callbackContext, + ProxyClient proxyClient, + Logger logger) { + assertNotNull(callbackContext); + return null; + } + } + + @Test + void justToCover3LinesOfCode() { + var uut = new MockTestHandler(); + + // Check with null CallbackContext + uut.handleRequest(proxy, null, null, null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + + // Check with non-null CallbackContext + uut.handleRequest(proxy, null, new CallbackContext(), null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + } +} diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/CreateHandlerTest.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/CreateHandlerTest.java index 4d1507d..08b3e17 100644 --- a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/CreateHandlerTest.java +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/CreateHandlerTest.java @@ -6,15 +6,13 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; -import static software.amazon.transfer.certificate.AbstractTestBase.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.ImportCertificateRequest; import software.amazon.awssdk.services.transfer.model.ImportCertificateResponse; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -27,28 +25,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; import software.amazon.cloudformation.exceptions.CfnThrottlingException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class CreateHandlerTest { +public class CreateHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new CreateHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final CreateHandler handler = new CreateHandler(client); - final ResourceModel model = ResourceModel.builder() .description(TEST_DESCRIPTION) .usage(TEST_USAGE) @@ -69,10 +66,9 @@ public void handleRequest_SimpleSuccess() { ImportCertificateResponse importCertificateResponse = ImportCertificateResponse.builder() .certificateId(TEST_CERTIFICATE_ID) .build(); - doReturn(importCertificateResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(importCertificateResponse).when(client).importCertificate(any(ImportCertificateRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -93,16 +89,14 @@ public void handleRequest_SimpleSuccess() { ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(ImportCertificateRequest.class); - verify(proxy).injectCredentialsAndInvokeV2(requestCaptor.capture(), any()); + verify(client).importCertificate(requestCaptor.capture()); ImportCertificateRequest actualRequest = requestCaptor.getValue(); assertThat(actualRequest.tags()).containsExactlyInAnyOrder(SDK_MODEL_TAG, SDK_SYSTEM_TAG); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).importCertificate(any(ImportCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -110,18 +104,14 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ImportCertificateRequest.class), any()); + .when(client) + .importCertificate(any(ImportCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -129,18 +119,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceExistsExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ResourceExistsException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ImportCertificateRequest.class), any()); + doThrow(ResourceExistsException.class).when(client).importCertificate(any(ImportCertificateRequest.class)); ResourceModel model = ResourceModel.builder().certificateId("testId").build(); @@ -148,18 +132,12 @@ public void handleRequest_ResourceExistsExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnAlreadyExistsException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnAlreadyExistsException.class, () -> callHandler(request)); } @Test public void handleRequest_ThrottlingExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ThrottlingException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ImportCertificateRequest.class), any()); + doThrow(ThrottlingException.class).when(client).importCertificate(any(ImportCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -167,18 +145,12 @@ public void handleRequest_ThrottlingExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnThrottlingException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnThrottlingException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ImportCertificateRequest.class), any()); + doThrow(TransferException.class).when(client).importCertificate(any(ImportCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -186,8 +158,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/DeleteHandlerTest.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/DeleteHandlerTest.java index 2596b06..b152b7d 100644 --- a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/DeleteHandlerTest.java +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/DeleteHandlerTest.java @@ -6,12 +6,12 @@ import static org.mockito.Mockito.doThrow; import static software.amazon.transfer.certificate.AbstractTestBase.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.awssdk.services.transfer.model.DeleteCertificateRequest; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; @@ -20,28 +20,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class DeleteHandlerTest { +public class DeleteHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new DeleteHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final DeleteHandler handler = new DeleteHandler(client); - final ResourceModel model = ResourceModel.builder().certificateId(TEST_CERTIFICATE_ID).build(); @@ -49,8 +48,7 @@ public void handleRequest_SimpleSuccess() { .desiredResourceState(model) .build(); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -63,9 +61,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).deleteCertificate(any(DeleteCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -73,16 +69,14 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class) + .when(client) + .deleteCertificate(any(DeleteCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -90,16 +84,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(ResourceNotFoundException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(ResourceNotFoundException.class).when(client).deleteCertificate(any(DeleteCertificateRequest.class)); ResourceModel model = ResourceModel.builder().certificateId(TEST_CERTIFICATE_ID).build(); @@ -108,16 +98,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).deleteCertificate(any(DeleteCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -125,8 +111,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ListHandlerTest.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ListHandlerTest.java index b2df19c..fb20c2a 100644 --- a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ListHandlerTest.java +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ListHandlerTest.java @@ -9,42 +9,41 @@ import java.util.List; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; +import software.amazon.awssdk.services.transfer.model.ListCertificatesRequest; import software.amazon.awssdk.services.transfer.model.ListCertificatesResponse; import software.amazon.awssdk.services.transfer.model.ListedCertificate; import software.amazon.awssdk.services.transfer.model.TransferException; import software.amazon.cloudformation.exceptions.CfnGeneralServiceException; import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ListHandlerTest { +public class ListHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new ListHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final ListHandler handler = new ListHandler(client); - ListedCertificate listedCertificate = ListedCertificate.builder() .description(TEST_DESCRIPTION) .arn(TEST_ARN) @@ -61,10 +60,9 @@ public void handleRequest_SimpleSuccess() { ListCertificatesResponse listCertificatesResponse = ListCertificatesResponse.builder() .certificates(listedCertificate) .build(); - doReturn(listCertificatesResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(listCertificatesResponse).when(client).listCertificates(any(ListCertificatesRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); List testModels = response.getResourceModels(); @@ -86,9 +84,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).listCertificates(any(ListCertificatesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -96,16 +92,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class).when(client).listCertificates(any(ListCertificatesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -113,16 +105,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).listCertificates(any(ListCertificatesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -130,8 +118,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ReadHandlerTest.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ReadHandlerTest.java index 3568c7d..ec8eb25 100644 --- a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ReadHandlerTest.java +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/ReadHandlerTest.java @@ -7,12 +7,12 @@ import static org.mockito.Mockito.doThrow; import static software.amazon.transfer.certificate.AbstractTestBase.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.awssdk.services.transfer.model.DescribeCertificateRequest; import software.amazon.awssdk.services.transfer.model.DescribeCertificateResponse; import software.amazon.awssdk.services.transfer.model.DescribedCertificate; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -23,28 +23,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ReadHandlerTest { +public class ReadHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new ReadHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final ReadHandler handler = new ReadHandler(client); - final ResourceModel model = ResourceModel.builder().certificateId(TEST_CERTIFICATE_ID).build(); @@ -57,10 +56,9 @@ public void handleRequest_SimpleSuccess() { .description(TEST_DESCRIPTION) .build()) .build(); - doReturn(describeCertificateResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(describeCertificateResponse).when(client).describeCertificate(any(DescribeCertificateRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -75,9 +73,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).describeCertificate(any(DescribeCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -85,16 +81,14 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InternalServiceErrorException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InternalServiceErrorException.class) + .when(client) + .describeCertificate(any(DescribeCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -102,16 +96,14 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(ResourceNotFoundException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(ResourceNotFoundException.class) + .when(client) + .describeCertificate(any(DescribeCertificateRequest.class)); ResourceModel model = ResourceModel.builder().certificateId(TEST_CERTIFICATE_ID).build(); @@ -120,16 +112,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(TransferException.class).when(client).describeCertificate(any(DescribeCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -137,8 +125,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/UpdateHandlerTest.java b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/UpdateHandlerTest.java index 0378d13..5f39965 100644 --- a/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/UpdateHandlerTest.java +++ b/aws-transfer-certificate/src/test/java/software/amazon/transfer/certificate/UpdateHandlerTest.java @@ -12,18 +12,16 @@ import java.util.Set; import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; import software.amazon.awssdk.services.transfer.model.TagResourceRequest; import software.amazon.awssdk.services.transfer.model.TransferException; -import software.amazon.awssdk.services.transfer.model.TransferRequest; import software.amazon.awssdk.services.transfer.model.UntagResourceRequest; import software.amazon.awssdk.services.transfer.model.UpdateCertificateRequest; import software.amazon.awssdk.services.transfer.model.UpdateCertificateResponse; @@ -31,28 +29,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class UpdateHandlerTest { +public class UpdateHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new UpdateHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final UpdateHandler handler = new UpdateHandler(client); - final ResourceModel model = ResourceModel.builder() .certificateId(TEST_CERTIFICATE_ID) .description(TEST_DESCRIPTION_2) @@ -65,10 +62,9 @@ public void handleRequest_SimpleSuccess() { UpdateCertificateResponse updateCertificateRequest = UpdateCertificateResponse.builder() .certificateId(TEST_CERTIFICATE_ID) .build(); - doReturn(updateCertificateRequest).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(updateCertificateRequest).when(client).updateCertificate(any(UpdateCertificateRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -80,12 +76,11 @@ public void handleRequest_SimpleSuccess() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(testModel).hasFieldOrPropertyWithValue("description", TEST_DESCRIPTION_2); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateCertificateRequest.class), any()); + verify(client, times(1)).updateCertificate(any(UpdateCertificateRequest.class)); } @Test public void handleRequest_AddTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set desiredTags = TEST_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -99,7 +94,7 @@ public void handleRequest_AddTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -110,13 +105,12 @@ public void handleRequest_AddTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(desiredTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(TagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateCertificateRequest.class), any()); + verify(client, times(1)).tagResource(any(TagResourceRequest.class)); + verify(client, times(1)).updateCertificate(any(UpdateCertificateRequest.class)); } @Test public void handleRequest_RemoveTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set systemTags = SYSTEM_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -130,7 +124,7 @@ public void handleRequest_RemoveTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -141,15 +135,13 @@ public void handleRequest_RemoveTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(systemTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UntagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateCertificateRequest.class), any()); + verify(client, times(1)).untagResource(any(UntagResourceRequest.class)); + verify(client, times(1)).updateCertificate(any(UpdateCertificateRequest.class)); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).updateCertificate(any(UpdateCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -159,18 +151,14 @@ public void handleRequest_InvalidRequestExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + .when(client) + .updateCertificate(any(UpdateCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -180,18 +168,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).updateCertificate(any(UpdateCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -201,16 +183,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(TransferException.class).when(client).updateCertificate(any(UpdateCertificateRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -220,8 +198,6 @@ public void handleRequest_TransferExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-connector/spotbugs-exclude.xml b/aws-transfer-connector/spotbugs-exclude.xml new file mode 100644 index 0000000..4141626 --- /dev/null +++ b/aws-transfer-connector/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/BaseHandlerStd.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/BaseHandlerStd.java new file mode 100644 index 0000000..2be20e2 --- /dev/null +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/BaseHandlerStd.java @@ -0,0 +1,40 @@ +package software.amazon.transfer.connector; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * The purpose of this base class is to allow a simple calling pattern that + * makes testing Uluru handlers easier and avoids having to store context + * in class fields. The {@link MockableBaseHandler} interface is used to + * make isolation of the inner call such that in testing we guarantee that + * the caller will not pick the wrong method and avoid human error. + */ +public abstract class BaseHandlerStd extends BaseHandler + implements MockableBaseHandler { + @Override + public final ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final Logger logger) { + return handleRequest( + proxy, + request, + callbackContext != null ? callbackContext : new CallbackContext(), + proxy.newProxy(ClientBuilder::getClient), + logger); + } + + @Override + public abstract ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/CreateHandler.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/CreateHandler.java index bd4e49f..ec17e83 100644 --- a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/CreateHandler.java +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/CreateHandler.java @@ -21,6 +21,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -28,24 +29,15 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class CreateHandler extends BaseHandler { - private TransferClient client; - - public CreateHandler(TransferClient client) { - this.client = client; - } - +public class CreateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); Map allTags = new HashMap<>(); @@ -75,7 +67,7 @@ public ProgressEvent handleRequest( .collect(Collectors.toList())) .build(); - try { + try (TransferClient client = proxyClient.client()) { CreateConnectorResponse response = proxy.injectCredentialsAndInvokeV2(createConnectorRequest, client::createConnector); model.setConnectorId(response.connectorId()); diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/DeleteHandler.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/DeleteHandler.java index c375077..b3ab052 100644 --- a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/DeleteHandler.java +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/DeleteHandler.java @@ -14,36 +14,28 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class DeleteHandler extends BaseHandler { - private TransferClient client; - - public DeleteHandler(TransferClient client) { - this.client = client; - } - +public class DeleteHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); final DeleteConnectorRequest deleteConnectorRequest = DeleteConnectorRequest.builder() .connectorId(model.getConnectorId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(deleteConnectorRequest, client::deleteConnector); logger.log( String.format("%s %s deleted successfully", ResourceModel.TYPE_NAME, model.getPrimaryIdentifier())); diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ListHandler.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ListHandler.java index 521c011..6c46304 100644 --- a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ListHandler.java +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ListHandler.java @@ -16,29 +16,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class ListHandler extends BaseHandler { - private TransferClient client; - - public ListHandler(TransferClient client) { - this.client = client; - } - +public class ListHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final List models = new ArrayList<>(); ListConnectorsRequest listConnectorsRequest = ListConnectorsRequest.builder() @@ -46,7 +38,7 @@ public ProgressEvent handleRequest( .nextToken(request.getNextToken()) .build(); - try { + try (TransferClient client = proxyClient.client()) { ListConnectorsResponse response = proxy.injectCredentialsAndInvokeV2(listConnectorsRequest, client::listConnectors); diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/MockableBaseHandler.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/MockableBaseHandler.java new file mode 100644 index 0000000..fa4ae09 --- /dev/null +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/MockableBaseHandler.java @@ -0,0 +1,24 @@ +package software.amazon.transfer.connector; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * Interface exposing the only handler method that should be used when + * testing Uluru handlers. This provides a mechanism to feed the call chain + * a mock client as needed without complex static mocking of the ClientBuilder. + * + * @param + */ +interface MockableBaseHandler { + ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackT callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ReadHandler.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ReadHandler.java index 9a74c9b..3001140 100644 --- a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ReadHandler.java +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/ReadHandler.java @@ -18,6 +18,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -25,30 +26,21 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class ReadHandler extends BaseHandler { - private TransferClient client; - - public ReadHandler(TransferClient client) { - this.client = client; - } - +public class ReadHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); DescribeConnectorRequest describeConnectorRequest = DescribeConnectorRequest.builder() .connectorId(model.getConnectorId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { DescribeConnectorResponse response = proxy.injectCredentialsAndInvokeV2(describeConnectorRequest, client::describeConnector); logger.log(String.format( diff --git a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/UpdateHandler.java b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/UpdateHandler.java index 84f6fa0..7e26705 100644 --- a/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/UpdateHandler.java +++ b/aws-transfer-connector/src/main/java/software/amazon/transfer/connector/UpdateHandler.java @@ -24,29 +24,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class UpdateHandler extends BaseHandler { - private TransferClient client; - - public UpdateHandler(TransferClient client) { - this.client = client; - } - +public class UpdateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); String arn = String.format( "arn:%s:transfer:%s:%s:connector/%s", @@ -76,7 +68,7 @@ public ProgressEvent handleRequest( Set tagsToAdd = Sets.difference(new HashSet<>(desiredTags), new HashSet<>(previousTags)); Set tagsToRemove = Sets.difference(new HashSet<>(previousTags), new HashSet<>(desiredTags)); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(updateConnectorRequest, client::updateConnector); logger.log(String.format("%s updated successfully", ResourceModel.TYPE_NAME)); diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/AbstractTestBase.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/AbstractTestBase.java index 5efd7f4..7becae2 100644 --- a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/AbstractTestBase.java +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/AbstractTestBase.java @@ -1,42 +1,64 @@ package software.amazon.transfer.connector; +import static org.mockito.Mockito.mock; + +import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -public class AbstractTestBase { - public static String TEST_ARN = "arn:test-arn"; - public static String TEST_ACCESS_ROLE = "access-role"; - public static String TEST_LOGGING_ROLE = "logging-role"; - public static String TEST_URL = "http://test.com/"; - public static String TEST_CONNECTOR_ID = "c-123456789"; - - public static String TEST_LOCAL_PROFILE = "local-profile"; - public static String TEST_PARTNER_PROFILE = "partner-profile"; - public static String TEST_MESSAGE_SUBJECT = "This is a test message subject."; - public static String TEST_COMPRESSION = "ZLIB"; - public static String TEST_ENCRYPTION_ALGORITHM = "AES128_CBC"; - public static String TEST_SIGNING_ALGORITHM = "SHA256"; - public static String TEST_MDN_SIGNING_ALGORITHM = "SHA256"; - public static String TEST_MDN_RESPONSE = "SYNC"; - public static String TEST_BASIC_AUTH_SECRET = "basic-auth-secret"; - public static String TEST_USER_SECRET_ID = "arn:aws:secretsmanager:us-east-1:123456789:secret:testest"; - public static Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); - public static Map SYSTEM_TAG_MAP = +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; + +import software.amazon.awssdk.awscore.AwsRequest; +import software.amazon.awssdk.awscore.AwsResponse; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.pagination.sync.SdkIterable; +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Credentials; +import software.amazon.cloudformation.proxy.LoggerProxy; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +public abstract class AbstractTestBase { + public static final String TEST_ARN = "arn:test-arn"; + public static final String TEST_ACCESS_ROLE = "access-role"; + public static final String TEST_LOGGING_ROLE = "logging-role"; + public static final String TEST_URL = "http://test.com/"; + public static final String TEST_CONNECTOR_ID = "c-123456789"; + + public static final String TEST_LOCAL_PROFILE = "local-profile"; + public static final String TEST_PARTNER_PROFILE = "partner-profile"; + public static final String TEST_MESSAGE_SUBJECT = "This is a test message subject."; + public static final String TEST_COMPRESSION = "ZLIB"; + public static final String TEST_ENCRYPTION_ALGORITHM = "AES128_CBC"; + public static final String TEST_SIGNING_ALGORITHM = "SHA256"; + public static final String TEST_MDN_SIGNING_ALGORITHM = "SHA256"; + public static final String TEST_MDN_RESPONSE = "SYNC"; + public static final String TEST_BASIC_AUTH_SECRET = "basic-auth-secret"; + public static final String TEST_USER_SECRET_ID = "arn:aws:secretsmanager:us-east-1:123456789:secret:testest"; + public static final String TEST_SECURITY_POLICY_NAME = "TransferSFTPConnectorSecurityPolicy-2023-07"; + public static final Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); + public static final Map SYSTEM_TAG_MAP = Collections.singletonMap("aws:cloudformation:stack-name", "StackName"); - public static Map TEST_TAG_MAP = + public static final Map TEST_TAG_MAP = ImmutableMap.of("key", "value", "aws:cloudformation:stack-name", "StackName"); - public static Set MODEL_TAGS = + public static final Set MODEL_TAGS = ImmutableSet.of(Tag.builder().key("key").value("value").build()); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("key") .value("value") .build(); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("aws:cloudformation:stack-name") .value("StackName") @@ -62,4 +84,79 @@ public static SftpConfig getSftpConfig() { .trustedHostKeys(Collections.emptyList()) .build(); } + + abstract MockableBaseHandler getHandler(); + + protected ProgressEvent callHandler(ResourceHandlerRequest request) { + return getHandler().handleRequest(proxy, request, null, proxyClient, logger); + } + + protected static final Credentials MOCK_CREDENTIALS; + protected static final LoggerProxy logger; + + static { + MOCK_CREDENTIALS = new Credentials("accessKey", "secretKey", "token"); + logger = new LoggerProxy(); + } + + protected AmazonWebServicesClientProxy proxy; + + protected ProxyClient proxyClient; + + @Mock + protected TransferClient client; + + @BeforeEach + public void setup() { + proxy = new AmazonWebServicesClientProxy( + logger, MOCK_CREDENTIALS, () -> Duration.ofSeconds(600).toMillis()); + client = mock(TransferClient.class); + proxyClient = MOCK_PROXY(proxy, client); + } + + static ProxyClient MOCK_PROXY(final AmazonWebServicesClientProxy proxy, final T sdkClient) { + return new ProxyClient() { + @Override + public ResponseT injectCredentialsAndInvokeV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeV2(request, requestFunction); + } + + @Override + public + CompletableFuture injectCredentialsAndInvokeV2Async( + RequestT request, Function> requestFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public < + RequestT extends AwsRequest, + ResponseT extends AwsResponse, + IterableT extends SdkIterable> + IterableT injectCredentialsAndInvokeIterableV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeIterableV2(request, requestFunction); + } + + @Override + public + ResponseInputStream injectCredentialsAndInvokeV2InputStream( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public + ResponseBytes injectCredentialsAndInvokeV2Bytes( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public T client() { + return sdkClient; + } + }; + } } diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/BaseHandlerStdTest.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/BaseHandlerStdTest.java new file mode 100644 index 0000000..c7c64d6 --- /dev/null +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/BaseHandlerStdTest.java @@ -0,0 +1,56 @@ +package software.amazon.transfer.connector; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +@ExtendWith(MockitoExtension.class) +public class BaseHandlerStdTest { + @Mock + private AmazonWebServicesClientProxy proxy; + + static class MockTestHandler extends BaseHandlerStd { + @Override + public ProgressEvent handleRequest( + AmazonWebServicesClientProxy proxy, + ResourceHandlerRequest request, + CallbackContext callbackContext, + ProxyClient proxyClient, + Logger logger) { + assertNotNull(callbackContext); + return null; + } + } + + @Test + void justToCover3LinesOfCode() { + var uut = new MockTestHandler(); + + // Check with null CallbackContext + uut.handleRequest(proxy, null, null, null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + + // Check with non-null CallbackContext + uut.handleRequest(proxy, null, new CallbackContext(), null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + } +} diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/CreateHandlerTest.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/CreateHandlerTest.java index d5ff68d..b024f0a 100644 --- a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/CreateHandlerTest.java +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/CreateHandlerTest.java @@ -5,7 +5,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static software.amazon.transfer.connector.AbstractTestBase.*; @@ -13,10 +12,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.CreateConnectorRequest; import software.amazon.awssdk.services.transfer.model.CreateConnectorResponse; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -29,34 +26,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; import software.amazon.cloudformation.exceptions.CfnThrottlingException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class CreateHandlerTest { +public class CreateHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; - - @Mock - private TransferClient client; + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); + public void setupTestData() { + handler = new CreateHandler(); } @Test public void handleRequest_SimpleSuccess() { - final CreateHandler handler = new CreateHandler(client); - final ResourceModel model = ResourceModel.builder() .accessRole(TEST_ACCESS_ROLE) .as2Config(getAs2Config()) @@ -75,10 +65,9 @@ public void handleRequest_SimpleSuccess() { CreateConnectorResponse createConnectorResponse = CreateConnectorResponse.builder().connectorId(TEST_CONNECTOR_ID).build(); - doReturn(createConnectorResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(createConnectorResponse).when(client).createConnector(any(CreateConnectorRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -96,18 +85,14 @@ public void handleRequest_SimpleSuccess() { assertThat(testModel).hasFieldOrPropertyWithValue("url", TEST_URL); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CreateConnectorRequest.class); - verify(proxy).injectCredentialsAndInvokeV2(requestCaptor.capture(), any()); + verify(client).createConnector(requestCaptor.capture()); CreateConnectorRequest actualRequest = requestCaptor.getValue(); assertThat(actualRequest.tags()).containsExactlyInAnyOrder(SDK_MODEL_TAG, SDK_SYSTEM_TAG); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateConnectorRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).createConnector(any(CreateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -115,18 +100,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateConnectorRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).createConnector(any(CreateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -134,18 +113,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceExistsExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ResourceExistsException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateConnectorRequest.class), any()); + doThrow(ResourceExistsException.class).when(client).createConnector(any(CreateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().connectorId(TEST_CONNECTOR_ID).build(); @@ -154,18 +127,12 @@ public void handleRequest_ResourceExistsExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnAlreadyExistsException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnAlreadyExistsException.class, () -> callHandler(request)); } @Test public void handleRequest_ThrottlingExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ThrottlingException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateConnectorRequest.class), any()); + doThrow(ThrottlingException.class).when(client).createConnector(any(CreateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -173,18 +140,12 @@ public void handleRequest_ThrottlingExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnThrottlingException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnThrottlingException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateConnectorRequest.class), any()); + doThrow(TransferException.class).when(client).createConnector(any(CreateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -192,8 +153,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/DeleteHandlerTest.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/DeleteHandlerTest.java index e9866b0..298faef 100644 --- a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/DeleteHandlerTest.java +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/DeleteHandlerTest.java @@ -4,16 +4,13 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static software.amazon.transfer.connector.AbstractTestBase.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.DeleteConnectorRequest; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; @@ -23,35 +20,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class DeleteHandlerTest { +public class DeleteHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; - - @Mock - private TransferClient client; + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new DeleteHandler(); } @Test public void handleRequest_SimpleSuccess() { - final DeleteHandler handler = new DeleteHandler(client); - final ResourceModel model = ResourceModel.builder().connectorId(TEST_CONNECTOR_ID).build(); @@ -59,8 +48,7 @@ public void handleRequest_SimpleSuccess() { .desiredResourceState(model) .build(); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -73,11 +61,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteConnectorRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).deleteConnector(any(DeleteConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -85,18 +69,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteConnectorRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).deleteConnector(any(DeleteConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -104,18 +82,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteConnectorRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).deleteConnector(any(DeleteConnectorRequest.class)); ResourceModel model = ResourceModel.builder().connectorId(TEST_CONNECTOR_ID).build(); @@ -124,18 +96,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteConnectorRequest.class), any()); + doThrow(TransferException.class).when(client).deleteConnector(any(DeleteConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -143,8 +109,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ListHandlerTest.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ListHandlerTest.java index e7d3791..dce9340 100644 --- a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ListHandlerTest.java +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ListHandlerTest.java @@ -5,7 +5,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static software.amazon.transfer.connector.AbstractTestBase.*; import java.util.List; @@ -13,10 +12,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ListConnectorsRequest; @@ -26,35 +23,27 @@ import software.amazon.cloudformation.exceptions.CfnGeneralServiceException; import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ListHandlerTest { +public class ListHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; - - @Mock - private TransferClient client; + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new ListHandler(); } @Test public void handleRequest_SimpleSuccess() { - final ListHandler handler = new ListHandler(client); - ListedConnector listedConnector = ListedConnector.builder() .arn(TEST_ARN) .connectorId(TEST_CONNECTOR_ID) @@ -70,10 +59,9 @@ public void handleRequest_SimpleSuccess() { ListConnectorsResponse listConnectorsResponse = ListConnectorsResponse.builder().connectors(listedConnector).build(); - doReturn(listConnectorsResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(listConnectorsResponse).when(client).listConnectors(any(ListConnectorsRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); List testModels = response.getResourceModels(); @@ -96,11 +84,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListConnectorsRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).listConnectors(any(ListConnectorsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -108,18 +92,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListConnectorsRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).listConnectors(any(ListConnectorsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -127,18 +105,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListConnectorsRequest.class), any()); + doThrow(TransferException.class).when(client).listConnectors(any(ListConnectorsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -146,8 +118,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ReadHandlerTest.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ReadHandlerTest.java index 69cb00c..e508615 100644 --- a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ReadHandlerTest.java +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/ReadHandlerTest.java @@ -5,7 +5,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static software.amazon.transfer.connector.AbstractTestBase.*; import java.util.List; @@ -13,10 +12,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.DescribeConnectorRequest; import software.amazon.awssdk.services.transfer.model.DescribeConnectorResponse; import software.amazon.awssdk.services.transfer.model.DescribedConnector; @@ -28,35 +25,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ReadHandlerTest { +public class ReadHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; - - @Mock - private TransferClient client; + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new ReadHandler(); } @Test public void handleRequest_SimpleSuccess() { - final ReadHandler handler = new ReadHandler(client); - final List addresses = List.of("0.0.0.0", "1.1.1.1", "2.2.2.2"); final ResourceModel model = ResourceModel.builder() .accessRole(TEST_ACCESS_ROLE) @@ -77,10 +66,9 @@ public void handleRequest_SimpleSuccess() { .serviceManagedEgressIpAddresses(addresses) .build()) .build(); - doReturn(describeConnectorResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(describeConnectorResponse).when(client).describeConnector(any(DescribeConnectorRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -94,11 +82,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeConnectorRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).describeConnector(any(DescribeConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -106,18 +90,14 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeConnectorRequest.class), any()); + .when(client) + .describeConnector(any(DescribeConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -125,18 +105,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeConnectorRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).describeConnector(any(DescribeConnectorRequest.class)); ResourceModel model = ResourceModel.builder().connectorId(TEST_CONNECTOR_ID).build(); @@ -145,18 +119,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeConnectorRequest.class), any()); + doThrow(TransferException.class).when(client).describeConnector(any(DescribeConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -164,8 +132,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/UpdateHandlerTest.java b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/UpdateHandlerTest.java index 0e4926c..a0805d9 100644 --- a/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/UpdateHandlerTest.java +++ b/aws-transfer-connector/src/test/java/software/amazon/transfer/connector/UpdateHandlerTest.java @@ -12,18 +12,16 @@ import java.util.Set; import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; import software.amazon.awssdk.services.transfer.model.TagResourceRequest; import software.amazon.awssdk.services.transfer.model.TransferException; -import software.amazon.awssdk.services.transfer.model.TransferRequest; import software.amazon.awssdk.services.transfer.model.UntagResourceRequest; import software.amazon.awssdk.services.transfer.model.UpdateConnectorRequest; import software.amazon.awssdk.services.transfer.model.UpdateConnectorResponse; @@ -31,28 +29,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class UpdateHandlerTest { +public class UpdateHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new UpdateHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final UpdateHandler handler = new UpdateHandler(client); - final ResourceModel model = ResourceModel.builder() .connectorId(TEST_CONNECTOR_ID) .accessRole(TEST_ACCESS_ROLE) @@ -65,10 +62,9 @@ public void handleRequest_SimpleSuccess() { UpdateConnectorResponse updateConnectorResponse = UpdateConnectorResponse.builder().connectorId(TEST_CONNECTOR_ID).build(); - doReturn(updateConnectorResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(updateConnectorResponse).when(client).updateConnector(any(UpdateConnectorRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -80,12 +76,11 @@ public void handleRequest_SimpleSuccess() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(testModel).hasFieldOrPropertyWithValue("accessRole", TEST_ACCESS_ROLE); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateConnectorRequest.class), any()); + verify(client, times(1)).updateConnector(any(UpdateConnectorRequest.class)); } @Test public void handleRequest_AddTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set desiredTags = TEST_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -99,7 +94,7 @@ public void handleRequest_AddTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -110,13 +105,12 @@ public void handleRequest_AddTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(desiredTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(TagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateConnectorRequest.class), any()); + verify(client, times(1)).tagResource(any(TagResourceRequest.class)); + verify(client, times(1)).updateConnector(any(UpdateConnectorRequest.class)); } @Test public void handleRequest_RemoveTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set systemTags = SYSTEM_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -130,7 +124,7 @@ public void handleRequest_RemoveTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -141,15 +135,13 @@ public void handleRequest_RemoveTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(systemTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UntagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateConnectorRequest.class), any()); + verify(client, times(1)).untagResource(any(UntagResourceRequest.class)); + verify(client, times(1)).updateConnector(any(UpdateConnectorRequest.class)); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InvalidRequestException.class).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doThrow(InvalidRequestException.class).when(client).updateConnector(any(UpdateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -159,18 +151,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).updateConnector(any(UpdateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -180,18 +166,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).updateConnector(any(UpdateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -201,16 +181,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(TransferException.class).when(client).updateConnector(any(UpdateConnectorRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -220,8 +196,6 @@ public void handleRequest_TransferExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-profile/spotbugs-exclude.xml b/aws-transfer-profile/spotbugs-exclude.xml new file mode 100644 index 0000000..2c86dcc --- /dev/null +++ b/aws-transfer-profile/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/BaseHandlerStd.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/BaseHandlerStd.java new file mode 100644 index 0000000..315f3ca --- /dev/null +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/BaseHandlerStd.java @@ -0,0 +1,40 @@ +package software.amazon.transfer.profile; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * The purpose of this base class is to allow a simple calling pattern that + * makes testing Uluru handlers easier and avoids having to store context + * in class fields. The {@link MockableBaseHandler} interface is used to + * make isolation of the inner call such that in testing we guarantee that + * the caller will not pick the wrong method and avoid human error. + */ +public abstract class BaseHandlerStd extends BaseHandler + implements MockableBaseHandler { + @Override + public final ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final Logger logger) { + return handleRequest( + proxy, + request, + callbackContext != null ? callbackContext : new CallbackContext(), + proxy.newProxy(ClientBuilder::getClient), + logger); + } + + @Override + public abstract ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/CreateHandler.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/CreateHandler.java index 5e92fa1..b862a5d 100644 --- a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/CreateHandler.java +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/CreateHandler.java @@ -19,6 +19,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -26,24 +27,15 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class CreateHandler extends BaseHandler { - private TransferClient client; - - public CreateHandler(TransferClient client) { - this.client = client; - } - +public class CreateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); Map allTags = new HashMap<>(); @@ -67,7 +59,7 @@ public ProgressEvent handleRequest( .profileType(model.getProfileType()) .build(); - try { + try (TransferClient client = proxyClient.client()) { CreateProfileResponse response = proxy.injectCredentialsAndInvokeV2(createProfileRequest, client::createProfile); model.setProfileId(response.profileId()); diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/DeleteHandler.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/DeleteHandler.java index 243c23d..0345b4a 100644 --- a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/DeleteHandler.java +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/DeleteHandler.java @@ -14,34 +14,26 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class DeleteHandler extends BaseHandler { - private TransferClient client; - - public DeleteHandler(TransferClient client) { - this.client = client; - } - +public class DeleteHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); DeleteProfileRequest deleteProfileRequest = DeleteProfileRequest.builder().profileId(model.getProfileId()).build(); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(deleteProfileRequest, client::deleteProfile); logger.log( String.format("%s %s deleted successfully", ResourceModel.TYPE_NAME, model.getPrimaryIdentifier())); diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ListHandler.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ListHandler.java index cb0f3ae..19dfd46 100644 --- a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ListHandler.java +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ListHandler.java @@ -18,30 +18,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class ListHandler extends BaseHandler { - - private TransferClient client; - - public ListHandler(TransferClient client) { - this.client = client; - } - +public class ListHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final List models = new ArrayList<>(); ListProfilesRequest listProfilesRequest = ListProfilesRequest.builder() .maxResults(10) @@ -49,7 +40,7 @@ public ProgressEvent handleRequest( .profileType(request.getDesiredResourceState().getProfileType()) .build(); - try { + try (TransferClient client = proxyClient.client()) { ListProfilesResponse response = proxy.injectCredentialsAndInvokeV2(listProfilesRequest, client::listProfiles); diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/MockableBaseHandler.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/MockableBaseHandler.java new file mode 100644 index 0000000..3e11c0b --- /dev/null +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/MockableBaseHandler.java @@ -0,0 +1,24 @@ +package software.amazon.transfer.profile; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * Interface exposing the only handler method that should be used when + * testing Uluru handlers. This provides a mechanism to feed the call chain + * a mock client as needed without complex static mocking of the ClientBuilder. + * + * @param + */ +interface MockableBaseHandler { + ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackT callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ReadHandler.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ReadHandler.java index f862d2d..1277bcb 100644 --- a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ReadHandler.java +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/ReadHandler.java @@ -18,6 +18,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -25,29 +26,20 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class ReadHandler extends BaseHandler { - private TransferClient client; - - public ReadHandler(TransferClient client) { - this.client = client; - } - +public class ReadHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); DescribeProfileRequest describeProfileRequest = DescribeProfileRequest.builder().profileId(model.getProfileId()).build(); - try { + try (TransferClient client = proxyClient.client()) { DescribeProfileResponse describeProfileResponse = proxy.injectCredentialsAndInvokeV2(describeProfileRequest, client::describeProfile); logger.log(String.format( diff --git a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/UpdateHandler.java b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/UpdateHandler.java index d238543..e055b6e 100644 --- a/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/UpdateHandler.java +++ b/aws-transfer-profile/src/main/java/software/amazon/transfer/profile/UpdateHandler.java @@ -24,29 +24,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class UpdateHandler extends BaseHandler { - private TransferClient client; - - public UpdateHandler(TransferClient client) { - this.client = client; - } - +public class UpdateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); UpdateProfileRequest updateProfileRequest = UpdateProfileRequest.builder() .profileId(model.getProfileId()) @@ -72,7 +64,7 @@ public ProgressEvent handleRequest( Set tagsToAdd = Sets.difference(new HashSet<>(desiredTags), new HashSet<>(previousTags)); Set tagsToRemove = Sets.difference(new HashSet<>(previousTags), new HashSet<>(desiredTags)); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(updateProfileRequest, client::updateProfile); logger.log(String.format("%s updated successfully", ResourceModel.TYPE_NAME)); diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/AbstractTestBase.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/AbstractTestBase.java index 1e2ba98..fddac6c 100644 --- a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/AbstractTestBase.java +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/AbstractTestBase.java @@ -1,29 +1,125 @@ package software.amazon.transfer.profile; +import static org.mockito.Mockito.mock; + +import java.time.Duration; import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -public class AbstractTestBase { +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; + +import software.amazon.awssdk.awscore.AwsRequest; +import software.amazon.awssdk.awscore.AwsResponse; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.pagination.sync.SdkIterable; +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Credentials; +import software.amazon.cloudformation.proxy.LoggerProxy; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +public abstract class AbstractTestBase { - public static Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); - public static Map SYSTEM_TAG_MAP = + public static final Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); + public static final Map SYSTEM_TAG_MAP = Collections.singletonMap("aws:cloudformation:stack-name", "StackName"); - public static Map TEST_TAG_MAP = + public static final Map TEST_TAG_MAP = ImmutableMap.of("key", "value", "aws:cloudformation:stack-name", "StackName"); - public static Set MODEL_TAGS = + public static final Set MODEL_TAGS = ImmutableSet.of(Tag.builder().key("key").value("value").build()); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("key") .value("value") .build(); - public static software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("aws:cloudformation:stack-name") .value("StackName") .build(); + + abstract MockableBaseHandler getHandler(); + + protected ProgressEvent callHandler(ResourceHandlerRequest request) { + return getHandler().handleRequest(proxy, request, null, proxyClient, logger); + } + + protected static final Credentials MOCK_CREDENTIALS; + protected static final LoggerProxy logger; + + static { + MOCK_CREDENTIALS = new Credentials("accessKey", "secretKey", "token"); + logger = new LoggerProxy(); + } + + protected AmazonWebServicesClientProxy proxy; + + protected ProxyClient proxyClient; + + @Mock + protected TransferClient client; + + @BeforeEach + public void setup() { + proxy = new AmazonWebServicesClientProxy( + logger, MOCK_CREDENTIALS, () -> Duration.ofSeconds(600).toMillis()); + client = mock(TransferClient.class); + proxyClient = MOCK_PROXY(proxy, client); + } + + static ProxyClient MOCK_PROXY(final AmazonWebServicesClientProxy proxy, final T sdkClient) { + return new ProxyClient() { + @Override + public ResponseT injectCredentialsAndInvokeV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeV2(request, requestFunction); + } + + @Override + public + CompletableFuture injectCredentialsAndInvokeV2Async( + RequestT request, Function> requestFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public < + RequestT extends AwsRequest, + ResponseT extends AwsResponse, + IterableT extends SdkIterable> + IterableT injectCredentialsAndInvokeIterableV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeIterableV2(request, requestFunction); + } + + @Override + public + ResponseInputStream injectCredentialsAndInvokeV2InputStream( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public + ResponseBytes injectCredentialsAndInvokeV2Bytes( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public T client() { + return sdkClient; + } + }; + } } diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/BaseHandlerStdTest.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/BaseHandlerStdTest.java new file mode 100644 index 0000000..2087159 --- /dev/null +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/BaseHandlerStdTest.java @@ -0,0 +1,56 @@ +package software.amazon.transfer.profile; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +@ExtendWith(MockitoExtension.class) +public class BaseHandlerStdTest { + @Mock + private AmazonWebServicesClientProxy proxy; + + static class MockTestHandler extends BaseHandlerStd { + @Override + public ProgressEvent handleRequest( + AmazonWebServicesClientProxy proxy, + ResourceHandlerRequest request, + CallbackContext callbackContext, + ProxyClient proxyClient, + Logger logger) { + assertNotNull(callbackContext); + return null; + } + } + + @Test + void justToCover3LinesOfCode() { + var uut = new MockTestHandler(); + + // Check with null CallbackContext + uut.handleRequest(proxy, null, null, null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + + // Check with non-null CallbackContext + uut.handleRequest(proxy, null, new CallbackContext(), null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + } +} diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/CreateHandlerTest.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/CreateHandlerTest.java index ceab894..711cbe8 100644 --- a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/CreateHandlerTest.java +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/CreateHandlerTest.java @@ -12,7 +12,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.CreateProfileRequest; import software.amazon.awssdk.services.transfer.model.CreateProfileResponse; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -23,30 +22,27 @@ import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; import software.amazon.cloudformation.exceptions.ResourceNotFoundException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class CreateHandlerTest { +public class CreateHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new CreateHandler(); } @Test public void handleRequest_SimpleSuccess() { - final CreateHandler handler = new CreateHandler(client); - final ResourceModel model = ResourceModel.builder() .as2Id("testid") .profileType("PARTNER") @@ -62,10 +58,9 @@ public void handleRequest_SimpleSuccess() { CreateProfileResponse createProfileResponse = CreateProfileResponse.builder().profileId("p-123456").build(); - doReturn(createProfileResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(createProfileResponse).when(client).createProfile(any(CreateProfileRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -81,18 +76,14 @@ public void handleRequest_SimpleSuccess() { assertThat(testModel).hasFieldOrPropertyWithValue("profileId", "p-123456"); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CreateProfileRequest.class); - verify(proxy).injectCredentialsAndInvokeV2(requestCaptor.capture(), any()); + verify(client).createProfile(requestCaptor.capture()); CreateProfileRequest actualRequest = requestCaptor.getValue(); assertThat(actualRequest.tags()).containsExactlyInAnyOrder(SDK_MODEL_TAG, SDK_SYSTEM_TAG); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateProfileRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).createProfile(any(CreateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -100,18 +91,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateProfileRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).createProfile(any(CreateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -119,18 +104,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateProfileRequest.class), any()); + doThrow(TransferException.class).when(client).createProfile(any(CreateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -138,18 +117,12 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateProfileRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).createProfile(any(CreateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -157,8 +130,6 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/DeleteHandlerTest.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/DeleteHandlerTest.java index b9c9a65..4da893a 100644 --- a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/DeleteHandlerTest.java +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/DeleteHandlerTest.java @@ -5,12 +5,11 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.DeleteProfileRequest; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; @@ -20,36 +19,34 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class DeleteHandlerTest { +public class DeleteHandlerTest extends AbstractTestBase { - @Mock - private AmazonWebServicesClientProxy proxy; + private MockableBaseHandler handler; - @Mock - private Logger logger; + @Override + MockableBaseHandler getHandler() { + return handler; + } - @Mock - private TransferClient client; + @BeforeEach + public void setupTestData() { + handler = new DeleteHandler(); + } @Test public void handleRequest_SimpleSuccess() { - final DeleteHandler handler = new DeleteHandler(client); - final ResourceModel model = ResourceModel.builder().profileId("testid").build(); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -62,11 +59,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteProfileRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).deleteProfile(any(DeleteProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -74,18 +67,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteProfileRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).deleteProfile(any(DeleteProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -93,18 +80,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteProfileRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).deleteProfile(any(DeleteProfileRequest.class)); ResourceModel model = ResourceModel.builder().profileId("testId").build(); @@ -112,18 +93,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteProfileRequest.class), any()); + doThrow(TransferException.class).when(client).deleteProfile(any(DeleteProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -131,8 +106,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ListHandlerTest.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ListHandlerTest.java index 6164d7b..eec62fd 100644 --- a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ListHandlerTest.java +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ListHandlerTest.java @@ -12,7 +12,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ListProfilesRequest; @@ -24,30 +23,27 @@ import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; import software.amazon.cloudformation.exceptions.ResourceNotFoundException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ListHandlerTest { +public class ListHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new ListHandler(); } @Test public void handleRequest_SimpleSuccess() { - final ListHandler handler = new ListHandler(client); - ListedProfile listedProfile = ListedProfile.builder() .profileId("testid") .arn("testarn") @@ -64,10 +60,9 @@ public void handleRequest_SimpleSuccess() { ListProfilesResponse listProfilesResponse = ListProfilesResponse.builder().profiles(listedProfile).build(); - doReturn(listProfilesResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(listProfilesResponse).when(client).listProfiles(any(ListProfilesRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); List testModels = response.getResourceModels(); @@ -91,11 +86,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListProfilesRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).listProfiles(any(ListProfilesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -103,18 +94,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListProfilesRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).listProfiles(any(ListProfilesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -122,18 +107,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListProfilesRequest.class), any()); + doThrow(TransferException.class).when(client).listProfiles(any(ListProfilesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -141,18 +120,12 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListProfilesRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).listProfiles(any(ListProfilesRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -160,8 +133,6 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ReadHandlerTest.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ReadHandlerTest.java index 3c09ed4..355752b 100644 --- a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ReadHandlerTest.java +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/ReadHandlerTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.DescribeProfileRequest; import software.amazon.awssdk.services.transfer.model.DescribeProfileResponse; import software.amazon.awssdk.services.transfer.model.DescribedProfile; @@ -23,30 +22,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class ReadHandlerTest { +public class ReadHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new ReadHandler(); } @Test public void handleRequest_SimpleSuccess() { - final ReadHandler handler = new ReadHandler(client); - final ResourceModel model = ResourceModel.builder().profileId("testId").build(); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() @@ -60,10 +56,9 @@ public void handleRequest_SimpleSuccess() { .build()) .build(); - doReturn(describeProfileResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(describeProfileResponse).when(client).describeProfile(any(DescribeProfileRequest.class)); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -79,11 +74,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeProfileRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).describeProfile(any(DescribeProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -91,18 +82,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeProfileRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).describeProfile(any(DescribeProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -110,18 +95,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeProfileRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).describeProfile(any(DescribeProfileRequest.class)); ResourceModel model = ResourceModel.builder().profileId("testId").build(); @@ -129,18 +108,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeProfileRequest.class), any()); + doThrow(TransferException.class).when(client).describeProfile(any(DescribeProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -148,8 +121,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/UpdateHandlerTest.java b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/UpdateHandlerTest.java index b395bb4..77807ca 100644 --- a/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/UpdateHandlerTest.java +++ b/aws-transfer-profile/src/test/java/software/amazon/transfer/profile/UpdateHandlerTest.java @@ -14,7 +14,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; @@ -26,38 +25,34 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class UpdateHandlerTest { +public class UpdateHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new UpdateHandler(); } @Test public void handleRequest_SimpleSuccess() { - final UpdateHandler handler = new UpdateHandler(client); - final ResourceModel model = ResourceModel.builder().profileId("testId").build(); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); - final ProgressEvent response = - handler.handleRequest(proxy, request, null, logger); + final ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -71,7 +66,6 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_AddTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set desiredTags = TEST_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -85,7 +79,7 @@ public void handleRequest_AddTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -96,13 +90,12 @@ public void handleRequest_AddTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(desiredTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(TagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateProfileRequest.class), any()); + verify(client, times(1)).tagResource(any(TagResourceRequest.class)); + verify(client, times(1)).updateProfile(any(UpdateProfileRequest.class)); } @Test public void handleRequest_RemoveTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set systemTags = SYSTEM_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -116,7 +109,7 @@ public void handleRequest_RemoveTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -127,17 +120,13 @@ public void handleRequest_RemoveTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(systemTags); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UntagResourceRequest.class), any()); - verify(proxy, times(1)).injectCredentialsAndInvokeV2(any(UpdateProfileRequest.class), any()); + verify(client, times(1)).untagResource(any(UntagResourceRequest.class)); + verify(client, times(1)).updateProfile(any(UpdateProfileRequest.class)); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(UpdateProfileRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).updateProfile(any(UpdateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -147,18 +136,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(UpdateProfileRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).updateProfile(any(UpdateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -168,18 +151,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(UpdateProfileRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).updateProfile(any(UpdateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -189,18 +166,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(UpdateProfileRequest.class), any()); + doThrow(TransferException.class).when(client).updateProfile(any(UpdateProfileRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -210,8 +181,6 @@ public void handleRequest_TransferExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-server/spotbugs-exclude.xml b/aws-transfer-server/spotbugs-exclude.xml new file mode 100644 index 0000000..c6d0c3a --- /dev/null +++ b/aws-transfer-server/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-user/docs/README.md b/aws-transfer-user/docs/README.md index cc778b6..9a20e0d 100644 --- a/aws-transfer-user/docs/README.md +++ b/aws-transfer-user/docs/README.md @@ -126,6 +126,8 @@ _Update requires_: [Replacement](https://docs.aws.amazon.com/AWSCloudFormation/l #### SshPublicKeys +This represents the SSH User Public Keys for CloudFormation resource + _Required_: No _Type_: List of String diff --git a/aws-transfer-user/spotbugs-exclude.xml b/aws-transfer-user/spotbugs-exclude.xml new file mode 100644 index 0000000..da49b89 --- /dev/null +++ b/aws-transfer-user/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-workflow/spotbugs-exclude.xml b/aws-transfer-workflow/spotbugs-exclude.xml new file mode 100644 index 0000000..e9c3478 --- /dev/null +++ b/aws-transfer-workflow/spotbugs-exclude.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/BaseHandlerStd.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/BaseHandlerStd.java new file mode 100644 index 0000000..0cd7199 --- /dev/null +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/BaseHandlerStd.java @@ -0,0 +1,40 @@ +package software.amazon.transfer.workflow; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * The purpose of this base class is to allow a simple calling pattern that + * makes testing Uluru handlers easier and avoids having to store context + * in class fields. The {@link MockableBaseHandler} interface is used to + * make isolation of the inner call such that in testing we guarantee that + * the caller will not pick the wrong method and avoid human error. + */ +public abstract class BaseHandlerStd extends BaseHandler + implements MockableBaseHandler { + @Override + public final ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final Logger logger) { + return handleRequest( + proxy, + request, + callbackContext != null ? callbackContext : new CallbackContext(), + proxy.newProxy(ClientBuilder::getClient), + logger); + } + + @Override + public abstract ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/CreateHandler.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/CreateHandler.java index 4a33566..abcf913 100644 --- a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/CreateHandler.java +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/CreateHandler.java @@ -21,6 +21,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -28,24 +29,15 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class CreateHandler extends BaseHandler { - private TransferClient client; - - public CreateHandler(TransferClient client) { - this.client = client; - } - +public class CreateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - ResourceModel model = request.getDesiredResourceState(); Map allTags = new HashMap<>(); @@ -79,7 +71,7 @@ public ProgressEvent handleRequest( .map(Converter.TagConverter::toSdk) .collect(Collectors.toList())) .build(); - try { + try (TransferClient client = proxyClient.client()) { CreateWorkflowResponse response = proxy.injectCredentialsAndInvokeV2(createWorkflowRequest, client::createWorkflow); model.setWorkflowId(response.workflowId()); diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/DeleteHandler.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/DeleteHandler.java index 7523665..06a46f8 100644 --- a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/DeleteHandler.java +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/DeleteHandler.java @@ -14,35 +14,27 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class DeleteHandler extends BaseHandler { - private TransferClient client; - - public DeleteHandler(TransferClient client) { - this.client = client; - } - +public class DeleteHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final ResourceModel model = request.getDesiredResourceState(); final DeleteWorkflowRequest deleteWorkflowRequest = DeleteWorkflowRequest.builder() .workflowId(model.getWorkflowId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { proxy.injectCredentialsAndInvokeV2(deleteWorkflowRequest, client::deleteWorkflow); logger.log( String.format("%s %s deleted successfully", ResourceModel.TYPE_NAME, model.getPrimaryIdentifier())); diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ListHandler.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ListHandler.java index b33d846..8d66629 100644 --- a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ListHandler.java +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ListHandler.java @@ -16,29 +16,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class ListHandler extends BaseHandler { - private TransferClient client; - - public ListHandler(TransferClient client) { - this.client = client; - } - +public class ListHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - final List models = new ArrayList<>(); ListWorkflowsRequest listWorkflowsRequest = ListWorkflowsRequest.builder() @@ -46,7 +38,7 @@ public ProgressEvent handleRequest( .nextToken(request.getNextToken()) .build(); - try { + try (TransferClient client = proxyClient.client()) { ListWorkflowsResponse response = proxy.injectCredentialsAndInvokeV2(listWorkflowsRequest, client::listWorkflows); diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/MockableBaseHandler.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/MockableBaseHandler.java new file mode 100644 index 0000000..666490d --- /dev/null +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/MockableBaseHandler.java @@ -0,0 +1,24 @@ +package software.amazon.transfer.workflow; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +/** + * Interface exposing the only handler method that should be used when + * testing Uluru handlers. This provides a mechanism to feed the call chain + * a mock client as needed without complex static mocking of the ClientBuilder. + * + * @param + */ +interface MockableBaseHandler { + ProgressEvent handleRequest( + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackT callbackContext, + final ProxyClient proxyClient, + final Logger logger); +} diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ReadHandler.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ReadHandler.java index ae2efaf..f98cab1 100644 --- a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ReadHandler.java +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/ReadHandler.java @@ -18,6 +18,7 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import com.amazonaws.util.CollectionUtils; @@ -25,29 +26,20 @@ import lombok.NoArgsConstructor; @NoArgsConstructor -public class ReadHandler extends BaseHandler { - private TransferClient client; - - public ReadHandler(TransferClient client) { - this.client = client; - } - +public class ReadHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, + final ProxyClient proxyClient, final Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - ResourceModel model = request.getDesiredResourceState(); DescribeWorkflowRequest describeWorkflowRequest = DescribeWorkflowRequest.builder() .workflowId(model.getWorkflowId()) .build(); - try { + try (TransferClient client = proxyClient.client()) { DescribeWorkflowResponse response = proxy.injectCredentialsAndInvokeV2(describeWorkflowRequest, client::describeWorkflow); logger.log(String.format( diff --git a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/UpdateHandler.java b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/UpdateHandler.java index a97da50..dc5175d 100644 --- a/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/UpdateHandler.java +++ b/aws-transfer-workflow/src/main/java/software/amazon/transfer/workflow/UpdateHandler.java @@ -23,29 +23,21 @@ import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import lombok.NoArgsConstructor; @NoArgsConstructor -public class UpdateHandler extends BaseHandler { - private TransferClient client; - - public UpdateHandler(TransferClient client) { - this.client = client; - } - +public class UpdateHandler extends BaseHandlerStd { @Override public ProgressEvent handleRequest( AmazonWebServicesClientProxy proxy, ResourceHandlerRequest request, CallbackContext callbackContext, + final ProxyClient proxyClient, Logger logger) { - if (this.client == null) { - this.client = ClientBuilder.getClient(); - } - ResourceModel model = request.getDesiredResourceState(); String arn = String.format( "arn:%s:transfer:%s:%s:workflow/%s", @@ -67,7 +59,7 @@ public ProgressEvent handleRequest( Set tagsToAdd = Sets.difference(new HashSet<>(desiredTags), new HashSet<>(previousTags)); Set tagsToRemove = Sets.difference(new HashSet<>(previousTags), new HashSet<>(desiredTags)); - try { + try (TransferClient client = proxyClient.client()) { if (!tagsToAdd.isEmpty()) { TagResourceRequest tagResourceRequest = TagResourceRequest.builder() .arn(arn) diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/AbstractTestBase.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/AbstractTestBase.java index d72984c..5a99f2a 100644 --- a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/AbstractTestBase.java +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/AbstractTestBase.java @@ -1,30 +1,51 @@ package software.amazon.transfer.workflow; +import static org.mockito.Mockito.mock; + +import java.time.Duration; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mock; + +import software.amazon.awssdk.awscore.AwsRequest; +import software.amazon.awssdk.awscore.AwsResponse; +import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.pagination.sync.SdkIterable; +import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.OverwriteExisting; import software.amazon.awssdk.services.transfer.model.WorkflowStepType; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Credentials; +import software.amazon.cloudformation.proxy.LoggerProxy; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; -public class AbstractTestBase { - static String TEST_DESCRIPTION = "unit test"; - static Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); - static Map SYSTEM_TAG_MAP = Collections.singletonMap("aws:cloudformation:stack-name", "StackName"); - static Map TEST_TAG_MAP = +public abstract class AbstractTestBase { + public static final String TEST_DESCRIPTION = "unit test"; + public static final Map RESOURCE_TAG_MAP = Collections.singletonMap("key", "value"); + public static final Map SYSTEM_TAG_MAP = + Collections.singletonMap("aws:cloudformation:stack-name", "StackName"); + public static final Map TEST_TAG_MAP = ImmutableMap.of("key", "value", "aws:cloudformation:stack-name", "StackName"); - static Set MODEL_TAGS = + public static final Set MODEL_TAGS = ImmutableSet.of(Tag.builder().key("key").value("value").build()); - static software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_MODEL_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("key") .value("value") .build(); - static software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = + public static final software.amazon.awssdk.services.transfer.model.Tag SDK_SYSTEM_TAG = software.amazon.awssdk.services.transfer.model.Tag.builder() .key("aws:cloudformation:stack-name") .value("StackName") @@ -64,4 +85,79 @@ public List getModelDecryptWorkflowSteps() { .build(); return Collections.singletonList(step); } + + abstract MockableBaseHandler getHandler(); + + protected ProgressEvent callHandler(ResourceHandlerRequest request) { + return getHandler().handleRequest(proxy, request, null, proxyClient, logger); + } + + protected static final Credentials MOCK_CREDENTIALS; + protected static final LoggerProxy logger; + + static { + MOCK_CREDENTIALS = new Credentials("accessKey", "secretKey", "token"); + logger = new LoggerProxy(); + } + + protected AmazonWebServicesClientProxy proxy; + + protected ProxyClient proxyClient; + + @Mock + protected TransferClient client; + + @BeforeEach + public void setup() { + proxy = new AmazonWebServicesClientProxy( + logger, MOCK_CREDENTIALS, () -> Duration.ofSeconds(600).toMillis()); + client = mock(TransferClient.class); + proxyClient = MOCK_PROXY(proxy, client); + } + + static ProxyClient MOCK_PROXY(final AmazonWebServicesClientProxy proxy, final T sdkClient) { + return new ProxyClient() { + @Override + public ResponseT injectCredentialsAndInvokeV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeV2(request, requestFunction); + } + + @Override + public + CompletableFuture injectCredentialsAndInvokeV2Async( + RequestT request, Function> requestFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public < + RequestT extends AwsRequest, + ResponseT extends AwsResponse, + IterableT extends SdkIterable> + IterableT injectCredentialsAndInvokeIterableV2( + RequestT request, Function requestFunction) { + return proxy.injectCredentialsAndInvokeIterableV2(request, requestFunction); + } + + @Override + public + ResponseInputStream injectCredentialsAndInvokeV2InputStream( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public + ResponseBytes injectCredentialsAndInvokeV2Bytes( + RequestT requestT, Function> function) { + throw new UnsupportedOperationException(); + } + + @Override + public T client() { + return sdkClient; + } + }; + } } diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/BaseHandlerStdTest.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/BaseHandlerStdTest.java new file mode 100644 index 0000000..78d226c --- /dev/null +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/BaseHandlerStdTest.java @@ -0,0 +1,56 @@ +package software.amazon.transfer.workflow; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import software.amazon.awssdk.services.transfer.TransferClient; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; + +@ExtendWith(MockitoExtension.class) +public class BaseHandlerStdTest { + @Mock + private AmazonWebServicesClientProxy proxy; + + static class MockTestHandler extends BaseHandlerStd { + @Override + public ProgressEvent handleRequest( + AmazonWebServicesClientProxy proxy, + ResourceHandlerRequest request, + CallbackContext callbackContext, + ProxyClient proxyClient, + Logger logger) { + assertNotNull(callbackContext); + return null; + } + } + + @Test + void justToCover3LinesOfCode() { + var uut = new MockTestHandler(); + + // Check with null CallbackContext + uut.handleRequest(proxy, null, null, null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + + // Check with non-null CallbackContext + uut.handleRequest(proxy, null, new CallbackContext(), null); + verify(proxy, times(1)).newProxy(any()); + verifyNoMoreInteractions(proxy); + reset(proxy); + } +} diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/CreateHandlerTest.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/CreateHandlerTest.java index b40caa2..44ba001 100644 --- a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/CreateHandlerTest.java +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/CreateHandlerTest.java @@ -5,7 +5,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import org.junit.jupiter.api.BeforeEach; @@ -14,7 +13,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.CreateWorkflowRequest; import software.amazon.awssdk.services.transfer.model.CreateWorkflowResponse; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; @@ -27,29 +25,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; import software.amazon.cloudformation.exceptions.CfnThrottlingException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) public class CreateHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new CreateHandler(); } @Test public void handleRequest_SimpleSuccess_Copy() { - CreateHandler handler = new CreateHandler(client); - ResourceModel model = ResourceModel.builder() .description(TEST_DESCRIPTION) .onExceptionSteps(getModelCopyWorkflowSteps()) @@ -65,9 +61,9 @@ public void handleRequest_SimpleSuccess_Copy() { CreateWorkflowResponse createWorkflowResponse = CreateWorkflowResponse.builder().workflowId("id").build(); - doReturn(createWorkflowResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(createWorkflowResponse).when(client).createWorkflow(any(CreateWorkflowRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -83,15 +79,13 @@ public void handleRequest_SimpleSuccess_Copy() { assertThat(testModel).hasFieldOrPropertyWithValue("onExceptionSteps", getModelCopyWorkflowSteps()); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CreateWorkflowRequest.class); - verify(proxy).injectCredentialsAndInvokeV2(requestCaptor.capture(), any()); + verify(client).createWorkflow(requestCaptor.capture()); CreateWorkflowRequest actualRequest = requestCaptor.getValue(); assertThat(actualRequest.tags()).containsExactlyInAnyOrder(SDK_MODEL_TAG, SDK_SYSTEM_TAG); } @Test public void handleRequest_SimpleSuccess_Decrypt() { - CreateHandler handler = new CreateHandler(client); - ResourceModel model = ResourceModel.builder() .description(TEST_DESCRIPTION) .onExceptionSteps(getModelDecryptWorkflowSteps()) @@ -107,9 +101,9 @@ public void handleRequest_SimpleSuccess_Decrypt() { CreateWorkflowResponse createWorkflowResponse = CreateWorkflowResponse.builder().workflowId("id").build(); - doReturn(createWorkflowResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(createWorkflowResponse).when(client).createWorkflow(any(CreateWorkflowRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -125,18 +119,14 @@ public void handleRequest_SimpleSuccess_Decrypt() { assertThat(testModel).hasFieldOrPropertyWithValue("onExceptionSteps", getModelDecryptWorkflowSteps()); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(CreateWorkflowRequest.class); - verify(proxy).injectCredentialsAndInvokeV2(requestCaptor.capture(), any()); + verify(client).createWorkflow(requestCaptor.capture()); CreateWorkflowRequest actualRequest = requestCaptor.getValue(); assertThat(actualRequest.tags()).containsExactlyInAnyOrder(SDK_MODEL_TAG, SDK_SYSTEM_TAG); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateWorkflowRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).createWorkflow(any(CreateWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -144,18 +134,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateWorkflowRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).createWorkflow(any(CreateWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -163,18 +147,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceExistsExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ResourceExistsException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateWorkflowRequest.class), any()); + doThrow(ResourceExistsException.class).when(client).createWorkflow(any(CreateWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().workflowId("testId").build(); @@ -182,18 +160,12 @@ public void handleRequest_ResourceExistsExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnAlreadyExistsException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnAlreadyExistsException.class, () -> callHandler(request)); } @Test public void handleRequest_ThrottlingExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(ThrottlingException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateWorkflowRequest.class), any()); + doThrow(ThrottlingException.class).when(client).createWorkflow(any(CreateWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -201,18 +173,12 @@ public void handleRequest_ThrottlingExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnThrottlingException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnThrottlingException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - CreateHandler handler = new CreateHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(CreateWorkflowRequest.class), any()); + doThrow(TransferException.class).when(client).createWorkflow(any(CreateWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -220,8 +186,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/DeleteHandlerTest.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/DeleteHandlerTest.java index 1618883..63abd01 100644 --- a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/DeleteHandlerTest.java +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/DeleteHandlerTest.java @@ -4,14 +4,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.DeleteWorkflowRequest; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; @@ -21,36 +19,34 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) -public class DeleteHandlerTest { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; +public class DeleteHandlerTest extends AbstractTestBase { + + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new DeleteHandler(); } @Test public void handleRequest_SimpleSuccess() { - final DeleteHandler handler = new DeleteHandler(client); - ResourceModel model = ResourceModel.builder().workflowId("testid").build(); ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -63,11 +59,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteWorkflowRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).deleteWorkflow(any(DeleteWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -75,18 +67,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteWorkflowRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).deleteWorkflow(any(DeleteWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -94,18 +80,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteWorkflowRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).deleteWorkflow(any(DeleteWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().workflowId("testId").build(); @@ -113,18 +93,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - DeleteHandler handler = new DeleteHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DeleteWorkflowRequest.class), any()); + doThrow(TransferException.class).when(client).deleteWorkflow(any(DeleteWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -132,8 +106,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ListHandlerTest.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ListHandlerTest.java index f3cddf1..0a0be90 100644 --- a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ListHandlerTest.java +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ListHandlerTest.java @@ -5,7 +5,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import java.util.List; @@ -14,7 +13,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ListWorkflowsRequest; @@ -24,29 +22,27 @@ import software.amazon.cloudformation.exceptions.CfnGeneralServiceException; import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) public class ListHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new ListHandler(); } @Test public void handleRequest_SimpleSuccess() { - final ListHandler handler = new ListHandler(client); - ListedWorkflow listedWorkflow = ListedWorkflow.builder() .description(TEST_DESCRIPTION) .arn("testarn") @@ -61,9 +57,9 @@ public void handleRequest_SimpleSuccess() { ListWorkflowsResponse listWorkflowsResponse = ListWorkflowsResponse.builder().workflows(listedWorkflow).build(); - doReturn(listWorkflowsResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(listWorkflowsResponse).when(client).listWorkflows(any(ListWorkflowsRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); List testModels = response.getResourceModels(); @@ -86,11 +82,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListWorkflowsRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).listWorkflows(any(ListWorkflowsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -98,18 +90,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListWorkflowsRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).listWorkflows(any(ListWorkflowsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -117,18 +103,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ListHandler handler = new ListHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(ListWorkflowsRequest.class), any()); + doThrow(TransferException.class).when(client).listWorkflows(any(ListWorkflowsRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -136,8 +116,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ReadHandlerTest.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ReadHandlerTest.java index 5a63445..766f457 100644 --- a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ReadHandlerTest.java +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/ReadHandlerTest.java @@ -5,14 +5,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.DescribeWorkflowRequest; import software.amazon.awssdk.services.transfer.model.DescribeWorkflowResponse; import software.amazon.awssdk.services.transfer.model.DescribedWorkflow; @@ -24,28 +22,27 @@ import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) public class ReadHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; + + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new ReadHandler(); } @Test public void handleRequest_SimpleSuccess() { - ReadHandler handler = new ReadHandler(client); ResourceModel model = ResourceModel.builder().workflowId("testId").build(); ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) @@ -56,9 +53,9 @@ public void handleRequest_SimpleSuccess() { .build()) .build(); - doReturn(describeWorkflowResponse).when(proxy).injectCredentialsAndInvokeV2(any(), any()); + doReturn(describeWorkflowResponse).when(client).describeWorkflow(any(DescribeWorkflowRequest.class)); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); ResourceModel testModel = response.getResourceModel(); assertThat(response).isNotNull(); @@ -73,11 +70,7 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_InvalidRequestExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeWorkflowRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).describeWorkflow(any(DescribeWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -85,18 +78,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeWorkflowRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).describeWorkflow(any(DescribeWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -104,18 +91,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeWorkflowRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).describeWorkflow(any(DescribeWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().workflowId("testId").build(); @@ -123,18 +104,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - ReadHandler handler = new ReadHandler(client); - - doThrow(TransferException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(DescribeWorkflowRequest.class), any()); + doThrow(TransferException.class).when(client).describeWorkflow(any(DescribeWorkflowRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -142,8 +117,6 @@ public void handleRequest_TransferExceptionFailed() { .desiredResourceState(model) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } } diff --git a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/UpdateHandlerTest.java b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/UpdateHandlerTest.java index 57f13b8..a149513 100644 --- a/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/UpdateHandlerTest.java +++ b/aws-transfer-workflow/src/test/java/software/amazon/transfer/workflow/UpdateHandlerTest.java @@ -13,48 +13,44 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.services.transfer.TransferClient; import software.amazon.awssdk.services.transfer.model.InternalServiceErrorException; import software.amazon.awssdk.services.transfer.model.InvalidRequestException; import software.amazon.awssdk.services.transfer.model.ResourceNotFoundException; import software.amazon.awssdk.services.transfer.model.TagResourceRequest; import software.amazon.awssdk.services.transfer.model.TransferException; -import software.amazon.awssdk.services.transfer.model.TransferRequest; +import software.amazon.awssdk.services.transfer.model.UntagResourceRequest; import software.amazon.cloudformation.exceptions.CfnGeneralServiceException; import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; import software.amazon.cloudformation.exceptions.CfnNotFoundException; import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException; -import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; -import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; @ExtendWith(MockitoExtension.class) public class UpdateHandlerTest extends AbstractTestBase { - private AmazonWebServicesClientProxy proxy; - private Logger logger; - private TransferClient client; - ResourceHandlerRequest request; + + private MockableBaseHandler handler; + + @Override + MockableBaseHandler getHandler() { + return handler; + } @BeforeEach - public void setup() { - proxy = mock(AmazonWebServicesClientProxy.class); - logger = mock(Logger.class); - client = mock(TransferClient.class); + public void setupTestData() { + handler = new UpdateHandler(); } @Test public void handleRequest_SimpleSuccess() { - UpdateHandler handler = new UpdateHandler(client); - ResourceModel model = ResourceModel.builder().build(); ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -68,7 +64,6 @@ public void handleRequest_SimpleSuccess() { @Test public void handleRequest_AddTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set allTags = TEST_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -82,7 +77,7 @@ public void handleRequest_AddTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -93,12 +88,11 @@ public void handleRequest_AddTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(allTags); - verify(proxy).injectCredentialsAndInvokeV2(any(), any()); + verify(client).tagResource(any(TagResourceRequest.class)); } @Test public void handleRequest_RemoveTagInvoked() { - UpdateHandler handler = new UpdateHandler(client); Set systemTags = SYSTEM_TAG_MAP.entrySet().stream() .map(tag -> Tag.builder().key(tag.getKey()).value(tag.getValue()).build()) @@ -112,7 +106,7 @@ public void handleRequest_RemoveTagInvoked() { .systemTags(SYSTEM_TAG_MAP) .build(); - ProgressEvent response = handler.handleRequest(proxy, request, null, logger); + ProgressEvent response = callHandler(request); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); @@ -123,16 +117,13 @@ public void handleRequest_RemoveTagInvoked() { assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); assertThat(response.getResourceModel().getTags()).isEqualTo(systemTags); - verify(proxy, times(2)).injectCredentialsAndInvokeV2(any(), any()); + verify(client, times(1)).tagResource(any(TagResourceRequest.class)); + verify(client, times(1)).untagResource(any(UntagResourceRequest.class)); } @Test public void handleRequest_InvalidRequestExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InvalidRequestException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TagResourceRequest.class), any()); + doThrow(InvalidRequestException.class).when(client).tagResource(any(TagResourceRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -142,18 +133,12 @@ public void handleRequest_InvalidRequestExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnInvalidRequestException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnInvalidRequestException.class, () -> callHandler(request)); } @Test public void handleRequest_InternalServiceErrorExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(InternalServiceErrorException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(InternalServiceErrorException.class).when(client).tagResource(any(TagResourceRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -163,18 +148,12 @@ public void handleRequest_InternalServiceErrorExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnServiceInternalErrorException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnServiceInternalErrorException.class, () -> callHandler(request)); } @Test public void handleRequest_ResourceNotFoundExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(ResourceNotFoundException.class) - .when(proxy) - .injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(ResourceNotFoundException.class).when(client).tagResource(any(TagResourceRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -184,16 +163,12 @@ public void handleRequest_ResourceNotFoundExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnNotFoundException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnNotFoundException.class, () -> callHandler(request)); } @Test public void handleRequest_TransferExceptionFailed() { - UpdateHandler handler = new UpdateHandler(client); - - doThrow(TransferException.class).when(proxy).injectCredentialsAndInvokeV2(any(TransferRequest.class), any()); + doThrow(TransferException.class).when(client).tagResource(any(TagResourceRequest.class)); ResourceModel model = ResourceModel.builder().build(); @@ -203,8 +178,6 @@ public void handleRequest_TransferExceptionFailed() { .systemTags(SYSTEM_TAG_MAP) .build(); - assertThrows(CfnGeneralServiceException.class, () -> { - handler.handleRequest(proxy, request, null, logger); - }); + assertThrows(CfnGeneralServiceException.class, () -> callHandler(request)); } }