diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index 870d4fc4..7aed74b6 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -48,6 +48,13 @@ jobs: - bin runs-on: ubuntu-latest timeout-minutes: 30 # instead of 360 by default + strategy: + matrix: + include: # Controls language used in all extension tests. Managed by test/e2e/main_test.go + - extension-language: rust + - extension-language: tinygo + env: + E2E_EXTENSION_LANGUAGE: ${{ matrix.extension-language }} steps: - name: "Checkout" uses: actions/checkout@v2 @@ -72,6 +79,13 @@ jobs: - bin runs-on: macos-latest timeout-minutes: 90 # instead of 360 by default + strategy: + matrix: + include: # Controls language used in all extension tests. Managed by test/e2e/main_test.go + - extension-language: rust + - extension-language: tinygo + env: + E2E_EXTENSION_LANGUAGE: ${{ matrix.extension-language }} steps: - name: "Checkout" uses: actions/checkout@v2 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 592029b8..ecb06530 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -78,6 +78,13 @@ jobs: - builders runs-on: ubuntu-latest timeout-minutes: 30 # instead of 360 by default + strategy: + matrix: + include: # Controls language used in all extension tests. Managed by test/e2e/main_test.go + - extension-language: rust + - extension-language: tinygo + env: + E2E_EXTENSION_LANGUAGE: ${{ matrix.extension-language }} steps: - name: "Checkout" uses: actions/checkout@v2 @@ -95,7 +102,7 @@ jobs: name: bin path: build/bin - - name: "Download `getenvoy` binary from GithHub release assets" + - name: "Download `getenvoy` binary from GitHub release assets" env: INPUT_FILE: getenvoy_${{ env.RELEASE_VERSION }}_Linux_x86_64.tar.gz INPUT_VERSION: tags/${{ env.RELEASE_TAG }} @@ -118,6 +125,13 @@ jobs: - builders runs-on: macos-latest timeout-minutes: 90 # instead of 360 by default + strategy: + matrix: + include: # Controls language used in all extension tests. Managed by test/e2e/main_test.go + - extension-language: rust + - extension-language: tinygo + env: + E2E_EXTENSION_LANGUAGE: ${{ matrix.extension-language }} steps: - name: "Checkout" uses: actions/checkout@v2 @@ -135,7 +149,7 @@ jobs: name: bin path: build/bin - - name: "Download `getenvoy` binary from GithHub release assets" + - name: "Download `getenvoy` binary from GitHub release assets" env: INPUT_FILE: getenvoy_${{ env.RELEASE_VERSION }}_Darwin_x86_64.tar.gz INPUT_VERSION: tags/${{ env.RELEASE_TAG }} diff --git a/DEVELOPER.md b/DEVELOPER.md index 72509330..9ac2cf65 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -44,7 +44,13 @@ and follow the wizard. ### How to run e2e Tests -Run: -```shell -make e2e -``` +End-to-end (e2e) tests rely on a `getenvoy` binary that defaults to what was built by `make bin`. + +In simplest case, execute `make e2e` to run all tests configured. You can also set the below ENV variables to effect the +runtime. These are defined in [main_test.go](test/e2e/main_test.go). + +Environment Variable | Description +--------------------------------- | ------------------------------------------------------------------------------------ +`E2E_GETENVOY_BINARY` | Overrides `getenvoy` binary. Defaults to `$PWD/build/bin/$GOOS/$GOARCH/getenvoy` +`E2E_TOOLCHAIN_CONTAINER_OPTIONS` | Overrides `--toolchain-container-options` in Docker commands. Defaults to "". +`E2E_EXTENSION_LANGUAGE` | Overrides `--language` in `getenvoy extension` commands. Defaults to "tinygo". diff --git a/ci/e2e/linux/run_tests.sh b/ci/e2e/linux/run_tests.sh index 2f56da58..7a8452ff 100755 --- a/ci/e2e/linux/run_tests.sh +++ b/ci/e2e/linux/run_tests.sh @@ -26,7 +26,7 @@ mkdir -p "${E2E_CACHE_DIR}" sudo chown -R $(id -u):$(id -g) "${E2E_CACHE_DIR}" # to speed up `getenvoy extension build|test`, re-use a single cache across all extensions created by e2e tests -export E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS="${E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS} -v ${E2E_CACHE_DIR}:/tmp/cache/getenvoy -e CARGO_HOME=/tmp/cache/getenvoy/extension/rust-builder/cargo" +export E2E_TOOLCHAIN_CONTAINER_OPTIONS="${E2E_TOOLCHAIN_CONTAINER_OPTIONS} -v ${E2E_CACHE_DIR}:/tmp/cache/getenvoy -e CARGO_HOME=/tmp/cache/getenvoy/extension/rust-builder/cargo" # run the normal make script. make e2e diff --git a/ci/e2e/macos/run_tests.sh b/ci/e2e/macos/run_tests.sh index b55d96aa..57609bf1 100755 --- a/ci/e2e/macos/run_tests.sh +++ b/ci/e2e/macos/run_tests.sh @@ -25,10 +25,10 @@ mkdir -p "${E2E_CACHE_DIR}" # TODO: support multiple language # to speed up `getenvoy extension build|test`, re-use a single cache across all extensions created by e2e tests -export E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS="${E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS} -v ${E2E_CACHE_DIR}:/tmp/cache/getenvoy -e CARGO_HOME=/tmp/cache/getenvoy/extension/rust-builder/cargo" +export E2E_TOOLCHAIN_CONTAINER_OPTIONS="${E2E_TOOLCHAIN_CONTAINER_OPTIONS} -v ${E2E_CACHE_DIR}:/tmp/cache/getenvoy -e CARGO_HOME=/tmp/cache/getenvoy/extension/rust-builder/cargo" # set HOME directory (TODO: why? why not GETENVOY_HOME? why not also in linux?) -export E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS="${E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS} -e HOME=/tmp/getenvoy" +export E2E_TOOLCHAIN_CONTAINER_OPTIONS="${E2E_TOOLCHAIN_CONTAINER_OPTIONS} -e HOME=/tmp/getenvoy" # run the normal make script. make e2e diff --git a/test/e2e/getenvoy_extension_build_test.go b/test/e2e/getenvoy_extension_build_test.go index 1d64850e..71b8227d 100644 --- a/test/e2e/getenvoy_extension_build_test.go +++ b/test/e2e/getenvoy_extension_build_test.go @@ -20,20 +20,20 @@ import ( "github.com/stretchr/testify/require" - e2e "github.com/tetratelabs/getenvoy/test/e2e/util" + "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/extension" ) -// TestGetEnvoyExtensionBuild runs the equivalent of "getenvoy extension build" for a matrix of extension.Categories and -// extension.Languages. "getenvoy extension init" is a prerequisite, so run first. +// TestGetEnvoyExtensionBuild runs the equivalent of "getenvoy extension build" for a matrix of extension.Categories. +// "getenvoy extension init" is a prerequisite, so run first. // // "getenvoy extension build" uses Docker. See TestMain for general notes on about the test runtime. func TestGetEnvoyExtensionBuild(t *testing.T) { const extensionName = "getenvoy_extension_build" - for _, test := range e2e.GetCategoryLanguageCombinations() { - test := test // pin! see https://github.com/kyoh86/scopelint for why + for _, category := range extension.Categories { + category := category // pin! see https://github.com/kyoh86/scopelint for why - t.Run(test.String(), func(t *testing.T) { + t.Run(category.String(), func(t *testing.T) { workDir, removeWorkDir := requireNewTempDir(t) defer removeWorkDir() @@ -41,16 +41,16 @@ func TestGetEnvoyExtensionBuild(t *testing.T) { defer revertChDir() // test requires "get envoy extension init" to have succeeded - requireExtensionInit(t, workDir, test.Category, test.Language, extensionName) + requireExtensionInit(t, workDir, category, extensionName) defer requireExtensionClean(t, workDir) // "getenvoy extension build" only returns stdout because `docker run -t` redirects stderr to stdout. // We don't verify stdout because it is low signal vs looking at files created. - cmd := GetEnvoy("extension build").Args(getBuiltinContainerOptions()...) + cmd := getEnvoy("extension build").Args(getToolchainContainerOptions()...) _ = requireExecNoStderr(t, cmd) // Verify the extension built - extensionWasmFile := filepath.Join(workDir, extensionWasmPath(test.Language)) + extensionWasmFile := filepath.Join(workDir, extensionWasmPath()) require.FileExists(t, extensionWasmFile, `extension wasm file %s missing after running [%v]`, extensionWasmFile, cmd) }) } diff --git a/test/e2e/getenvoy_extension_examples_test.go b/test/e2e/getenvoy_extension_examples_test.go index 148aa701..08358de7 100644 --- a/test/e2e/getenvoy_extension_examples_test.go +++ b/test/e2e/getenvoy_extension_examples_test.go @@ -22,27 +22,20 @@ import ( "github.com/stretchr/testify/require" "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/extension" - e2e "github.com/tetratelabs/getenvoy/test/e2e/util" ) // TestGetEnvoyExtensionExampleAdd runs the equivalent of "getenvoy extension example XXX" commands for a matrix of -// extension.Categories and extension.Languages. +// extension.Categories. // // "getenvoy extension example" does not use Docker. See TestMain for general notes on about the test runtime. func TestGetEnvoyExtensionExample(t *testing.T) { const extensionName = "getenvoy_extension_example" - for _, test := range e2e.GetCategoryLanguageCombinations() { - test := test // pin! see https://github.com/kyoh86/scopelint for why + for _, category := range extension.Categories { + category := category // pin! see https://github.com/kyoh86/scopelint for why - t.Run(test.String(), func(t *testing.T) { - var extensionConfigFileName string - switch test.Language { - case extension.LanguageTinyGo: - extensionConfigFileName = "extension.txt" - default: - extensionConfigFileName = "extension.json" - } + t.Run(category.String(), func(t *testing.T) { + extensionConfigFileName := extensionConfigFileName() workDir, removeWorkDir := requireNewTempDir(t) defer removeWorkDir() @@ -51,11 +44,11 @@ func TestGetEnvoyExtensionExample(t *testing.T) { defer revertChDir() // "getenvoy extension example XXX" commands require an extension init to succeed - requireExtensionInit(t, workDir, test.Category, test.Language, extensionName) + requireExtensionInit(t, workDir, category, extensionName) defer requireExtensionClean(t, workDir) // "getenvoy extension examples list" should start empty - cmd := GetEnvoy("extension examples list") + cmd := getEnvoy("extension examples list") stderr := requireExecNoStdout(t, cmd) require.Equal(t, `Extension has no example setups. @@ -63,7 +56,7 @@ Use "getenvoy extension examples add --help" for more information on how to add `, stderr, `invalid stderr running [%v]`, cmd) // "getenvoy extension examples add" should result in stderr describing files created. - cmd = GetEnvoy("extension examples add") + cmd = getEnvoy("extension examples add") stderr = requireExecNoStdout(t, cmd) exampleFiles := []string{ @@ -90,12 +83,12 @@ Use "getenvoy extension examples add --help" for more information on how to add } // "getenvoy extension examples list" should now include an example - cmd = GetEnvoy("extension examples list") + cmd = getEnvoy("extension examples list") stdout := requireExecNoStderr(t, cmd) require.Equal(t, "EXAMPLE\ndefault\n", stdout, `invalid stdout running [%v]`, cmd) // "getenvoy extension examples add" should result in stderr describing files created. - cmd = GetEnvoy("extension examples remove --name default") + cmd = getEnvoy("extension examples remove --name default") stderr = requireExecNoStdout(t, cmd) // Check stderr mentions the files removed diff --git a/test/e2e/getenvoy_extension_init_test.go b/test/e2e/getenvoy_extension_init_test.go index 28479580..500a3cb8 100644 --- a/test/e2e/getenvoy_extension_init_test.go +++ b/test/e2e/getenvoy_extension_init_test.go @@ -24,11 +24,9 @@ import ( workspaces "github.com/tetratelabs/getenvoy/pkg/extension/workspace" "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/extension" toolchains "github.com/tetratelabs/getenvoy/pkg/extension/workspace/toolchain" - e2e "github.com/tetratelabs/getenvoy/test/e2e/util" ) -// TestGetEnvoyExtensionInit runs the equivalent of "getenvoy extension init" for a matrix of extension.Categories and -// extension.Languages. +// TestGetEnvoyExtensionInit runs the equivalent of "getenvoy extension init" for a matrix of extension.Categories. // // "getenvoy extension init" does not use Docker. See TestMain for general notes on about the test runtime. func TestGetEnvoyExtensionInit(t *testing.T) { @@ -37,15 +35,14 @@ func TestGetEnvoyExtensionInit(t *testing.T) { type testTuple struct { testName string extension.Category - extension.Language currentDirectory bool } tests := make([]testTuple, 0) - for _, c := range e2e.GetCategoryLanguageCombinations() { + for _, c := range extension.Categories { tests = append(tests, - testTuple{c.String() + "-currentDirectory", c.Category, c.Language, true}, - testTuple{c.String() + "-newDirectory", c.Category, c.Language, false}, + testTuple{c.String() + "-currentDirectory", c, true}, + testTuple{c.String() + "-newDirectory", c, false}, ) } @@ -64,10 +61,10 @@ func TestGetEnvoyExtensionInit(t *testing.T) { } // "getenvoy extension init" should result in stderr describing files created. - cmd := GetEnvoy("extension init"). + cmd := getEnvoy("extension init"). Arg(workDir). Arg("--category").Arg(test.Category.String()). - Arg("--language").Arg(test.Language.String()). + Arg("--language").Arg(extensionLanguage.String()). Arg("--name").Arg(extensionName) stderr := requireExecNoStdout(t, cmd) @@ -91,7 +88,7 @@ func TestGetEnvoyExtensionInit(t *testing.T) { require.NotNil(t, workspace, `nil workspace running [%v]`, cmd) require.Equal(t, extensionName, workspace.GetExtensionDescriptor().Name, `wrong extension name running [%v]`, cmd) require.Equal(t, test.Category, workspace.GetExtensionDescriptor().Category, `wrong extension category running [%v]`, cmd) - require.Equal(t, test.Language, workspace.GetExtensionDescriptor().Language, `wrong extension language running [%v]`, cmd) + require.Equal(t, extensionLanguage, workspace.GetExtensionDescriptor().Language, `wrong extension extensionLanguage running [%v]`, cmd) // Check the default toolchain is loadable toolchain, err := toolchains.LoadToolchain(toolchains.Default, workspace) diff --git a/test/e2e/getenvoy_extension_push_test.go b/test/e2e/getenvoy_extension_push_test.go index c609afb7..d5361ea3 100644 --- a/test/e2e/getenvoy_extension_push_test.go +++ b/test/e2e/getenvoy_extension_push_test.go @@ -41,22 +41,14 @@ func TestGetEnvoyExtensionPush(t *testing.T) { // When unspecified, we default the tag to Docker's default "latest". Note: recent tools enforce qualifying this! const defaultTag = "latest" - type testTuple struct { - name string - extension.Category - extension.Language - } - - // Push is not language-specific, so we don't need to test a large matrix, and doing so would slow down e2e runtime. + // Push is not category-specific, so we don't need to test a large matrix, and doing so would slow down e2e runtime. // Instead, we choose something that executes "getenvoy extension build" quickly. - tests := []testTuple{ - {"tinygo HTTP filter", extension.EnvoyHTTPFilter, extension.LanguageTinyGo}, - } + categories := []extension.Category{extension.EnvoyHTTPFilter} - for _, test := range tests { - test := test // pin! see https://github.com/kyoh86/scopelint for why + for _, category := range categories { + category := category // pin! see https://github.com/kyoh86/scopelint for why - t.Run(test.name, func(t *testing.T) { + t.Run(category.String(), func(t *testing.T) { workDir, removeWorkDir := requireNewTempDir(t) defer removeWorkDir() @@ -64,12 +56,12 @@ func TestGetEnvoyExtensionPush(t *testing.T) { defer revertChDir() // push requires "get envoy extension init" and "get envoy extension build" to have succeeded - requireExtensionInit(t, workDir, test.Category, test.Language, extensionName) + requireExtensionInit(t, workDir, category, extensionName) defer requireExtensionClean(t, workDir) - wasmBytes := requireExtensionBuild(t, test.Language, workDir) + wasmBytes := requireExtensionBuild(t, workDir) // After pushing, stderr should include the registry URL and the image tag. - cmd := GetEnvoy("extension push").Arg(localRegistryWasmImageRef) + cmd := getEnvoy("extension push").Arg(localRegistryWasmImageRef) stderr := requireExecNoStdout(t, cmd) // Assemble a fully-qualified image ref as we'll pull this later diff --git a/test/e2e/getenvoy_extension_run_test.go b/test/e2e/getenvoy_extension_run_test.go index bda0b744..85cbae64 100644 --- a/test/e2e/getenvoy_extension_run_test.go +++ b/test/e2e/getenvoy_extension_run_test.go @@ -27,6 +27,7 @@ import ( "github.com/tetratelabs/log" "github.com/tetratelabs/getenvoy/pkg/common" + "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/extension" e2e "github.com/tetratelabs/getenvoy/test/e2e/util" utilenvoy "github.com/tetratelabs/getenvoy/test/e2e/util/envoy" ) @@ -34,18 +35,18 @@ import ( const extensionName = "getenvoy_extension_run" const terminateTimeout = 2 * time.Minute -// TestGetEnvoyExtensionRun runs the equivalent of "getenvoy extension run" for a matrix of extension.Categories and -// extension.Languages. "getenvoy extension init" is a prerequisite, so run first. +// TestGetEnvoyExtensionRun runs the equivalent of "getenvoy extension run" for a matrix of extension.Categories. +// "getenvoy extension init" is a prerequisite, so run first. // // "getenvoy extension run" uses Docker. See TestMain for general notes on about the test runtime. func TestGetEnvoyExtensionRun(t *testing.T) { debugDir, revertOriginalDebugDir := backupDebugDir(t) defer revertOriginalDebugDir() - for _, test := range e2e.GetCategoryLanguageCombinations() { - test := test // pin! see https://github.com/kyoh86/scopelint for why + for _, category := range extension.Categories { + category := category // pin! see https://github.com/kyoh86/scopelint for why - t.Run(test.String(), func(t *testing.T) { + t.Run(category.String(), func(t *testing.T) { workDir, removeWorkDir := requireNewTempDir(t) defer removeWorkDir() @@ -53,11 +54,11 @@ func TestGetEnvoyExtensionRun(t *testing.T) { defer revertChDir() // run requires "get envoy extension init" to have succeeded - requireExtensionInit(t, workDir, test.Category, test.Language, extensionName) + requireExtensionInit(t, workDir, category, extensionName) defer requireExtensionClean(t, workDir) // "getenvoy extension run" only returns stdout because `docker run -t` redirects stderr to stdout. - cmd := GetEnvoy("extension run --envoy-options '-l trace'").Args(getBuiltinContainerOptions()...) + cmd := getEnvoy("extension run --envoy-options '-l trace'").Args(getToolchainContainerOptions()...) _, stderr, terminate := cmd.Start(t, terminateTimeout) // The underlying call is conditional to ensure errors that raise before we stop the server, stop it. @@ -136,7 +137,7 @@ func TestGetEnvoyExtensionRun(t *testing.T) { // Typically, this will run in the default ~/.getenvoy directory, as a means to avoid re-downloads of files such as // .getenvoy/builds/standard/1.17.0/darwin/bin/envoy (~100MB) // -// While CI usually overrides the `HOME` variable with E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS, a developer may be +// While CI usually overrides the `HOME` variable with E2E_TOOLCHAIN_CONTAINER_OPTIONS, a developer may be // running this on their laptop. To avoid clobbering their old debug data, backup the func backupDebugDir(t *testing.T) (string, func()) { debugDir := filepath.Join(common.HomeDir, "debug") diff --git a/test/e2e/getenvoy_extension_test_test.go b/test/e2e/getenvoy_extension_test_test.go index 13f53e15..ef873520 100644 --- a/test/e2e/getenvoy_extension_test_test.go +++ b/test/e2e/getenvoy_extension_test_test.go @@ -21,20 +21,19 @@ import ( "github.com/stretchr/testify/require" "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/extension" - e2e "github.com/tetratelabs/getenvoy/test/e2e/util" ) -// TestGetEnvoyExtensionTest runs the equivalent of "getenvoy extension test" for a matrix of extension.Categories and -// extension.Languages. "getenvoy extension init" is a prerequisite, so run first. +// TestGetEnvoyExtensionTest runs the equivalent of "getenvoy extension test" for a matrix of extension.Categories. +// "getenvoy extension init" is a prerequisite, so run first. // // "getenvoy extension test" uses Docker. See TestMain for general notes on about the test runtime. func TestGetEnvoyExtensionTest(t *testing.T) { const extensionName = "getenvoy_extension_test" - for _, test := range e2e.GetCategoryLanguageCombinations() { - test := test // pin! see https://github.com/kyoh86/scopelint for why + for _, category := range extension.Categories { + category := category // pin! see https://github.com/kyoh86/scopelint for why - t.Run(test.String(), func(t *testing.T) { + t.Run(category.String(), func(t *testing.T) { workDir, removeWorkDir := requireNewTempDir(t) defer removeWorkDir() @@ -42,15 +41,16 @@ func TestGetEnvoyExtensionTest(t *testing.T) { defer revertChDir() // test requires "get envoy extension init" to have succeeded - requireExtensionInit(t, workDir, test.Category, test.Language, extensionName) + requireExtensionInit(t, workDir, category, extensionName) defer requireExtensionClean(t, workDir) - cmd := GetEnvoy("extension test").Args(getBuiltinContainerOptions()...) + cmd := getEnvoy("extension test").Args(getToolchainContainerOptions()...) // "getenvoy extension test" only returns stdout because `docker run -t` redirects stderr to stdout. stdout := requireExecNoStderr(t, cmd) - // Verify the tests ran - switch test.Language { + // Verify the tests ran. This depends on language-specific details, such as the build tool. For example, + // Rust uses "cargo". + switch extensionLanguage { case extension.LanguageRust: // `cargo` colorizes output. After stripping ANSI codes, ensure the output is successful. stdout = stripAnsiEscapeRegexp.ReplaceAllString(stdout, "") diff --git a/test/e2e/getenvoy_test.go b/test/e2e/getenvoy_test.go index 4e5bbbf3..5dc1a383 100644 --- a/test/e2e/getenvoy_test.go +++ b/test/e2e/getenvoy_test.go @@ -21,7 +21,7 @@ import ( ) func TestGetEnvoyVersion(t *testing.T) { - stdout, stderr, err := GetEnvoy("--version").Exec() + stdout, stderr, err := getEnvoy("--version").Exec() require.Regexp(t, `^getenvoy version ([^\s]+)\n$`, stdout) require.Equal(t, ``, stderr) @@ -29,7 +29,7 @@ func TestGetEnvoyVersion(t *testing.T) { } func TestGetEnvoyString(t *testing.T) { - g := GetEnvoy("--version") + g := getEnvoy("--version") require.Regexp(t, `.*getenvoy --version$`, g.String()) } diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 956e0f9d..a941b667 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -31,8 +31,10 @@ import ( ) var ( - // GetEnvoy is a convenient alias. - GetEnvoy = e2e.GetEnvoy + // getEnvoy is the absolute path to the "getenvoy" binary used in all tests. + getEnvoy = e2e.GetEnvoy + // extensionLanguage is the "--language" parameter of "getenvoy init" used in all tests. + extensionLanguage extension.Language // stripAnsiEscapeRegexp is a regular expression to clean ANSI Control sequences // feat https://stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python#33925425 @@ -41,29 +43,50 @@ var ( //nolint:golint const ( - E2E_GETENVOY_BINARY = "E2E_GETENVOY_BINARY" - E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS = "E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS" + E2E_EXTENSION_LANGUAGE = "E2E_EXTENSION_LANGUAGE" + E2E_GETENVOY_BINARY = "E2E_GETENVOY_BINARY" + E2E_TOOLCHAIN_CONTAINER_OPTIONS = "E2E_TOOLCHAIN_CONTAINER_OPTIONS" ) -// TestMain ensures util.GetEnvoyBinaryPath is set as all end-to-end (e2e) tests will invoke it. +// TestMain ensures the "getenvoy" binary and "--language" parameter to "get envoy init" are valid, as these are +// constant for all tests that us them. // // Note: "getenvoy extension build" and commands that imply it, can be extremely slow due to implicit responsibilities // such as downloading modules or compilation. Commands like this use Docker, so changes to the Dockerfile or contents // like "commands.sh" will effect performance. // -// Note: Pay close attention to values of util.E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS as these can change assumptions. +// Note: Pay close attention to values of util.E2E_TOOLCHAIN_CONTAINER_OPTIONS as these can change assumptions. // CI may override this to set HOME or CARGO_HOME (rust) used by "getenvoy" and effect its execution. func TestMain(m *testing.M) { // As this is an e2e test, we execute all tests with a binary compiled earlier. path, err := getEnvoyBinary() if err != nil { - fmt.Fprintf(os.Stderr, `failed to start e2e tests: %v`, err) + fmt.Fprintf(os.Stderr, `failed to start e2e tests due to an invalid "getenvoy" binary: %v`, err) os.Exit(1) } e2e.GetEnvoyBinaryPath = path + extensionLanguage, err = getExtensionLanguage() + if err != nil { + fmt.Fprintf(os.Stderr, `failed to start e2e tests due to an invalid extension language": %v`, err) + os.Exit(1) + } os.Exit(m.Run()) } +// getExtensionLanguage reads E2E_EXTENSION_LANGUAGE or defaults to extension.LanguageTinyGo because it builds an order +// of magnitude faster extension.LanguageRust. +func getExtensionLanguage() (extension.Language, error) { + fromEnv := os.Getenv(E2E_EXTENSION_LANGUAGE) + if fromEnv == "" { + return extension.LanguageTinyGo, nil // default + } + parsed, err := extension.ParseLanguage(fromEnv) + if err != nil { + return "", fmt.Errorf("%s is not a valid extension language. Correct environment variable %s", fromEnv, E2E_GETENVOY_BINARY) + } + return parsed, nil +} + // getEnvoyBinary reads E2E_GETENVOY_BINARY or defaults to "$PWD/build/bin/$GOOS/$GOARCH/getenvoy" // An error is returned if the value isn't an executable file. func getEnvoyBinary() (string, error) { @@ -73,7 +96,7 @@ func getEnvoyBinary() (string, error) { relativePath := filepath.Join("..", "..", "build", "bin", runtime.GOOS, runtime.GOARCH, "getenvoy") abs, err := filepath.Abs(relativePath) if err != nil { - return "", fmt.Errorf("resolve path to %s. Correct environment variable %s", path, E2E_GETENVOY_BINARY) + return "", fmt.Errorf("%s didn't resolve to a valid path. Correct environment variable %s", path, E2E_GETENVOY_BINARY) } path = abs } @@ -92,8 +115,8 @@ func getEnvoyBinary() (string, error) { return path, nil } -func getBuiltinContainerOptions() []string { - value := os.Getenv(E2E_BUILTIN_TOOLCHAIN_CONTAINER_OPTIONS) +func getToolchainContainerOptions() []string { + value := os.Getenv(E2E_TOOLCHAIN_CONTAINER_OPTIONS) if value == "" { return nil } @@ -171,35 +194,24 @@ func requireExec(t *testing.T, cmd Command) (string, string) { } // requireExtensionInit is useful for tests that depend on "getenvoy extension init" as a prerequisite. -func requireExtensionInit(t *testing.T, workDir string, category extension.Category, language extension.Language, name string) { - cmd := GetEnvoy("extension init"). +func requireExtensionInit(t *testing.T, workDir string, category extension.Category, name string) { + cmd := getEnvoy("extension init"). Arg(workDir). Arg("--category").Arg(string(category)). - Arg("--language").Arg(string(language)). + Arg("--language").Arg(string(extensionLanguage)). Arg("--name").Arg(name) // stderr returned is not tested because doing so is redundant to TestGetEnvoyExtensionInit. _ = requireExecNoStdout(t, cmd) } -// extensionWasmPath returns the language-specific location of the extension.wasm. -func extensionWasmPath(language extension.Language) string { - switch language { - case extension.LanguageRust: - return filepath.Join("target", "getenvoy", "extension.wasm") - case extension.LanguageTinyGo: - return filepath.Join("build", "extension.wasm") - } - panic("unsupported language " + language) -} - // requireExtensionInit is useful for tests that depend on "getenvoy extension build" as a prerequisite. // The result of calling this is the bytes representing the built wasm -func requireExtensionBuild(t *testing.T, language extension.Language, workDir string) []byte { - cmd := GetEnvoy("extension build").Args(getBuiltinContainerOptions()...) +func requireExtensionBuild(t *testing.T, workDir string) []byte { + cmd := getEnvoy("extension build").Args(getToolchainContainerOptions()...) // stderr returned is not tested because doing so is redundant to TestGetEnvoyExtensionInit. _ = requireExecNoStderr(t, cmd) - extensionWasmFile := filepath.Join(workDir, extensionWasmPath(language)) + extensionWasmFile := filepath.Join(workDir, extensionWasmPath()) require.FileExists(t, extensionWasmFile, `extension wasm file %s missing after running [%v]`, extensionWasmFile, cmd) wasmBytes, err := ioutil.ReadFile(extensionWasmFile) @@ -214,6 +226,27 @@ func requireExtensionClean(t *testing.T, workDir string) { err := os.Chdir(workDir) require.NoError(t, err, `error changing to directory: %v`, workDir) - cmd := GetEnvoy("extension clean") + cmd := getEnvoy("extension clean") _, _ = requireExec(t, cmd) } + +// extensionWasmPath returns the language-specific location of the extension.wasm. +func extensionWasmPath() string { + switch extensionLanguage { + case extension.LanguageRust: + return filepath.Join("target", "getenvoy", "extension.wasm") + case extension.LanguageTinyGo: + return filepath.Join("build", "extension.wasm") + } + panic("unsupported extension language " + extensionLanguage) +} + +// extensionWasmPath returns the language-specific basename of the extension config file. +func extensionConfigFileName() string { + switch extensionLanguage { + case extension.LanguageTinyGo: + return "extension.txt" + default: + return "extension.json" + } +} diff --git a/test/e2e/util/data.go b/test/e2e/util/data.go deleted file mode 100644 index f0cda09e..00000000 --- a/test/e2e/util/data.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2020 Tetrate -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package util - -import ( - "fmt" - - "github.com/tetratelabs/getenvoy/pkg/extension/workspace/config/extension" -) - -// CategoryLanguageTuple represents a combination of extension category and -// programming language. -type CategoryLanguageTuple struct { - extension.Category - extension.Language -} - -func (t CategoryLanguageTuple) String() string { - return fmt.Sprintf("category=%s, language=%s", t.Category, t.Language) -} - -// GetCategoryLanguageCombinations returns all combinations of a supported -// extension category with a supported programming language. -func GetCategoryLanguageCombinations() []CategoryLanguageTuple { - tuples := make([]CategoryLanguageTuple, 0) - for _, category := range extension.Categories { - for _, language := range extension.Languages { - tuples = append(tuples, CategoryLanguageTuple{category, language}) - } - } - return tuples -}