diff --git a/pom.xml b/pom.xml
index 0dbcd13b..c01132fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
software.amazon.cloudformation
aws-cloudformation-rpdk-java-plugin
- 1.0.5
+ 2.0.0
AWS CloudFormation RPDK Java Plugin
The CloudFormation Resource Provider Development Kit (RPDK) allows you to author your own resource providers that can be used by CloudFormation. This plugin library helps to provide runtime bindings for the execution of your providers by CloudFormation.
@@ -307,12 +307,12 @@
BRANCH
COVEREDRATIO
- 0.80
+ 0.79
INSTRUCTION
COVEREDRATIO
- 0.87
+ 0.89
diff --git a/python/rpdk/java/__init__.py b/python/rpdk/java/__init__.py
index c918e14c..5684f64a 100644
--- a/python/rpdk/java/__init__.py
+++ b/python/rpdk/java/__init__.py
@@ -1,5 +1,5 @@
import logging
-__version__ = "0.1.6"
+__version__ = "2.0.0"
logging.getLogger(__name__).addHandler(logging.NullHandler())
diff --git a/python/rpdk/java/codegen.py b/python/rpdk/java/codegen.py
index 609f7dc3..9d03c919 100644
--- a/python/rpdk/java/codegen.py
+++ b/python/rpdk/java/codegen.py
@@ -2,7 +2,9 @@
# pylint doesn't recognize abstract methods
import logging
import shutil
+import xml.etree.ElementTree as ET # nosec
from collections import namedtuple
+from xml.etree.ElementTree import ParseError # nosec
from rpdk.core.data_loaders import resource_stream
from rpdk.core.exceptions import InternalError, SysExitRecommendedError
@@ -37,10 +39,29 @@ def wrapper(*args, **kwargs):
return wrapper
+DEFAULT_PROTOCOL_VERSION = "2.0.0"
+PROTOCOL_VERSION_SETTING = "protocolVersion"
+DEFAULT_SETTINGS = {PROTOCOL_VERSION_SETTING: DEFAULT_PROTOCOL_VERSION}
+
+MINIMUM_JAVA_DEPENDENCY_VERSION = "2.0.0"
+
+
class JavaArchiveNotFoundError(SysExitRecommendedError):
pass
+class JavaPluginVersionNotSupportedError(SysExitRecommendedError):
+ pass
+
+
+class JavaPluginNotFoundError(SysExitRecommendedError):
+ pass
+
+
+class InvalidMavenPOMError(SysExitRecommendedError):
+ pass
+
+
class JavaLanguagePlugin(LanguagePlugin):
MODULE_NAME = __name__
RUNTIME = "java8"
@@ -66,7 +87,7 @@ def _namespace_from_project(self, project):
fallback = ("com",) + project.type_info
namespace = tuple(safe_reserved(s.lower()) for s in fallback)
self.namespace = project.settings["namespace"] = namespace
- project._write_settings("java") # pylint: disable=protected-access
+ project.write_settings()
self.package_name = ".".join(self.namespace)
@@ -283,6 +304,7 @@ def _init_settings(self, project):
project.runtime = self.RUNTIME
project.entrypoint = self.ENTRY_POINT.format(self.package_name)
project.test_entrypoint = self.TEST_ENTRY_POINT.format(self.package_name)
+ project.settings.update(DEFAULT_SETTINGS)
@staticmethod
def _get_generated_root(project):
@@ -377,6 +399,24 @@ def generate(self, project):
)
project.overwrite(path, contents)
+ # Update settings
+ java_plugin_dependency_version = self._get_java_plugin_dependency_version(
+ project
+ )
+ if java_plugin_dependency_version < MINIMUM_JAVA_DEPENDENCY_VERSION:
+ raise JavaPluginVersionNotSupportedError(
+ "'aws-cloudformation-rpdk-java-plugin' {} is no longer supported."
+ "Please update it in pom.xml to version {} or above.".format(
+ java_plugin_dependency_version, MINIMUM_JAVA_DEPENDENCY_VERSION
+ )
+ )
+ protocol_version = project.settings.get(PROTOCOL_VERSION_SETTING)
+ if protocol_version != DEFAULT_PROTOCOL_VERSION:
+ project.settings[PROTOCOL_VERSION_SETTING] = DEFAULT_PROTOCOL_VERSION
+ project.write_settings()
+
+ LOG.debug("Generate complete")
+
@staticmethod
def _find_jar(project):
jar_glob = list(
@@ -399,6 +439,26 @@ def _find_jar(project):
return jar_glob[0]
+ @staticmethod
+ def _get_java_plugin_dependency_version(project):
+ try:
+ tree = ET.parse(project.root / "pom.xml")
+ root = tree.getroot()
+ namespace = {"mvn": "http://maven.apache.org/POM/4.0.0"}
+ plugin_dependency_version = root.find(
+ "./mvn:dependencies/mvn:dependency"
+ "/[mvn:artifactId='aws-cloudformation-rpdk-java-plugin']/mvn:version",
+ namespace,
+ )
+ if plugin_dependency_version is None:
+ raise JavaPluginNotFoundError(
+ "'aws-cloudformation-rpdk-java-plugin' maven dependency "
+ "not found in pom.xml."
+ )
+ return plugin_dependency_version.text
+ except ParseError:
+ raise InvalidMavenPOMError("pom.xml is invalid.")
+
@logdebug
def package(self, project, zip_file):
"""Packaging Java project"""
diff --git a/python/rpdk/java/templates/init/shared/pom.xml b/python/rpdk/java/templates/init/shared/pom.xml
index d811a269..b40c08d5 100644
--- a/python/rpdk/java/templates/init/shared/pom.xml
+++ b/python/rpdk/java/templates/init/shared/pom.xml
@@ -23,7 +23,7 @@
software.amazon.cloudformation
aws-cloudformation-rpdk-java-plugin
- 1.0.5
+ 2.0.0
diff --git a/src/main/java/software/amazon/cloudformation/LambdaWrapper.java b/src/main/java/software/amazon/cloudformation/LambdaWrapper.java
index 264164b6..c8bfdcad 100644
--- a/src/main/java/software/amazon/cloudformation/LambdaWrapper.java
+++ b/src/main/java/software/amazon/cloudformation/LambdaWrapper.java
@@ -14,7 +14,6 @@
*/
package software.amazon.cloudformation;
-import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
@@ -26,7 +25,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Arrays;
@@ -34,7 +32,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -47,8 +44,6 @@
import software.amazon.cloudformation.exceptions.BaseHandlerException;
import software.amazon.cloudformation.exceptions.FileScrubberException;
import software.amazon.cloudformation.exceptions.TerminalException;
-import software.amazon.cloudformation.injection.CloudFormationProvider;
-import software.amazon.cloudformation.injection.CloudWatchEventsProvider;
import software.amazon.cloudformation.injection.CloudWatchLogsProvider;
import software.amazon.cloudformation.injection.CloudWatchProvider;
import software.amazon.cloudformation.injection.CredentialsProvider;
@@ -60,8 +55,6 @@
import software.amazon.cloudformation.metrics.MetricsPublisher;
import software.amazon.cloudformation.metrics.MetricsPublisherImpl;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
-import software.amazon.cloudformation.proxy.CallbackAdapter;
-import software.amazon.cloudformation.proxy.CloudFormationCallbackAdapter;
import software.amazon.cloudformation.proxy.Credentials;
import software.amazon.cloudformation.proxy.DelayFactory;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
@@ -70,21 +63,18 @@
import software.amazon.cloudformation.proxy.MetricsPublisherProxy;
import software.amazon.cloudformation.proxy.OperationStatus;
import software.amazon.cloudformation.proxy.ProgressEvent;
-import software.amazon.cloudformation.proxy.RequestContext;
import software.amazon.cloudformation.proxy.ResourceHandlerRequest;
import software.amazon.cloudformation.resource.ResourceTypeSchema;
import software.amazon.cloudformation.resource.SchemaValidator;
import software.amazon.cloudformation.resource.Serializer;
import software.amazon.cloudformation.resource.Validator;
import software.amazon.cloudformation.resource.exceptions.ValidationException;
-import software.amazon.cloudformation.scheduler.CloudWatchScheduler;
public abstract class LambdaWrapper implements RequestStreamHandler {
public static final SdkHttpClient HTTP_CLIENT = ApacheHttpClient.builder().build();
private static final List MUTATING_ACTIONS = Arrays.asList(Action.CREATE, Action.DELETE, Action.UPDATE);
- private static final int INVOCATION_TIMEOUT_MS = 60000;
protected final Serializer serializer;
protected LoggerProxy loggerProxy;
@@ -95,33 +85,22 @@ public abstract class LambdaWrapper implements RequestStre
// provider... prefix indicates credential provided by resource owner
- final CredentialsProvider platformCredentialsProvider;
final CredentialsProvider providerCredentialsProvider;
- final CloudFormationProvider cloudFormationProvider;
- final CloudWatchProvider platformCloudWatchProvider;
final CloudWatchProvider providerCloudWatchProvider;
- final CloudWatchEventsProvider platformCloudWatchEventsProvider;
final CloudWatchLogsProvider cloudWatchLogsProvider;
final SchemaValidator validator;
final TypeReference> typeReference;
- private CallbackAdapter callbackAdapter;
- private MetricsPublisher platformMetricsPublisher;
private MetricsPublisher providerMetricsPublisher;
- private CloudWatchScheduler scheduler;
private LogPublisher platformLambdaLogger;
private CloudWatchLogHelper cloudWatchLogHelper;
private CloudWatchLogPublisher providerEventsLogger;
protected LambdaWrapper() {
- this.platformCredentialsProvider = new SessionCredentialsProvider();
this.providerCredentialsProvider = new SessionCredentialsProvider();
- this.cloudFormationProvider = new CloudFormationProvider(this.platformCredentialsProvider, HTTP_CLIENT);
- this.platformCloudWatchProvider = new CloudWatchProvider(this.platformCredentialsProvider, HTTP_CLIENT);
this.providerCloudWatchProvider = new CloudWatchProvider(this.providerCredentialsProvider, HTTP_CLIENT);
- this.platformCloudWatchEventsProvider = new CloudWatchEventsProvider(this.platformCredentialsProvider, HTTP_CLIENT);
this.cloudWatchLogsProvider = new CloudWatchLogsProvider(this.providerCredentialsProvider, HTTP_CLIENT);
this.serializer = new Serializer();
this.validator = new Validator();
@@ -131,31 +110,20 @@ protected LambdaWrapper() {
/*
* This .ctor provided for testing
*/
- public LambdaWrapper(final CallbackAdapter callbackAdapter,
- final CredentialsProvider platformCredentialsProvider,
- final CredentialsProvider providerCredentialsProvider,
- final CloudWatchLogPublisher providerEventsLogger,
+ public LambdaWrapper(final CredentialsProvider providerCredentialsProvider,
final LogPublisher platformEventsLogger,
- final MetricsPublisher platformMetricsPublisher,
+ final CloudWatchLogPublisher providerEventsLogger,
final MetricsPublisher providerMetricsPublisher,
- final CloudWatchScheduler scheduler,
final SchemaValidator validator,
final Serializer serializer,
final SdkHttpClient httpClient) {
- this.callbackAdapter = callbackAdapter;
- this.platformCredentialsProvider = platformCredentialsProvider;
this.providerCredentialsProvider = providerCredentialsProvider;
- this.cloudFormationProvider = new CloudFormationProvider(this.platformCredentialsProvider, httpClient);
- this.platformCloudWatchProvider = new CloudWatchProvider(this.platformCredentialsProvider, httpClient);
this.providerCloudWatchProvider = new CloudWatchProvider(this.providerCredentialsProvider, httpClient);
- this.platformCloudWatchEventsProvider = new CloudWatchEventsProvider(this.platformCredentialsProvider, httpClient);
this.cloudWatchLogsProvider = new CloudWatchLogsProvider(this.providerCredentialsProvider, httpClient);
this.providerEventsLogger = providerEventsLogger;
this.platformLambdaLogger = platformEventsLogger;
- this.platformMetricsPublisher = platformMetricsPublisher;
this.providerMetricsPublisher = providerMetricsPublisher;
- this.scheduler = scheduler;
this.serializer = serializer;
this.validator = validator;
this.typeReference = getTypeReference();
@@ -166,12 +134,10 @@ public LambdaWrapper(final CallbackAdapter callbackAdapter,
* passed at function invoke and not available during construction
*/
private void initialiseRuntime(final String resourceType,
- final Credentials platformCredentials,
final Credentials providerCredentials,
final String providerLogGroupName,
final Context context,
- final String awsAccountId,
- final URI callbackEndpoint) {
+ final String awsAccountId) {
this.loggerProxy = new LoggerProxy();
this.metricsPublisherProxy = new MetricsPublisherProxy();
@@ -179,20 +145,8 @@ private void initialiseRuntime(final String resourceType,
this.platformLambdaLogger = new LambdaLogPublisher(context.getLogger());
this.loggerProxy.addLogPublisher(this.platformLambdaLogger);
- this.cloudFormationProvider.setCallbackEndpoint(callbackEndpoint);
- this.platformCredentialsProvider.setCredentials(platformCredentials);
-
// Initialisation skipped if dependencies were set during injection (in unit
// tests).
- // e.g. "if (this.platformMetricsPublisher == null)"
- if (this.platformMetricsPublisher == null) {
- // platformMetricsPublisher needs aws account id to differentiate metrics
- // namespace
- this.platformMetricsPublisher = new MetricsPublisherImpl(this.platformCloudWatchProvider, this.loggerProxy,
- awsAccountId, resourceType);
- }
- this.metricsPublisherProxy.addMetricsPublisher(this.platformMetricsPublisher);
- this.platformMetricsPublisher.refreshClient();
// NOTE: providerCredentials and providerLogGroupName are null/not null in
// sync.
@@ -222,18 +176,6 @@ private void initialiseRuntime(final String resourceType,
this.loggerProxy.addLogPublisher(this.providerEventsLogger);
this.providerEventsLogger.refreshClient();
}
-
- if (this.callbackAdapter == null) {
- this.callbackAdapter = new CloudFormationCallbackAdapter<>(this.cloudFormationProvider, this.loggerProxy,
- this.serializer, ResourceTypeSchema
- .load(provideResourceSchemaJSONObject()));
- }
- this.callbackAdapter.refreshClient();
-
- if (this.scheduler == null) {
- this.scheduler = new CloudWatchScheduler(this.platformCloudWatchEventsProvider, this.loggerProxy, this.serializer);
- }
- this.scheduler.refreshClient();
}
@Override
@@ -254,8 +196,6 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
String input = this.serializer.decompress(IOUtils.toString(inputStream, StandardCharsets.UTF_8));
JSONObject rawInput = new JSONObject(new JSONTokener(input));
- bearerToken = rawInput.getString("bearerToken");
-
// deserialize incoming payload to modelled request
try {
request = this.serializer.deserialize(input, typeReference);
@@ -292,7 +232,7 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
} finally {
// A response will be output on all paths, though CloudFormation will
// not block on invoking the handlers, but rather listen for callbacks
- writeResponse(outputStream, createProgressResponse(handlerResponse, bearerToken));
+ writeResponse(outputStream, handlerResponse);
}
}
@@ -313,42 +253,13 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
}
}
- if (StringUtils.isEmpty(request.getResponseEndpoint())) {
- throw new TerminalException("No callback endpoint received");
- }
-
- // ensure required execution credentials have been passed and inject them
- if (request.getRequestData().getPlatformCredentials() == null) {
- throw new TerminalException("Missing required platform credentials");
- }
-
- // initialise dependencies with platform credentials
- initialiseRuntime(request.getResourceType(), request.getRequestData().getPlatformCredentials(),
- request.getRequestData().getProviderCredentials(), request.getRequestData().getProviderLogGroupName(), context,
- request.getAwsAccountId(), URI.create(request.getResponseEndpoint()));
+ // initialise dependencies
+ initialiseRuntime(request.getResourceType(), request.getRequestData().getProviderCredentials(),
+ request.getRequestData().getProviderLogGroupName(), context, request.getAwsAccountId());
// transform the request object to pass to caller
ResourceHandlerRequest resourceHandlerRequest = transform(request);
- RequestContext requestContext = request.getRequestContext();
-
- if (requestContext == null || requestContext.getInvocation() == 0) {
- // Acknowledge the task for first time invocation
- this.callbackAdapter.reportProgress(request.getBearerToken(), null, OperationStatus.IN_PROGRESS,
- OperationStatus.PENDING, null, null);
- }
-
- if (requestContext != null) {
- // If this invocation was triggered by a 're-invoke' CloudWatch Event, clean it
- // up
- String cloudWatchEventsRuleName = requestContext.getCloudWatchEventsRuleName();
- if (!StringUtils.isBlank(cloudWatchEventsRuleName)) {
- this.scheduler.cleanupCloudWatchEvents(cloudWatchEventsRuleName, requestContext.getCloudWatchEventsTargetId());
- log(String.format("Cleaned up previous Request Context of Rule %s and Target %s",
- requestContext.getCloudWatchEventsRuleName(), requestContext.getCloudWatchEventsTargetId()));
- }
- }
-
this.metricsPublisherProxy.publishInvocationMetric(Instant.now(), request.getAction());
// for CUD actions, validate incoming model - any error is a terminal failure on
@@ -382,48 +293,27 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
}
}
publishExceptionMetric(request.getAction(), e, HandlerErrorCode.InvalidRequest);
- this.callbackAdapter.reportProgress(request.getBearerToken(), HandlerErrorCode.InvalidRequest,
- OperationStatus.FAILED, OperationStatus.IN_PROGRESS, null, validationMessageBuilder.toString());
return ProgressEvent.defaultFailureHandler(new TerminalException(validationMessageBuilder.toString(), e),
HandlerErrorCode.InvalidRequest);
}
}
+ CallbackT callbackContext = request.getCallbackContext();
// last mile proxy creation with passed-in credentials (unless we are operating
// in a non-AWS model)
AmazonWebServicesClientProxy awsClientProxy = null;
if (request.getRequestData().getCallerCredentials() != null) {
- awsClientProxy = new AmazonWebServicesClientProxy(requestContext == null, this.loggerProxy,
+ awsClientProxy = new AmazonWebServicesClientProxy(callbackContext == null, this.loggerProxy,
request.getRequestData().getCallerCredentials(),
() -> (long) context.getRemainingTimeInMillis(),
DelayFactory.CONSTANT_DEFAULT_DELAY_FACTORY);
}
- boolean computeLocally = true;
- ProgressEvent handlerResponse = null;
-
- while (computeLocally) {
- // rebuild callback context on each invocation cycle
- requestContext = request.getRequestContext();
- CallbackT callbackContext = (requestContext != null) ? requestContext.getCallbackContext() : null;
-
- handlerResponse = wrapInvocationAndHandleErrors(awsClientProxy, resourceHandlerRequest, request, callbackContext);
+ ProgressEvent handlerResponse = wrapInvocationAndHandleErrors(awsClientProxy,
+ resourceHandlerRequest, request, callbackContext);
- // report the progress status back to configured endpoint on
- // mutating/potentially asynchronous actions
-
- if (isMutatingAction) {
- this.callbackAdapter.reportProgress(request.getBearerToken(), handlerResponse.getErrorCode(),
- handlerResponse.getStatus(), OperationStatus.IN_PROGRESS, handlerResponse.getResourceModel(),
- handlerResponse.getMessage());
- } else if (handlerResponse.getStatus() == OperationStatus.IN_PROGRESS) {
- throw new TerminalException("READ and LIST handlers must return synchronously.");
- }
- // When the handler responses IN_PROGRESS with a callback delay, we trigger a
- // callback to re-invoke
- // the handler for the Resource type to implement stabilization checks and
- // long-poll creation checks
- computeLocally = scheduleReinvocation(request, handlerResponse, context);
+ if (handlerResponse.getStatus() == OperationStatus.IN_PROGRESS && !isMutatingAction) {
+ throw new TerminalException("READ and LIST handlers must return synchronously.");
}
return handlerResponse;
@@ -479,22 +369,16 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp
}
- private Response createProgressResponse(final ProgressEvent progressEvent,
- final String bearerToken) {
-
- Response response = new Response<>();
- response.setMessage(progressEvent.getMessage());
- response.setOperationStatus(progressEvent.getStatus());
- response.setResourceModel(progressEvent.getResourceModel());
- response.setErrorCode(progressEvent.getErrorCode());
- response.setBearerToken(bearerToken);
- response.setResourceModels(progressEvent.getResourceModels());
- response.setNextToken(progressEvent.getNextToken());
+ private void writeResponse(final OutputStream outputStream, final ProgressEvent response)
+ throws IOException {
+ ResourceT model = response.getResourceModel();
+ if (model != null) {
+ JSONObject modelObject = new JSONObject(this.serializer.serialize(model));
+ ResourceTypeSchema.load(provideResourceSchemaJSONObject()).removeWriteOnlyProperties(modelObject);
+ ResourceT sanitizedModel = this.serializer.deserializeStrict(modelObject.toString(), getModelTypeReference());
- return response;
- }
-
- private void writeResponse(final OutputStream outputStream, final Response response) throws IOException {
+ response.setResourceModel(sanitizedModel);
+ }
String output = this.serializer.serialize(response);
outputStream.write(output.getBytes(StandardCharsets.UTF_8));
@@ -522,64 +406,6 @@ private void validateModel(final JSONObject modelObject) throws ValidationExcept
this.validator.validateObject(serializedModel, resourceSchemaJSONObject);
}
- /**
- * Managed scheduling of handler re-invocations.
- *
- * @param request the original request to the function
- * @param handlerResponse the previous response from handler
- * @param context LambdaContext granting runtime metadata
- * @return boolean indicating whether to continue invoking locally, or exit for
- * async reinvoke
- */
- private boolean scheduleReinvocation(final HandlerRequest request,
- final ProgressEvent handlerResponse,
- final Context context) {
-
- if (handlerResponse.getStatus() != OperationStatus.IN_PROGRESS) {
- // no reinvoke required
- return false;
- }
-
- RequestContext reinvocationContext = new RequestContext<>();
- RequestContext requestContext = request.getRequestContext();
-
- int counter = 1;
- if (requestContext != null) {
- counter += requestContext.getInvocation();
- }
- reinvocationContext.setInvocation(counter);
-
- reinvocationContext.setCallbackContext(handlerResponse.getCallbackContext());
- request.setRequestContext(reinvocationContext);
-
- // when a handler requests a sub-minute callback delay, and if the lambda
- // invocation
- // has enough runtime (with 20% buffer), we can reschedule from a thread wait
- // otherwise we re-invoke through CloudWatchEvents which have a granularity of
- // minutes
- // This also guarantees a maximum of a minute of execution time per local
- // reinvocation
- if ((handlerResponse.getCallbackDelaySeconds() < 60) && context
- .getRemainingTimeInMillis() > Math.abs(handlerResponse.getCallbackDelaySeconds()) * 1200 + INVOCATION_TIMEOUT_MS) {
- log(String.format("Scheduling re-invoke locally after %s seconds, with Context {%s}",
- handlerResponse.getCallbackDelaySeconds(), reinvocationContext.toString()));
- sleepUninterruptibly(handlerResponse.getCallbackDelaySeconds(), TimeUnit.SECONDS);
- return true;
- }
-
- log(String.format("Scheduling re-invoke with Context {%s}", reinvocationContext.toString()));
- try {
- int callbackDelayMinutes = Math.abs(handlerResponse.getCallbackDelaySeconds() / 60);
- this.scheduler.rescheduleAfterMinutes(context.getInvokedFunctionArn(), callbackDelayMinutes, request);
- } catch (final Throwable e) {
- handlerResponse.setMessage("Failed to schedule re-invoke.");
- handlerResponse.setStatus(OperationStatus.FAILED);
- handlerResponse.setErrorCode(HandlerErrorCode.InternalFailure);
- }
-
- return false;
- }
-
/**
* Transforms the incoming request to the subset of typed models which the
* handler implementor needs
diff --git a/src/main/java/software/amazon/cloudformation/proxy/HandlerRequest.java b/src/main/java/software/amazon/cloudformation/proxy/HandlerRequest.java
index a5d698bb..cc8ada67 100644
--- a/src/main/java/software/amazon/cloudformation/proxy/HandlerRequest.java
+++ b/src/main/java/software/amazon/cloudformation/proxy/HandlerRequest.java
@@ -29,10 +29,10 @@ public class HandlerRequest {
private String bearerToken;
private String nextToken;
private String region;
- private String responseEndpoint;
private String resourceType;
private String resourceTypeVersion;
private RequestData requestData;
private String stackId;
+ private CallbackT callbackContext;
private RequestContext requestContext;
}
diff --git a/src/main/java/software/amazon/cloudformation/proxy/RequestData.java b/src/main/java/software/amazon/cloudformation/proxy/RequestData.java
index d63affb8..d6b1cbc1 100644
--- a/src/main/java/software/amazon/cloudformation/proxy/RequestData.java
+++ b/src/main/java/software/amazon/cloudformation/proxy/RequestData.java
@@ -22,7 +22,6 @@
@NoArgsConstructor
public class RequestData {
private Credentials callerCredentials;
- private Credentials platformCredentials;
private Credentials providerCredentials;
private String providerLogGroupName;
private String logicalResourceId;
diff --git a/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java b/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java
index 9adfc9bd..8b104bad 100644
--- a/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java
+++ b/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java
@@ -16,11 +16,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.*;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.lambda.runtime.Context;
@@ -35,9 +32,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import org.json.JSONObject;
import org.junit.jupiter.api.BeforeEach;
@@ -45,12 +40,9 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import software.amazon.awssdk.http.SdkHttpClient;
-import software.amazon.awssdk.services.cloudformation.model.OperationStatusCheckFailedException;
import software.amazon.cloudformation.exceptions.ResourceAlreadyExistsException;
import software.amazon.cloudformation.exceptions.ResourceNotFoundException;
import software.amazon.cloudformation.exceptions.TerminalException;
@@ -58,11 +50,9 @@
import software.amazon.cloudformation.loggers.CloudWatchLogPublisher;
import software.amazon.cloudformation.loggers.LogPublisher;
import software.amazon.cloudformation.metrics.MetricsPublisher;
-import software.amazon.cloudformation.proxy.CallbackAdapter;
import software.amazon.cloudformation.proxy.Credentials;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
import software.amazon.cloudformation.proxy.HandlerRequest;
-import software.amazon.cloudformation.proxy.HandlerResponse;
import software.amazon.cloudformation.proxy.OperationStatus;
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.RequestData;
@@ -71,25 +61,15 @@
import software.amazon.cloudformation.resource.Serializer;
import software.amazon.cloudformation.resource.Validator;
import software.amazon.cloudformation.resource.exceptions.ValidationException;
-import software.amazon.cloudformation.scheduler.CloudWatchScheduler;
@ExtendWith(MockitoExtension.class)
public class LambdaWrapperTest {
private static final String TEST_DATA_BASE_PATH = "src/test/java/software/amazon/cloudformation/data/%s";
- @Mock
- private CallbackAdapter callbackAdapter;
-
- @Mock
- private CredentialsProvider platformCredentialsProvider;
-
@Mock
private CredentialsProvider providerLoggingCredentialsProvider;
- @Mock
- private MetricsPublisher platformMetricsPublisher;
-
@Mock
private MetricsPublisher providerMetricsPublisher;
@@ -99,9 +79,6 @@ public class LambdaWrapperTest {
@Mock
private LogPublisher platformEventsLogger;
- @Mock
- private CloudWatchScheduler scheduler;
-
@Mock
private SchemaValidator validator;
@@ -118,9 +95,8 @@ public class LambdaWrapperTest {
@BeforeEach
public void initWrapper() {
- wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider,
- platformEventsLogger, providerEventsLogger, platformMetricsPublisher,
- providerMetricsPublisher, scheduler, validator, httpClient);
+ wrapper = new WrapperOverride(providerLoggingCredentialsProvider, platformEventsLogger, providerEventsLogger,
+ providerMetricsPublisher, validator, httpClient);
}
public static InputStream loadRequestStream(final String fileName) {
@@ -142,25 +118,20 @@ private Context getLambdaContext() {
}
private void verifyInitialiseRuntime() {
- verify(platformCredentialsProvider).setCredentials(any(Credentials.class));
verify(providerLoggingCredentialsProvider).setCredentials(any(Credentials.class));
- verify(callbackAdapter).refreshClient();
- verify(platformMetricsPublisher).refreshClient();
verify(providerMetricsPublisher).refreshClient();
- verify(scheduler).refreshClient();
}
- private void verifyHandlerResponse(final OutputStream out, final HandlerResponse expected) throws IOException {
+ private void verifyHandlerResponse(final OutputStream out, final ProgressEvent expected)
+ throws IOException {
final Serializer serializer = new Serializer();
- final HandlerResponse<
- TestModel> handlerResponse = serializer.deserialize(out.toString(), new TypeReference>() {
+ final ProgressEvent handlerResponse = serializer.deserialize(out.toString(),
+ new TypeReference>() {
});
- assertThat(handlerResponse.getBearerToken()).isEqualTo(expected.getBearerToken());
assertThat(handlerResponse.getErrorCode()).isEqualTo(expected.getErrorCode());
assertThat(handlerResponse.getNextToken()).isEqualTo(expected.getNextToken());
- assertThat(handlerResponse.getOperationStatus()).isEqualTo(expected.getOperationStatus());
- assertThat(handlerResponse.getStabilizationData()).isEqualTo(expected.getStabilizationData());
+ assertThat(handlerResponse.getStatus()).isEqualTo(expected.getStatus());
assertThat(handlerResponse.getResourceModel()).isEqualTo(expected.getResourceModel());
}
@@ -187,14 +158,10 @@ public void invokeHandler_nullResponse_returnsFailure(final String requestDataPa
verifyInitialiseRuntime();
// validation failure metric should be published for final error handling
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
- any(TerminalException.class), any(HandlerErrorCode.class));
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
any(TerminalException.class), any(HandlerErrorCode.class));
// all metrics should be published even on terminal failure
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
@@ -203,16 +170,13 @@ public void invokeHandler_nullResponse_returnsFailure(final String requestDataPa
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
}
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
verify(providerEventsLogger).refreshClient();
verify(providerEventsLogger, times(2)).publishLogEvent(any());
verifyNoMoreInteractions(providerEventsLogger);
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("Handler failed to provide a response.").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("Handler failed to provide a response.").build());
// assert handler receives correct injections
assertThat(wrapper.awsClientProxy).isNotNull();
@@ -243,22 +207,14 @@ private void invokeHandler_without_customerLoggingCredentials(final String reque
wrapper.handleRequest(in, out, context);
// verify initialiseRuntime was called and initialised dependencies
- verify(platformCredentialsProvider).setCredentials(any(Credentials.class));
verify(providerLoggingCredentialsProvider, times(0)).setCredentials(any(Credentials.class));
- verify(callbackAdapter).refreshClient();
- verify(platformMetricsPublisher).refreshClient();
verify(providerMetricsPublisher, times(0)).refreshClient();
- verify(scheduler).refreshClient();
// validation failure metric should be published for final error handling
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
- any(TerminalException.class), any(HandlerErrorCode.class));
verify(providerMetricsPublisher, times(0)).publishExceptionMetric(any(Instant.class), any(),
any(TerminalException.class), any(HandlerErrorCode.class));
// all metrics should be published even on terminal failure
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
verify(providerMetricsPublisher, times(0)).publishInvocationMetric(any(Instant.class), eq(action));
verify(providerMetricsPublisher, times(0)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
@@ -267,14 +223,11 @@ private void invokeHandler_without_customerLoggingCredentials(final String reque
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
}
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
verifyNoMoreInteractions(providerEventsLogger);
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("Handler failed to provide a response.").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("Handler failed to provide a response.").build());
}
}
@@ -300,24 +253,14 @@ public void invokeHandler_handlerFailed_returnsFailure(final String requestDataP
// verify initialiseRuntime was called and initialised dependencies
verifyInitialiseRuntime();
- // all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
-
- // validation failure metric should not be published
- verifyNoMoreInteractions(platformMetricsPublisher);
-
// verify that model validation occurred for CREATE/UPDATE/DELETE
if (action == Action.CREATE || action == Action.UPDATE || action == Action.DELETE) {
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
}
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("Custom Fault").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("Custom Fault").build());
// assert handler receives correct injections
assertThat(wrapper.awsClientProxy).isNotNull();
@@ -339,8 +282,7 @@ public void invokeHandler_withNullInput() throws IOException {
try (final InputStream in = null; final OutputStream out = new ByteArrayOutputStream()) {
final Context context = getLambdaContext();
wrapper.handleRequest(in, out, context);
- verifyNoMoreInteractions(callbackAdapter, platformMetricsPublisher, platformEventsLogger, providerMetricsPublisher,
- providerEventsLogger);
+ verifyNoMoreInteractions(providerMetricsPublisher, providerEventsLogger);
}
}
@@ -370,24 +312,13 @@ public void invokeHandler_CompleteSynchronously_returnsSuccess(final String requ
// verify initialiseRuntime was called and initialised dependencies
verifyInitialiseRuntime();
- // all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
-
- // validation failure metric should not be published
- verifyNoMoreInteractions(platformMetricsPublisher);
-
// verify that model validation occurred for CREATE/UPDATE/DELETE
if (action == Action.CREATE || action == Action.UPDATE || action == Action.DELETE) {
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
}
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
// verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.SUCCESS).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.SUCCESS).build());
// assert handler receives correct injections
assertThat(wrapper.awsClientProxy).isNotNull();
@@ -414,7 +345,7 @@ public void invokeHandler_DependenciesInitialised_CompleteSynchronously_returnsS
wrapper.setTransformResponse(resourceHandlerRequest);
// use a request context in our payload to bypass certain callbacks
- try (final InputStream in = loadRequestStream("create.with-request-context.request.json");
+ try (final InputStream in = loadRequestStream("create.with-callback-context.request.json");
final OutputStream out = new ByteArrayOutputStream()) {
final Context context = getLambdaContext();
@@ -426,12 +357,8 @@ public void invokeHandler_DependenciesInitialised_CompleteSynchronously_returnsS
assertThat(wrapper.loggerProxy).isNotNull();
assertThat(wrapper.metricsPublisherProxy).isNotNull();
assertThat(wrapper.lambdaLogger).isNotNull();
- assertThat(wrapper.platformCredentialsProvider).isNotNull();
assertThat(wrapper.providerCredentialsProvider).isNotNull();
- assertThat(wrapper.cloudFormationProvider).isNotNull();
- assertThat(wrapper.platformCloudWatchProvider).isNotNull();
assertThat(wrapper.providerCloudWatchProvider).isNotNull();
- assertThat(wrapper.platformCloudWatchEventsProvider).isNotNull();
assertThat(wrapper.cloudWatchLogsProvider).isNotNull();
assertThat(wrapper.validator).isNotNull();
}
@@ -463,8 +390,6 @@ public void invokeHandler_InProgress_returnsInProgress(final String requestDataP
verifyInitialiseRuntime();
// all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
@@ -472,32 +397,19 @@ public void invokeHandler_InProgress_returnsInProgress(final String requestDataP
if (action == Action.CREATE || action == Action.UPDATE || action == Action.DELETE) {
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
- // re-invocation via CloudWatch should occur
- verify(scheduler, times(1)).rescheduleAfterMinutes(anyString(), eq(0),
- ArgumentMatchers.>any());
-
- // CloudFormation should receive a callback invocation
- verify(callbackAdapter, times(1)).reportProgress(eq("123456"), isNull(), eq(OperationStatus.IN_PROGRESS),
- eq(OperationStatus.IN_PROGRESS), eq(TestModel.builder().property1("abc").property2(123).build()), isNull());
-
// verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.IN_PROGRESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.IN_PROGRESS)
+ .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
} else {
verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.FAILED)
- .errorCode(HandlerErrorCode.InternalFailure.name())
- .message("READ and LIST handlers must return synchronously.").build());
+ ProgressEvent.builder().status(OperationStatus.FAILED)
+ .errorCode(HandlerErrorCode.InternalFailure).message("READ and LIST handlers must return synchronously.")
+ .build());
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), eq(action),
any(TerminalException.class), eq(HandlerErrorCode.InternalFailure));
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), eq(action),
- any(TerminalException.class), eq(HandlerErrorCode.InternalFailure));
}
// validation failure metric should not be published
- verifyNoMoreInteractions(platformMetricsPublisher);
verifyNoMoreInteractions(providerMetricsPublisher);
- verifyNoMoreInteractions(scheduler);
// assert handler receives correct injections
assertThat(wrapper.awsClientProxy).isNotNull();
@@ -508,8 +420,8 @@ public void invokeHandler_InProgress_returnsInProgress(final String requestDataP
}
@ParameterizedTest
- @CsvSource({ "create.with-request-context.request.json,CREATE", "update.with-request-context.request.json,UPDATE",
- "delete.with-request-context.request.json,DELETE" })
+ @CsvSource({ "create.with-callback-context.request.json,CREATE", "update.with-callback-context.request.json,UPDATE",
+ "delete.with-callback-context.request.json,DELETE" })
public void reInvokeHandler_InProgress_returnsInProgress(final String requestDataPath, final String actionAsString)
throws IOException {
final Action action = Action.valueOf(actionAsString);
@@ -535,14 +447,10 @@ public void reInvokeHandler_InProgress_returnsInProgress(final String requestDat
verifyInitialiseRuntime();
// all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
-
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(action), anyLong());
// validation failure metric should not be published
- verifyNoMoreInteractions(platformMetricsPublisher);
verifyNoMoreInteractions(providerMetricsPublisher);
// verify that model validation occurred for CREATE/UPDATE/DELETE
@@ -550,22 +458,9 @@ public void reInvokeHandler_InProgress_returnsInProgress(final String requestDat
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
}
- // re-invocation via CloudWatch should occur
- verify(scheduler, times(1)).rescheduleAfterMinutes(anyString(), eq(1),
- ArgumentMatchers.>any());
-
- // this was a re-invocation, so a cleanup is required
- verify(scheduler, times(1)).cleanupCloudWatchEvents(eq("reinvoke-handler-4754ac8a-623b-45fe-84bc-f5394118a8be"),
- eq("reinvoke-target-4754ac8a-623b-45fe-84bc-f5394118a8be"));
-
- // CloudFormation should receive a callback invocation
- verify(callbackAdapter, times(1)).reportProgress(eq("123456"), isNull(), eq(OperationStatus.IN_PROGRESS),
- eq(OperationStatus.IN_PROGRESS), eq(TestModel.builder().property1("abc").property2(123).build()), isNull());
-
// verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.IN_PROGRESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.IN_PROGRESS)
+ .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
}
}
@@ -587,48 +482,28 @@ public void invokeHandler_SchemaValidationFailure(final String requestDataPath,
verifyInitialiseRuntime();
// validation failure metric should be published but no others
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), eq(action),
- any(Exception.class), any(HandlerErrorCode.class));
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), eq(action),
any(Exception.class), any(HandlerErrorCode.class));
// all metrics should be published, even for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(action));
- // duration metric only published when the provider handler is invoked
- verifyNoMoreInteractions(platformMetricsPublisher);
-
// verify that model validation occurred for CREATE/UPDATE/DELETE
if (action == Action.CREATE || action == Action.UPDATE || action == Action.DELETE) {
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
}
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
- // first report to acknowledge the task
- verify(callbackAdapter).reportProgress(any(), any(), eq(OperationStatus.IN_PROGRESS), eq(OperationStatus.PENDING),
- any(), any());
-
- // second report to record validation failure
- verify(callbackAdapter).reportProgress(any(), any(), eq(OperationStatus.FAILED), eq(OperationStatus.IN_PROGRESS),
- any(), any());
- verifyNoMoreInteractions(callbackAdapter);
-
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456").errorCode("InvalidRequest")
- .operationStatus(OperationStatus.FAILED).message("Model validation failed with unknown cause.").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InvalidRequest)
+ .status(OperationStatus.FAILED).message("Model validation failed with unknown cause.").build());
}
}
@Test
public void invokeHandler_invalidModelTypes_causesSchemaValidationFailure() throws IOException {
// use actual validator to verify behaviour
- final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider, platformEventsLogger,
- providerEventsLogger, platformMetricsPublisher,
- providerMetricsPublisher, scheduler, new Validator() {
+ final WrapperOverride wrapper = new WrapperOverride(providerLoggingCredentialsProvider, platformEventsLogger,
+ providerEventsLogger, providerMetricsPublisher, new Validator() {
}, httpClient);
wrapper.setTransformResponse(resourceHandlerRequest);
@@ -641,8 +516,8 @@ providerMetricsPublisher, scheduler, new Validator() {
// verify output response
verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("InvalidRequest")
- .operationStatus(OperationStatus.FAILED)
+ ProgressEvent.builder().errorCode(HandlerErrorCode.InvalidRequest)
+ .status(OperationStatus.FAILED)
.message("Model validation failed (#/property1: expected type: String, found: JSONArray)").build());
}
}
@@ -650,10 +525,8 @@ providerMetricsPublisher, scheduler, new Validator() {
@Test
public void invokeHandler_extraneousModelFields_causesSchemaValidationFailure() throws IOException {
// use actual validator to verify behaviour
- final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider, platformEventsLogger,
- providerEventsLogger, platformMetricsPublisher,
- providerMetricsPublisher, scheduler, new Validator() {
+ final WrapperOverride wrapper = new WrapperOverride(providerLoggingCredentialsProvider, platformEventsLogger,
+ providerEventsLogger, providerMetricsPublisher, new Validator() {
}, httpClient);
wrapper.setTransformResponse(resourceHandlerRequest);
@@ -665,36 +538,18 @@ providerMetricsPublisher, scheduler, new Validator() {
wrapper.handleRequest(in, out, context);
// validation failure metric should be published but no others
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), eq(Action.CREATE),
- any(Exception.class), any(HandlerErrorCode.class));
-
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), eq(Action.CREATE),
any(Exception.class), any(HandlerErrorCode.class));
// all metrics should be published, even for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
-
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
// verify initialiseRuntime was called and initialised dependencies
verifyInitialiseRuntime();
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
- // first report to acknowledge the task
- verify(callbackAdapter).reportProgress(any(), any(), eq(OperationStatus.IN_PROGRESS), eq(OperationStatus.PENDING),
- any(), any());
-
- // second report to record validation failure
- verify(callbackAdapter).reportProgress(any(), any(), eq(OperationStatus.FAILED), eq(OperationStatus.IN_PROGRESS),
- any(), any());
-
- verifyNoMoreInteractions(callbackAdapter);
-
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456").errorCode("InvalidRequest")
- .operationStatus(OperationStatus.FAILED)
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InvalidRequest)
+ .status(OperationStatus.FAILED)
.message("Model validation failed (#: extraneous key [fieldCausesValidationError] is not permitted)").build());
}
}
@@ -722,26 +577,8 @@ public void invokeHandler_withMalformedRequest_causesSchemaValidationFailure() t
wrapper.handleRequest(in, out, context);
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456")
- .operationStatus(OperationStatus.SUCCESS).resourceModel(TestModel.builder().build()).build());
- }
- }
-
- @Test
- public void invokeHandler_withoutPlatformCredentials_returnsFailure() throws IOException {
- // without platform credentials the handler is unable to do
- // basic SDK initialization and any such request should fail fast
- try (final InputStream in = loadRequestStream("create.request-without-platform-credentials.json");
- final OutputStream out = new ByteArrayOutputStream()) {
- final Context context = getLambdaContext();
-
- wrapper.handleRequest(in, out, context);
-
- // verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("Missing required platform credentials")
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.SUCCESS)
+ .resourceModel(TestModel.builder().build()).build());
}
}
@@ -757,8 +594,6 @@ public void invokeHandler_withoutCallerCredentials_passesNoAWSProxy() throws IOE
.status(OperationStatus.SUCCESS).resourceModel(model).build();
wrapper.setInvokeHandlerResponse(pe);
- // without platform credentials the handler is unable to do
- // basic SDK initialization and any such request should fail fast
try (final InputStream in = loadRequestStream("create.request-without-caller-credentials.json");
final OutputStream out = new ByteArrayOutputStream()) {
final Context context = getLambdaContext();
@@ -766,9 +601,8 @@ public void invokeHandler_withoutCallerCredentials_passesNoAWSProxy() throws IOE
wrapper.handleRequest(in, out, context);
// verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.SUCCESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.SUCCESS)
+ .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
// proxy should be null by virtue of having not had callerCredentials passed in
assertThat(wrapper.awsClientProxy).isNull();
@@ -787,8 +621,6 @@ public void invokeHandler_withDefaultInjection_returnsSuccess() throws IOExcepti
.status(OperationStatus.SUCCESS).resourceModel(model).build();
wrapper.setInvokeHandlerResponse(pe);
- // without platform credentials the handler is unable to do
- // basic SDK initialization and any such request should fail fast
try (final InputStream in = loadRequestStream("create.request.json");
final OutputStream out = new ByteArrayOutputStream()) {
final Context context = getLambdaContext();
@@ -796,9 +628,8 @@ public void invokeHandler_withDefaultInjection_returnsSuccess() throws IOExcepti
wrapper.handleRequest(in, out, context);
// verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.SUCCESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.SUCCESS)
+ .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
// proxy uses caller credentials and will be injected
assertThat(wrapper.awsClientProxy).isNotNull();
@@ -817,46 +648,14 @@ public void invokeHandler_withDefaultInjection_returnsInProgress() throws IOExce
.status(OperationStatus.IN_PROGRESS).resourceModel(model).build();
wrapper.setInvokeHandlerResponse(pe);
- // without platform credentials the handler is unable to do
- // basic SDK initialization and any such request should fail fast
try (final InputStream in = loadRequestStream("create.request.json");
final OutputStream out = new ByteArrayOutputStream()) {
final Context context = getLambdaContext();
wrapper.handleRequest(in, out, context);
// verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.IN_PROGRESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
- }
- }
-
- @Test
- public void invokeHandler_failToRescheduleInvocation() throws IOException {
- final TestModel model = new TestModel();
- model.setProperty1("abc");
- model.setProperty2(123);
- doThrow(new AmazonServiceException("some error")).when(scheduler).rescheduleAfterMinutes(anyString(), anyInt(),
- ArgumentMatchers.>any());
- wrapper.setTransformResponse(resourceHandlerRequest);
-
- // respond with in progress status to trigger callback invocation
- final ProgressEvent pe = ProgressEvent.builder()
- .status(OperationStatus.IN_PROGRESS).resourceModel(model).build();
- wrapper.setInvokeHandlerResponse(pe);
-
- try (final InputStream in = loadRequestStream("create.request.json");
- final OutputStream out = new ByteArrayOutputStream()) {
- final Context context = getLambdaContext();
-
- wrapper.handleRequest(in, out, context);
-
- // verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED)
- .message("some error (Service: null; Status Code: 0; Error Code: null; Request ID: null)")
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
+ verifyHandlerResponse(out, ProgressEvent.builder().status(OperationStatus.IN_PROGRESS)
+ .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
}
}
@@ -867,247 +666,12 @@ public void invokeHandler_clientsRefreshedOnEveryInvoke() throws IOException {
wrapper.handleRequest(in, out, context);
}
- verify(callbackAdapter, times(1)).refreshClient();
- verify(platformMetricsPublisher, times(1)).refreshClient();
- verify(scheduler, times(1)).refreshClient();
-
// invoke the same wrapper instance again to ensure client is refreshed
context = getLambdaContext();
try (InputStream in = loadRequestStream("create.request.json"); OutputStream out = new ByteArrayOutputStream()) {
wrapper.handleRequest(in, out, context);
}
- verify(callbackAdapter, times(2)).refreshClient();
- verify(platformMetricsPublisher, times(2)).refreshClient();
- verify(scheduler, times(2)).refreshClient();
- }
-
- @Test
- public void invokeHandler_platformCredentialsRefreshedOnEveryInvoke() throws IOException {
- Context context = getLambdaContext();
- try (InputStream in = loadRequestStream("create.request.json"); OutputStream out = new ByteArrayOutputStream()) {
- wrapper.handleRequest(in, out, context);
- }
-
- final Credentials expected = new Credentials("32IEHAHFIAG538KYASAI", "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal");
- verify(platformCredentialsProvider, times(1)).setCredentials(eq(expected));
- // invoke the same wrapper instance again to ensure client is refreshed
- context = getLambdaContext();
- try (InputStream in = loadRequestStream("create.request.with-new-credentials.json");
- OutputStream out = new ByteArrayOutputStream()) {
- wrapper.handleRequest(in, out, context);
- }
-
- final Credentials expectedNew = new Credentials("GT530IJDHALYZQSZZ8XG", "UeJEwC/dqcYEn2viFd5TjKjR5TaMOfdeHrlLXxQL",
- "469gs8raWJCaZcItXhGJ7dt3urI13fOTcde6ibhuHJz6r6bRRCWvLYGvCsqrN8WUClYL9lxZHymrWXvZ9xN0GoI2LFdcAAinZk5t");
-
- verify(platformCredentialsProvider, times(1)).setCredentials(eq(expectedNew));
- }
-
- @Test
- public void invokeHandler_withNoResponseEndpoint_returnsFailure() throws IOException {
- final TestModel model = new TestModel();
-
- // an InProgress response is always re-scheduled.
- // If no explicit time is supplied, a 1-minute interval is used
- final ProgressEvent pe = ProgressEvent.builder()
- .status(OperationStatus.SUCCESS).resourceModel(model).build();
- wrapper.setInvokeHandlerResponse(pe);
- wrapper.setTransformResponse(resourceHandlerRequest);
-
- // our ObjectMapper implementation will ignore extraneous fields rather than
- // fail them
- // this slightly loosens the coupling between caller (CloudFormation) and
- // handlers.
- try (final InputStream in = loadRequestStream("no-response-endpoint.request.json");
- final OutputStream out = new ByteArrayOutputStream()) {
- final Context context = getLambdaContext();
-
- wrapper.handleRequest(in, out, context);
-
- // malformed input exception is published
- verify(lambdaLogger, times(1)).log(anyString());
- verifyNoMoreInteractions(platformMetricsPublisher);
-
- // verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("No callback endpoint received")
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
- }
- }
-
- @Test
- public void invokeHandler_localReinvokeWithSufficientRemainingTime() throws IOException {
- final TestModel model = TestModel.builder().property1("abc").property2(123).build();
-
- // an InProgress response is always re-scheduled.
- // If no explicit time is supplied, a 1-minute interval is used
- final ProgressEvent pe1 = ProgressEvent.builder().status(OperationStatus.IN_PROGRESS) // iterate
- // locally once
- .callbackDelaySeconds(5).resourceModel(model).build();
- final ProgressEvent pe2 = ProgressEvent.builder().status(OperationStatus.SUCCESS) // then exit loop
- .resourceModel(model).build();
- wrapper.enqueueResponses(Arrays.asList(pe1, pe2));
-
- wrapper.setTransformResponse(resourceHandlerRequest);
-
- try (final InputStream in = loadRequestStream("create.with-request-context.request.json");
- final OutputStream out = new ByteArrayOutputStream()) {
-
- final Context context = getLambdaContext();
- // give enough time to invoke again locally
- when(context.getRemainingTimeInMillis()).thenReturn(75000);
-
- wrapper.handleRequest(in, out, context);
-
- // verify initialiseRuntime was called and initialised dependencies
- verifyInitialiseRuntime();
-
- // all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(platformMetricsPublisher, times(2)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
- verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(providerMetricsPublisher, times(2)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
- // validation failure metric should not be published
- verifyNoMoreInteractions(platformMetricsPublisher);
- verifyNoMoreInteractions(providerMetricsPublisher);
-
- // verify that model validation occurred for CREATE/UPDATE/DELETE
- verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
-
- // this was a re-invocation, so a cleanup is required
- verify(scheduler, times(1)).cleanupCloudWatchEvents(eq("reinvoke-handler-4754ac8a-623b-45fe-84bc-f5394118a8be"),
- eq("reinvoke-target-4754ac8a-623b-45fe-84bc-f5394118a8be"));
-
- // re-invocation via CloudWatch should NOT occur for <60 when Lambda remaining
- // time allows
- verifyNoMoreInteractions(scheduler);
-
- final ArgumentCaptor bearerTokenCaptor = ArgumentCaptor.forClass(String.class);
- final ArgumentCaptor errorCodeCaptor = ArgumentCaptor.forClass(HandlerErrorCode.class);
- final ArgumentCaptor operationStatusCaptor = ArgumentCaptor.forClass(OperationStatus.class);
- final ArgumentCaptor resourceModelCaptor = ArgumentCaptor.forClass(TestModel.class);
- final ArgumentCaptor statusMessageCaptor = ArgumentCaptor.forClass(String.class);
-
- verify(callbackAdapter, times(2)).reportProgress(bearerTokenCaptor.capture(), errorCodeCaptor.capture(),
- operationStatusCaptor.capture(), operationStatusCaptor.capture(), resourceModelCaptor.capture(),
- statusMessageCaptor.capture());
-
- final List bearerTokens = bearerTokenCaptor.getAllValues();
- final List errorCodes = errorCodeCaptor.getAllValues();
- final List operationStatuses = operationStatusCaptor.getAllValues();
- final List resourceModels = resourceModelCaptor.getAllValues();
- final List statusMessages = statusMessageCaptor.getAllValues();
-
- // CloudFormation should receive 2 callback invocation; once for IN_PROGRESS,
- // once for COMPLETION
- assertThat(bearerTokens).containsExactly("123456", "123456");
- assertThat(errorCodes).containsExactly(null, null);
- assertThat(resourceModels).containsExactly(TestModel.builder().property1("abc").property2(123).build(),
- TestModel.builder().property1("abc").property2(123).build());
- assertThat(statusMessages).containsExactly(null, null);
- assertThat(operationStatuses).containsExactly(OperationStatus.IN_PROGRESS, OperationStatus.IN_PROGRESS,
- OperationStatus.SUCCESS, OperationStatus.IN_PROGRESS);
-
- // verify final output response is for success response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.SUCCESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
- }
- }
-
- @Test
- public void invokeHandler_localReinvokeWithSufficientRemainingTimeForFirstIterationOnly_SchedulesViaCloudWatch()
- throws IOException {
- final TestModel model = TestModel.builder().property1("abc").property2(123).build();
-
- // an InProgress response is always re-scheduled.
- // If no explicit time is supplied, a 1-minute interval is used
- final ProgressEvent pe1 = ProgressEvent.builder().status(OperationStatus.IN_PROGRESS) // iterate
- // locally once
- .callbackDelaySeconds(5).resourceModel(model).build();
- final ProgressEvent pe2 = ProgressEvent.builder().status(OperationStatus.IN_PROGRESS) // second
- // iteration
- // will exceed
- // runtime
- .callbackDelaySeconds(5).resourceModel(model).build();
- wrapper.enqueueResponses(Arrays.asList(pe1, pe2));
-
- wrapper.setTransformResponse(resourceHandlerRequest);
-
- try (final InputStream in = loadRequestStream("create.with-request-context.request.json");
- final OutputStream out = new ByteArrayOutputStream()) {
-
- final Context context = getLambdaContext();
- // first remaining time allows for a local reinvocation, whereas the latter will
- // force the second invocation to be via CWE
- when(context.getRemainingTimeInMillis()).thenReturn(70000, 5000);
-
- wrapper.handleRequest(in, out, context);
-
- // verify initialiseRuntime was called and initialised dependencies
- verifyInitialiseRuntime();
-
- // all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(platformMetricsPublisher, times(2)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
- verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(providerMetricsPublisher, times(2)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
- // validation failure metric should not be published
- verifyNoMoreInteractions(platformMetricsPublisher);
- verifyNoMoreInteractions(providerMetricsPublisher);
-
- // verify that model validation occurred for CREATE/UPDATE/DELETE
- verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
-
- // re-invocation via CloudWatch should occur for the second iteration
- verify(scheduler, times(1)).rescheduleAfterMinutes(anyString(), eq(0),
- ArgumentMatchers.>any());
-
- // this was a re-invocation, so a cleanup is required
- verify(scheduler, times(1)).cleanupCloudWatchEvents(eq("reinvoke-handler-4754ac8a-623b-45fe-84bc-f5394118a8be"),
- eq("reinvoke-target-4754ac8a-623b-45fe-84bc-f5394118a8be"));
-
- final ArgumentCaptor bearerTokenCaptor = ArgumentCaptor.forClass(String.class);
- final ArgumentCaptor errorCodeCaptor = ArgumentCaptor.forClass(HandlerErrorCode.class);
- final ArgumentCaptor operationStatusCaptor = ArgumentCaptor.forClass(OperationStatus.class);
- final ArgumentCaptor resourceModelCaptor = ArgumentCaptor.forClass(TestModel.class);
- final ArgumentCaptor statusMessageCaptor = ArgumentCaptor.forClass(String.class);
-
- verify(callbackAdapter, times(2)).reportProgress(bearerTokenCaptor.capture(), errorCodeCaptor.capture(),
- operationStatusCaptor.capture(), operationStatusCaptor.capture(), resourceModelCaptor.capture(),
- statusMessageCaptor.capture());
-
- final List bearerTokens = bearerTokenCaptor.getAllValues();
- final List errorCodes = errorCodeCaptor.getAllValues();
- final List operationStatuses = operationStatusCaptor.getAllValues();
- final List resourceModels = resourceModelCaptor.getAllValues();
- final List statusMessages = statusMessageCaptor.getAllValues();
-
- // CloudFormation should receive 2 callback invocation; both for IN_PROGRESS
- assertThat(bearerTokens).containsExactly("123456", "123456");
- assertThat(errorCodes).containsExactly(null, null);
- assertThat(resourceModels).containsExactly(TestModel.builder().property1("abc").property2(123).build(),
- TestModel.builder().property1("abc").property2(123).build());
- assertThat(statusMessages).containsExactly(null, null);
- assertThat(operationStatuses).containsExactly(OperationStatus.IN_PROGRESS, OperationStatus.IN_PROGRESS,
- OperationStatus.IN_PROGRESS, OperationStatus.IN_PROGRESS);
-
- // verify final output response is for second IN_PROGRESS response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").operationStatus(OperationStatus.IN_PROGRESS)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
- }
}
@Test
@@ -1127,29 +691,20 @@ public void invokeHandler_throwsAmazonServiceException_returnsServiceException()
verifyInitialiseRuntime();
// all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
// failure metric should be published
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
- any(AmazonServiceException.class), any(HandlerErrorCode.class));
-
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
any(AmazonServiceException.class), any(HandlerErrorCode.class));
// verify that model validation occurred for CREATE/UPDATE/DELETE
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
// verify output response
verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("GeneralServiceException")
- .operationStatus(OperationStatus.FAILED)
+ ProgressEvent.builder().errorCode(HandlerErrorCode.GeneralServiceException)
+ .status(OperationStatus.FAILED)
.message("some error (Service: null; Status Code: 0; Error Code: null; Request ID: null)").build());
}
}
@@ -1171,29 +726,20 @@ public void invokeHandler_throwsResourceAlreadyExistsException_returnsAlreadyExi
verifyInitialiseRuntime();
// all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
// failure metric should be published
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
- any(ResourceAlreadyExistsException.class), any(HandlerErrorCode.class));
-
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
any(ResourceAlreadyExistsException.class), any(HandlerErrorCode.class));
// verify that model validation occurred for CREATE/UPDATE/DELETE
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
// verify output response
verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("AlreadyExists")
- .operationStatus(OperationStatus.FAILED)
+ ProgressEvent.builder().errorCode(HandlerErrorCode.AlreadyExists)
+ .status(OperationStatus.FAILED)
.message("Resource of type 'AWS::Test::TestModel' with identifier 'id-1234' already exists.").build());
}
}
@@ -1215,29 +761,20 @@ public void invokeHandler_throwsResourceNotFoundException_returnsNotFound() thro
verifyInitialiseRuntime();
// all metrics should be published, once for a single invocation
- verify(platformMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
- verify(platformMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
-
verify(providerMetricsPublisher, times(1)).publishInvocationMetric(any(Instant.class), eq(Action.CREATE));
verify(providerMetricsPublisher, times(1)).publishDurationMetric(any(Instant.class), eq(Action.CREATE), anyLong());
// failure metric should be published
- verify(platformMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
- any(ResourceNotFoundException.class), any(HandlerErrorCode.class));
-
verify(providerMetricsPublisher, times(1)).publishExceptionMetric(any(Instant.class), any(),
any(ResourceNotFoundException.class), any(HandlerErrorCode.class));
// verify that model validation occurred for CREATE/UPDATE/DELETE
verify(validator, times(1)).validateObject(any(JSONObject.class), any(JSONObject.class));
- // no re-invocation via CloudWatch should occur
- verifyNoMoreInteractions(scheduler);
-
// verify output response
verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("NotFound")
- .operationStatus(OperationStatus.FAILED)
+ ProgressEvent.builder().errorCode(HandlerErrorCode.NotFound)
+ .status(OperationStatus.FAILED)
.message("Resource of type 'AWS::Test::TestModel' with identifier 'id-1234' was not found.").build());
}
}
@@ -1246,8 +783,8 @@ public void invokeHandler_throwsResourceNotFoundException_returnsNotFound() thro
public void invokeHandler_metricPublisherThrowable_returnsFailureResponse() throws IOException {
// simulate runtime Errors in the metrics publisher (such as dependency
// resolution conflicts)
- doThrow(new Error("not an Exception")).when(platformMetricsPublisher).publishInvocationMetric(any(), any());
- doThrow(new Error("not an Exception")).when(platformMetricsPublisher).publishExceptionMetric(any(), any(), any(), any());
+ doThrow(new Error("not an Exception")).when(providerMetricsPublisher).publishInvocationMetric(any(), any());
+ doThrow(new Error("not an Exception")).when(providerMetricsPublisher).publishExceptionMetric(any(), any(), any(), any());
try (final InputStream in = loadRequestStream("create.request.json");
final OutputStream out = new ByteArrayOutputStream()) {
@@ -1263,13 +800,12 @@ public void invokeHandler_metricPublisherThrowable_returnsFailureResponse() thro
verifyInitialiseRuntime();
// no further calls to metrics publisher should occur
- verifyNoMoreInteractions(platformMetricsPublisher);
verifyNoMoreInteractions(providerMetricsPublisher);
// verify output response
verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("not an Exception")
+ ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("not an Exception")
.resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
}
}
@@ -1287,8 +823,9 @@ public void invokeHandler_withInvalidPayload_returnsFailureResponse() throws IOE
// verify output response
verifyHandlerResponse(out,
- HandlerResponse.builder().errorCode("InternalFailure").operationStatus(OperationStatus.FAILED)
- .message("A JSONObject text must begin with '{' at 0 [character 1 line 1]").build());
+ ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("A JSONObject text must begin with '{' at 0 [character 1 line 1]")
+ .build());
}
}
@@ -1304,8 +841,8 @@ public void invokeHandler_withNullInputStream_returnsFailureResponse() throws IO
}
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("No request object received").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("No request object received").build());
}
}
@@ -1322,8 +859,8 @@ public void invokeHandler_withEmptyPayload_returnsFailure() throws IOException {
}
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message("Invalid request object received").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("Invalid request object received").build());
}
}
@@ -1340,8 +877,8 @@ public void invokeHandler_withEmptyResourceProperties_returnsFailure() throws IO
}
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().errorCode("InternalFailure").bearerToken("123456")
- .operationStatus(OperationStatus.FAILED).message("Invalid resource properties object received").build());
+ verifyHandlerResponse(out, ProgressEvent.builder().errorCode(HandlerErrorCode.InternalFailure)
+ .status(OperationStatus.FAILED).message("Invalid resource properties object received").build());
}
}
@@ -1354,10 +891,9 @@ public void stringifiedPayload_validation_successful() throws IOException {
// may have quoted values where the JSON Serialization is still able to
// construct a valid POJO
SchemaValidator validator = new Validator();
- final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider, platformEventsLogger,
- providerEventsLogger, platformMetricsPublisher,
- providerMetricsPublisher, scheduler, validator, httpClient);
+ final WrapperOverride wrapper = new WrapperOverride(providerLoggingCredentialsProvider, platformEventsLogger,
+ providerEventsLogger, providerMetricsPublisher, validator,
+ httpClient);
// explicit fault response is treated as an unsuccessful synchronous completion
final ProgressEvent pe = ProgressEvent.builder()
@@ -1373,44 +909,9 @@ public void stringifiedPayload_validation_successful() throws IOException {
wrapper.handleRequest(in, out, context);
// verify output response
- verifyHandlerResponse(out, HandlerResponse.builder().bearerToken("123456").message("Handler was invoked")
- .operationStatus(OperationStatus.SUCCESS).build());
-
- }
- }
-
- @Test
- public void handleRequest_apiThrowsOperationStatusException_returnsFailedStatus() throws IOException {
- final String errorMessage = "Unexpected status";
- final OperationStatusCheckFailedException exception = OperationStatusCheckFailedException.builder().message(errorMessage)
- .build();
+ verifyHandlerResponse(out, ProgressEvent.builder().message("Handler was invoked")
+ .status(OperationStatus.SUCCESS).build());
- // simulate runtime Errors in the callback adapter (such as multiple handlers
- // are invoked
- // for single task by CloudFormation)
- doThrow(exception).when(callbackAdapter).reportProgress(any(), any(), eq(OperationStatus.IN_PROGRESS),
- eq(OperationStatus.PENDING), any(), any());
-
- try (final InputStream in = loadRequestStream("create.request.json");
- final OutputStream out = new ByteArrayOutputStream()) {
- final Context context = getLambdaContext();
-
- wrapper.handleRequest(in, out, context);
-
- // verify initialiseRuntime was called and initialised dependencies
- verifyInitialiseRuntime();
- // only calls to callback adapter to acknowledge the task
- verify(callbackAdapter).reportProgress(any(), any(), eq(OperationStatus.IN_PROGRESS), eq(OperationStatus.PENDING),
- any(), any());
-
- // no further calls to callback adapter should occur
- verifyNoMoreInteractions(callbackAdapter);
-
- // verify output response
- verifyHandlerResponse(out,
- HandlerResponse.builder().bearerToken("123456").errorCode("InternalFailure")
- .operationStatus(OperationStatus.FAILED).message(errorMessage)
- .resourceModel(TestModel.builder().property1("abc").property2(123).build()).build());
}
}
diff --git a/src/test/java/software/amazon/cloudformation/WrapperOverride.java b/src/test/java/software/amazon/cloudformation/WrapperOverride.java
index ccfa0b94..40458d41 100644
--- a/src/test/java/software/amazon/cloudformation/WrapperOverride.java
+++ b/src/test/java/software/amazon/cloudformation/WrapperOverride.java
@@ -15,8 +15,6 @@
package software.amazon.cloudformation;
import com.fasterxml.jackson.core.type.TypeReference;
-import java.io.ByteArrayInputStream;
-import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -31,13 +29,11 @@
import software.amazon.cloudformation.loggers.LogPublisher;
import software.amazon.cloudformation.metrics.MetricsPublisher;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
-import software.amazon.cloudformation.proxy.CallbackAdapter;
import software.amazon.cloudformation.proxy.HandlerRequest;
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.ResourceHandlerRequest;
import software.amazon.cloudformation.resource.SchemaValidator;
import software.amazon.cloudformation.resource.Serializer;
-import software.amazon.cloudformation.scheduler.CloudWatchScheduler;
/**
* Test class used for testing of LambdaWrapper functionality
@@ -55,25 +51,19 @@ public WrapperOverride() {
/**
* This .ctor provided for testing
*/
- public WrapperOverride(final CallbackAdapter callbackAdapter,
- final CredentialsProvider platformCredentialsProvider,
- final CredentialsProvider providerLoggingCredentialsProvider,
+ public WrapperOverride(final CredentialsProvider providerLoggingCredentialsProvider,
final LogPublisher platformEventsLogger,
final CloudWatchLogPublisher providerEventsLogger,
- final MetricsPublisher platformMetricsPublisher,
final MetricsPublisher providerMetricsPublisher,
- final CloudWatchScheduler scheduler,
final SchemaValidator validator,
final SdkHttpClient httpClient) {
- super(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider, providerEventsLogger,
- platformEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, validator, new Serializer(),
- httpClient);
+ super(providerLoggingCredentialsProvider, platformEventsLogger, providerEventsLogger, providerMetricsPublisher, validator,
+ new Serializer(), httpClient);
}
@Override
protected JSONObject provideResourceSchemaJSONObject() {
- return new JSONObject(new JSONTokener(new ByteArrayInputStream("{ \"properties\": { \"property1\": { \"type\": \"string\" }, \"property2\": { \"type\": \"integer\" } }, \"additionalProperties\": false }"
- .getBytes(StandardCharsets.UTF_8))));
+ return new JSONObject(new JSONTokener(this.getClass().getResourceAsStream("wrapper-override.json")));
}
@Override
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request-with-stringified-resource.json b/src/test/java/software/amazon/cloudformation/data/create.request-with-stringified-resource.json
index a76ada91..fb88410f 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request-with-stringified-resource.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request-with-stringified-resource.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request-without-caller-credentials.json b/src/test/java/software/amazon/cloudformation/data/create.request-without-caller-credentials.json
index 9ade6040..6ea673f7 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request-without-caller-credentials.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request-without-caller-credentials.json
@@ -8,11 +8,6 @@
"resourceTypeVersion": "1.0",
"requestContext": {},
"requestData": {
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request-without-logging-credentials.json b/src/test/java/software/amazon/cloudformation/data/create.request-without-logging-credentials.json
index 6ece680a..5c0c23f7 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request-without-logging-credentials.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request-without-logging-credentials.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"logicalResourceId": "myBucket",
"resourceProperties": {
"property1": "abc",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request.json b/src/test/java/software/amazon/cloudformation/data/create.request.json
index 29d9d6e9..49976366 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-model-fields.json b/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-model-fields.json
index 9ed2cd44..7b8764f2 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-model-fields.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-model-fields.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-request-fields.json b/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-request-fields.json
index 9931a033..492e1c57 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-request-fields.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request.with-extraneous-request-fields.json
@@ -15,11 +15,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request.with-new-credentials.json b/src/test/java/software/amazon/cloudformation/data/create.request.with-new-credentials.json
index 45a54368..259218fd 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request.with-new-credentials.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.request.with-new-credentials.json
@@ -13,11 +13,6 @@
"secretAccessKey": "2VTH81RmywQPwF0n0f7g2KyGaARd7YKs71/C3y9J0",
"sessionToken": "pmHYfNFZAaJkvLGYW1s3mWFVlUu9ygNJcvBZS0gF7gmYe5jTqNYjSjtgwgdOSFt1yB4ETRp2TgGnjpgXPTz7espt3Au4nnxh1Mto"
},
- "platformCredentials": {
- "accessKeyId": "GT530IJDHALYZQSZZ8XG",
- "secretAccessKey": "UeJEwC/dqcYEn2viFd5TjKjR5TaMOfdeHrlLXxQL",
- "sessionToken": "469gs8raWJCaZcItXhGJ7dt3urI13fOTcde6ibhuHJz6r6bRRCWvLYGvCsqrN8WUClYL9lxZHymrWXvZ9xN0GoI2LFdcAAinZk5t"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/create.request-without-platform-credentials.json b/src/test/java/software/amazon/cloudformation/data/create.with-callback-context.request.json
similarity index 91%
rename from src/test/java/software/amazon/cloudformation/data/create.request-without-platform-credentials.json
rename to src/test/java/software/amazon/cloudformation/data/create.with-callback-context.request.json
index 49976366..01ce361c 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.request-without-platform-credentials.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.with-callback-context.request.json
@@ -6,7 +6,9 @@
"responseEndpoint": "https://cloudformation.us-west-2.amazonaws.com",
"resourceType": "AWS::Test::TestModel",
"resourceTypeVersion": "1.0",
- "requestContext": {},
+ "callbackContext": {
+ "contextPropertyA": "Value"
+ },
"requestData": {
"callerCredentials": {
"accessKeyId": "IASAYK835GAIFHAHEI23",
@@ -20,10 +22,7 @@
},
"providerLogGroupName": "providerLoggingGroupName",
"logicalResourceId": "myBucket",
- "resourceProperties": {
- "property1": "abc",
- "property2": 123
- },
+ "resourceProperties": {},
"systemTags": {
"aws:cloudformation:stack-id": "SampleStack"
},
diff --git a/src/test/java/software/amazon/cloudformation/data/create.with-request-context.request.json b/src/test/java/software/amazon/cloudformation/data/create.with-request-context.request.json
index c3357f80..b2595364 100644
--- a/src/test/java/software/amazon/cloudformation/data/create.with-request-context.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/create.with-request-context.request.json
@@ -20,11 +20,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/delete.request.json b/src/test/java/software/amazon/cloudformation/data/delete.request.json
index 2342cabb..f7225b3b 100644
--- a/src/test/java/software/amazon/cloudformation/data/delete.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/delete.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/delete.with-callback-context.request.json b/src/test/java/software/amazon/cloudformation/data/delete.with-callback-context.request.json
new file mode 100644
index 00000000..9d141773
--- /dev/null
+++ b/src/test/java/software/amazon/cloudformation/data/delete.with-callback-context.request.json
@@ -0,0 +1,28 @@
+{
+ "awsAccountId": "123456789012",
+ "bearerToken": "123456",
+ "region": "us-east-1",
+ "action": "DELETE",
+ "responseEndpoint": "https://cloudformation.us-west-2.amazonaws.com",
+ "resourceType": "AWS::Test::TestModel",
+ "resourceTypeVersion": "1.0",
+ "callbackContext": {
+ "contextPropertyA": "Value"
+ },
+ "requestData": {
+ "callerCredentials": {
+ "accessKeyId": "IASAYK835GAIFHAHEI23",
+ "secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
+ "sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
+ },
+ "providerCredentials": {
+ "accessKeyId": "HDI0745692Y45IUTYR78",
+ "secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
+ "sessionToken": "842HYOFIQAEUDF78R8T7IU43HSADYGIFHBJSDHFA87SDF9PYvN1CEYASDUYFT5TQ97YASIHUDFAIUEYRISDKJHFAYSUDTFSDFADS"
+ },
+ "providerLogGroupName": "providerLoggingGroupName",
+ "logicalResourceId": "myBucket",
+ "resourceProperties": {}
+ },
+ "stackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968"
+}
diff --git a/src/test/java/software/amazon/cloudformation/data/delete.with-request-context.request.json b/src/test/java/software/amazon/cloudformation/data/delete.with-request-context.request.json
index 5051bac6..b690d30b 100644
--- a/src/test/java/software/amazon/cloudformation/data/delete.with-request-context.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/delete.with-request-context.request.json
@@ -20,11 +20,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/empty.resource.request.json b/src/test/java/software/amazon/cloudformation/data/empty.resource.request.json
index a0a60ece..2f9a6577 100644
--- a/src/test/java/software/amazon/cloudformation/data/empty.resource.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/empty.resource.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"logicalResourceId": "myBucket",
"systemTags": {
"aws:cloudformation:stack-id": "SampleStack"
diff --git a/src/test/java/software/amazon/cloudformation/data/list.request.json b/src/test/java/software/amazon/cloudformation/data/list.request.json
index 2c850ee3..45bfd95f 100644
--- a/src/test/java/software/amazon/cloudformation/data/list.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/list.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/malformed.request.json b/src/test/java/software/amazon/cloudformation/data/malformed.request.json
index fb310987..c36dfef2 100644
--- a/src/test/java/software/amazon/cloudformation/data/malformed.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/malformed.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/no-response-endpoint.request.json b/src/test/java/software/amazon/cloudformation/data/no-response-endpoint.request.json
index 17fe0f97..b717899e 100644
--- a/src/test/java/software/amazon/cloudformation/data/no-response-endpoint.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/no-response-endpoint.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/read.request.json b/src/test/java/software/amazon/cloudformation/data/read.request.json
index 648b5240..aa9fc2d1 100644
--- a/src/test/java/software/amazon/cloudformation/data/read.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/read.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/update.request.json b/src/test/java/software/amazon/cloudformation/data/update.request.json
index 304a196e..bfa64bb5 100644
--- a/src/test/java/software/amazon/cloudformation/data/update.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/update.request.json
@@ -13,11 +13,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/data/update.with-callback-context.request.json b/src/test/java/software/amazon/cloudformation/data/update.with-callback-context.request.json
new file mode 100644
index 00000000..a4a723ec
--- /dev/null
+++ b/src/test/java/software/amazon/cloudformation/data/update.with-callback-context.request.json
@@ -0,0 +1,38 @@
+{
+ "awsAccountId": "123456789012",
+ "bearerToken": "123456",
+ "region": "us-east-1",
+ "action": "UPDATE",
+ "responseEndpoint": "https://cloudformation.us-west-2.amazonaws.com",
+ "resourceType": "AWS::Test::TestModel",
+ "resourceTypeVersion": "1.0",
+ "callbackContext": {
+ "contextPropertyA": "Value"
+ },
+ "requestData": {
+ "callerCredentials": {
+ "accessKeyId": "IASAYK835GAIFHAHEI23",
+ "secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
+ "sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
+ },
+ "providerCredentials": {
+ "accessKeyId": "HDI0745692Y45IUTYR78",
+ "secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
+ "sessionToken": "842HYOFIQAEUDF78R8T7IU43HSADYGIFHBJSDHFA87SDF9PYvN1CEYASDUYFT5TQ97YASIHUDFAIUEYRISDKJHFAYSUDTFSDFADS"
+ },
+ "providerLogGroupName": "providerLoggingGroupName",
+ "logicalResourceId": "myBucket",
+ "resourceProperties": {},
+ "previousResourceProperties": {},
+ "systemTags": {
+ "aws:cloudformation:stack-id": "SampleStack"
+ },
+ "stackTags": {
+ "tag1": "abc"
+ },
+ "previousStackTags": {
+ "tag1": "def"
+ }
+ },
+ "stackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968"
+}
diff --git a/src/test/java/software/amazon/cloudformation/data/update.with-request-context.request.json b/src/test/java/software/amazon/cloudformation/data/update.with-request-context.request.json
index c304b3bd..45649587 100644
--- a/src/test/java/software/amazon/cloudformation/data/update.with-request-context.request.json
+++ b/src/test/java/software/amazon/cloudformation/data/update.with-request-context.request.json
@@ -20,11 +20,6 @@
"secretAccessKey": "66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0",
"sessionToken": "lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg"
},
- "platformCredentials": {
- "accessKeyId": "32IEHAHFIAG538KYASAI",
- "secretAccessKey": "0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66",
- "sessionToken": "gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal"
- },
"providerCredentials": {
"accessKeyId": "HDI0745692Y45IUTYR78",
"secretAccessKey": "4976TUYVI234/5GW87ERYG823RF87GY9EIUH452I3",
diff --git a/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogHelperTest.java b/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogHelperTest.java
index 4aaceed0..ec418ae3 100644
--- a/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogHelperTest.java
+++ b/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogHelperTest.java
@@ -24,13 +24,11 @@
import static org.mockito.Mockito.when;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.google.common.collect.ImmutableList;
-import org.junit.jupiter.api.AfterEach;
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.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient;
import software.amazon.awssdk.services.cloudwatchlogs.model.CreateLogGroupRequest;
import software.amazon.awssdk.services.cloudwatchlogs.model.CreateLogStreamRequest;
@@ -38,7 +36,6 @@
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeLogGroupsResponse;
import software.amazon.awssdk.services.cloudwatchlogs.model.LogGroup;
import software.amazon.cloudformation.injection.CloudWatchLogsProvider;
-import software.amazon.cloudformation.injection.CloudWatchProvider;
import software.amazon.cloudformation.proxy.MetricsPublisherProxy;
@ExtendWith(MockitoExtension.class)
@@ -56,20 +53,8 @@ public class CloudWatchLogHelperTest {
@Mock
private MetricsPublisherProxy metricsPublisherProxy;
- @Mock
- private CloudWatchProvider platformCloudWatchProvider;
-
- @Mock
- private CloudWatchClient platformCloudWatchClient;
-
private static final String LOG_GROUP_NAME = "log-group-name";
- @AfterEach
- public void afterEach() {
- verifyNoMoreInteractions(platformCloudWatchProvider);
- verifyNoMoreInteractions(platformCloudWatchClient);
- }
-
@Test
public void testWithExistingLogGroup() {
final CloudWatchLogHelper cloudWatchLogHelper = new CloudWatchLogHelper(cloudWatchLogsProvider, LOG_GROUP_NAME,
diff --git a/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogPublisherTest.java b/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogPublisherTest.java
index 0ec91e57..acb2df6c 100644
--- a/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogPublisherTest.java
+++ b/src/test/java/software/amazon/cloudformation/loggers/CloudWatchLogPublisherTest.java
@@ -23,17 +23,14 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
-import org.junit.jupiter.api.AfterEach;
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.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient;
import software.amazon.awssdk.services.cloudwatchlogs.model.PutLogEventsRequest;
import software.amazon.cloudformation.injection.CloudWatchLogsProvider;
-import software.amazon.cloudformation.injection.CloudWatchProvider;
import software.amazon.cloudformation.proxy.MetricsPublisherProxy;
@ExtendWith(MockitoExtension.class)
@@ -51,21 +48,9 @@ public class CloudWatchLogPublisherTest {
@Mock
private MetricsPublisherProxy metricsPublisherProxy;
- @Mock
- private CloudWatchProvider platformCloudWatchProvider;
-
- @Mock
- private CloudWatchClient platformCloudWatchClient;
-
private static final String LOG_GROUP_NAME = "log-group-name";
private static final String LOG_STREAM_NAME = "log-stream-name";
- @AfterEach
- public void afterEach() {
- verifyNoMoreInteractions(platformCloudWatchProvider);
- verifyNoMoreInteractions(platformCloudWatchClient);
- }
-
@Test
public void testPublishLogEventsHappyCase() {
final CloudWatchLogPublisher logPublisher = new CloudWatchLogPublisher(cloudWatchLogsProvider, LOG_GROUP_NAME,
diff --git a/src/test/java/software/amazon/cloudformation/metrics/MetricsPublisherImplTest.java b/src/test/java/software/amazon/cloudformation/metrics/MetricsPublisherImplTest.java
index 45521fa6..631b85d2 100644
--- a/src/test/java/software/amazon/cloudformation/metrics/MetricsPublisherImplTest.java
+++ b/src/test/java/software/amazon/cloudformation/metrics/MetricsPublisherImplTest.java
@@ -45,15 +45,9 @@ public class MetricsPublisherImplTest {
@Mock
private Logger loggerProxy;
- @Mock
- private CloudWatchProvider platformCloudWatchProvider;
-
@Mock
private CloudWatchProvider providerCloudWatchProvider;
- @Mock
- private CloudWatchClient platformCloudWatchClient;
-
@Mock
private CloudWatchClient providerCloudWatchClient;
@@ -62,40 +56,28 @@ public class MetricsPublisherImplTest {
@BeforeEach
public void beforeEach() {
- when(platformCloudWatchProvider.get()).thenReturn(platformCloudWatchClient);
when(providerCloudWatchProvider.get()).thenReturn(providerCloudWatchClient);
- when(platformCloudWatchClient.putMetricData(any(PutMetricDataRequest.class)))
- .thenReturn(mock(PutMetricDataResponse.class));
when(providerCloudWatchClient.putMetricData(any(PutMetricDataRequest.class)))
.thenReturn(mock(PutMetricDataResponse.class));
}
@AfterEach
public void afterEach() {
- verifyNoMoreInteractions(platformCloudWatchProvider);
- verifyNoMoreInteractions(platformCloudWatchClient);
verifyNoMoreInteractions(providerCloudWatchProvider);
verifyNoMoreInteractions(providerCloudWatchClient);
}
@Test
public void testPublishDurationMetric() {
- final MetricsPublisherImpl platformMetricsPublisher = new MetricsPublisherImpl(platformCloudWatchProvider, loggerProxy,
- awsAccountId, resourceTypeName);
- platformMetricsPublisher.refreshClient();
-
final MetricsPublisherImpl providerMetricsPublisher = new MetricsPublisherImpl(providerCloudWatchProvider, loggerProxy,
awsAccountId, resourceTypeName);
providerMetricsPublisher.refreshClient();
final Instant instant = Instant.parse("2019-06-04T17:50:00Z");
- platformMetricsPublisher.publishDurationMetric(instant, Action.UPDATE, 123456);
providerMetricsPublisher.publishDurationMetric(instant, Action.UPDATE, 123456);
final ArgumentCaptor argument1 = ArgumentCaptor.forClass(PutMetricDataRequest.class);
- final ArgumentCaptor argument2 = ArgumentCaptor.forClass(PutMetricDataRequest.class);
- verify(platformCloudWatchClient).putMetricData(argument1.capture());
- verify(providerCloudWatchClient).putMetricData(argument2.capture());
+ verify(providerCloudWatchClient).putMetricData(argument1.capture());
final PutMetricDataRequest request = argument1.getValue();
assertThat(request.namespace())
@@ -113,23 +95,16 @@ public void testPublishDurationMetric() {
@Test
public void testPublishExceptionMetric() {
- final MetricsPublisherImpl platformMetricsPublisher = new MetricsPublisherImpl(platformCloudWatchProvider, loggerProxy,
- awsAccountId, resourceTypeName);
- platformMetricsPublisher.refreshClient();
-
final MetricsPublisherImpl providerMetricsPublisher = new MetricsPublisherImpl(providerCloudWatchProvider, loggerProxy,
awsAccountId, resourceTypeName);
providerMetricsPublisher.refreshClient();
final Instant instant = Instant.parse("2019-06-03T17:50:00Z");
final RuntimeException e = new RuntimeException("some error");
- platformMetricsPublisher.publishExceptionMetric(instant, Action.CREATE, e, HandlerErrorCode.InternalFailure);
- providerMetricsPublisher.publishDurationMetric(instant, Action.UPDATE, 123456);
+ providerMetricsPublisher.publishExceptionMetric(instant, Action.CREATE, e, HandlerErrorCode.InternalFailure);
final ArgumentCaptor argument1 = ArgumentCaptor.forClass(PutMetricDataRequest.class);
- final ArgumentCaptor argument2 = ArgumentCaptor.forClass(PutMetricDataRequest.class);
- verify(platformCloudWatchClient).putMetricData(argument1.capture());
- verify(providerCloudWatchClient).putMetricData(argument2.capture());
+ verify(providerCloudWatchClient).putMetricData(argument1.capture());
final PutMetricDataRequest request = argument1.getValue();
assertThat(request.namespace())
@@ -149,22 +124,15 @@ public void testPublishExceptionMetric() {
@Test
public void testPublishInvocationMetric() {
- final MetricsPublisherImpl platformMetricsPublisher = new MetricsPublisherImpl(platformCloudWatchProvider, loggerProxy,
- awsAccountId, resourceTypeName);
- platformMetricsPublisher.refreshClient();
-
final MetricsPublisherImpl providerMetricsPublisher = new MetricsPublisherImpl(providerCloudWatchProvider, loggerProxy,
awsAccountId, resourceTypeName);
providerMetricsPublisher.refreshClient();
final Instant instant = Instant.parse("2019-06-04T17:50:00Z");
- platformMetricsPublisher.publishInvocationMetric(instant, Action.UPDATE);
- providerMetricsPublisher.publishDurationMetric(instant, Action.UPDATE, 123456);
+ providerMetricsPublisher.publishInvocationMetric(instant, Action.UPDATE);
final ArgumentCaptor argument1 = ArgumentCaptor.forClass(PutMetricDataRequest.class);
- final ArgumentCaptor argument2 = ArgumentCaptor.forClass(PutMetricDataRequest.class);
- verify(platformCloudWatchClient).putMetricData(argument1.capture());
- verify(providerCloudWatchClient).putMetricData(argument2.capture());
+ verify(providerCloudWatchClient).putMetricData(argument1.capture());
final PutMetricDataRequest request = argument1.getValue();
assertThat(request.namespace())
diff --git a/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java b/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java
index 6785ada5..facd9f4a 100644
--- a/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java
+++ b/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java
@@ -32,7 +32,6 @@
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
-import org.mockito.stubbing.Answer;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
@@ -40,14 +39,7 @@
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.http.SdkHttpResponse;
-import software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient;
-import software.amazon.awssdk.services.cloudwatchevents.model.PutRuleRequest;
-import software.amazon.awssdk.services.cloudwatchevents.model.PutRuleResponse;
-import software.amazon.awssdk.services.cloudwatchevents.model.PutTargetsRequest;
-import software.amazon.awssdk.services.cloudwatchevents.model.PutTargetsResponse;
import software.amazon.cloudformation.Action;
-import software.amazon.cloudformation.Response;
-import software.amazon.cloudformation.injection.CloudWatchEventsProvider;
import software.amazon.cloudformation.injection.CredentialsProvider;
import software.amazon.cloudformation.loggers.CloudWatchLogPublisher;
import software.amazon.cloudformation.loggers.LogPublisher;
@@ -65,21 +57,15 @@
import software.amazon.cloudformation.proxy.service.ThrottleException;
import software.amazon.cloudformation.resource.Serializer;
import software.amazon.cloudformation.resource.Validator;
-import software.amazon.cloudformation.scheduler.CloudWatchScheduler;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class End2EndCallChainTest {
-
- static final AwsServiceException.Builder builder = mock(AwsServiceException.Builder.class);
-
//
// The same that is asserted inside the ServiceClient
//
private final AwsSessionCredentials MockCreds = AwsSessionCredentials.create("accessKeyId", "secretKey", "token");
private final Credentials credentials = new Credentials(MockCreds.accessKeyId(), MockCreds.secretAccessKey(),
MockCreds.sessionToken());
- @SuppressWarnings("unchecked")
- private final CallbackAdapter adapter = mock(CallbackAdapter.class);
@Test
public void happyCase() {
@@ -150,10 +136,8 @@ private HandlerRequest prepareRequest(Model model) th
request.setRegion("us-east-2");
request.setResourceType("AWS::Code::Repository");
request.setStackId(UUID.randomUUID().toString());
- request.setResponseEndpoint("https://cloudformation.amazonaws.com");
RequestData data = new RequestData<>();
data.setResourceProperties(model);
- data.setPlatformCredentials(credentials);
data.setCallerCredentials(credentials);
request.setRequestData(data);
return request;
@@ -200,7 +184,6 @@ public void notFound() throws Exception {
final InputStream stream = prepareStream(serializer, request);
final ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
final LoggerProxy loggerProxy = mock(LoggerProxy.class);
- final CredentialsProvider platformCredentialsProvider = prepareMockProvider();
final CredentialsProvider providerLoggingCredentialsProvider = prepareMockProvider();
final Context cxt = mock(Context.class);
// bail out immediately
@@ -225,29 +208,19 @@ public AwsErrorDetails awsErrorDetails() {
when(client.describeRepository(eq(describeRequest))).thenThrow(notFound);
final SdkHttpClient httpClient = mock(SdkHttpClient.class);
- final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider,
+ final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(providerLoggingCredentialsProvider,
mock(CloudWatchLogPublisher.class),
mock(LogPublisher.class), mock(MetricsPublisher.class),
- mock(MetricsPublisher.class),
- new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider,
- httpClient) {
- @Override
- public CloudWatchEventsClient get() {
- return mock(CloudWatchEventsClient.class);
- }
- }, loggerProxy, serializer), new Validator(), serializer,
- client, httpClient);
+ new Validator(), serializer, client, httpClient);
wrapper.handleRequest(stream, output, cxt);
verify(client).describeRepository(eq(describeRequest));
- Response response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
- new TypeReference>() {
+ ProgressEvent response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
+ new TypeReference>() {
});
assertThat(response).isNotNull();
- assertThat(response.getOperationStatus()).isEqualTo(OperationStatus.FAILED);
- assertThat(response.getBearerToken()).isEqualTo("dwezxdfgfgh");
+ assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED);
assertThat(response.getMessage()).contains("NotFound");
}
@@ -260,7 +233,6 @@ public void createHandler() throws Exception {
final InputStream stream = prepareStream(serializer, request);
final ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
final LoggerProxy loggerProxy = mock(LoggerProxy.class);
- final CredentialsProvider platformCredentialsProvider = prepareMockProvider();
final CredentialsProvider providerLoggingCredentialsProvider = prepareMockProvider();
final Context cxt = mock(Context.class);
// bail out immediately
@@ -284,30 +256,20 @@ public void createHandler() throws Exception {
when(client.describeRepository(eq(describeRequest))).thenReturn(describeResponse);
final SdkHttpClient httpClient = mock(SdkHttpClient.class);
- final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider,
+ final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(providerLoggingCredentialsProvider,
mock(CloudWatchLogPublisher.class),
mock(LogPublisher.class), mock(MetricsPublisher.class),
- mock(MetricsPublisher.class),
- new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider,
- httpClient) {
- @Override
- public CloudWatchEventsClient get() {
- return mock(CloudWatchEventsClient.class);
- }
- }, loggerProxy, serializer), new Validator(), serializer,
- client, httpClient);
+ new Validator(), serializer, client, httpClient);
wrapper.handleRequest(stream, output, cxt);
verify(client).createRepository(eq(createRequest));
verify(client).describeRepository(eq(describeRequest));
- Response response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
- new TypeReference>() {
+ ProgressEvent response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
+ new TypeReference>() {
});
assertThat(response).isNotNull();
- assertThat(response.getOperationStatus()).isEqualTo(OperationStatus.SUCCESS);
- assertThat(response.getBearerToken()).isEqualTo("dwezxdfgfgh");
+ assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS);
assertThat(request.getRequestData()).isNotNull();
Model responseModel = response.getResourceModel();
assertThat(responseModel.getRepoName()).isEqualTo("repository");
@@ -322,8 +284,6 @@ public void createHandlerAlreadyExists() throws Exception {
final Serializer serializer = new Serializer();
final InputStream stream = prepareStream(serializer, request);
final ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
- final LoggerProxy loggerProxy = mock(LoggerProxy.class);
- final CredentialsProvider platformCredentialsProvider = prepareMockProvider();
final CredentialsProvider providerLoggingCredentialsProvider = prepareMockProvider();
final Context cxt = mock(Context.class);
// bail out immediately
@@ -351,29 +311,19 @@ public AwsErrorDetails awsErrorDetails() {
when(client.createRepository(eq(createRequest))).thenThrow(exists);
final SdkHttpClient httpClient = mock(SdkHttpClient.class);
- final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider,
+ final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(providerLoggingCredentialsProvider,
mock(CloudWatchLogPublisher.class),
mock(LogPublisher.class), mock(MetricsPublisher.class),
- mock(MetricsPublisher.class),
- new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider,
- httpClient) {
- @Override
- public CloudWatchEventsClient get() {
- return mock(CloudWatchEventsClient.class);
- }
- }, loggerProxy, serializer), new Validator(), serializer,
- client, httpClient);
+ new Validator(), serializer, client, httpClient);
wrapper.handleRequest(stream, output, cxt);
verify(client).createRepository(eq(createRequest));
- Response response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
- new TypeReference>() {
+ ProgressEvent response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
+ new TypeReference>() {
});
assertThat(response).isNotNull();
- assertThat(response.getOperationStatus()).isEqualTo(OperationStatus.FAILED);
- assertThat(response.getBearerToken()).isEqualTo("dwezxdfgfgh");
+ assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED);
assertThat(request.getRequestData()).isNotNull();
Model responseModel = response.getResourceModel();
assertThat(responseModel.getRepoName()).isEqualTo("repository");
@@ -389,7 +339,6 @@ public void createHandlerThrottleException() throws Exception {
final InputStream stream = prepareStream(serializer, request);
ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
final LoggerProxy loggerProxy = mock(LoggerProxy.class);
- final CredentialsProvider platformCredentialsProvider = prepareMockProvider();
final CredentialsProvider providerLoggingCredentialsProvider = prepareMockProvider();
final Context cxt = mock(Context.class);
// bail out very slowly
@@ -416,50 +365,30 @@ public AwsErrorDetails awsErrorDetails() {
};
when(client.describeRepository(eq(describeRequest))).thenThrow(throttleException);
- final ByteArrayOutputStream cweRequestOutput = new ByteArrayOutputStream(2048);
- CloudWatchEventsClient cloudWatchEventsClient = mock(CloudWatchEventsClient.class);
- when(cloudWatchEventsClient.putRule(any(PutRuleRequest.class))).thenReturn(mock(PutRuleResponse.class));
- when(cloudWatchEventsClient.putTargets(any(PutTargetsRequest.class)))
- .thenAnswer((Answer) invocationOnMock -> {
- PutTargetsRequest putTargetsRequest = invocationOnMock.getArgument(0, PutTargetsRequest.class);
- cweRequestOutput.write(putTargetsRequest.targets().get(0).input().getBytes(StandardCharsets.UTF_8));
- return PutTargetsResponse.builder().build();
- });
-
final SdkHttpClient httpClient = mock(SdkHttpClient.class);
- final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider,
+ final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(providerLoggingCredentialsProvider,
mock(CloudWatchLogPublisher.class),
mock(LogPublisher.class), mock(MetricsPublisher.class),
- mock(MetricsPublisher.class),
- new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider,
- httpClient) {
- @Override
- public CloudWatchEventsClient get() {
- return cloudWatchEventsClient;
- }
- }, loggerProxy, serializer), new Validator(), serializer,
- client, httpClient);
-
- // Bail early for the handshake. Expect cloudwatch events
+ new Validator(), serializer, client, httpClient);
+
+ // Bail early for the handshake. Reinvoke handler again
wrapper.handleRequest(stream, output, cxt);
- // Replay Cloudwatch events stream
- // refresh the stream
+ ProgressEvent event = serializer.deserialize(output.toString("UTF8"),
+ new TypeReference>() {
+ });
+ request.setCallbackContext(event.getCallbackContext());
output = new ByteArrayOutputStream(2048);
- wrapper.handleRequest(new ByteArrayInputStream(cweRequestOutput.toByteArray()), output, cxt);
+ wrapper.handleRequest(prepareStream(serializer, request), output, cxt);
// Handshake mode 1 try, Throttle retries 4 times (1, 0s), (2, 3s), (3, 6s), (4,
// 9s)
verify(client, times(5)).describeRepository(eq(describeRequest));
- verify(cloudWatchEventsClient, times(1)).putRule(any(PutRuleRequest.class));
- verify(cloudWatchEventsClient, times(1)).putTargets(any(PutTargetsRequest.class));
- Response response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
- new TypeReference>() {
+ ProgressEvent response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
+ new TypeReference>() {
});
assertThat(response).isNotNull();
- assertThat(response.getOperationStatus()).isEqualTo(OperationStatus.FAILED);
- assertThat(response.getBearerToken()).isEqualTo("dwezxdfgfgh");
+ assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED);
assertThat(response.getMessage()).contains("Exceeded");
}
@@ -472,7 +401,6 @@ public void createHandlerThottleExceptionEarlyInProgressBailout() throws Excepti
final InputStream stream = prepareStream(serializer, request);
final ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
final LoggerProxy loggerProxy = mock(LoggerProxy.class);
- final CredentialsProvider platformCredentialsProvider = prepareMockProvider();
final CredentialsProvider providerLoggingCredentialsProvider = prepareMockProvider();
final Context cxt = mock(Context.class);
// bail out immediately
@@ -500,30 +428,20 @@ public AwsErrorDetails awsErrorDetails() {
when(client.describeRepository(eq(describeRequest))).thenThrow(throttleException);
final SdkHttpClient httpClient = mock(SdkHttpClient.class);
- final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider,
+ final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(providerLoggingCredentialsProvider,
mock(CloudWatchLogPublisher.class),
mock(LogPublisher.class), mock(MetricsPublisher.class),
- mock(MetricsPublisher.class),
- new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider,
- httpClient) {
- @Override
- public CloudWatchEventsClient get() {
- return mock(CloudWatchEventsClient.class);
- }
- }, loggerProxy, serializer), new Validator(), serializer,
- client, httpClient);
+ new Validator(), serializer, client, httpClient);
wrapper.handleRequest(stream, output, cxt);
// only 1 call (1, 0s), the next attempt is at 3s which exceed 50 ms remaining
verify(client).describeRepository(eq(describeRequest));
- Response response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
- new TypeReference>() {
+ ProgressEvent response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
+ new TypeReference>() {
});
assertThat(response).isNotNull();
- assertThat(response.getOperationStatus()).isEqualTo(OperationStatus.IN_PROGRESS);
- assertThat(response.getBearerToken()).isEqualTo("dwezxdfgfgh");
+ assertThat(response.getStatus()).isEqualTo(OperationStatus.IN_PROGRESS);
}
@Order(40)
@@ -535,7 +453,6 @@ public void accessDenied() throws Exception {
final InputStream stream = prepareStream(serializer, request);
final ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
final LoggerProxy loggerProxy = mock(LoggerProxy.class);
- final CredentialsProvider platformCredentialsProvider = prepareMockProvider();
final CredentialsProvider providerLoggingCredentialsProvider = prepareMockProvider();
final Context cxt = mock(Context.class);
// bail out immediately
@@ -563,29 +480,19 @@ public AwsErrorDetails awsErrorDetails() {
when(client.describeRepository(eq(describeRequest))).thenThrow(accessDenied);
final SdkHttpClient httpClient = mock(SdkHttpClient.class);
- final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider,
- providerLoggingCredentialsProvider,
+ final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(providerLoggingCredentialsProvider,
mock(CloudWatchLogPublisher.class),
mock(LogPublisher.class), mock(MetricsPublisher.class),
- mock(MetricsPublisher.class),
- new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider,
- httpClient) {
- @Override
- public CloudWatchEventsClient get() {
- return mock(CloudWatchEventsClient.class);
- }
- }, loggerProxy, serializer), new Validator(), serializer,
- client, httpClient);
+ new Validator(), serializer, client, httpClient);
wrapper.handleRequest(stream, output, cxt);
verify(client).describeRepository(eq(describeRequest));
- Response response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
- new TypeReference>() {
+ ProgressEvent response = serializer.deserialize(output.toString(StandardCharsets.UTF_8.name()),
+ new TypeReference>() {
});
assertThat(response).isNotNull();
- assertThat(response.getOperationStatus()).isEqualTo(OperationStatus.FAILED);
- assertThat(response.getBearerToken()).isEqualTo("dwezxdfgfgh");
+ assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED);
assertThat(response.getMessage()).contains("AccessDenied");
}
diff --git a/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java b/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java
index 315cd4cd..e130b7cc 100644
--- a/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java
+++ b/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java
@@ -27,7 +27,6 @@
import software.amazon.cloudformation.loggers.LogPublisher;
import software.amazon.cloudformation.metrics.MetricsPublisher;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
-import software.amazon.cloudformation.proxy.CallbackAdapter;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
import software.amazon.cloudformation.proxy.HandlerRequest;
import software.amazon.cloudformation.proxy.LoggerProxy;
@@ -37,27 +36,21 @@
import software.amazon.cloudformation.proxy.service.ServiceClient;
import software.amazon.cloudformation.resource.SchemaValidator;
import software.amazon.cloudformation.resource.Serializer;
-import software.amazon.cloudformation.scheduler.CloudWatchScheduler;
public class ServiceHandlerWrapper extends LambdaWrapper {
private final ServiceClient serviceClient;
- public ServiceHandlerWrapper(final CallbackAdapter callbackAdapter,
- final CredentialsProvider platformCredentialsProvider,
- final CredentialsProvider providerLoggingCredentialsProvider,
+ public ServiceHandlerWrapper(final CredentialsProvider providerLoggingCredentialsProvider,
final CloudWatchLogPublisher providerEventsLogger,
final LogPublisher platformEventsLogger,
- final MetricsPublisher platformMetricsPublisher,
final MetricsPublisher providerMetricsPublisher,
- final CloudWatchScheduler scheduler,
final SchemaValidator validator,
final Serializer serializer,
final ServiceClient client,
final SdkHttpClient httpClient) {
- super(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider, providerEventsLogger,
- platformEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, validator, serializer,
- httpClient);
+ super(providerLoggingCredentialsProvider, platformEventsLogger, providerEventsLogger, providerMetricsPublisher, validator,
+ serializer, httpClient);
this.serviceClient = client;
}
@@ -86,10 +79,10 @@ protected ResourceHandlerRequest transform(final HandlerRequestbuilder().clientRequestToken(request.getBearerToken())
- .desiredResourceState(desiredResourceState).previousResourceState(previousResourceState)
- .desiredResourceTags(getDesiredResourceTags(request)).systemTags(systemTags)
- .logicalResourceIdentifier(request.getRequestData().getLogicalResourceId()).nextToken(request.getNextToken()).build();
+ return ResourceHandlerRequest.builder().desiredResourceState(desiredResourceState)
+ .previousResourceState(previousResourceState).desiredResourceTags(getDesiredResourceTags(request))
+ .systemTags(systemTags).logicalResourceIdentifier(request.getRequestData().getLogicalResourceId())
+ .nextToken(request.getNextToken()).build();
}
@Override
diff --git a/src/test/java/software/amazon/cloudformation/proxy/service/CreateRequest.java b/src/test/java/software/amazon/cloudformation/proxy/service/CreateRequest.java
index dd47c57b..ac77b5e3 100644
--- a/src/test/java/software/amazon/cloudformation/proxy/service/CreateRequest.java
+++ b/src/test/java/software/amazon/cloudformation/proxy/service/CreateRequest.java
@@ -19,6 +19,7 @@
import software.amazon.awssdk.awscore.AwsRequest;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.core.SdkField;
+import software.amazon.awssdk.core.SdkPojo;
@lombok.Getter
@lombok.EqualsAndHashCode(callSuper = false)
@@ -48,7 +49,7 @@ public List> sdkFields() {
@lombok.Getter
@lombok.EqualsAndHashCode(callSuper = true)
@lombok.ToString(callSuper = true)
- public static class Builder extends BuilderImpl {
+ public static class Builder extends BuilderImpl implements SdkPojo {
private String repoName;
private String userName;
@@ -72,5 +73,14 @@ public Builder overrideConfiguration(AwsRequestOverrideConfiguration awsRequestO
super.overrideConfiguration(awsRequestOverrideConfig);
return this;
}
+
+ @Override
+ public List> sdkFields() {
+ return Collections.emptyList();
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
}
}
diff --git a/src/test/java/software/amazon/cloudformation/proxy/service/CreateResponse.java b/src/test/java/software/amazon/cloudformation/proxy/service/CreateResponse.java
index 9be3a2da..76b54a76 100644
--- a/src/test/java/software/amazon/cloudformation/proxy/service/CreateResponse.java
+++ b/src/test/java/software/amazon/cloudformation/proxy/service/CreateResponse.java
@@ -18,6 +18,7 @@
import java.util.List;
import software.amazon.awssdk.awscore.AwsResponse;
import software.amazon.awssdk.core.SdkField;
+import software.amazon.awssdk.core.SdkPojo;
@lombok.Getter
@lombok.EqualsAndHashCode(callSuper = true)
@@ -42,7 +43,7 @@ public List> sdkFields() {
return Collections.emptyList();
}
- public static class Builder extends BuilderImpl {
+ public static class Builder extends BuilderImpl implements SdkPojo {
private String repoName;
private String error;
@@ -60,5 +61,13 @@ public Builder error(String name) {
this.error = name;
return this;
}
+
+ public List> sdkFields() {
+ return Collections.emptyList();
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
}
}
diff --git a/src/test/java/software/amazon/cloudformation/proxy/service/DescribeRequest.java b/src/test/java/software/amazon/cloudformation/proxy/service/DescribeRequest.java
index fe6ee132..9dff68d6 100644
--- a/src/test/java/software/amazon/cloudformation/proxy/service/DescribeRequest.java
+++ b/src/test/java/software/amazon/cloudformation/proxy/service/DescribeRequest.java
@@ -19,6 +19,7 @@
import software.amazon.awssdk.awscore.AwsRequest;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.core.SdkField;
+import software.amazon.awssdk.core.SdkPojo;
@lombok.Getter
@lombok.EqualsAndHashCode(callSuper = false)
@@ -45,7 +46,7 @@ public Builder toBuilder() {
@lombok.Getter
@lombok.EqualsAndHashCode(callSuper = true)
@lombok.ToString(callSuper = true)
- public static class Builder extends BuilderImpl {
+ public static class Builder extends BuilderImpl implements SdkPojo {
private String repoName;
@Override
@@ -63,5 +64,14 @@ public Builder overrideConfiguration(AwsRequestOverrideConfiguration awsRequestO
super.overrideConfiguration(awsRequestOverrideConfig);
return this;
}
+
+ @Override
+ public List> sdkFields() {
+ return Collections.emptyList();
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
}
}
diff --git a/src/test/java/software/amazon/cloudformation/proxy/service/DescribeResponse.java b/src/test/java/software/amazon/cloudformation/proxy/service/DescribeResponse.java
index 828e81ec..e842dc2f 100644
--- a/src/test/java/software/amazon/cloudformation/proxy/service/DescribeResponse.java
+++ b/src/test/java/software/amazon/cloudformation/proxy/service/DescribeResponse.java
@@ -19,6 +19,7 @@
import java.util.List;
import software.amazon.awssdk.awscore.AwsResponse;
import software.amazon.awssdk.core.SdkField;
+import software.amazon.awssdk.core.SdkPojo;
@lombok.Getter
@lombok.EqualsAndHashCode(callSuper = true)
@@ -45,7 +46,7 @@ public List> sdkFields() {
return Collections.emptyList();
}
- public static class Builder extends BuilderImpl {
+ public static class Builder extends BuilderImpl implements SdkPojo {
private String repoName;
private String repoArn;
private Date createdWhen;
@@ -69,5 +70,14 @@ public Builder createdWhen(Date when) {
createdWhen = when;
return this;
}
+
+ @Override
+ public List> sdkFields() {
+ return Collections.emptyList();
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
}
}
diff --git a/src/test/java/software/amazon/cloudformation/resource/SerializerTest.java b/src/test/java/software/amazon/cloudformation/resource/SerializerTest.java
index b0467701..d4f7f6a7 100644
--- a/src/test/java/software/amazon/cloudformation/resource/SerializerTest.java
+++ b/src/test/java/software/amazon/cloudformation/resource/SerializerTest.java
@@ -29,7 +29,6 @@
import software.amazon.cloudformation.TestContext;
import software.amazon.cloudformation.TestModel;
import software.amazon.cloudformation.proxy.HandlerRequest;
-import software.amazon.cloudformation.proxy.RequestContext;
import software.amazon.cloudformation.proxy.RequestData;
public class SerializerTest {
@@ -71,32 +70,19 @@ public void testDeserialize_AccuratePayload() throws IOException {
assertThat(r.getAwsAccountId()).isEqualTo("123456789012");
assertThat(r.getBearerToken()).isEqualTo("123456");
assertThat(r.getRegion()).isEqualTo("us-east-1");
- assertThat(r.getRequestContext()).isNotNull();
+ assertThat(r.getBearerToken()).isEqualTo("123456");
assertThat(r.getRequestData()).isNotNull();
- assertThat(r.getResponseEndpoint()).isEqualTo("https://cloudformation.us-west-2.amazonaws.com");
assertThat(r.getResourceType()).isEqualTo("AWS::Test::TestModel");
assertThat(r.getResourceTypeVersion()).isEqualTo("1.0");
assertThat(r.getStackId())
.isEqualTo("arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968");
-
- final RequestContext requestContext = r.getRequestContext();
- assertThat(requestContext.getCloudWatchEventsRuleName()).isNull();
- assertThat(requestContext.getCloudWatchEventsTargetId()).isNull();
- assertThat(requestContext.getInvocation()).isEqualTo(0);
- assertThat(requestContext.getCallbackContext()).isNull();
+ assertThat(r.getCallbackContext()).isNull();
final RequestData requestData = r.getRequestData();
assertThat(requestData.getCallerCredentials()).isNotNull();
assertThat(requestData.getCallerCredentials().getAccessKeyId()).isEqualTo("IASAYK835GAIFHAHEI23");
assertThat(requestData.getCallerCredentials().getSecretAccessKey()).isEqualTo("66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0");
- assertThat(requestData.getCallerCredentials().getSessionToken())
- .isEqualTo("lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg");
- assertThat(requestData.getPlatformCredentials()).isNotNull();
- assertThat(requestData.getPlatformCredentials().getAccessKeyId()).isEqualTo("32IEHAHFIAG538KYASAI");
- assertThat(requestData.getPlatformCredentials().getSecretAccessKey())
- .isEqualTo("0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66");
- assertThat(requestData.getPlatformCredentials().getSessionToken())
- .isEqualTo("gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal");
+ assertThat(requestData.getCallerCredentials().getSessionToken());
assertThat(requestData.getLogicalResourceId()).isEqualTo("myBucket");
assertThat(requestData.getStackTags()).containsExactly(entry("tag1", "abc"));
assertThat(requestData.getPreviousResourceProperties()).isNull();
@@ -123,17 +109,11 @@ public void testDeserialize_ExtranousRequestFields_AreIncluded() throws IOExcept
assertThat(r.getRegion()).isEqualTo("us-east-1");
assertThat(r.getRequestContext()).isNotNull();
assertThat(r.getRequestData()).isNotNull();
- assertThat(r.getResponseEndpoint()).isEqualTo("https://cloudformation.us-west-2.amazonaws.com");
assertThat(r.getResourceType()).isEqualTo("AWS::Test::TestModel");
assertThat(r.getResourceTypeVersion()).isEqualTo("1.0");
assertThat(r.getStackId())
.isEqualTo("arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968");
-
- final RequestContext requestContext = r.getRequestContext();
- assertThat(requestContext.getCloudWatchEventsRuleName()).isNull();
- assertThat(requestContext.getCloudWatchEventsTargetId()).isNull();
- assertThat(requestContext.getInvocation()).isEqualTo(0);
- assertThat(requestContext.getCallbackContext()).isNull();
+ assertThat(r.getCallbackContext()).isNull();
final RequestData requestData = r.getRequestData();
assertThat(requestData.getCallerCredentials()).isNotNull();
@@ -141,12 +121,6 @@ public void testDeserialize_ExtranousRequestFields_AreIncluded() throws IOExcept
assertThat(requestData.getCallerCredentials().getSecretAccessKey()).isEqualTo("66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0");
assertThat(requestData.getCallerCredentials().getSessionToken())
.isEqualTo("lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg");
- assertThat(requestData.getPlatformCredentials()).isNotNull();
- assertThat(requestData.getPlatformCredentials().getAccessKeyId()).isEqualTo("32IEHAHFIAG538KYASAI");
- assertThat(requestData.getPlatformCredentials().getSecretAccessKey())
- .isEqualTo("0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66");
- assertThat(requestData.getPlatformCredentials().getSessionToken())
- .isEqualTo("gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal");
assertThat(requestData.getLogicalResourceId()).isEqualTo("myBucket");
assertThat(requestData.getStackTags()).containsExactly(entry("tag1", "abc"));
@@ -173,31 +147,19 @@ public void testDeserialize_ExtranousModelFields_AreAllowed() throws IOException
assertThat(r.getBearerToken()).isEqualTo("123456");
assertThat(r.getRegion()).isEqualTo("us-east-1");
assertThat(r.getRequestContext()).isNotNull();
+ assertThat(r.getCallbackContext()).isNull();
assertThat(r.getRequestData()).isNotNull();
- assertThat(r.getResponseEndpoint()).isEqualTo("https://cloudformation.us-west-2.amazonaws.com");
assertThat(r.getResourceType()).isEqualTo("AWS::Test::TestModel");
assertThat(r.getResourceTypeVersion()).isEqualTo("1.0");
assertThat(r.getStackId())
.isEqualTo("arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/e722ae60-fe62-11e8-9a0e-0ae8cc519968");
- final RequestContext requestContext = r.getRequestContext();
- assertThat(requestContext.getCloudWatchEventsRuleName()).isNull();
- assertThat(requestContext.getCloudWatchEventsTargetId()).isNull();
- assertThat(requestContext.getInvocation()).isEqualTo(0);
- assertThat(requestContext.getCallbackContext()).isNull();
-
final RequestData requestData = r.getRequestData();
assertThat(requestData.getCallerCredentials()).isNotNull();
assertThat(requestData.getCallerCredentials().getAccessKeyId()).isEqualTo("IASAYK835GAIFHAHEI23");
assertThat(requestData.getCallerCredentials().getSecretAccessKey()).isEqualTo("66iOGPN5LnpZorcLr8Kh25u8AbjHVllv5/poh2O0");
assertThat(requestData.getCallerCredentials().getSessionToken())
.isEqualTo("lameHS2vQOknSHWhdFYTxm2eJc1JMn9YBNI4nV4mXue945KPL6DHfW8EsUQT5zwssYEC1NvYP9yD6Y5s5lKR3chflOHPFsIe6eqg");
- assertThat(requestData.getPlatformCredentials()).isNotNull();
- assertThat(requestData.getPlatformCredentials().getAccessKeyId()).isEqualTo("32IEHAHFIAG538KYASAI");
- assertThat(requestData.getPlatformCredentials().getSecretAccessKey())
- .isEqualTo("0O2hop/5vllVHjbA8u52hK8rLcroZpnL5NPGOi66");
- assertThat(requestData.getPlatformCredentials().getSessionToken())
- .isEqualTo("gqe6eIsFPHOlfhc3RKl5s5Y6Dy9PYvN1CEYsswz5TQUsE8WfHD6LPK549euXm4Vn4INBY9nMJ1cJe2mxTYFdhWHSnkOQv2SHemal");
assertThat(requestData.getLogicalResourceId()).isEqualTo("myBucket");
assertThat(requestData.getStackTags()).containsExactly(entry("tag1", "abc"));
diff --git a/src/test/resources/software/amazon/cloudformation/proxy/handler/model.json b/src/test/resources/software/amazon/cloudformation/proxy/handler/model.json
index d485a189..1fe72db6 100644
--- a/src/test/resources/software/amazon/cloudformation/proxy/handler/model.json
+++ b/src/test/resources/software/amazon/cloudformation/proxy/handler/model.json
@@ -30,5 +30,8 @@
],
"createOnlyProperties": [
"/properties/RepoName"
+ ],
+ "primaryIdentifier": [
+ "/properties/RepoName"
]
}
diff --git a/src/test/resources/software/amazon/cloudformation/wrapper-override.json b/src/test/resources/software/amazon/cloudformation/wrapper-override.json
new file mode 100644
index 00000000..d2ebeaa3
--- /dev/null
+++ b/src/test/resources/software/amazon/cloudformation/wrapper-override.json
@@ -0,0 +1,16 @@
+{
+ "typeName": "Test::Resource::Type",
+ "description": "Description",
+ "properties": {
+ "property1": {
+ "type": "string"
+ },
+ "property2": {
+ "type": "integer"
+ }
+ },
+ "additionalProperties": false,
+ "primaryIdentifier": [
+ "/properties/property1"
+ ]
+}
diff --git a/tests/test_codegen.py b/tests/test_codegen.py
index deaa0db9..57ead838 100644
--- a/tests/test_codegen.py
+++ b/tests/test_codegen.py
@@ -8,7 +8,13 @@
import pytest
from rpdk.core.exceptions import InternalError, SysExitRecommendedError
from rpdk.core.project import Project
-from rpdk.java.codegen import JavaArchiveNotFoundError, JavaLanguagePlugin
+from rpdk.java.codegen import (
+ InvalidMavenPOMError,
+ JavaArchiveNotFoundError,
+ JavaLanguagePlugin,
+ JavaPluginNotFoundError,
+ JavaPluginVersionNotSupportedError,
+)
RESOURCE = "DZQWCC"
@@ -84,6 +90,36 @@ def test_generate(project):
assert not test_file.is_file()
+def test_protocol_version_is_set(project):
+ assert project.settings["protocolVersion"] == "2.0.0"
+
+
+def test_generate_low_protocol_version_is_updated(project):
+ project.settings["protocolVersion"] = "1.0.0"
+ project.generate()
+ assert project.settings["protocolVersion"] == "2.0.0"
+
+
+def update_pom_with_plugin_version(project, version_id):
+ pom_tree = ET.parse(project.root / "pom.xml")
+ root = pom_tree.getroot()
+ namespace = {"mvn": "http://maven.apache.org/POM/4.0.0"}
+ version = root.find(
+ "./mvn:dependencies/mvn:dependency"
+ "/[mvn:artifactId='aws-cloudformation-rpdk-java-plugin']/mvn:version",
+ namespace,
+ )
+ version.text = version_id
+ pom_tree.write(project.root / "pom.xml")
+
+
+def test_generate_with_not_support_version(project):
+ update_pom_with_plugin_version(project, "1.0.0")
+
+ with pytest.raises(JavaPluginVersionNotSupportedError):
+ project.generate()
+
+
def make_target(project, count):
target = project.root / "target"
target.mkdir(exist_ok=True)
@@ -114,6 +150,33 @@ def test__find_jar_two(project):
project._plugin._find_jar(project)
+def make_pom_xml_without_plugin(project):
+ pom_tree = ET.parse(project.root / "pom.xml")
+ root = pom_tree.getroot()
+ namespace = {"mvn": "http://maven.apache.org/POM/4.0.0"}
+ plugin = root.find(
+ ".//mvn:dependency/[mvn:artifactId='aws-cloudformation-rpdk-java-plugin']",
+ namespace,
+ )
+ dependencies = root.find("mvn:dependencies", namespace)
+ dependencies.remove(plugin)
+ pom_tree.write(project.root / "pom.xml")
+
+
+def test__get_plugin_version_not_found(project):
+ make_pom_xml_without_plugin(project)
+ with pytest.raises(JavaPluginNotFoundError):
+ project._plugin._get_java_plugin_dependency_version(project)
+
+
+def test__get_plugin_version_invalid_pom(project):
+ pom = open(project.root / "pom.xml", "w")
+ pom.write("invalid pom")
+ pom.close()
+ with pytest.raises(InvalidMavenPOMError):
+ project._plugin._get_java_plugin_dependency_version(project)
+
+
def test_package(project):
project.load_schema()
project.generate()