diff --git a/.github/workflows/test-command.yml b/.github/workflows/test-command.yml index da4c22a71c..412422adaa 100644 --- a/.github/workflows/test-command.yml +++ b/.github/workflows/test-command.yml @@ -263,3 +263,99 @@ jobs: GITHUB_TARGET_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} GITHUB_REF: ${{ github.event.client_payload.pull_request.head.ref }} GITHUB_OWNER: ${{ github.event.client_payload.github.payload.repository.owner.login }} + + # Run the Game E2E test + e2e-general-cli: + runs-on: ubuntu-latest + needs: [ parse, build ] + if: needs.parse.outputs.run-e2e == 'true' + container: cloudposse/test-harness:latest + steps: + # Update GitHub status for pending pipeline run + - name: "Update GitHub Status for pending" + uses: docker://cloudposse/github-status-updater + with: + args: "-action update_state -ref ${{ github.event.client_payload.pull_request.head.sha }} -repo ${{ github.event.client_payload.github.payload.repository.name }}" + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + GITHUB_STATE: pending + GITHUB_CONTEXT: "/test e2e - General CLI" + GITHUB_DESCRIPTION: "started by @${{ github.event.client_payload.github.actor }}" + GITHUB_TARGET_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_REF: ${{ github.event.client_payload.pull_request.head.ref }} + GITHUB_OWNER: ${{ github.event.client_payload.github.payload.repository.owner.login }} + + # Checkout the code from GitHub Pull Request + - name: "Checkout the code" + uses: actions/checkout@v2 + with: + token: ${{ secrets.PAT }} + repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }} + ref: ${{ github.event.client_payload.pull_request.head.ref }} + + # Download the built artifacts + - name: "Download the built artifacts" + uses: actions/download-artifact@v2 + + - name: "Run E2E tests" + shell: bash -x -e -o pipefail {0} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_DEFENSEUNICORNS_COMMERCIAL_SA_ZARF }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_DEFENSEUNICORNS_COMMERCIAL_SA_ZARF }} + AWS_DEFAULT_REGION: us-east-1 + run: | + # cloudposse/test-harness has golang 1.15, we need 1.16. This is the easiest way I know to do it. This should definitely be revisited and cleaned up. + git clone --branch v0.8.0 --depth 1 https://github.com/asdf-vm/asdf.git $HOME/.asdf + source ~/.asdf/asdf.sh + export PATH="$HOME/.asdf/bin:$PATH" + asdf plugin-add golang https://github.com/kennyp/asdf-golang.git + asdf install golang 1.16.7 + asdf global golang 1.16.7 + export GOPATH="$HOME/go" + export PATH="$PATH:$GOPATH/bin" + chmod +x build/zarf + make test-cloud-e2e-general-cli + + # Update GitHub status for failing pipeline run + - name: "Update GitHub Status for failure" + if: ${{ failure() }} + uses: docker://cloudposse/github-status-updater + with: + args: "-action update_state -ref ${{ github.event.client_payload.pull_request.head.sha }} -repo ${{ github.event.client_payload.github.payload.repository.name }}" + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + GITHUB_STATE: failure + GITHUB_CONTEXT: "/test e2e - General CLI" + GITHUB_DESCRIPTION: "run failed" + GITHUB_TARGET_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_REF: ${{ github.event.client_payload.pull_request.head.ref }} + GITHUB_OWNER: ${{ github.event.client_payload.github.payload.repository.owner.login }} + + # Update GitHub status for successful pipeline run + - name: "Update GitHub Status for success" + uses: docker://cloudposse/github-status-updater + with: + args: "-action update_state -ref ${{ github.event.client_payload.pull_request.head.sha }} -repo ${{ github.event.client_payload.github.payload.repository.name }}" + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + GITHUB_STATE: success + GITHUB_CONTEXT: "/test e2e - General CLI" + GITHUB_DESCRIPTION: "run passed" + GITHUB_TARGET_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_REF: ${{ github.event.client_payload.pull_request.head.ref }} + GITHUB_OWNER: ${{ github.event.client_payload.github.payload.repository.owner.login }} + + # Update GitHub status for cancelled pipeline run + - name: "Update GitHub Status for cancelled" + if: ${{ cancelled() }} + uses: docker://cloudposse/github-status-updater + with: + args: "-action update_state -ref ${{ github.event.client_payload.pull_request.head.sha }} -repo ${{ github.event.client_payload.github.payload.repository.name }}" + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + GITHUB_STATE: error + GITHUB_CONTEXT: "/test e2e - General CLI" + GITHUB_DESCRIPTION: "run cancelled" + GITHUB_TARGET_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_REF: ${{ github.event.client_payload.pull_request.head.ref }} + GITHUB_OWNER: ${{ github.event.client_payload.github.payload.repository.owner.login }} diff --git a/Makefile b/Makefile index 334d45cdaa..076619157d 100644 --- a/Makefile +++ b/Makefile @@ -66,5 +66,9 @@ package-example-game: ## Create the Doom example test-cloud-e2e-example-game: ## Runs the Doom game as an E2E test in the cloud. Requires access to an AWS account. Costs money. Make sure you ran the `build-cli`, `init-package`, and `package-example-game` targets first cd test/e2e && go test ./... -run TestE2eExampleGame -v -timeout 1200s +.PHONY: test-cloud-e2e-general-cli +test-cloud-e2e-general-cli: ## Runs tests of the CLI that don't need a cluster + cd test/e2e && go test ./... -run TestGeneralCli -v -timeout 1200s + .PHONY: test-e2e test-e2e: package-example-game test-cloud-e2e-example-game ## DEPRECATED - to be replaced by individual e2e test targets diff --git a/test/e2e/e2e_example_game_test.go b/test/e2e/e2e_example_game_test.go index d517a2055e..364a06b851 100644 --- a/test/e2e/e2e_example_game_test.go +++ b/test/e2e/e2e_example_game_test.go @@ -44,11 +44,11 @@ func TestE2eExampleGame(t *testing.T) { keyPair := teststructure.LoadEc2KeyPair(t, tmpFolder) // Finally run the actual test - test(t, terraformOptions, keyPair,username) + testGameExample(t, terraformOptions, keyPair,username) }) } -func test(t *testing.T, terraformOptions *terraform.Options, keyPair *aws.Ec2Keypair, username string) { +func testGameExample(t *testing.T, terraformOptions *terraform.Options, keyPair *aws.Ec2Keypair, username string) { // Run `terraform output` to get the value of an output variable publicInstanceIP := terraform.Output(t, terraformOptions, "public_instance_ip") @@ -65,18 +65,22 @@ func test(t *testing.T, terraformOptions *terraform.Options, keyPair *aws.Ec2Key require.NoError(t, err, output) // run `zarf init` - output, err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("cd /home/%s/build && sudo ./zarf init --confirm --components management --host localhost", username)) + output, err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("sudo bash -c 'cd /home/%s/build && ./zarf init --confirm --components management --host localhost'", username)) require.NoError(t, err, output) // Wait until the Docker registry is ready - output, err = ssh.CheckSshCommandE(t, publicHost, "curl -sfSL --retry 15 --retry-connrefused --retry-delay 10 -o /dev/null -w \"%{http_code}\" \"https://localhost/v2/\"") + output, err = ssh.CheckSshCommandE(t, publicHost, "timeout 300 bash -c 'while [[ \"$(curl -sfSL --retry 15 --retry-connrefused --retry-delay 5 -o /dev/null -w \"%{http_code}\" \"https://localhost/v2/\")\" != \"200\" ]]; do sleep 1; done' || false") require.NoError(t, err, output) // Deploy the game - output, err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("cd /home/%s/build && sudo ./zarf package deploy zarf-package-appliance-demo-doom.tar.zst --confirm", username)) + output, err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("sudo bash -c 'cd /home/%s/build && ./zarf package deploy zarf-package-appliance-demo-doom.tar.zst --confirm'", username)) require.NoError(t, err, output) // Wait for the game to be live. Right now we're just checking that `curl` returns 0. It can be enhanced by scraping the HTML that gets returned or something. - output, err = ssh.CheckSshCommandE(t, publicHost, "timeout 60 bash -c 'while [[ \"$(curl -sfSL --retry 15 --retry-connrefused --retry-delay 5 -o /dev/null -w \"%{http_code}\" \"https://localhost\")\" != \"200\" ]]; do sleep 1; done' || false") + output, err = ssh.CheckSshCommandE(t, publicHost, "timeout 300 bash -c 'while [[ \"$(curl -sfSL --retry 15 --retry-connrefused --retry-delay 5 -o /dev/null -w \"%{http_code}\" \"https://localhost\")\" != \"200\" ]]; do sleep 1; done' || false") + require.NoError(t, err, output) + + // Run `zarf destroy` to make sure that works correctly + output, err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("sudo bash -c 'cd /home/%s/build && ./zarf destroy --confirm'", username)) require.NoError(t, err, output) } diff --git a/test/e2e/e2e_general_cli_test.go b/test/e2e/e2e_general_cli_test.go new file mode 100644 index 0000000000..4628a19b7f --- /dev/null +++ b/test/e2e/e2e_general_cli_test.go @@ -0,0 +1,75 @@ +package test + +import ( + "fmt" + "github.com/gruntwork-io/terratest/modules/aws" + "github.com/gruntwork-io/terratest/modules/ssh" + "github.com/gruntwork-io/terratest/modules/terraform" + teststructure "github.com/gruntwork-io/terratest/modules/test-structure" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" +) + +func TestGeneralCli(t *testing.T) { + t.Parallel() + + // Our SSH username, will change based on which AMI we use + username := "ubuntu" + + // Copy the terraform folder to a temp directory so we can run multiple tests in parallel + tmpFolder := teststructure.CopyTerraformFolderToTemp(t, "..", "tf/public-ec2-instance") + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer teststructure.RunTestStage(t, "TEARDOWN", func() { + teardown(t, tmpFolder) + }) + + // Deploy the terraform infra + teststructure.RunTestStage(t, "SETUP", func() { + setup(t, tmpFolder) + }) + + // Upload the Zarf artifacts + teststructure.RunTestStage(t, "UPLOAD", func() { + terraformOptions := teststructure.LoadTerraformOptions(t, tmpFolder) + keyPair := teststructure.LoadEc2KeyPair(t, tmpFolder) + + syncFileToRemoteServer(t, terraformOptions, keyPair, username, "../../build/zarf", fmt.Sprintf("/home/%s/build/zarf", username), "0700") + }) + + teststructure.RunTestStage(t, "TEST", func() { + terraformOptions := teststructure.LoadTerraformOptions(t, tmpFolder) + keyPair := teststructure.LoadEc2KeyPair(t, tmpFolder) + + // Finally run the actual test + testGeneralCliStuff(t, terraformOptions, keyPair,username) + }) +} + +func testGeneralCliStuff(t *testing.T, terraformOptions *terraform.Options, keyPair *aws.Ec2Keypair, username string) { + // Run `terraform output` to get the value of an output variable + publicInstanceIP := terraform.Output(t, terraformOptions, "public_instance_ip") + + // We're going to try to SSH to the instance IP, using the Key Pair we created earlier, and the user "ubuntu", + // as we know the Instance is running an Ubuntu AMI that has such a user + publicHost := ssh.Host{ + Hostname: publicInstanceIP, + SshKeyPair: keyPair.KeyPair, + SshUserName: username, + } + + // Test `zarf prepare sha256sum` for a local asset + expectedShasum := "61b50898f982d015ed87093ba822de0fe011cec6dd67db39f99d8c56391a6109\n" + output,err := ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("cd /home/%s/build && echo 'random test data 🦄' > shasum-test-file", username)) + require.NoError(t, err, output) + output,err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("cd /home/%s/build && ./zarf prepare sha256sum shasum-test-file 2> /dev/null", username)) + require.NoError(t, err, output) + assert.Equal(t, expectedShasum, output, "The expected SHASUM should equal the actual SHASUM") + + // Test `zarf prepare sha256sum` for a remote asset + expectedShasum = "c3cdea0573ba5a058ec090b5d2683bf398e8b1614c37ec81136ed03b78167617\n" + output,err = ssh.CheckSshCommandE(t, publicHost, fmt.Sprintf("cd /home/%s/build && ./zarf prepare sha256sum https://zarf-public.s3-us-gov-west-1.amazonaws.com/pipelines/zarf-prepare-shasum-remote-test-file.txt 2> /dev/null", username)) + require.NoError(t, err, output) + assert.Equal(t, expectedShasum, output, "The expected SHASUM should equal the actual SHASUM") +}