From 0a2437cad0b2f3621cebc7d91bf970e81398648d Mon Sep 17 00:00:00 2001 From: oleiade Date: Wed, 4 Sep 2024 14:57:05 +0200 Subject: [PATCH] Add tests asserting the behavior of the --no-archive-upload flag --- cmd/tests/cmd_cloud_run_test.go | 159 ++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/cmd/tests/cmd_cloud_run_test.go b/cmd/tests/cmd_cloud_run_test.go index aad3f7eb4c2..b15d7269305 100644 --- a/cmd/tests/cmd_cloud_run_test.go +++ b/cmd/tests/cmd_cloud_run_test.go @@ -1,9 +1,19 @@ package tests import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "path/filepath" "testing" "go.k6.io/k6/errext/exitcodes" + "go.k6.io/k6/lib/fsext" + + "github.com/stretchr/testify/require" + "go.k6.io/k6/cloudapi" "github.com/stretchr/testify/assert" "go.k6.io/k6/cmd" @@ -58,3 +68,152 @@ func TestCloudRunCommandIncompatibleFlags(t *testing.T) { }) } } + +func TestCloudRunLocalExecution(t *testing.T) { + t.Parallel() + + t.Run("should upload the test archive with a multipart request as a default", func(t *testing.T) { + t.Parallel() + + script := ` +export const options = { + cloud: { + name: 'Hello k6 Cloud!', + projectID: 123456, + }, +}; + +export default function() {};` + + ts := makeTestState(t, script, []string{"--local-execution"}, 0) + + testServerHandlerFunc := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + // When using the local execution mode, the test archive should be uploaded to the cloud + // as a multipart request. + formData, err := parseMultipartRequest(req) + require.NoError(t, err, "expected a correctly formed multipart request") + assert.Contains(t, formData, "name") + assert.Equal(t, "Hello k6 Cloud!", formData["name"]) + assert.Contains(t, formData, "project_id") + assert.Equal(t, "123456", formData["project_id"]) + assert.Contains(t, formData, "file") + assert.NotEmpty(t, formData["file"]) + + resp.WriteHeader(http.StatusOK) + _, err = fmt.Fprint(resp, `{ + "reference_id": "1337", + "config": { + "testRunDetails": "https://some.other.url/foo/tests/org/1337?bar=baz" + } + }`) + assert.NoError(t, err) + }) + + srv := getCloudTestEndChecker(t, 1337, testServerHandlerFunc, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed) + ts.Env["K6_CLOUD_HOST"] = srv.URL + + cmd.ExecuteWithGlobalState(ts.GlobalState) + + stdout := ts.Stdout.String() + t.Log(stdout) + assert.Contains(t, stdout, "execution: local") + assert.Contains(t, stdout, "output: cloud (https://some.other.url/foo/tests/org/1337?bar=baz)") + }) + + t.Run("does not upload the archive when --no-archive-upload is provided", func(t *testing.T) { + t.Parallel() + + script := ` +export const options = { + cloud: { + name: 'Hello k6 Cloud!', + projectID: 123456, + }, +}; + +export default function() {};` + + ts := makeTestState(t, script, []string{"--local-execution", "--no-archive-upload"}, 0) + + testServerHandlerFunc := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + body, err := io.ReadAll(req.Body) + require.NoError(t, err) + + var payload map[string]interface{} + err = json.Unmarshal(body, &payload) + require.NoError(t, err) + + assert.Contains(t, payload, "name") + assert.Equal(t, "Hello k6 Cloud!", payload["name"]) + assert.Contains(t, payload, "project_id") + assert.Equal(t, float64(123456), payload["project_id"]) + assert.NotContains(t, payload, "file") + + resp.WriteHeader(http.StatusOK) + _, err = fmt.Fprint(resp, `{ + "reference_id": "1337", + "config": { + "testRunDetails": "https://some.other.url/foo/tests/org/1337?bar=baz" + } + }`) + assert.NoError(t, err) + }) + + srv := getCloudTestEndChecker(t, 1337, testServerHandlerFunc, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed) + ts.Env["K6_CLOUD_HOST"] = srv.URL + + cmd.ExecuteWithGlobalState(ts.GlobalState) + + stdout := ts.Stdout.String() + t.Log(stdout) + assert.Contains(t, stdout, "execution: local") + assert.Contains(t, stdout, "output: cloud (https://some.other.url/foo/tests/org/1337?bar=baz)") + }) +} + +func makeTestState(tb testing.TB, script string, cliFlags []string, expExitCode exitcodes.ExitCode) *GlobalTestState { + if cliFlags == nil { + cliFlags = []string{"-v", "--log-output=stdout"} + } + + ts := NewGlobalTestState(tb) + require.NoError(tb, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, "test.js"), []byte(script), 0o644)) + ts.CmdArgs = append(append([]string{"k6", "cloud", "run"}, cliFlags...), "test.js") + ts.ExpectedExitCode = int(expExitCode) + + return ts +} + +func parseMultipartRequest(r *http.Request) (map[string]string, error) { + // Parse the multipart form data + reader, err := r.MultipartReader() + if err != nil { + return nil, err + } + + // Initialize a map to store the parsed form data + formData := make(map[string]string) + + // Iterate through the parts + for { + part, nextErr := reader.NextPart() + if nextErr == io.EOF { + break + } + if nextErr != nil { + return nil, err + } + + // Read the part content + buf := new(bytes.Buffer) + _, err = io.Copy(buf, part) + if err != nil { + return nil, err + } + + // Store the part content in the map + formData[part.FormName()] = buf.String() + } + + return formData, nil +}