diff --git a/tests/bridge_test.go b/tests/bridge_test.go index 6750e7ae..87e9a877 100644 --- a/tests/bridge_test.go +++ b/tests/bridge_test.go @@ -24,6 +24,7 @@ import ( "fmt" "net" "os" + "path/filepath" "strconv" "time" @@ -177,6 +178,18 @@ func newTestBugReport(br *bridge.Bridge) *testBugReport { } func (r *testBugReport) report() error { + if r.request.IncludeLogs == true { + data := []byte("Test log file.\n") + logName := "20231031_122940334_bri_000_v3.6.1+qa_br-178.log" + logPath, err := r.bridge.GetLogsPath() + if err != nil { + return err + } + + if err := os.WriteFile(filepath.Join(logPath, logName), data, 0o600); err != nil { + return err + } + } return r.bridge.ReportBug(context.Background(), &r.request) } @@ -202,7 +215,7 @@ func (s *scenario) theUserReportsABugWithSingleHeaderChange(key, value string) e bugReport.request.Email = value case "Client": bugReport.request.EmailClient = value - case "Attachment": + case "IncludeLogs": att, err := strconv.ParseBool(value) if err != nil { return fmt.Errorf("failed to parse bug report attachment preferences: %w", err) diff --git a/tests/environment_test.go b/tests/environment_test.go index 38d2234e..75267909 100644 --- a/tests/environment_test.go +++ b/tests/environment_test.go @@ -91,44 +91,71 @@ func (s *scenario) theHeaderInTheRequestToHasSetTo(method, path, key, value stri } func (s *scenario) theHeaderInTheMultipartRequestToHasSetTo(method, path, key, value string) error { + req, err := s.getLastCallMultipartForm(method, path) + if err != nil { + return fmt.Errorf("failed to parse multipart form: %w", err) + } + if haveValue := req.FormValue(key); haveValue != value { + return fmt.Errorf("header field %q have %q, want %q", key, haveValue, value) + } + return nil +} + +func (s *scenario) checkParsedMultipartFormForFile(method, path, file string, hasFile bool) error { + req, err := s.getLastCallMultipartForm(method, path) + if err != nil { + return fmt.Errorf("failed to parse multipart form: %w", err) + } + + if _, ok := req.MultipartForm.File[file]; hasFile != ok { + return fmt.Errorf("Multipart file in bug report is %t, want it to be %t", ok, hasFile) + } + + return nil +} + +func (s *scenario) theHeaderInTheMultipartRequestToHasFile(method, path, file string) error { + return s.checkParsedMultipartFormForFile(method, path, file, true) +} + +func (s *scenario) theHeaderInTheMultipartRequestToHasNoFile(method, path, file string) error { + return s.checkParsedMultipartFormForFile(method, path, file, false) +} + +func (s *scenario) getLastCallMultipartForm(method, path string) (*http.Request, error) { // We have to exclude HTTP-Overrides to avoid race condition with the creating and sending of the draft message. call, err := s.t.getLastCallExcludingHTTPOverride(method, path) if err != nil { - return err + return nil, err } buf := new(bytes.Buffer) if _, err := buf.WriteString(fmt.Sprintf("%s %s HTTP/1.1\r\n", call.Method, call.URL.Path)); err != nil { - return fmt.Errorf("failed to write request line: %w", err) + return nil, fmt.Errorf("failed to write request line: %w", err) } if err := call.RequestHeader.Write(buf); err != nil { - return fmt.Errorf("failed to write header: %w", err) + return nil, fmt.Errorf("failed to write header: %w", err) } if _, err := buf.WriteString("\r\n"); err != nil { - return fmt.Errorf("failed to write header: %w", err) + return nil, fmt.Errorf("failed to write header: %w", err) } if _, err := buf.Write(call.RequestBody); err != nil { - return fmt.Errorf("failed to write body: %w", err) + return nil, fmt.Errorf("failed to write body: %w", err) } req, err := http.ReadRequest(bufio.NewReader(buf)) if err != nil { - return fmt.Errorf("failed to read request: %w", err) + return nil, fmt.Errorf("failed to read request: %w", err) } if err := req.ParseMultipartForm(1 << 10); err != nil { - return fmt.Errorf("failed to parse multipart form: %w", err) + return nil, fmt.Errorf("failed to parse multipart form: %w", err) } - - if haveValue := req.FormValue(key); haveValue != value { - return fmt.Errorf("header field %q have %q, want %q", key, haveValue, value) - } - - return nil + return req, nil } func (s *scenario) theBodyInTheRequestToIs(method, path string, value *godog.DocString) error { diff --git a/tests/features/user/report_problem.feature b/tests/features/user/report_problem.feature index b8b574cd..e7b8c4b2 100644 --- a/tests/features/user/report_problem.feature +++ b/tests/features/user/report_problem.feature @@ -12,8 +12,17 @@ Feature: The user reports a problem Then the header in the "POST" multipart request to "/core/v4/reports/bug" has "Title" set to "[Bridge] Bug - title" And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Description" set to "description" And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Username" set to "[user:user]" - And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Attachment" set to "" + And the header in the "POST" multipart request to "/core/v4/reports/bug" has no file "logs.zip" + Scenario: User sends a problem report with logs attached + When the user reports a bug with field "IncludeLogs" set to "true" + Then it succeeds + And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Title" set to "[Bridge] Bug - title" + And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Description" set to "description" + And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Username" set to "[user:user]" + And the header in the "POST" multipart request to "/core/v4/reports/bug" has file "logs.zip" + + @regression Scenario: User sends a problem report while signed out of Bridge When user "[user:user]" logs out @@ -41,7 +50,8 @@ Feature: The user reports a problem "Description": "Testing Description", "Username": "[user:user]", "Email": "[user:user]@[domain]", - "EmailClient": "Apple Mail" + "EmailClient": "Apple Mail", + "IncludeLogs": true } """ Then the header in the "POST" multipart request to "/core/v4/reports/bug" has "Title" set to "[Bridge] Bug - Testing Title" @@ -51,3 +61,4 @@ Feature: The user reports a problem And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Username" set to "[user:user]" And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Email" set to "[user:user]@[domain]" And the header in the "POST" multipart request to "/core/v4/reports/bug" has "Client" set to "Apple Mail" + And the header in the "POST" multipart request to "/core/v4/reports/bug" has file "logs.zip" \ No newline at end of file diff --git a/tests/steps_test.go b/tests/steps_test.go index cc68deba..db67d42f 100644 --- a/tests/steps_test.go +++ b/tests/steps_test.go @@ -29,6 +29,8 @@ func (s *scenario) steps(ctx *godog.ScenarioContext) { ctx.Step(`^the user agent is "([^"]*)"$`, s.theUserAgentIs) ctx.Step(`^the header in the "([^"]*)" request to "([^"]*)" has "([^"]*)" set to "([^"]*)"$`, s.theHeaderInTheRequestToHasSetTo) ctx.Step(`^the header in the "([^"]*)" multipart request to "([^"]*)" has "([^"]*)" set to "([^"]*)"$`, s.theHeaderInTheMultipartRequestToHasSetTo) + ctx.Step(`^the header in the "([^"]*)" multipart request to "([^"]*)" has file "([^"]*)"$`, s.theHeaderInTheMultipartRequestToHasFile) + ctx.Step(`^the header in the "([^"]*)" multipart request to "([^"]*)" has no file "([^"]*)"$`, s.theHeaderInTheMultipartRequestToHasNoFile) ctx.Step(`^the body in the "([^"]*)" request to "([^"]*)" is:$`, s.theBodyInTheRequestToIs) ctx.Step(`^the body in the "([^"]*)" response to "([^"]*)" is:$`, s.theBodyInTheResponseToIs) ctx.Step(`^the API requires bridge version at least "([^"]*)"$`, s.theAPIRequiresBridgeVersion)