feat: add support for listing function versions and aliases in AWS Lambda Plugin (#41263)
This commit is contained in:
parent
b79b160d2f
commit
180af275b5
|
|
@ -9,7 +9,11 @@ import com.amazonaws.services.lambda.model.AWSLambdaException;
|
|||
import com.amazonaws.services.lambda.model.FunctionConfiguration;
|
||||
import com.amazonaws.services.lambda.model.InvokeRequest;
|
||||
import com.amazonaws.services.lambda.model.InvokeResult;
|
||||
import com.amazonaws.services.lambda.model.ListAliasesRequest;
|
||||
import com.amazonaws.services.lambda.model.ListAliasesResult;
|
||||
import com.amazonaws.services.lambda.model.ListFunctionsResult;
|
||||
import com.amazonaws.services.lambda.model.ListVersionsByFunctionRequest;
|
||||
import com.amazonaws.services.lambda.model.ListVersionsByFunctionResult;
|
||||
import com.amazonaws.services.lambda.model.ResourceNotFoundException;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
|
||||
|
|
@ -70,6 +74,10 @@ public class AwsLambdaPlugin extends BasePlugin {
|
|||
ActionExecutionResult result;
|
||||
switch (Objects.requireNonNull(command)) {
|
||||
case "LIST_FUNCTIONS" -> result = listFunctions(actionConfiguration, connection);
|
||||
case "LIST_FUNCTION_VERSIONS" -> result =
|
||||
listFunctionVersions(actionConfiguration, connection);
|
||||
case "LIST_FUNCTION_ALIASES" -> result =
|
||||
listFunctionAliases(actionConfiguration, connection);
|
||||
case "INVOKE_FUNCTION" -> result = invokeFunction(actionConfiguration, connection);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + command);
|
||||
}
|
||||
|
|
@ -98,24 +106,108 @@ public class AwsLambdaPlugin extends BasePlugin {
|
|||
throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR, "request type is missing");
|
||||
}
|
||||
ActionExecutionResult actionExecutionResult = listFunctions(null, connection);
|
||||
ArrayNode body = (ArrayNode) actionExecutionResult.getBody();
|
||||
List<Map<String, String>> functionNames = StreamSupport.stream(body.spliterator(), false)
|
||||
.map(function -> function.get("functionName").asText())
|
||||
.sorted()
|
||||
.map(functionName -> Map.of("label", functionName, "value", functionName))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
String requestType = request.getRequestType();
|
||||
ActionExecutionResult actionExecutionResult;
|
||||
List<Map<String, String>> options;
|
||||
Map<?, Object> params = request.getParameters() == null ? Map.of() : request.getParameters();
|
||||
|
||||
switch (requestType) {
|
||||
case "FUNCTION_NAMES" -> {
|
||||
actionExecutionResult = listFunctions(null, connection);
|
||||
ArrayNode body = (ArrayNode) actionExecutionResult.getBody();
|
||||
options = StreamSupport.stream(body.spliterator(), false)
|
||||
.map(function -> function.get("functionName").asText())
|
||||
.sorted()
|
||||
.map(functionName -> Map.of("label", functionName, "value", functionName))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
case "FUNCTION_VERSIONS" -> {
|
||||
// Handle both old and new parameter structures
|
||||
String functionName;
|
||||
if (params.containsKey("parameters") && params.get("parameters") instanceof Map) {
|
||||
Map<?, ?> parameters = (Map<?, ?>) params.get("parameters");
|
||||
functionName = (String) parameters.get("functionName");
|
||||
} else {
|
||||
functionName = (String) params.get("functionName");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(functionName)) {
|
||||
throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
|
||||
"function name is required for listing versions");
|
||||
}
|
||||
actionExecutionResult = listFunctionVersions(null, connection, functionName);
|
||||
ArrayNode body = (ArrayNode) actionExecutionResult.getBody();
|
||||
options = StreamSupport.stream(body.spliterator(), false)
|
||||
.map(version -> version.get("version").asText())
|
||||
.sorted()
|
||||
.map(version -> Map.of("label", version, "value", version))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
case "FUNCTION_ALIASES" -> {
|
||||
// Handle both old and new parameter structures
|
||||
String functionName;
|
||||
if (params.containsKey("parameters") && params.get("parameters") instanceof Map) {
|
||||
Map<?, ?> parameters = (Map<?, ?>) params.get("parameters");
|
||||
functionName = (String) parameters.get("functionName");
|
||||
} else {
|
||||
functionName = (String) params.get("functionName");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(functionName)) {
|
||||
throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
|
||||
"function name is required for listing aliases");
|
||||
}
|
||||
actionExecutionResult = listFunctionAliases(null, connection, functionName);
|
||||
ArrayNode body = (ArrayNode) actionExecutionResult.getBody();
|
||||
options = StreamSupport.stream(body.spliterator(), false)
|
||||
.map(alias -> alias.get("name").asText())
|
||||
.sorted()
|
||||
.map(alias -> Map.of("label", alias, "value", alias))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
default -> throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR, "Unsupported request type: " + requestType);
|
||||
}
|
||||
|
||||
TriggerResultDTO triggerResultDTO = new TriggerResultDTO();
|
||||
triggerResultDTO.setTrigger(functionNames);
|
||||
triggerResultDTO.setTrigger(options);
|
||||
|
||||
return Mono.just(triggerResultDTO);
|
||||
}
|
||||
|
||||
ActionExecutionResult invokeFunction(ActionConfiguration actionConfiguration, AWSLambda connection) {
|
||||
InvokeRequest invokeRequest = new InvokeRequest();
|
||||
invokeRequest.setFunctionName(
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionName", STRING_TYPE));
|
||||
|
||||
// Validate and set function name (required parameter)
|
||||
String functionName =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionName", STRING_TYPE);
|
||||
if (!StringUtils.hasText(functionName)) {
|
||||
throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
|
||||
"Function name is required for Lambda invocation");
|
||||
}
|
||||
|
||||
// Get version and alias parameters
|
||||
String functionVersion =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionVersion", STRING_TYPE);
|
||||
String functionAlias =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionAlias", STRING_TYPE);
|
||||
|
||||
// Set function name (without qualifier)
|
||||
invokeRequest.setFunctionName(functionName);
|
||||
|
||||
// Use setQualifier for version/alias instead of embedding in function name
|
||||
if (StringUtils.hasText(functionAlias)) {
|
||||
// If alias is specified, use it (alias takes precedence over version)
|
||||
invokeRequest.setQualifier(functionAlias);
|
||||
} else if (StringUtils.hasText(functionVersion)) {
|
||||
// If version is specified and no alias, use version
|
||||
invokeRequest.setQualifier(functionVersion);
|
||||
}
|
||||
// If neither version nor alias is specified, defaults to $LATEST
|
||||
invokeRequest.setPayload(
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "body", STRING_TYPE));
|
||||
invokeRequest.setInvocationType(
|
||||
|
|
@ -145,6 +237,61 @@ public class AwsLambdaPlugin extends BasePlugin {
|
|||
return result;
|
||||
}
|
||||
|
||||
ActionExecutionResult listFunctionVersions(
|
||||
ActionConfiguration actionConfiguration, AWSLambda connection, String functionName) {
|
||||
if (actionConfiguration != null) {
|
||||
functionName =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionName", STRING_TYPE);
|
||||
}
|
||||
if (!StringUtils.hasText(functionName)) {
|
||||
throw new AppsmithPluginException(
|
||||
AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
|
||||
"function name is required for listing versions");
|
||||
}
|
||||
|
||||
ListVersionsByFunctionRequest request = new ListVersionsByFunctionRequest();
|
||||
request.setFunctionName(functionName);
|
||||
|
||||
ListVersionsByFunctionResult listVersionsResult = connection.listVersionsByFunction(request);
|
||||
List<FunctionConfiguration> versions = listVersionsResult.getVersions();
|
||||
|
||||
ActionExecutionResult result = new ActionExecutionResult();
|
||||
result.setBody(objectMapper.valueToTree(versions));
|
||||
result.setIsExecutionSuccess(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
ActionExecutionResult listFunctionVersions(ActionConfiguration actionConfiguration, AWSLambda connection) {
|
||||
String functionName =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionName", STRING_TYPE);
|
||||
return listFunctionVersions(null, connection, functionName);
|
||||
}
|
||||
|
||||
ActionExecutionResult listFunctionAliases(
|
||||
ActionConfiguration actionConfiguration, AWSLambda connection, String functionName) {
|
||||
if (actionConfiguration != null) {
|
||||
functionName =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionName", STRING_TYPE);
|
||||
}
|
||||
|
||||
ListAliasesRequest request = new ListAliasesRequest();
|
||||
request.setFunctionName(functionName);
|
||||
|
||||
ListAliasesResult listAliasesResult = connection.listAliases(request);
|
||||
List<com.amazonaws.services.lambda.model.AliasConfiguration> aliases = listAliasesResult.getAliases();
|
||||
|
||||
ActionExecutionResult result = new ActionExecutionResult();
|
||||
result.setBody(objectMapper.valueToTree(aliases));
|
||||
result.setIsExecutionSuccess(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
ActionExecutionResult listFunctionAliases(ActionConfiguration actionConfiguration, AWSLambda connection) {
|
||||
String functionName =
|
||||
getDataValueSafelyFromFormData(actionConfiguration.getFormData(), "functionName", STRING_TYPE);
|
||||
return listFunctionAliases(null, connection, functionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AWSLambda> datasourceCreate(DatasourceConfiguration datasourceConfiguration) {
|
||||
log.debug(Thread.currentThread().getName() + ": datasourceCreate() called for AWS Lambda plugin.");
|
||||
|
|
|
|||
|
|
@ -36,6 +36,66 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Function version",
|
||||
"tooltipText": "Optional: Specify a version number (e.g., 1, 2, $LATEST) or leave empty for $LATEST.",
|
||||
"subtitle": "",
|
||||
"isRequired": false,
|
||||
"propertyName": "function_version",
|
||||
"configProperty": "actionConfiguration.formData.functionVersion.data",
|
||||
"controlType": "DROP_DOWN",
|
||||
"initialValue": "",
|
||||
"options": [],
|
||||
"placeholderText": "Leave empty for $LATEST version",
|
||||
"fetchOptionsConditionally": true,
|
||||
"setFirstOptionAsDefault": false,
|
||||
"alternateViewTypes": ["json"],
|
||||
"conditionals": {
|
||||
"enable": "{{actionConfiguration.formData.functionName.data}}",
|
||||
"fetchDynamicValues": {
|
||||
"condition": "{{actionConfiguration.formData.command.data === 'INVOKE_FUNCTION' && actionConfiguration.formData.functionName.data}}",
|
||||
"config": {
|
||||
"params": {
|
||||
"requestType": "FUNCTION_VERSIONS",
|
||||
"displayType": "DROP_DOWN",
|
||||
"parameters": {
|
||||
"functionName": "{{actionConfiguration.formData.functionName.data}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Function alias",
|
||||
"tooltipText": "Optional: Specify an alias name (e.g., PROD, STAGING) or leave empty for no alias.",
|
||||
"subtitle": "",
|
||||
"isRequired": false,
|
||||
"propertyName": "function_alias",
|
||||
"configProperty": "actionConfiguration.formData.functionAlias.data",
|
||||
"controlType": "DROP_DOWN",
|
||||
"initialValue": "",
|
||||
"options": [],
|
||||
"placeholderText": "Leave empty for no alias",
|
||||
"fetchOptionsConditionally": true,
|
||||
"setFirstOptionAsDefault": false,
|
||||
"alternateViewTypes": ["json"],
|
||||
"conditionals": {
|
||||
"enable": "{{actionConfiguration.formData.functionName.data}}",
|
||||
"fetchDynamicValues": {
|
||||
"condition": "{{actionConfiguration.formData.command.data === 'INVOKE_FUNCTION' && actionConfiguration.formData.functionName.data}}",
|
||||
"config": {
|
||||
"params": {
|
||||
"requestType": "FUNCTION_ALIASES",
|
||||
"displayType": "DROP_DOWN",
|
||||
"parameters": {
|
||||
"functionName": "{{actionConfiguration.formData.functionName.data}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Type of invocation",
|
||||
"tooltipText": "Should the invocation be synchronous or asynchronous?",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"identifier": "LIST_FUNCTION_ALIASES",
|
||||
"controlType": "SECTION_V2",
|
||||
"conditionals": {
|
||||
"show": "{{actionConfiguration.formData.command.data === 'LIST_FUNCTION_ALIASES'}}"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"controlType": "DOUBLE_COLUMN_ZONE",
|
||||
"label": "Function details",
|
||||
"children": [
|
||||
{
|
||||
"label": "Function name",
|
||||
"tooltipText": "The name of the AWS Lambda function to list aliases for.",
|
||||
"subtitle": "",
|
||||
"isRequired": true,
|
||||
"propertyName": "function_name",
|
||||
"configProperty": "actionConfiguration.formData.functionName.data",
|
||||
"controlType": "DROP_DOWN",
|
||||
"initialValue": "",
|
||||
"options": [],
|
||||
"placeholderText": "All function names will be fetched.",
|
||||
"fetchOptionsConditionally": true,
|
||||
"setFirstOptionAsDefault": true,
|
||||
"alternateViewTypes": ["json"],
|
||||
"conditionals": {
|
||||
"enable": "{{true}}",
|
||||
"fetchDynamicValues": {
|
||||
"condition": "{{actionConfiguration.formData.command.data === 'LIST_FUNCTION_ALIASES'}}",
|
||||
"config": {
|
||||
"params": {
|
||||
"requestType": "FUNCTION_NAMES",
|
||||
"displayType": "DROP_DOWN"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"identifier": "LIST_FUNCTION_VERSIONS",
|
||||
"controlType": "SECTION_V2",
|
||||
"conditionals": {
|
||||
"show": "{{actionConfiguration.formData.command.data === 'LIST_FUNCTION_VERSIONS'}}"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"controlType": "DOUBLE_COLUMN_ZONE",
|
||||
"label": "Function details",
|
||||
"children": [
|
||||
{
|
||||
"label": "Function name",
|
||||
"tooltipText": "The name of the AWS Lambda function to list versions for.",
|
||||
"subtitle": "",
|
||||
"isRequired": true,
|
||||
"propertyName": "function_name",
|
||||
"configProperty": "actionConfiguration.formData.functionName.data",
|
||||
"controlType": "DROP_DOWN",
|
||||
"initialValue": "",
|
||||
"options": [],
|
||||
"placeholderText": "All function names will be fetched.",
|
||||
"fetchOptionsConditionally": true,
|
||||
"setFirstOptionAsDefault": true,
|
||||
"alternateViewTypes": ["json"],
|
||||
"conditionals": {
|
||||
"enable": "{{true}}",
|
||||
"fetchDynamicValues": {
|
||||
"condition": "{{actionConfiguration.formData.command.data === 'LIST_FUNCTION_VERSIONS'}}",
|
||||
"config": {
|
||||
"params": {
|
||||
"requestType": "FUNCTION_NAMES",
|
||||
"displayType": "DROP_DOWN"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -13,12 +13,21 @@
|
|||
"description": "Choose the method you would like to use",
|
||||
"configProperty": "actionConfiguration.formData.command.data",
|
||||
"controlType": "DROP_DOWN",
|
||||
"isRequired": true,
|
||||
"initialValue": "LIST_FUNCTIONS",
|
||||
"options": [
|
||||
{
|
||||
"label": "List all functions",
|
||||
"value": "LIST_FUNCTIONS"
|
||||
},
|
||||
{
|
||||
"label": "List function versions",
|
||||
"value": "LIST_FUNCTION_VERSIONS"
|
||||
},
|
||||
{
|
||||
"label": "List function aliases",
|
||||
"value": "LIST_FUNCTION_ALIASES"
|
||||
},
|
||||
{
|
||||
"label": "Invoke a function",
|
||||
"value": "INVOKE_FUNCTION"
|
||||
|
|
@ -30,5 +39,5 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"files": ["list.json", "invoke.json"]
|
||||
"files": ["list.json", "listVersions.json", "listAliases.json", "invoke.json"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import com.amazonaws.services.lambda.AWSLambda;
|
||||
import com.amazonaws.services.lambda.model.AliasConfiguration;
|
||||
import com.amazonaws.services.lambda.model.FunctionConfiguration;
|
||||
import com.amazonaws.services.lambda.model.InvokeRequest;
|
||||
import com.amazonaws.services.lambda.model.InvokeResult;
|
||||
import com.amazonaws.services.lambda.model.ListAliasesRequest;
|
||||
import com.amazonaws.services.lambda.model.ListAliasesResult;
|
||||
import com.amazonaws.services.lambda.model.ListFunctionsResult;
|
||||
import com.amazonaws.services.lambda.model.ListVersionsByFunctionRequest;
|
||||
import com.amazonaws.services.lambda.model.ListVersionsByFunctionResult;
|
||||
import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException;
|
||||
import com.appsmith.external.models.ActionConfiguration;
|
||||
import com.appsmith.external.models.ActionExecutionResult;
|
||||
|
|
@ -14,6 +20,7 @@ import com.appsmith.external.models.TriggerRequestDTO;
|
|||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
|
@ -31,6 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Testcontainers
|
||||
|
|
@ -193,4 +201,305 @@ public class AwsLambdaPluginTest {
|
|||
pluginExecutor.trigger(mockLambda, datasourceConfiguration, request).block();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteListFunctionVersions() {
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
Map<String, Object> configMap = new HashMap<>();
|
||||
setDataValueSafelyInFormData(configMap, "command", "LIST_FUNCTION_VERSIONS");
|
||||
setDataValueSafelyInFormData(configMap, "functionName", "test-aws-lambda");
|
||||
|
||||
ActionConfiguration actionConfiguration = new ActionConfiguration();
|
||||
actionConfiguration.setFormData(configMap);
|
||||
|
||||
// Mock the Lambda connection
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
ListVersionsByFunctionResult mockVersionsResult = new ListVersionsByFunctionResult();
|
||||
mockVersionsResult.setVersions(List.of(
|
||||
new FunctionConfiguration().withVersion("$LATEST"),
|
||||
new FunctionConfiguration().withVersion("1"),
|
||||
new FunctionConfiguration().withVersion("2")));
|
||||
when(mockLambda.listVersionsByFunction(any(ListVersionsByFunctionRequest.class)))
|
||||
.thenReturn(mockVersionsResult);
|
||||
|
||||
Mono<ActionExecutionResult> resultMono =
|
||||
pluginExecutor.execute(mockLambda, datasourceConfiguration, actionConfiguration);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertEquals(3, ((ArrayNode) result.getBody()).size());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteListFunctionAliases() {
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
Map<String, Object> configMap = new HashMap<>();
|
||||
setDataValueSafelyInFormData(configMap, "command", "LIST_FUNCTION_ALIASES");
|
||||
setDataValueSafelyInFormData(configMap, "functionName", "test-aws-lambda");
|
||||
|
||||
ActionConfiguration actionConfiguration = new ActionConfiguration();
|
||||
actionConfiguration.setFormData(configMap);
|
||||
|
||||
// Mock the Lambda connection
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
ListAliasesResult mockAliasesResult = new ListAliasesResult();
|
||||
mockAliasesResult.setAliases(
|
||||
List.of(new AliasConfiguration().withName("PROD"), new AliasConfiguration().withName("STAGING")));
|
||||
when(mockLambda.listAliases(any(ListAliasesRequest.class))).thenReturn(mockAliasesResult);
|
||||
|
||||
Mono<ActionExecutionResult> resultMono =
|
||||
pluginExecutor.execute(mockLambda, datasourceConfiguration, actionConfiguration);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertEquals(2, ((ArrayNode) result.getBody()).size());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteInvokeFunctionWithVersion() {
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
Map<String, Object> configMap = new HashMap<>();
|
||||
setDataValueSafelyInFormData(configMap, "command", "INVOKE_FUNCTION");
|
||||
setDataValueSafelyInFormData(configMap, "body", "{\"data\": \"\"}");
|
||||
setDataValueSafelyInFormData(configMap, "functionName", "test-aws-lambda");
|
||||
setDataValueSafelyInFormData(configMap, "functionVersion", "2");
|
||||
|
||||
ActionConfiguration actionConfiguration = new ActionConfiguration();
|
||||
actionConfiguration.setFormData(configMap);
|
||||
|
||||
// Mock the Lambda connection
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
InvokeResult mockResult = new InvokeResult();
|
||||
mockResult.setPayload(ByteBuffer.wrap("Hello World from version 2".getBytes()));
|
||||
when(mockLambda.invoke(any())).thenReturn(mockResult);
|
||||
|
||||
// Capture the InvokeRequest to verify the qualifier is set correctly
|
||||
ArgumentCaptor<InvokeRequest> requestCaptor = ArgumentCaptor.forClass(InvokeRequest.class);
|
||||
|
||||
Mono<ActionExecutionResult> resultMono =
|
||||
pluginExecutor.execute(mockLambda, datasourceConfiguration, actionConfiguration);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertTrue(result.getIsExecutionSuccess());
|
||||
assertEquals("Hello World from version 2", result.getBody().toString());
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
// Verify that the InvokeRequest was called with the correct qualifier
|
||||
verify(mockLambda).invoke(requestCaptor.capture());
|
||||
InvokeRequest capturedRequest = requestCaptor.getValue();
|
||||
assertEquals("test-aws-lambda", capturedRequest.getFunctionName());
|
||||
assertEquals("2", capturedRequest.getQualifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteInvokeFunctionWithAlias() {
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
Map<String, Object> configMap = new HashMap<>();
|
||||
setDataValueSafelyInFormData(configMap, "command", "INVOKE_FUNCTION");
|
||||
setDataValueSafelyInFormData(configMap, "body", "{\"data\": \"\"}");
|
||||
setDataValueSafelyInFormData(configMap, "functionName", "test-aws-lambda");
|
||||
setDataValueSafelyInFormData(configMap, "functionAlias", "PROD");
|
||||
|
||||
ActionConfiguration actionConfiguration = new ActionConfiguration();
|
||||
actionConfiguration.setFormData(configMap);
|
||||
|
||||
// Mock the Lambda connection
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
InvokeResult mockResult = new InvokeResult();
|
||||
mockResult.setPayload(ByteBuffer.wrap("Hello World from PROD alias".getBytes()));
|
||||
when(mockLambda.invoke(any())).thenReturn(mockResult);
|
||||
|
||||
// Capture the InvokeRequest to verify the qualifier is set correctly
|
||||
ArgumentCaptor<InvokeRequest> requestCaptor = ArgumentCaptor.forClass(InvokeRequest.class);
|
||||
|
||||
Mono<ActionExecutionResult> resultMono =
|
||||
pluginExecutor.execute(mockLambda, datasourceConfiguration, actionConfiguration);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertTrue(result.getIsExecutionSuccess());
|
||||
assertEquals("Hello World from PROD alias", result.getBody().toString());
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
// Verify that the InvokeRequest was called with the correct qualifier
|
||||
verify(mockLambda).invoke(requestCaptor.capture());
|
||||
InvokeRequest capturedRequest = requestCaptor.getValue();
|
||||
assertEquals("test-aws-lambda", capturedRequest.getFunctionName());
|
||||
assertEquals("PROD", capturedRequest.getQualifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteInvokeFunctionWithAliasTakesPrecedenceOverVersion() {
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
Map<String, Object> configMap = new HashMap<>();
|
||||
setDataValueSafelyInFormData(configMap, "command", "INVOKE_FUNCTION");
|
||||
setDataValueSafelyInFormData(configMap, "body", "{\"data\": \"\"}");
|
||||
setDataValueSafelyInFormData(configMap, "functionName", "test-aws-lambda");
|
||||
setDataValueSafelyInFormData(configMap, "functionVersion", "2");
|
||||
setDataValueSafelyInFormData(configMap, "functionAlias", "PROD");
|
||||
|
||||
ActionConfiguration actionConfiguration = new ActionConfiguration();
|
||||
actionConfiguration.setFormData(configMap);
|
||||
|
||||
// Mock the Lambda connection
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
InvokeResult mockResult = new InvokeResult();
|
||||
mockResult.setPayload(ByteBuffer.wrap("Hello World from PROD alias (alias takes precedence)".getBytes()));
|
||||
when(mockLambda.invoke(any())).thenReturn(mockResult);
|
||||
|
||||
// Capture the InvokeRequest to verify the qualifier is set correctly
|
||||
ArgumentCaptor<InvokeRequest> requestCaptor = ArgumentCaptor.forClass(InvokeRequest.class);
|
||||
|
||||
Mono<ActionExecutionResult> resultMono =
|
||||
pluginExecutor.execute(mockLambda, datasourceConfiguration, actionConfiguration);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertTrue(result.getIsExecutionSuccess());
|
||||
assertEquals(
|
||||
"Hello World from PROD alias (alias takes precedence)",
|
||||
result.getBody().toString());
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
// Verify that the InvokeRequest was called with the alias (not version) as qualifier
|
||||
verify(mockLambda).invoke(requestCaptor.capture());
|
||||
InvokeRequest capturedRequest = requestCaptor.getValue();
|
||||
assertEquals("test-aws-lambda", capturedRequest.getFunctionName());
|
||||
assertEquals("PROD", capturedRequest.getQualifier()); // Should be alias, not version "2"
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteInvokeFunctionWithoutVersionOrAlias() {
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
Map<String, Object> configMap = new HashMap<>();
|
||||
setDataValueSafelyInFormData(configMap, "command", "INVOKE_FUNCTION");
|
||||
setDataValueSafelyInFormData(configMap, "body", "{\"data\": \"\"}");
|
||||
setDataValueSafelyInFormData(configMap, "functionName", "test-aws-lambda");
|
||||
// No functionVersion or functionAlias specified
|
||||
|
||||
ActionConfiguration actionConfiguration = new ActionConfiguration();
|
||||
actionConfiguration.setFormData(configMap);
|
||||
|
||||
// Mock the Lambda connection
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
InvokeResult mockResult = new InvokeResult();
|
||||
mockResult.setPayload(ByteBuffer.wrap("Hello World from $LATEST".getBytes()));
|
||||
when(mockLambda.invoke(any())).thenReturn(mockResult);
|
||||
|
||||
// Capture the InvokeRequest to verify no qualifier is set (defaults to $LATEST)
|
||||
ArgumentCaptor<InvokeRequest> requestCaptor = ArgumentCaptor.forClass(InvokeRequest.class);
|
||||
|
||||
Mono<ActionExecutionResult> resultMono =
|
||||
pluginExecutor.execute(mockLambda, datasourceConfiguration, actionConfiguration);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertTrue(result.getIsExecutionSuccess());
|
||||
assertEquals("Hello World from $LATEST", result.getBody().toString());
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
// Verify that the InvokeRequest was called without a qualifier (defaults to $LATEST)
|
||||
verify(mockLambda).invoke(requestCaptor.capture());
|
||||
InvokeRequest capturedRequest = requestCaptor.getValue();
|
||||
assertEquals("test-aws-lambda", capturedRequest.getFunctionName());
|
||||
// When no qualifier is set, it should be null (AWS defaults to $LATEST)
|
||||
assertEquals(null, capturedRequest.getQualifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriggerFunctionNames() {
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
ListFunctionsResult mockFunctionsResult = new ListFunctionsResult();
|
||||
mockFunctionsResult.setFunctions(List.of(
|
||||
new FunctionConfiguration().withFunctionName("function1"),
|
||||
new FunctionConfiguration().withFunctionName("function2")));
|
||||
when(mockLambda.listFunctions()).thenReturn(mockFunctionsResult);
|
||||
|
||||
TriggerRequestDTO request = new TriggerRequestDTO();
|
||||
request.setRequestType("FUNCTION_NAMES");
|
||||
|
||||
Mono<com.appsmith.external.models.TriggerResultDTO> resultMono =
|
||||
pluginExecutor.trigger(mockLambda, datasourceConfiguration, request);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertEquals(2, ((List<?>) result.getTrigger()).size());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriggerFunctionVersions() {
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
ListVersionsByFunctionResult mockVersionsResult = new ListVersionsByFunctionResult();
|
||||
mockVersionsResult.setVersions(List.of(
|
||||
new FunctionConfiguration().withVersion("$LATEST"),
|
||||
new FunctionConfiguration().withVersion("1"),
|
||||
new FunctionConfiguration().withVersion("2")));
|
||||
when(mockLambda.listVersionsByFunction(any(ListVersionsByFunctionRequest.class)))
|
||||
.thenReturn(mockVersionsResult);
|
||||
|
||||
TriggerRequestDTO request = new TriggerRequestDTO();
|
||||
request.setRequestType("FUNCTION_VERSIONS");
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("functionName", "test-function");
|
||||
request.setParameters(params);
|
||||
|
||||
Mono<com.appsmith.external.models.TriggerResultDTO> resultMono =
|
||||
pluginExecutor.trigger(mockLambda, datasourceConfiguration, request);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertEquals(3, ((List<?>) result.getTrigger()).size());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriggerFunctionAliases() {
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
|
||||
ListAliasesResult mockAliasesResult = new ListAliasesResult();
|
||||
mockAliasesResult.setAliases(
|
||||
List.of(new AliasConfiguration().withName("PROD"), new AliasConfiguration().withName("STAGING")));
|
||||
when(mockLambda.listAliases(any(ListAliasesRequest.class))).thenReturn(mockAliasesResult);
|
||||
|
||||
TriggerRequestDTO request = new TriggerRequestDTO();
|
||||
request.setRequestType("FUNCTION_ALIASES");
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("functionName", "test-function");
|
||||
request.setParameters(params);
|
||||
|
||||
Mono<com.appsmith.external.models.TriggerResultDTO> resultMono =
|
||||
pluginExecutor.trigger(mockLambda, datasourceConfiguration, request);
|
||||
StepVerifier.create(resultMono)
|
||||
.assertNext(result -> {
|
||||
assertEquals(2, ((List<?>) result.getTrigger()).size());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriggerUnsupportedRequestType() {
|
||||
AWSLambda mockLambda = mock(AWSLambda.class);
|
||||
DatasourceConfiguration datasourceConfiguration = createDatasourceConfiguration();
|
||||
TriggerRequestDTO request = new TriggerRequestDTO();
|
||||
request.setRequestType("UNSUPPORTED_TYPE");
|
||||
|
||||
assertThrows(AppsmithPluginException.class, () -> {
|
||||
pluginExecutor.trigger(mockLambda, datasourceConfiguration, request).block();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user