【问题标题】:LocalStackContainer integration testing a lambdaLocalStackContainer 集成测试 lambda
【发布时间】:2021-02-11 18:33:45
【问题描述】:

有没有一种方法可以(集成)使用 testcontainers 和以下 LocalStackContainer 为 AWS 测试 Lambda:

new LocalStackContainer(DockerImageName.parse('localstack/localstack:0.11.6'))
    .withServices(LocalStackContainer.Service.LAMBDA)

具体来说,我如何将 Lambda“上传”到本地运行的服务中,以便随后触发和测试它?

【问题讨论】:

    标签: java aws-lambda spock testcontainers localstack


    【解决方案1】:

    LocalStackContainer 启动后,您可以在容器内执行命令来设置您的基础架构。 LocalStack 提供 awslocal 二进制文件来创建任何 AWS 资源。

    在您的测试中,您可以有一个@BeforeAll 步骤,您可以在其中使用您的容器引用并创建所有内容。

    以下示例针对 S3 和 SQS 执行此操作(引用自 blog post):

    @Testcontainers
    @SpringBootTest
    public class YourLocalStackIT {
     
      @Container
      static LocalStackContainer localStack = new LocalStackContainer("0.11.6")
        .withServices(S3, SQS)
        .withEnv("DEFAULT_REGION", "eu-central-1");
     
      @BeforeAll
      static void beforeAll() throws IOException, InterruptedException {
        localStack.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", QUEUE_NAME);
        localStack.execInContainer("awslocal", "s3", "mb", "s3://" + BUCKET_NAME);
      }
     
      private static final String QUEUE_NAME = "order-event-test-queue";
      private static final String BUCKET_NAME = "order-event-test-bucket";
     
      // ... actual test
    }
    

    您现在可以将其用作模板来准备您的 AWS Lambda 函数。

    关于源代码上传,我想将您的 Lambda 的 .zip 版本也安装或复制到您的容器中然后在其中访问它是有意义的。

    可以像下面这样创建一个 NodeJS lambda:

    awslocal lambda create-function \
        --region eu-central1 \
        --function-name your-api \
        --runtime nodejs8.10 \
        --handler lambda.apiHandler \
        --memory-size 128 \
        --zip-file fileb://api-handler.zip
    

    【讨论】:

    • 感谢@rieckpil,这看起来是一个很好的起点!我试试看!
    【解决方案2】:

    我已经设法设置了 Localstack 和 MySql 测试容器(在 groovy spock 中),如下所示:

      @Shared
      public static Network network = Network.newNetwork()
    
      @Shared
      @ClassRule
      public static MySQLContainer mySql = new MySQLContainer(DockerImageName.parse('mysql:5.7'))
        .withNetwork(network)
        .withNetworkAliases(MY_SQL_HOST_NAME) as MySQLContainer
    
      @Shared
      @ClassRule
      public static LocalStackContainer localStack = new LocalStackContainer(DockerImageName.parse('localstack/localstack:0.11.6'))
        .withServices(SQS, LAMBDA, CLOUDWATCH, DYNAMODB, KMS, STS, IAM)
        .withNetwork(network)
        .withEnv('LAMBDA_DOCKER_NETWORK', network.name)
        .withCopyFileToContainer(MountableFile.forHostPath(new File('the jar file').path), '/opt/code/localstack/lambda.jar')
        .withCopyFileToContainer(MountableFile.forClasspathResource('seed.yaml'), '/init/seed.yaml')
    
    • 这设置了一个桥接网络,以便两个容器可以 互相交流。还设置 LAMBDA_DOCKER_NETWORK 允许 lambda 与 MySql、SQS 等进行通信。
    • 将 lambda jar 文件复制到容器中 (withCopyFileToContainer)
    • 我还需要 KMS,因此 seed.yaml 会对其进行初始化(请参阅本地 KMS 文档)

    一旦容器启动并运行,就可以使用 awslocal 和标准 CLI 命令部署 lambda:

        def result = localStack.execInContainer(
          'awslocal', 'lambda', 'create-function',
          '--function-name', 'lambda-name',
          '--runtime', 'java8',
          '--handler', 'uk.co.blah.blah.Handler',
          '--role', 'arn:aws:iam::123456:role/irrelevant',
          '--zip-file', 'fileb://lambda.jar',
          '--environment', "Variables={MY_SQL_USERNAME=${mySql.username},MY_SQL_PASSWORD=${encryptedDbPassword},PLATFORM_DB_URL=${"jdbc:mysql://${MY_SQL_HOST_NAME}:3306"}," +
            "AWS_REGION=${localStack.region}}"
        )
    

    最后,可以在测试中手动触发 lambda,如下所示:

    localStack.execInContainer('awslocal', 'lambda', 'invoke', '--function-name', 'lambda-name', 'output0.json')
    

    【讨论】:

      猜你喜欢
      • 2019-12-03
      • 1970-01-01
      • 2015-11-07
      • 1970-01-01
      • 2021-01-07
      • 2023-01-24
      • 2012-10-29
      • 2012-10-07
      • 1970-01-01
      相关资源
      最近更新 更多