简体   繁体   中英

How do you add a testing stage to a CodePipeline in AWS CDK?

I'm having trouble finding the right reference because when I search, most of what I want is how to test constructs themselves. What I'm searching for is how to run my application tests, not the infrastructure/construct tests. Is that a testing stage that I should add?

The tests that I'm referring to are the ones normally run by running npm test (or rake test in the Ruby/Rails world, or ./manage.py test in the Django world). Whether you call them integration or unit tests is debatable. They don't necessarily run a whole web server, but they do use the database. In my case these tests might use DynamoDB, SQS, and other services. The functions being tested would be a mixed of Lambda functions and their internal units. I wouldn't expect to run them in a Lambda environment. I would expect to run this tests locally on my machine constantly as I develop. These would be the tests that are run on a pull requests from GitHub as one of the things that block or allow the pull request to be merged. This is the standard Heroku CI/CD model in case you are familiar with that.

For reference, my current pipeline stack looks like this (it started from https://cdkworkshop.com/ and I'm evolving it, Example4Be is my application):

import * as cdk from "aws-cdk-lib"
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"
import {Construct} from "constructs"
import {Example4BeDeployStage} from "./example4-be-deploy-stage"
import {CodeBuildStep, CodePipeline, CodePipelineSource} from "aws-cdk-lib/pipelines"

export class PipelineStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props)

        const githubSecretId = "github-flexpointtech-token"
        const secret = new secretsmanager.Secret(this, githubSecretId)

        // The basic pipeline declaration. This sets the initial structure
        // of our pipeline
        const pipeline = new CodePipeline(this, "Example4BePipeline", {
            synth: new CodeBuildStep("Synth", {
                    input: CodePipelineSource.gitHub("flexpointtech/example4-be", "main", {
                        authentication: cdk.SecretValue.secretsManager(githubSecretId)
                    }),
                    installCommands: [
                        "npm install -g aws-cdk"
                    ],
                    commands: [
                        "npm ci",
                        "npm run build",
                        "npx cdk synth"
                    ]
                }
            )
        })

        pipeline.node.addDependency(secret)

        const deploy = new Example4BeDeployStage(this, "Deploy")
        const deployStage = pipeline.addStage(deploy)

        deployStage.addPost(
            new CodeBuildStep("VerifyViewerEndpoint", {
                envFromCfnOutputs: {
                    ENDPOINT_URL: deploy.hcViewerUrl
                },
                commands: [
                    "curl -Ssf $ENDPOINT_URL"
                ]
            }),

            new CodeBuildStep("VerifyAPIGatewayEndpoint", {
                envFromCfnOutputs: {
                    ENDPOINT_URL: deploy.hcEndpoint
                },
                commands: [
                    "curl -Ssf $ENDPOINT_URL",
                    "curl -Ssf $ENDPOINT_URL/hello",
                    "curl -Ssf $ENDPOINT_URL/test"
                ]
            })
        )
    }
}

Here are some CDK testing strategies. Not one-size-fits-all.

Unit Tests

Your unit tests ideally passed before you committed the PR to main in github (perhaps as a github action ). No reason why you can't re-run them as a npm run test command in your pipeline.

Integration Tests

In many cases it makes sense to add a test deploy stage in a dedicated test account, following AWS's multi-account best practice . One possible flow is:

[Build] -> [Test Deploy Stage] -> [Prod Deploy Stage] -> [Destroy Test Deploy Stage]

The Test Deploy stage is identical to Prod Deploy except for the account. You can add test steps (eg verify API returns the expected value) after the test deploy stage. The pipeline tears down the test environment at the end of its execution.

You can add arbitrary testing code steps to arbitrary Pipeline stages to support your preferred testing idioms cloud-side. For more advanced use cases, you can seed data and perform arbitrary API calls with custom resources .

AWS Amplify Frontend CI/CD

AWS Amplify has Heroku-/Netlify-like CI/CD features for front-end apps, including testable web previews for github PRs . CDK has support for Amplify .(important: you want a Amplify "frontend" App, ignore the "backend")

Blue-Green Deployments

For lambda-based apps, the CDK has built-in blue-green deployments with codedeploy . AWS will gradually feed traffic to your updated lambda version, rolling back if it encounters errors.

I was following the aws documentation about it when dealing with the same problem and you can build a testing stack to run as a step. You can find the documentation here

 import aws_cdk as cdk from constructs import Construct from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep from my_pipeline.my_pipeline_app_stage import MyPipelineAppStage class MyPipelineStack(cdk.Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) pipeline = CodePipeline(self, "Pipeline", pipeline_name="MyPipeline", synth=ShellStep("Synth", input=CodePipelineSource.git_hub("OWNER/REPO", "main"), commands=["npm install -g aws-cdk", "python -m pip install -r requirements.txt", "cdk synth"])) pipeline.add_stage(MyPipelineAppStage(self, "test", env=cdk.Environment(account="111111111111", region="eu-west-1")))

You are running a step build separately

 import aws_cdk as cdk from constructs import Construct from my_pipeline.my_pipeline_lambda_stack import MyLambdaStack class MyPipelineAppStage(cdk.Stage): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) lambdaStack = MyLambdaStack(self, "LambdaStack")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM