package software.amazon.sns.subscription; import org.junit.jupiter.api.AfterEach; 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.sns.SnsClient; import software.amazon.awssdk.services.sns.model.*; import software.amazon.cloudformation.exceptions.*; import software.amazon.cloudformation.proxy.*; import java.time.Duration; import java.util.HashMap; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class DeleteHandlerTest extends AbstractTestBase { @Mock private AmazonWebServicesClientProxy proxy; @Mock private ProxyClient proxyClient; @Mock SnsClient snsClient; private DeleteHandler handler; private Map attributes; private ResourceModel model; @BeforeEach public void setup() { handler = new DeleteHandler(); proxy = new AmazonWebServicesClientProxy(logger, MOCK_CREDENTIALS, () -> Duration.ofSeconds(600).toMillis()); snsClient = mock(SnsClient.class); proxyClient = MOCK_PROXY(proxy, snsClient); buildObjects(); } @AfterEach public void tear_down() { verify(snsClient, atLeastOnce()).serviceName(); verifyNoMoreInteractions(snsClient); } private void buildObjects() { model = ResourceModel.builder().subscriptionArn("testArn").topicArn("topicArn").build(); attributes = new HashMap<>(); attributes.put("SubscriptionArn", model.getSubscriptionArn()); attributes.put("TopicArn", "topicArn"); attributes.put("Protocol", "email"); attributes.put("Endpoint", "end1"); attributes.put("RawMessageDelivery", "false"); attributes.put("PendingConfirmation", "false"); } private HashMap buildObjects_PendingTrue() { model = ResourceModel.builder().subscriptionArn("testArn").topicArn("topicArn").build(); HashMap attributes = new HashMap<>(); attributes.put("SubscriptionArn", model.getSubscriptionArn()); attributes.put("TopicArn", "topicArn"); attributes.put("Protocol", "email"); attributes.put("Endpoint", "end1"); attributes.put("RawMessageDelivery", "false"); attributes.put("PendingConfirmation", "true"); return attributes; } @Test public void handleRequest_SimpleSuccess() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); final UnsubscribeResponse unsubscribeResponse = UnsubscribeResponse.builder().build(); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenReturn(unsubscribeResponse); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); final ProgressEvent response = handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); assertThat(response.getCallbackDelaySeconds()).isEqualTo(0); assertThat(response.getResourceModel()).isNull(); assertThat(response.getResourceModels()).isNull(); assertThat(response.getMessage()).isNull(); assertThat(response.getErrorCode()).isNull(); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); verify(proxyClient.client()).unsubscribe(any(UnsubscribeRequest.class)); verify(proxyClient.client(), times(2)).getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class)); } @Test public void handleRequest_SubscriptionPending() { final HashMap attributes = buildObjects_PendingTrue(); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse); assertThrows(CfnInvalidRequestException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); verify(proxyClient.client(), never()).unsubscribe(any(UnsubscribeRequest.class)); } @Test public void handleRequest_TopicArnDoesNotExist() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(NotFoundException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnNotFoundException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); verify(proxyClient.client(), never()).unsubscribe(any(UnsubscribeRequest.class)); verify(proxyClient.client(), never()).getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class)); } @Test public void handleRequest_TopicArnSubscriptionLimitExceededException() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(SubscriptionLimitExceededException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnServiceLimitExceededException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); } @Test public void handleRequest_TopicArnFilterPolicyLimitExceededException() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(FilterPolicyLimitExceededException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnServiceLimitExceededException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); } @Test public void handleRequest_TopicArnInvalidParameterExceptionException() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(InvalidParameterException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnInvalidRequestException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); } @Test public void handleRequest_TopicArnInternalErrorException() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(InternalErrorException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnInternalFailureException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); } @Test public void handleRequest_TopicArnAuthorizationErrorException() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(AuthorizationErrorException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnAccessDeniedException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); } @Test public void handleRequest_TopicArnInvalidSecurityException() { when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenThrow(InvalidSecurityException.class); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnInvalidCredentialsException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); } @Test public void handleRequest_SubscriptionDoesNotExist() { final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn", "topicArn"); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenThrow(NotFoundException.class); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); assertThrows(CfnNotFoundException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); verify(proxyClient.client()).getTopicAttributes(any(GetTopicAttributesRequest.class)); verify(proxyClient.client(), never()).unsubscribe(any(UnsubscribeRequest.class)); verify(proxyClient.client()).getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class)); } @Test public void handleRequest_SubscriptionLimitExceededExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(SubscriptionLimitExceededException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnServiceLimitExceededException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } @Test public void handleRequest_FilterPolicyLimitExceededExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(FilterPolicyLimitExceededException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnServiceLimitExceededException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } @Test public void handleRequest_InvalidParameterExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(InvalidParameterException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnInvalidRequestException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } @Test public void handleRequest_InternalErrorExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(InternalErrorException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnInternalFailureException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } @Test public void handleRequest_AuthorizationErrorExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(AuthorizationErrorException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnAccessDeniedException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } @Test public void handleRequest_InvalidSecurityExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(InvalidSecurityException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnInvalidCredentialsException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } @Test public void handleRequest_NotFoundExceptionUnsubscribe() { final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .desiredResourceState(model) .build(); final Map topicAttributes = new HashMap<>(); topicAttributes.put("TopicArn","topicarn"); final GetTopicAttributesResponse getTopicAttributesResponse = GetTopicAttributesResponse.builder().attributes(topicAttributes).build(); when(proxyClient.client().getTopicAttributes(any(GetTopicAttributesRequest.class))).thenReturn(getTopicAttributesResponse); when(proxyClient.client().unsubscribe(any(UnsubscribeRequest.class))).thenThrow(NotFoundException.class); final GetSubscriptionAttributesResponse getSubscriptionResponse = GetSubscriptionAttributesResponse.builder().attributes(attributes).build(); when(proxyClient.client().getSubscriptionAttributes(any(GetSubscriptionAttributesRequest.class))).thenReturn(getSubscriptionResponse).thenReturn(getSubscriptionResponse); assertThrows(CfnNotFoundException.class, () -> handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger)); } }