// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package testmethod import ( "context" "embed" "fmt" "os" "os/exec" "path" "path/filepath" "runtime" "strings" "testing" "time" ) //go:embed data/* var embedFS embed.FS // Go builds a key provider as a Go binary and returns its path. func Go(t *testing.T) []string { t.Helper() // goMod is embedded like this because the go:embed tag doesn't like having module files in embedded paths. var goMod = []byte(`module testmethod go 1.22`) tempDir := t.TempDir() dir := path.Join(tempDir, "testmethod-go") if err := os.MkdirAll(dir, 0700); err != nil { t.Errorf("Failed to create temporary directory (%v)", err) } if err := os.WriteFile(path.Join(dir, "go.mod"), goMod, 0600); err != nil { t.Errorf("%v", err) } if err := ejectFile("testmethod.go", path.Join(dir, "testmethod.go")); err != nil { t.Errorf("%v", err) } targetBinary := filepath.FromSlash(path.Join(dir, "testmethod")) if runtime.GOOS == "windows" { targetBinary += ".exe" // If we do not use raw backslashes below, the binary won't be found by HCL after parsing. targetBinary = strings.ReplaceAll(targetBinary, "\\", `\\`) } t.Logf("\033[32mCompiling test method binary...\033[0m") cmd := exec.Command("go", "build", "-o", targetBinary) cmd.Dir = dir // TODO move this to a proper test logger once available. cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { t.Skipf("Failed to build test method binary (%v)", err) } return []string{targetBinary} } // Python returns the path to a Python script acting as an encryption method. The function returns all arguments // required to run the Python script, including the Python interpreter. func Python(t *testing.T) []string { t.Helper() tempDir := t.TempDir() dir := path.Join(tempDir, "testmethod-py") if err := os.MkdirAll(dir, 0700); err != nil { t.Errorf("Failed to create temporary directory (%v)", err) } target := path.Join(dir, "testmethod.py") if runtime.GOOS == "windows" { // If we do not use raw backslashes below, the binary won't be found by HCL after parsing. target = strings.ReplaceAll(target, "\\", `\\`) } if err := ejectFile("testmethod.py", target); err != nil { t.Errorf("%v", err) } python := findExecutable(t, []string{"python", "python3"}, []string{"--version"}) return []string{python, target} } func ejectFile(file string, target string) error { contents, err := embedFS.ReadFile(path.Join("data", file)) if err != nil { return fmt.Errorf("failed to read %s file from embedded dataset (%w)", file, err) } if err := os.WriteFile(target, contents, 0600); err != nil { return fmt.Errorf("failed to create %s file at %s (%w)", file, target, err) } return nil } func findExecutable(t *testing.T, options []string, testArguments []string) string { for _, opt := range options { var lastError error func() { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() cmd := exec.CommandContext(ctx, opt, testArguments...) lastError = cmd.Run() }() if lastError == nil { return opt } } t.Skipf("No viable alternative found between %s", strings.Join(options, ", ")) return "" }