From 779414b781f53a4cb92e5f38835c41cadef6c0ba Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 12:49:24 +0200 Subject: [PATCH 01/16] Prepare CI for new mazerunner tests, use GO111MODULE for older golang versions --- .github/workflows/test-package.yml | 24 +++++++------ .gitignore | 3 +- Gemfile | 2 +- Gemfile.lock | 55 ------------------------------ features/fixtures/app/run.sh | 2 ++ 5 files changed, 19 insertions(+), 67 deletions(-) delete mode 100644 Gemfile.lock diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index adddc5ac..392fda7c 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -4,15 +4,14 @@ on: [ push, pull_request ] jobs: test: - - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.os }}-latest defaults: run: working-directory: 'go/src/github.com/bugsnag/bugsnag-go/v2' # relative to $GITHUB_WORKSPACE strategy: fail-fast: false matrix: - os: [ubuntu-20.04, windows-latest] + os: [ubuntu, windows] go-version: ['1.11', '1.12', '1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22'] steps: @@ -27,31 +26,36 @@ jobs: if: matrix.os == 'windows' run: | bash -c 'echo "GOPATH=$GITHUB_WORKSPACE\\\\go" >> $GITHUB_ENV' + - name: set GO111MODULE + run: | + bash -c 'echo "GO111MODULE=on" >> $GITHUB_ENV' - uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: install dependencies run: go get -v -d ./... - name: run tests - run: go test ./... + run: go test $(go list ./... | grep -v /features/) - name: vet package # go1.12 vet shows spurious 'unknown identifier' issues if: matrix.go-version != '1.12' - run: go vet ./... + run: go vet $(go list ./... | grep -v /features/) + - name: install integration dependencies + if: matrix.os == 'ubuntu' + run: | + sudo apt-get update + sudo apt-get install libcurl4-openssl-dev - name: install Ruby if: matrix.os == 'ubuntu' uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7 + ruby-version: '3.2' bundler-cache: true working-directory: go/src/github.com/bugsnag/bugsnag-go # relative to $GITHUB_WORKSPACE - - name: install integration dependencies - if: matrix.os == 'ubuntu' - run: sudo apt-get install docker-compose - name: maze tests working-directory: go/src/github.com/bugsnag/bugsnag-go if: matrix.os == 'ubuntu' env: GO_VERSION: ${{ matrix.go-version }} - run: bundle exec bugsnag-maze-runner --color --format progress + run: bundle exec maze-runner --color --format progress \ No newline at end of file diff --git a/.gitignore b/.gitignore index 98616f19..109a5be3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ maze_output vendor -features/fixtures/testbuild \ No newline at end of file +# ignore the gemfile to prevent testing against stale versions +Gemfile.lock \ No newline at end of file diff --git a/Gemfile b/Gemfile index 2971d8a3..ad46a955 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source 'https://rubygems.org' -gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'v1' +gem "bugsnag-maze-runner", "~> 9.9" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 5ff8a517..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,55 +0,0 @@ -GIT - remote: https://github.com/bugsnag/maze-runner - revision: 7377529a77eb7585afc66cd2080fcdc4eea3306a - branch: v1 - specs: - bugsnag-maze-runner (1.1.0) - cucumber (~> 3.1.0) - cucumber-expressions (= 5.0.15) - minitest (~> 5.0) - os (~> 1.0.0) - rack (~> 2.0.0) - rake (~> 12.3.3) - test-unit (~> 3.2.0) - -GEM - remote: https://rubygems.org/ - specs: - backports (3.21.0) - builder (3.2.4) - cucumber (3.1.0) - builder (>= 2.1.2) - cucumber-core (~> 3.1.0) - cucumber-expressions (~> 5.0.4) - cucumber-wire (~> 0.0.1) - diff-lcs (~> 1.3) - gherkin (~> 5.0) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.2) - cucumber-core (3.1.0) - backports (>= 3.8.0) - cucumber-tag_expressions (~> 1.1.0) - gherkin (>= 5.0.0) - cucumber-expressions (5.0.15) - cucumber-tag_expressions (1.1.1) - cucumber-wire (0.0.1) - diff-lcs (1.4.4) - gherkin (5.1.0) - minitest (5.14.4) - multi_json (1.15.0) - multi_test (0.1.2) - os (1.0.1) - power_assert (2.0.0) - rack (2.0.9.3) - rake (12.3.3) - test-unit (3.2.9) - power_assert - -PLATFORMS - ruby - -DEPENDENCIES - bugsnag-maze-runner! - -BUNDLED WITH - 2.1.4 diff --git a/features/fixtures/app/run.sh b/features/fixtures/app/run.sh index 3a98cd7e..67eb31d5 100755 --- a/features/fixtures/app/run.sh +++ b/features/fixtures/app/run.sh @@ -23,3 +23,5 @@ $PROC & # signal APP_PID=$! wait $APP_PID + +go run . \ No newline at end of file From 0b8413e52580661baa4e160df17ec66d22e058a9 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 15:45:39 +0200 Subject: [PATCH 02/16] Temporarily disable ubuntu tests on CI --- .github/workflows/test-package.yml | 2 +- Gemfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 392fda7c..d51eec2a 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu, windows] + os: [windows] go-version: ['1.11', '1.12', '1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22'] steps: diff --git a/Gemfile b/Gemfile index ad46a955..e20e035b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source 'https://rubygems.org' -gem "bugsnag-maze-runner", "~> 9.9" \ No newline at end of file +gem "bugsnag-maze-runner", "~> 9.0" \ No newline at end of file From cebe14b46302949bc61744ced97a7db2c5e17d13 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 12:55:05 +0200 Subject: [PATCH 03/16] Add Bugsnag-Integrity header with sha1 sum --- v2/headers/prefixed.go | 14 ++++++++++---- v2/headers/prefixed_test.go | 7 +++++-- v2/payload.go | 14 +++++++++++--- v2/sessions/publisher.go | 21 ++++++++++++++++++++- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/v2/headers/prefixed.go b/v2/headers/prefixed.go index 099d7947..8a518e80 100644 --- a/v2/headers/prefixed.go +++ b/v2/headers/prefixed.go @@ -1,14 +1,20 @@ package headers -import "time" +import ( + "fmt" + "time" +) + +// PrefixedHeaders returns a map of Content-Type and the 'Bugsnag-' headers for +// API key, payload version, and the time at which the request is being sent. +func PrefixedHeaders(apiKey, payloadVersion, sha1 string) map[string]string { + integrityHeader := fmt.Sprintf("sha1 %v", sha1) -//PrefixedHeaders returns a map of Content-Type and the 'Bugsnag-' headers for -//API key, payload version, and the time at which the request is being sent. -func PrefixedHeaders(apiKey, payloadVersion string) map[string]string { return map[string]string{ "Content-Type": "application/json", "Bugsnag-Api-Key": apiKey, "Bugsnag-Payload-Version": payloadVersion, "Bugsnag-Sent-At": time.Now().UTC().Format(time.RFC3339), + "Bugsnag-Integrity": integrityHeader, } } diff --git a/v2/headers/prefixed_test.go b/v2/headers/prefixed_test.go index 739d9e4f..1df826d4 100644 --- a/v2/headers/prefixed_test.go +++ b/v2/headers/prefixed_test.go @@ -1,6 +1,7 @@ package headers import ( + "fmt" "strings" "testing" "time" @@ -8,9 +9,10 @@ import ( const APIKey = "abcd1234abcd1234" const testPayloadVersion = "3" +const testSHA = "5e13ae4640ae4ae0e09c05b7bb060f544dabd042" func TestConstantBugsnagPrefixedHeaders(t *testing.T) { - headers := PrefixedHeaders(APIKey, testPayloadVersion) + headers := PrefixedHeaders(APIKey, testPayloadVersion, testSHA) testCases := []struct { header string expected string @@ -18,6 +20,7 @@ func TestConstantBugsnagPrefixedHeaders(t *testing.T) { {header: "Content-Type", expected: "application/json"}, {header: "Bugsnag-Api-Key", expected: APIKey}, {header: "Bugsnag-Payload-Version", expected: testPayloadVersion}, + {header: "Bugsnag-Integrity", expected: fmt.Sprintf("sha1 %v", testSHA)}, } for _, tc := range testCases { t.Run(tc.header, func(st *testing.T) { @@ -29,7 +32,7 @@ func TestConstantBugsnagPrefixedHeaders(t *testing.T) { } func TestTimeDependentBugsnagPrefixedHeaders(t *testing.T) { - headers := PrefixedHeaders(APIKey, testPayloadVersion) + headers := PrefixedHeaders(APIKey, testPayloadVersion, testSHA) sentAtString := headers["Bugsnag-Sent-At"] if !strings.HasSuffix(sentAtString, "Z") { t.Errorf("Error when setting Bugsnag-Sent-At header: %s, doesn't end with a Z", sentAtString) diff --git a/v2/payload.go b/v2/payload.go index be2234ce..4d1a0e8e 100644 --- a/v2/payload.go +++ b/v2/payload.go @@ -2,6 +2,8 @@ package bugsnag import ( "bytes" + "crypto/sha1" + "encoding/hex" "encoding/json" "fmt" "net/http" @@ -32,10 +34,16 @@ func (p *payload) deliver() error { } buf, err := p.MarshalJSON() + if err != nil { + return fmt.Errorf("bugsnag/payload.deliver: %v", err) + } + hasher := sha1.New() + _, err = hasher.Write(buf) if err != nil { return fmt.Errorf("bugsnag/payload.deliver: %v", err) } + sha1_hash := hex.EncodeToString(hasher.Sum(nil)) client := http.Client{ Transport: p.Transport, @@ -44,7 +52,7 @@ func (p *payload) deliver() error { if err != nil { return fmt.Errorf("bugsnag/payload.deliver unable to create request: %v", err) } - for k, v := range headers.PrefixedHeaders(p.APIKey, notifyPayloadVersion) { + for k, v := range headers.PrefixedHeaders(p.APIKey, notifyPayloadVersion, sha1_hash) { req.Header.Add(k, v) } resp, err := client.Do(req) @@ -76,7 +84,7 @@ func (p *payload) MarshalJSON() ([]byte, error) { OsName: runtime.GOOS, RuntimeVersions: device.GetRuntimeVersions(), }, - Request: p.Request, + Request: p.Request, Exceptions: p.exceptions(), GroupingHash: p.GroupingHash, Metadata: p.MetaData.sanitize(p.ParamsFilters), @@ -123,7 +131,7 @@ func (p *payload) makeSession() *sessionJSON { func (p *payload) severityReasonPayload() *severityReasonJSON { if reason := p.handledState.SeverityReason; reason != "" { json := &severityReasonJSON{ - Type: reason, + Type: reason, UnhandledOverridden: p.handledState.Unhandled != p.Unhandled, } if p.handledState.Framework != "" { diff --git a/v2/sessions/publisher.go b/v2/sessions/publisher.go index b06985fa..bdb658ff 100644 --- a/v2/sessions/publisher.go +++ b/v2/sessions/publisher.go @@ -2,6 +2,8 @@ package sessions import ( "bytes" + "crypto/sha1" + "encoding/hex" "encoding/json" "fmt" "net/http" @@ -36,41 +38,58 @@ func (p *publisher) publish(sessions []*Session) error { // log every minute return nil } + if apiKey := p.config.APIKey; len(apiKey) != 32 { return fmt.Errorf("bugsnag/sessions/publisher.publish invalid API key: '%s'", apiKey) } + nrs, rs := p.config.NotifyReleaseStages, p.config.ReleaseStage if rs != "" && (nrs != nil && !contains(nrs, rs)) { // Always send sessions if the release stage is not set, but don't send any // sessions when notify release stages don't match the current release stage return nil } + if len(sessions) == 0 { return fmt.Errorf("bugsnag/sessions/publisher.publish requested publication of 0") } + p.config.mutex.Lock() defer p.config.mutex.Unlock() + payload := makeSessionPayload(sessions, p.config) buf, err := json.Marshal(payload) if err != nil { return fmt.Errorf("bugsnag/sessions/publisher.publish unable to marshal json: %v", err) } + + hasher := sha1.New() + _, err = hasher.Write(buf) + if err != nil { + return fmt.Errorf("bugsnag/payload.deliver: %v", err) + } + sha1_hash := hex.EncodeToString(hasher.Sum(nil)) + req, err := http.NewRequest("POST", p.config.Endpoint, bytes.NewBuffer(buf)) if err != nil { return fmt.Errorf("bugsnag/sessions/publisher.publish unable to create request: %v", err) } - for k, v := range headers.PrefixedHeaders(p.config.APIKey, sessionPayloadVersion) { + + for k, v := range headers.PrefixedHeaders(p.config.APIKey, sessionPayloadVersion, sha1_hash) { req.Header.Add(k, v) } + res, err := p.client.Do(req) if err != nil { return fmt.Errorf("bugsnag/sessions/publisher.publish unable to deliver session: %v", err) } + defer func(res *http.Response) { if err := res.Body.Close(); err != nil { p.config.logf("%v", err) } }(res) + if res.StatusCode != 202 { return fmt.Errorf("bugsnag/session.publish expected 202 response status, got HTTP %s", res.Status) } From d50e51d1fc6c38081b2b8c4fb5af0d18c6835042 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 13:05:13 +0200 Subject: [PATCH 04/16] Add command pattern in main test app --- features/fixtures/app/Dockerfile | 18 ++-- features/fixtures/app/command.go | 42 +++++++++ features/fixtures/app/main.go | 127 +++++++-------------------- features/fixtures/docker-compose.yml | 6 +- 4 files changed, 86 insertions(+), 107 deletions(-) create mode 100644 features/fixtures/app/command.go diff --git a/features/fixtures/app/Dockerfile b/features/fixtures/app/Dockerfile index e046de76..61400ce0 100644 --- a/features/fixtures/app/Dockerfile +++ b/features/fixtures/app/Dockerfile @@ -4,8 +4,10 @@ FROM golang:${GO_VERSION}-alpine RUN apk update && apk upgrade && apk add git bash build-base ENV GOPATH /app +ENV GO111MODULE="on" -COPY testbuild /app/src/github.com/bugsnag/bugsnag-go +COPY features /app/src/features +COPY v2 /app/src/github.com/bugsnag/bugsnag-go/v2 WORKDIR /app/src/github.com/bugsnag/bugsnag-go/v2 # Ensure subsequent steps are re-run if the GO_VERSION variable changes @@ -20,17 +22,13 @@ RUN if [[ $(echo -e "1.11\n$GO_VERSION\n1.16" | sort -V | head -2 | tail -1) == go install ./...; \ fi -# Copy test scenarios -COPY ./app /app/src/test -WORKDIR /app/src/test +WORKDIR /app/src/features/fixtures/app # Create app module - avoid locking bugsnag dep by not checking it in # Skip on old versions of Go which pre-date modules -RUN if [[ $GO_VERSION != '1.11' && $GO_VERSION != '1.12' ]]; then \ - go mod init && go mod tidy; \ - echo "replace github.com/bugsnag/bugsnag-go/v2 => /app/src/github.com/bugsnag/bugsnag-go/v2" >> go.mod; \ - go mod tidy; \ - fi +RUN go mod init && go mod tidy && \ + echo "replace github.com/bugsnag/bugsnag-go/v2 => /app/src/github.com/bugsnag/bugsnag-go/v2" >> go.mod && \ + go mod tidy RUN chmod +x run.sh -CMD ["/app/src/test/run.sh"] +CMD ["/app/src/features/fixtures/app/run.sh"] \ No newline at end of file diff --git a/features/fixtures/app/command.go b/features/fixtures/app/command.go new file mode 100644 index 00000000..8c45c601 --- /dev/null +++ b/features/fixtures/app/command.go @@ -0,0 +1,42 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + "time" +) + +const DEFAULT_MAZE_ADDRESS = "http://localhost:9339" + +type Command struct { + Action string `json:"action,omitempty"` + ScenarioName string `json:"scenario_name,omitempty"` + APIKey string `json:"api_key,omitempty"` + NotifyEndpoint string `json:"notify_endpoint,omitempty"` + SessionsEndpoint string `json:"sessions_endpoint,omitempty"` + UUID string `json:"uuid,omitempty"` + RunUUID string `json:"run_uuid,omitempty"` +} + +func GetCommand(mazeAddress string) Command { + var command Command + mazeURL := fmt.Sprintf("%+v/command", mazeAddress) + client := http.Client{Timeout: 2 * time.Second} + res, err := client.Get(mazeURL) + if err != nil { + fmt.Printf("[Bugsnag] Error while receiving command: %+v\n", err) + return command + } + + if res != nil { + err = json.NewDecoder(res.Body).Decode(&command) + res.Body.Close() + if err != nil { + fmt.Printf("[Bugsnag] Error while decoding command: %+v\n", err) + return command + } + } + + return command +} diff --git a/features/fixtures/app/main.go b/features/fixtures/app/main.go index 96243536..37d8fc88 100644 --- a/features/fixtures/app/main.go +++ b/features/fixtures/app/main.go @@ -2,115 +2,54 @@ package main import ( "context" - "flag" "fmt" "log" "os" "runtime" - "strconv" - "strings" "time" bugsnag "github.com/bugsnag/bugsnag-go/v2" ) -func configureBasicBugsnag(testcase string, ctx context.Context) { - config := bugsnag.Configuration{ - APIKey: os.Getenv("API_KEY"), - AppVersion: os.Getenv("APP_VERSION"), - AppType: os.Getenv("APP_TYPE"), - Hostname: os.Getenv("HOSTNAME"), - MainContext: ctx, - } - - if notifyReleaseStages := os.Getenv("NOTIFY_RELEASE_STAGES"); notifyReleaseStages != "" { - config.NotifyReleaseStages = strings.Split(notifyReleaseStages, ",") - } +var scenariosMap = map[string]func(Command) func(){} - if releaseStage := os.Getenv("RELEASE_STAGE"); releaseStage != "" { - config.ReleaseStage = releaseStage - } - - if filters := os.Getenv("PARAMS_FILTERS"); filters != "" { - config.ParamsFilters = []string{filters} - } - - sync, err := strconv.ParseBool(os.Getenv("SYNCHRONOUS")) - if err == nil { - config.Synchronous = sync - } - - acs, err := strconv.ParseBool(os.Getenv("AUTO_CAPTURE_SESSIONS")) - if err == nil { - config.AutoCaptureSessions = acs +func main() { + addr := os.Getenv("DEFAULT_MAZE_ADDRESS") + if addr == "" { + addr = DEFAULT_MAZE_ADDRESS } - switch testcase { - case "endpoint-notify": - config.Endpoints = bugsnag.Endpoints{Notify: os.Getenv("BUGSNAG_ENDPOINT")} - case "endpoint-session": - config.Endpoints = bugsnag.Endpoints{Sessions: os.Getenv("BUGSNAG_ENDPOINT")} - default: - config.Endpoints = bugsnag.Endpoints{ - Notify: os.Getenv("BUGSNAG_ENDPOINT"), - Sessions: os.Getenv("BUGSNAG_ENDPOINT"), - } + endpoints := bugsnag.Endpoints{ + Notify: fmt.Sprintf("%+v/notify", addr), + Sessions: fmt.Sprintf("%+v/sessions", addr), } - bugsnag.Configure(config) - - time.Sleep(200 * time.Millisecond) + // HAS TO RUN FIRST BECAUSE OF PANIC WRAP + // https://github.com/bugsnag/panicwrap/blob/master/panicwrap.go#L177-L203 + bugsnag.Configure(bugsnag.Configuration{ + APIKey: "166f5ad3590596f9aa8d601ea89af845", + Endpoints: endpoints, + }) // Increase publish rate for testing - bugsnag.DefaultSessionPublishInterval = time.Millisecond * 100 -} - -func main() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - test := flag.String("test", "handled", "what the app should send, either handled, unhandled, session, autonotify") - flag.Parse() - - configureBasicBugsnag(*test, ctx) - time.Sleep(100 * time.Millisecond) // Ensure tests are less flaky by ensuring the start-up session gets sent - - switch *test { - case "unhandled": - unhandledCrash() - case "handled", "endpoint-legacy", "endpoint-notify", "endpoint-session": - handledError() - case "handled-with-callback": - handledCallbackError() - case "session": - session() - case "autonotify": - autonotify() - case "metadata": - metadata() - case "onbeforenotify": - onBeforeNotify() - case "filtered": - filtered() - case "recover": - dontDie() - case "session-and-error": - sessionAndError() - case "send-and-exit": - sendAndExit() - case "user": - user() - case "multiple-handled": - multipleHandled() - case "multiple-unhandled": - multipleUnhandled() - case "make-unhandled-with-callback": - handledToUnhandled() - case "nested-error": - nestedHandledError() - default: - log.Println("Not a valid test flag: " + *test) - os.Exit(1) + bugsnag.DefaultSessionPublishInterval = time.Millisecond * 50 + + // Listening to the OS Signals + ticker := time.NewTicker(1 * time.Second) + for { + select { + case <-ticker.C: + command := GetCommand(addr) + fmt.Printf("[Bugsnag] Received command: %+v\n", command) + if command.Action != "run-scenario" { + continue + } + prepareScenarioFunc, ok := scenariosMap[command.ScenarioName] + if ok { + scenarioFunc := prepareScenarioFunc(command) + scenarioFunc() + time.Sleep(200 * time.Millisecond) + } + } } - } func multipleHandled() { diff --git a/features/fixtures/docker-compose.yml b/features/fixtures/docker-compose.yml index 6bc2f8df..444f1e32 100644 --- a/features/fixtures/docker-compose.yml +++ b/features/fixtures/docker-compose.yml @@ -1,12 +1,12 @@ -version: '3.4' services: app: build: - context: . - dockerfile: app/Dockerfile + context: ../../ + dockerfile: ./features/fixtures/app/Dockerfile args: - GO_VERSION environment: + - DEFAULT_MAZE_ADDRESS - API_KEY - ERROR_CLASS - BUGSNAG_ENDPOINT From d9b0f518de31ad576a81500bd27bbeadf12b12d4 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 19:41:11 +0200 Subject: [PATCH 05/16] Prepare ruby steps for new mazerunner version, set test server address --- features/steps/go_steps.rb | 41 ++++++++++++++++++++++++++++++++++++++ features/support/env.rb | 23 +++++++-------------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/features/steps/go_steps.rb b/features/steps/go_steps.rb index 16a0e307..001a5ca9 100644 --- a/features/steps/go_steps.rb +++ b/features/steps/go_steps.rb @@ -1,4 +1,45 @@ require 'net/http' +require 'os' + +When('I run {string}') do |scenario_name| + execute_command 'run-scenario', scenario_name +end + +When('I configure the base endpoint') do + steps %( + When I set environment variable "DEFAULT_MAZE_ADDRESS" to "http://#{local_ip}:9339" + ) +end + +def execute_command(action, scenario_name = '') + address = $address ? $address : "#{local_ip}:9339" + + command = { + action: action, + scenario_name: scenario_name, + notify_endpoint: "http://#{address}/notify", + sessions_endpoint: "http://#{address}/sessions", + api_key: $api_key, + } + + $logger.debug("Queuing command: #{command}") + Maze::Server.commands.add command + + # Ensure fixture has read the command + count = 900 + sleep 0.1 until Maze::Server.commands.remaining.empty? || (count -= 1) < 1 + raise 'Test fixture did not GET /command' unless Maze::Server.commands.remaining.empty? +end + +def local_ip + if OS.mac? + 'host.docker.internal' + else + ip_addr = `ifconfig | grep -Eo 'inet (addr:)?([0-9]*\\\.){3}[0-9]*' | grep -v '127.0.0.1'` + ip_list = /((?:[0-9]*\.){3}[0-9]*)/.match(ip_addr) + ip_list.captures.first + end +end Given("I set environment variable {string} to the app directory") do |key| step("I set environment variable \"#{key}\" to \"/app/src/test/\"") diff --git a/features/support/env.rb b/features/support/env.rb index 3e70280e..d55c94b1 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,16 +1,7 @@ -require 'fileutils' -require 'socket' -require 'timeout' - -testBuildFolder = 'features/fixtures/testbuild' - -FileUtils.rm_rf(testBuildFolder) -Dir.mkdir testBuildFolder - -# Copy the existing dir -`find . -name '*.go' -o -name 'go.sum' -o -name 'go.mod' \ - -not -path "./examples/*" \ - -not -path "./testutil/*" \ - -not -path "./v2/testutil/*" \ - -not -path "./features/*" \ - -not -name '*_test.go' | cpio -pdm #{testBuildFolder}` +Before do + $address = nil + $api_key = "166f5ad3590596f9aa8d601ea89af845" + steps %( + When I configure the base endpoint + ) + end \ No newline at end of file From fea99fdb43049ae4bc67c21555e1e506499659f5 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 14:00:46 +0200 Subject: [PATCH 06/16] Separate test functions into scenario files --- features/fixtures/app/autoconfig_scenario.go | 33 ++++++ features/fixtures/app/handled_scenario.go | 100 ++++++++++++++++++ features/fixtures/app/metadata_scenario.go | 32 ++++++ features/fixtures/app/nethttp_scenario.go | 103 +++++++++++++++++++ features/fixtures/app/panic_scenario.go | 22 ++++ features/fixtures/app/session_scenario.go | 23 +++++ features/fixtures/app/unhandled_scenario.go | 35 +++++++ features/fixtures/app/user_scenario.go | 19 ++++ features/fixtures/app/utils.go | 55 ++++++++++ 9 files changed, 422 insertions(+) create mode 100644 features/fixtures/app/autoconfig_scenario.go create mode 100644 features/fixtures/app/handled_scenario.go create mode 100644 features/fixtures/app/metadata_scenario.go create mode 100644 features/fixtures/app/nethttp_scenario.go create mode 100644 features/fixtures/app/panic_scenario.go create mode 100644 features/fixtures/app/session_scenario.go create mode 100644 features/fixtures/app/unhandled_scenario.go create mode 100644 features/fixtures/app/user_scenario.go create mode 100644 features/fixtures/app/utils.go diff --git a/features/fixtures/app/autoconfig_scenario.go b/features/fixtures/app/autoconfig_scenario.go new file mode 100644 index 00000000..8b52b44f --- /dev/null +++ b/features/fixtures/app/autoconfig_scenario.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + + bugsnag "github.com/bugsnag/bugsnag-go/v2" +) + +func AutoconfigPanicScenario(command Command) func() { + scenarioFunc := func() { + panic("PANIQ!") + } + return scenarioFunc +} + +func AutoconfigHandledScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.Notify(fmt.Errorf("gone awry!")) + } + return scenarioFunc +} + +func AutoconfigMetadataScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.OnBeforeNotify(func(event *bugsnag.Event, config *bugsnag.Configuration) error { + event.MetaData.Add("fruit", "Tomato", "beefsteak") + event.MetaData.Add("snacks", "Carrot", "4") + return nil + }) + bugsnag.Notify(fmt.Errorf("gone awry!")) + } + return scenarioFunc +} \ No newline at end of file diff --git a/features/fixtures/app/handled_scenario.go b/features/fixtures/app/handled_scenario.go new file mode 100644 index 00000000..ba0974ec --- /dev/null +++ b/features/fixtures/app/handled_scenario.go @@ -0,0 +1,100 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/bugsnag/bugsnag-go/v2" +) + +func HandledErrorScenario(command Command) func() { + scenarioFunc := func() { + if _, err := os.Open("nonexistent_file.txt"); err != nil { + if errClass := os.Getenv("ERROR_CLASS"); errClass != "" { + bugsnag.Notify(err, bugsnag.ErrorClass{Name: errClass}) + } else { + bugsnag.Notify(err) + } + } + } + return scenarioFunc +} + +func MultipleHandledErrorsScenario(command Command) func() { + //Make the order of the below predictable + bugsnag.Configure(bugsnag.Configuration{Synchronous: true}) + + scenarioFunc := func() { + ctx := bugsnag.StartSession(context.Background()) + bugsnag.Notify(fmt.Errorf("oops"), ctx) + bugsnag.Notify(fmt.Errorf("oops"), ctx) + } + return scenarioFunc +} + +func NestedHandledErrorScenario(command Command) func() { + scenarioFunc := func() { + if err := Login("token " + os.Getenv("API_KEY")); err != nil { + bugsnag.Notify(NewCustomErr("terminate process", err)) + } else { + i := len(os.Getenv("API_KEY")) + // Some nonsense to avoid inlining checkValue + if val, err := CheckValue(i); err != nil { + fmt.Printf("err: %v, val: %d\n", err, val) + } + if val, err := CheckValue(i - 46); err != nil { + fmt.Printf("err: %v, val: %d\n", err, val) + } + + log.Fatalf("This test is broken - no error was generated.") + } + } + return scenarioFunc +} + +func HandledCallbackErrorScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.Notify(fmt.Errorf("inadequent Prep Error"), func(event *bugsnag.Event) { + event.Context = "nonfatal.go:14" + event.Severity = bugsnag.SeverityInfo + + event.Stacktrace[1].File = ">insertion<" + event.Stacktrace[1].LineNumber = 0 + }) + } + return scenarioFunc +} + +func HandledToUnhandledScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.Notify(fmt.Errorf("unknown event"), func(event *bugsnag.Event) { + event.Unhandled = true + event.Severity = bugsnag.SeverityError + }) + } + return scenarioFunc +} + +func OnBeforeNotifyScenario(command Command) func() { + bugsnag.Configure(bugsnag.Configuration{Synchronous: true}) + + scenarioFunc := func() { + bugsnag.OnBeforeNotify( + func(event *bugsnag.Event, config *bugsnag.Configuration) error { + if event.Message == "ignore this error" { + return fmt.Errorf("not sending errors to ignore") + } + // continue notifying as normal + if event.Message == "change error message" { + event.Message = "error message was changed" + } + return nil + }) + bugsnag.Notify(fmt.Errorf("ignore this error")) + bugsnag.Notify(fmt.Errorf("don't ignore this error")) + bugsnag.Notify(fmt.Errorf("change error message")) + } + return scenarioFunc +} diff --git a/features/fixtures/app/metadata_scenario.go b/features/fixtures/app/metadata_scenario.go new file mode 100644 index 00000000..e4cb7f70 --- /dev/null +++ b/features/fixtures/app/metadata_scenario.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + + "github.com/bugsnag/bugsnag-go/v2" +) + +func MetadataScenario(command Command) func() { + scenarioFunc := func() { + customerData := map[string]string{"Name": "Joe Bloggs", "Age": "21"} + bugsnag.Notify(fmt.Errorf("oops"), bugsnag.MetaData{ + "Scheme": { + "Customer": customerData, + "Level": "Blue", + }, + }) + } + return scenarioFunc +} + +func FilteredMetadataScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.Notify(fmt.Errorf("oops"), bugsnag.MetaData{ + "Account": { + "Name": "Company XYZ", + "Price(dollars)": "1 Million", + }, + }) + } + return scenarioFunc +} diff --git a/features/fixtures/app/nethttp_scenario.go b/features/fixtures/app/nethttp_scenario.go new file mode 100644 index 00000000..0018f10b --- /dev/null +++ b/features/fixtures/app/nethttp_scenario.go @@ -0,0 +1,103 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "time" + + "github.com/bugsnag/bugsnag-go/v2" +) + +func HttpServerScenario(Command) func() { + scenarioFunc := func() { + http.HandleFunc("/handled", handledError) + http.HandleFunc("/autonotify-then-recover", unhandledCrash) + http.HandleFunc("/session", session) + http.HandleFunc("/autonotify", autonotify) + http.HandleFunc("/onbeforenotify", onBeforeNotify) + http.HandleFunc("/recover", dontdie) + http.HandleFunc("/user", user) + + http.ListenAndServe(":4512", recoverWrap(bugsnag.Handler(nil))) + } + + return scenarioFunc +} + +// Simple wrapper to send internal server error on panics +func recoverWrap(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer func() { + r := recover() + if r != nil { + http.Error(w, "", http.StatusInternalServerError) + } + }() + h.ServeHTTP(w, r) + }) +} + +func handledError(w http.ResponseWriter, r *http.Request) { + if _, err := os.Open("nonexistent_file.txt"); err != nil { + if errClass := os.Getenv("ERROR_CLASS"); errClass != "" { + bugsnag.Notify(err, r.Context(), bugsnag.ErrorClass{Name: errClass}) + } else { + bugsnag.Notify(err, r.Context()) + } + } +} + +func unhandledCrash(w http.ResponseWriter, r *http.Request) { + // Invalid type assertion, will panic + func(a interface{}) string { + return a.(string) + }(struct{}{}) +} + +func session(w http.ResponseWriter, r *http.Request) { + log.Println("single session") +} + +func autonotify(w http.ResponseWriter, r *http.Request) { + go func(ctx context.Context) { + defer func() { recover() }() + defer bugsnag.AutoNotify(ctx) + panic("Go routine killed with auto notify") + }(r.Context()) +} + +func onBeforeNotify(w http.ResponseWriter, r *http.Request) { + bugsnag.OnBeforeNotify( + func(event *bugsnag.Event, config *bugsnag.Configuration) error { + if event.Message == "Ignore this error" { + return fmt.Errorf("not sending errors to ignore") + } + // continue notifying as normal + if event.Message == "Change error message" { + event.Message = "Error message was changed" + } + return nil + }) + bugsnag.Notify(fmt.Errorf("Ignore this error")) + time.Sleep(100 * time.Millisecond) + bugsnag.Notify(fmt.Errorf("Don't ignore this error")) + time.Sleep(100 * time.Millisecond) + bugsnag.Notify(fmt.Errorf("Change error message")) + time.Sleep(100 * time.Millisecond) +} + +func dontdie(w http.ResponseWriter, r *http.Request) { + defer bugsnag.Recover(r.Context()) + panic("Request killed but recovered") +} + +func user(w http.ResponseWriter, r *http.Request) { + bugsnag.Notify(fmt.Errorf("oops"), r.Context(), bugsnag.User{ + Id: "test-user-id", + Name: "test-user-name", + Email: "test-user-email", + }) +} \ No newline at end of file diff --git a/features/fixtures/app/panic_scenario.go b/features/fixtures/app/panic_scenario.go new file mode 100644 index 00000000..aed6c1ec --- /dev/null +++ b/features/fixtures/app/panic_scenario.go @@ -0,0 +1,22 @@ +package main + +import ( + "github.com/bugsnag/bugsnag-go/v2" +) + +func AutonotifyPanicScenario(command Command) func() { + scenarioFunc := func() { + defer bugsnag.AutoNotify() + panic("Go routine killed with auto notify") + } + + return scenarioFunc +} + +func RecoverAfterPanicScenario(command Command) func() { + scenarioFunc := func() { + defer bugsnag.Recover() + panic("Go routine killed but recovered") + } + return scenarioFunc +} \ No newline at end of file diff --git a/features/fixtures/app/session_scenario.go b/features/fixtures/app/session_scenario.go new file mode 100644 index 00000000..cdd66a80 --- /dev/null +++ b/features/fixtures/app/session_scenario.go @@ -0,0 +1,23 @@ +package main + +import ( + "context" + "fmt" + + "github.com/bugsnag/bugsnag-go/v2" +) + +func SendSessionScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.StartSession(context.Background()) + } + return scenarioFunc +} + +func SessionAndErrorScenario(command Command) func() { + scenarioFunc := func() { + ctx := bugsnag.StartSession(context.Background()) + bugsnag.Notify(fmt.Errorf("oops"), ctx) + } + return scenarioFunc +} \ No newline at end of file diff --git a/features/fixtures/app/unhandled_scenario.go b/features/fixtures/app/unhandled_scenario.go new file mode 100644 index 00000000..1fbed7de --- /dev/null +++ b/features/fixtures/app/unhandled_scenario.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "fmt" + + "github.com/bugsnag/bugsnag-go/v2" +) + +//go:noinline +func UnhandledCrashScenario(command Command) func() { + scenarioFunc := func() { + fmt.Printf("Calling panic\n") + // Invalid type assertion, will panic + func(a interface{}) string { + return a.(string) + }(struct{}{}) + } + return scenarioFunc +} + +func MultipleUnhandledErrorsScenario(command Command) func() { + scenarioFunc := func() { + //Make the order of the below predictable + notifier := bugsnag.New(bugsnag.Configuration{Synchronous: true}) + notifier.FlushSessionsOnRepanic(false) + + ctx := bugsnag.StartSession(context.Background()) + defer func() { recover() }() + defer notifier.AutoNotify(ctx) + defer notifier.AutoNotify(ctx) + panic("oops") + } + return scenarioFunc +} \ No newline at end of file diff --git a/features/fixtures/app/user_scenario.go b/features/fixtures/app/user_scenario.go new file mode 100644 index 00000000..b8b57239 --- /dev/null +++ b/features/fixtures/app/user_scenario.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + + "github.com/bugsnag/bugsnag-go/v2" +) + +func SetUserScenario(command Command) func() { + scenarioFunc := func() { + bugsnag.Notify(fmt.Errorf("oops"), bugsnag.User{ + Id: "test-user-id", + Name: "test-user-name", + Email: "test-user-email", + }) + } + + return scenarioFunc +} \ No newline at end of file diff --git a/features/fixtures/app/utils.go b/features/fixtures/app/utils.go new file mode 100644 index 00000000..87937b27 --- /dev/null +++ b/features/fixtures/app/utils.go @@ -0,0 +1,55 @@ +package main + +import ( + "fmt" + "runtime" +) + +type CustomErr struct { + msg string + cause error + callers []uintptr +} + +func NewCustomErr(msg string, cause error) error { + callers := make([]uintptr, 8) + runtime.Callers(2, callers) + return CustomErr{ + msg: msg, + cause: cause, + callers: callers, + } +} + +func (err CustomErr) Error() string { + return err.msg +} + +func (err CustomErr) Unwrap() error { + return err.cause +} + +func (err CustomErr) Callers() []uintptr { + return err.callers +} + +func Login(token string) error { + val, err := CheckValue(len(token) * -1) + if err != nil { + return NewCustomErr("login failed", err) + } + fmt.Printf("val: %d\n", val) + return nil +} + +func CheckValue(i int) (int, error) { + if i < 0 { + return 0, NewCustomErr("invalid token", nil) + } else if i%2 == 0 { + return i / 2, nil + } else if i < 9 { + return i * 3, nil + } + + return i * 4, nil +} \ No newline at end of file From 2522f88f2ef53b8051e632ebdabe9964b3079892 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 14:02:01 +0200 Subject: [PATCH 07/16] Add scenarios to map in main file --- features/fixtures/app/main.go | 244 +++------------------------------- 1 file changed, 22 insertions(+), 222 deletions(-) diff --git a/features/fixtures/app/main.go b/features/fixtures/app/main.go index 37d8fc88..7332a1a0 100644 --- a/features/fixtures/app/main.go +++ b/features/fixtures/app/main.go @@ -1,17 +1,34 @@ package main import ( - "context" "fmt" - "log" "os" - "runtime" "time" - bugsnag "github.com/bugsnag/bugsnag-go/v2" + "github.com/bugsnag/bugsnag-go/v2" ) -var scenariosMap = map[string]func(Command) func(){} +var scenariosMap = map[string]func(Command) func(){ + "UnhandledScenario": UnhandledCrashScenario, + "HandledScenario": HandledErrorScenario, + "MultipleUnhandledScenario": MultipleUnhandledErrorsScenario, + "MultipleHandledScenario": MultipleHandledErrorsScenario, + "NestedErrorScenario": NestedHandledErrorScenario, + "MetadataScenario": MetadataScenario, + "FilteredMetadataScenario": FilteredMetadataScenario, + "HandledCallbackErrorScenario": HandledCallbackErrorScenario, + "SendSessionScenario": SendSessionScenario, + "HandledToUnhandledScenario": HandledToUnhandledScenario, + "SetUserScenario": SetUserScenario, + "RecoverAfterPanicScenario": RecoverAfterPanicScenario, + "AutonotifyPanicScenario": AutonotifyPanicScenario, + "SessionAndErrorScenario": SessionAndErrorScenario, + "OnBeforeNotifyScenario": OnBeforeNotifyScenario, + "AutoconfigPanicScenario": AutoconfigPanicScenario, + "AutoconfigHandledScenario": AutoconfigHandledScenario, + "AutoconfigMetadataScenario": AutoconfigMetadataScenario, + "HttpServerScenario": HttpServerScenario, +} func main() { addr := os.Getenv("DEFAULT_MAZE_ADDRESS") @@ -51,220 +68,3 @@ func main() { } } } - -func multipleHandled() { - //Make the order of the below predictable - bugsnag.Configure(bugsnag.Configuration{Synchronous: true}) - - ctx := bugsnag.StartSession(context.Background()) - bugsnag.Notify(fmt.Errorf("oops"), ctx) - bugsnag.Notify(fmt.Errorf("oops"), ctx) -} - -func multipleUnhandled() { - //Make the order of the below predictable - notifier := bugsnag.New(bugsnag.Configuration{Synchronous: true}) - notifier.FlushSessionsOnRepanic(false) - - ctx := bugsnag.StartSession(context.Background()) - defer func() { recover() }() - defer notifier.AutoNotify(ctx) - defer notifier.AutoNotify(ctx) - panic("oops") -} - -//go:noinline -func unhandledCrash() { - // Invalid type assertion, will panic - func(a interface{}) string { - return a.(string) - }(struct{}{}) -} - -func handledError() { - if _, err := os.Open("nonexistent_file.txt"); err != nil { - if errClass := os.Getenv("ERROR_CLASS"); errClass != "" { - bugsnag.Notify(err, bugsnag.ErrorClass{Name: errClass}) - } else { - bugsnag.Notify(err) - } - } - // Give some time for the error to be sent before exiting - time.Sleep(200 * time.Millisecond) -} - -func session() { - bugsnag.StartSession(context.Background()) - - // Give some time for the session to be sent before exiting - time.Sleep(200 * time.Millisecond) -} - -func autonotify() { - go func() { - defer bugsnag.AutoNotify() - panic("Go routine killed with auto notify") - }() - - // Give enough time for the panic to happen - time.Sleep(100 * time.Millisecond) -} - -func metadata() { - customerData := map[string]string{"Name": "Joe Bloggs", "Age": "21"} - bugsnag.Notify(fmt.Errorf("oops"), bugsnag.MetaData{ - "Scheme": { - "Customer": customerData, - "Level": "Blue", - }, - }) - time.Sleep(200 * time.Millisecond) -} - -func filtered() { - bugsnag.Notify(fmt.Errorf("oops"), bugsnag.MetaData{ - "Account": { - "Name": "Company XYZ", - "Price(dollars)": "1 Million", - }, - }) - time.Sleep(200 * time.Millisecond) -} - -func onBeforeNotify() { - bugsnag.OnBeforeNotify( - func(event *bugsnag.Event, config *bugsnag.Configuration) error { - if event.Message == "Ignore this error" { - return fmt.Errorf("not sending errors to ignore") - } - // continue notifying as normal - if event.Message == "Change error message" { - event.Message = "Error message was changed" - } - return nil - }) - bugsnag.Notify(fmt.Errorf("Ignore this error")) - time.Sleep(100 * time.Millisecond) - bugsnag.Notify(fmt.Errorf("Don't ignore this error")) - time.Sleep(100 * time.Millisecond) - bugsnag.Notify(fmt.Errorf("Change error message")) - time.Sleep(100 * time.Millisecond) -} - -func dontDie() { - go func() { - defer bugsnag.Recover() - panic("Go routine killed but recovered") - }() - time.Sleep(100 * time.Millisecond) -} - -func sessionAndError() { - ctx := bugsnag.StartSession(context.Background()) - bugsnag.Notify(fmt.Errorf("oops"), ctx) - - time.Sleep(200 * time.Millisecond) -} - -func sendAndExit() { - bugsnag.Notify(fmt.Errorf("oops")) -} - -func user() { - bugsnag.Notify(fmt.Errorf("oops"), bugsnag.User{ - Id: "test-user-id", - Name: "test-user-name", - Email: "test-user-email", - }) - - time.Sleep(200 * time.Millisecond) -} - -func handledCallbackError() { - bugsnag.Notify(fmt.Errorf("Inadequent Prep Error"), func(event *bugsnag.Event) { - event.Context = "nonfatal.go:14" - event.Severity = bugsnag.SeverityInfo - - event.Stacktrace[1].File = ">insertion<" - event.Stacktrace[1].LineNumber = 0 - }) - // Give some time for the error to be sent before exiting - time.Sleep(200 * time.Millisecond) -} - -func handledToUnhandled() { - bugsnag.Notify(fmt.Errorf("unknown event"), func(event *bugsnag.Event) { - event.Unhandled = true - event.Severity = bugsnag.SeverityError - }) - // Give some time for the error to be sent before exiting - time.Sleep(200 * time.Millisecond) -} - -type customErr struct { - msg string - cause error - callers []uintptr -} - -func newCustomErr(msg string, cause error) error { - callers := make([]uintptr, 8) - runtime.Callers(2, callers) - return customErr{ - msg: msg, - cause: cause, - callers: callers, - } -} - -func (err customErr) Error() string { - return err.msg -} - -func (err customErr) Unwrap() error { - return err.cause -} - -func (err customErr) Callers() []uintptr { - return err.callers -} - -func nestedHandledError() { - if err := login("token " + os.Getenv("API_KEY")); err != nil { - bugsnag.Notify(newCustomErr("terminate process", err)) - // Give some time for the error to be sent before exiting - time.Sleep(200 * time.Millisecond) - } else { - i := len(os.Getenv("API_KEY")) - // Some nonsense to avoid inlining checkValue - if val, err := checkValue(i); err != nil { - fmt.Printf("err: %v, val: %d", err, val) - } - if val, err := checkValue(i - 46); err != nil { - fmt.Printf("err: %v, val: %d", err, val) - } - - log.Fatalf("This test is broken - no error was generated.") - } -} - -func login(token string) error { - val, err := checkValue(len(token) * -1) - if err != nil { - return newCustomErr("login failed", err) - } - fmt.Printf("val: %d", val) - return nil -} - -func checkValue(i int) (int, error) { - if i < 0 { - return 0, newCustomErr("invalid token", nil) - } else if i%2 == 0 { - return i / 2, nil - } else if i < 9 { - return i * 3, nil - } - - return i * 4, nil -} From 6b02a9ff9c2f06d73178aecbb9727cd4d5bf0287 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 16:25:03 +0200 Subject: [PATCH 08/16] Remove nethttp and autoconfigure test apps --- features/fixtures/autoconfigure/Dockerfile | 36 ------ features/fixtures/autoconfigure/cases.go | 24 ---- features/fixtures/autoconfigure/main.go | 34 ----- features/fixtures/autoconfigure/run.sh | 25 ---- features/fixtures/net_http/Dockerfile | 35 ------ features/fixtures/net_http/main.go | 140 --------------------- 6 files changed, 294 deletions(-) delete mode 100644 features/fixtures/autoconfigure/Dockerfile delete mode 100644 features/fixtures/autoconfigure/cases.go delete mode 100644 features/fixtures/autoconfigure/main.go delete mode 100755 features/fixtures/autoconfigure/run.sh delete mode 100644 features/fixtures/net_http/Dockerfile delete mode 100644 features/fixtures/net_http/main.go diff --git a/features/fixtures/autoconfigure/Dockerfile b/features/fixtures/autoconfigure/Dockerfile deleted file mode 100644 index 2d6db32c..00000000 --- a/features/fixtures/autoconfigure/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -ARG GO_VERSION -FROM golang:${GO_VERSION}-alpine - -RUN apk update && apk upgrade && apk add git bash build-base - -ENV GOPATH /app - -COPY testbuild /app/src/github.com/bugsnag/bugsnag-go -WORKDIR /app/src/github.com/bugsnag/bugsnag-go/v2 - -# Ensure subsequent steps are re-run if the GO_VERSION variable changes -ARG GO_VERSION - -# Get bugsnag dependencies using a conditional call to run go get or go install based on the go version -RUN if [[ $(echo -e "1.11\n$GO_VERSION\n1.16" | sort -V | head -2 | tail -1) == "$GO_VERSION" ]]; then \ - echo "Version is between 1.11 and 1.16, running go get"; \ - go get ./...; \ - else \ - echo "Version is greater than 1.16, running go install"; \ - go install ./...; \ - fi - -# Copy test scenarios -COPY ./autoconfigure /app/src/test -WORKDIR /app/src/test - -# Create app module - avoid locking bugsnag dep by not checking it in -# Skip on old versions of Go which pre-date modules -RUN if [[ $GO_VERSION != '1.11' && $GO_VERSION != '1.12' ]]; then \ - go mod init && go mod tidy; \ - echo "replace github.com/bugsnag/bugsnag-go/v2 => /app/src/github.com/bugsnag/bugsnag-go/v2" >> go.mod; \ - go mod tidy; \ - fi - -RUN chmod +x run.sh -CMD ["/app/src/test/run.sh"] diff --git a/features/fixtures/autoconfigure/cases.go b/features/fixtures/autoconfigure/cases.go deleted file mode 100644 index 2700a4c8..00000000 --- a/features/fixtures/autoconfigure/cases.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/bugsnag/bugsnag-go/v2" -) - -func explicitPanic() { - panic("PANIQ!") -} - -func handledEvent() { - bugsnag.Notify(fmt.Errorf("gone awry!")) -} - -func handledMetadata() { - bugsnag.OnBeforeNotify(func(event *bugsnag.Event, config *bugsnag.Configuration) error { - event.MetaData.Add("fruit", "Tomato", "beefsteak") - event.MetaData.Add("snacks", "Carrot", "4") - return nil - }) - handledEvent() -} diff --git a/features/fixtures/autoconfigure/main.go b/features/fixtures/autoconfigure/main.go deleted file mode 100644 index 8dddcebe..00000000 --- a/features/fixtures/autoconfigure/main.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "time" - - "github.com/bugsnag/bugsnag-go/v2" -) - -var testcase = flag.String("test", "", "the error scenario to run") - -func main() { - bugsnag.Configure(bugsnag.Configuration{}) - - // Increase publish rate for testing - bugsnag.DefaultSessionPublishInterval = time.Millisecond * 50 - - flag.Parse() - - switch *testcase { - case "panic": - explicitPanic() - case "handled": - handledEvent() - case "handled-metadata": - handledMetadata() - case "no-op": - // nothing to see here - default: - fmt.Printf("No test case found for '%s'\n", *testcase) - } - time.Sleep(time.Millisecond * 100) // time to send before termination -} diff --git a/features/fixtures/autoconfigure/run.sh b/features/fixtures/autoconfigure/run.sh deleted file mode 100755 index 3a98cd7e..00000000 --- a/features/fixtures/autoconfigure/run.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# SIGTERM or SIGINT trapped (likely SIGTERM from docker), pass it onto app -# process -function _term_or_init { - kill -TERM "$APP_PID" 2>/dev/null - wait $APP_PID -} - -# The bugsnag notifier monitor process needs at least 300ms, in order to ensure -# that it can send its notify -function _exit { - sleep 1 -} - -trap _term_or_init SIGTERM SIGINT -trap _exit EXIT - -PROC="${@:1}" -$PROC & - -# Wait on the app process to ensure that this script is able to trap the SIGTERM -# signal -APP_PID=$! -wait $APP_PID diff --git a/features/fixtures/net_http/Dockerfile b/features/fixtures/net_http/Dockerfile deleted file mode 100644 index fb5e526e..00000000 --- a/features/fixtures/net_http/Dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -ARG GO_VERSION -FROM golang:${GO_VERSION}-alpine - -RUN apk update && \ - apk upgrade && \ - apk add git build-base - -ENV GOPATH /app - -COPY testbuild /app/src/github.com/bugsnag/bugsnag-go -WORKDIR /app/src/github.com/bugsnag/bugsnag-go/v2 - -# Ensure subsequent steps are re-run if the GO_VERSION variable changes -ARG GO_VERSION - -# Get bugsnag dependencies using a conditional call to run go get or go install based on the go version -RUN if [[ $(echo -e "1.11\n$GO_VERSION\n1.16" | sort -V | head -2 | tail -1) == "$GO_VERSION" ]]; then \ - echo "Version is between 1.11 and 1.16, running go get"; \ - go get ./...; \ - else \ - echo "Version is greater than 1.16, running go install"; \ - go install ./...; \ - fi - -# Copy test scenarios -COPY ./net_http /app/src/test -WORKDIR /app/src/test - -# Create app module - avoid locking bugsnag dep by not checking it in -# Skip on old versions of Go which pre-date modules -RUN if [[ $GO_VERSION != '1.11' && $GO_VERSION != '1.12' ]]; then \ - go mod init && go mod tidy; \ - echo "replace github.com/bugsnag/bugsnag-go/v2 => /app/src/github.com/bugsnag/bugsnag-go/v2" >> go.mod; \ - go mod tidy; \ - fi diff --git a/features/fixtures/net_http/main.go b/features/fixtures/net_http/main.go deleted file mode 100644 index 516efd2a..00000000 --- a/features/fixtures/net_http/main.go +++ /dev/null @@ -1,140 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "net/http" - "os" - "strconv" - "strings" - "time" - - bugsnag "github.com/bugsnag/bugsnag-go/v2" -) - -func main() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - configureBasicBugsnag(ctx) - - http.HandleFunc("/handled", handledError) - http.HandleFunc("/autonotify-then-recover", unhandledCrash) - http.HandleFunc("/session", session) - http.HandleFunc("/autonotify", autonotify) - http.HandleFunc("/onbeforenotify", onBeforeNotify) - http.HandleFunc("/recover", dontdie) - http.HandleFunc("/user", user) - - http.ListenAndServe(":"+os.Getenv("SERVER_PORT"), recoverWrap(bugsnag.Handler(nil))) -} - -// Simple wrapper to send internal server error on panics -func recoverWrap(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - defer func() { - r := recover() - if r != nil { - http.Error(w, "", http.StatusInternalServerError) - } - }() - h.ServeHTTP(w, r) - }) -} - -func configureBasicBugsnag(ctx context.Context) { - config := bugsnag.Configuration{ - APIKey: os.Getenv("API_KEY"), - Endpoints: bugsnag.Endpoints{ - Notify: os.Getenv("BUGSNAG_ENDPOINT"), - Sessions: os.Getenv("BUGSNAG_ENDPOINT"), - }, - AppVersion: os.Getenv("APP_VERSION"), - AppType: os.Getenv("APP_TYPE"), - Hostname: os.Getenv("HOSTNAME"), - MainContext: ctx, - } - - if notifyReleaseStages := os.Getenv("NOTIFY_RELEASE_STAGES"); notifyReleaseStages != "" { - config.NotifyReleaseStages = strings.Split(notifyReleaseStages, ",") - } - - if releaseStage := os.Getenv("RELEASE_STAGE"); releaseStage != "" { - config.ReleaseStage = releaseStage - } - - if filters := os.Getenv("PARAMS_FILTERS"); filters != "" { - config.ParamsFilters = []string{filters} - } - - acs, err := strconv.ParseBool(os.Getenv("AUTO_CAPTURE_SESSIONS")) - if err == nil { - config.AutoCaptureSessions = acs - } - bugsnag.Configure(config) - - // Increase publish rate for testing - bugsnag.DefaultSessionPublishInterval = time.Millisecond * 300 -} - -func handledError(w http.ResponseWriter, r *http.Request) { - if _, err := os.Open("nonexistent_file.txt"); err != nil { - if errClass := os.Getenv("ERROR_CLASS"); errClass != "" { - bugsnag.Notify(err, r.Context(), bugsnag.ErrorClass{Name: errClass}) - } else { - bugsnag.Notify(err, r.Context()) - } - } -} - -func unhandledCrash(w http.ResponseWriter, r *http.Request) { - // Invalid type assertion, will panic - func(a interface{}) string { - return a.(string) - }(struct{}{}) -} - -func session(w http.ResponseWriter, r *http.Request) { - log.Println("single session") -} - -func autonotify(w http.ResponseWriter, r *http.Request) { - go func(ctx context.Context) { - defer func() { recover() }() - defer bugsnag.AutoNotify(ctx) - panic("Go routine killed with auto notify") - }(r.Context()) -} - -func onBeforeNotify(w http.ResponseWriter, r *http.Request) { - bugsnag.OnBeforeNotify( - func(event *bugsnag.Event, config *bugsnag.Configuration) error { - if event.Message == "Ignore this error" { - return fmt.Errorf("not sending errors to ignore") - } - // continue notifying as normal - if event.Message == "Change error message" { - event.Message = "Error message was changed" - } - return nil - }) - bugsnag.Notify(fmt.Errorf("Ignore this error")) - time.Sleep(100 * time.Millisecond) - bugsnag.Notify(fmt.Errorf("Don't ignore this error")) - time.Sleep(100 * time.Millisecond) - bugsnag.Notify(fmt.Errorf("Change error message")) - time.Sleep(100 * time.Millisecond) -} - -func dontdie(w http.ResponseWriter, r *http.Request) { - defer bugsnag.Recover(r.Context()) - panic("Request killed but recovered") -} - -func user(w http.ResponseWriter, r *http.Request) { - bugsnag.Notify(fmt.Errorf("oops"), r.Context(), bugsnag.User{ - Id: "test-user-id", - Name: "test-user-name", - Email: "test-user-email", - }) -} From 5d80e4beca69bb487a3c27d9932a9174d2209f4f Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 16:27:14 +0200 Subject: [PATCH 09/16] Remove autoconfig and nethttp from docker-compose, use only real bugsnag env vars --- features/fixtures/docker-compose.yml | 51 ++-------------------------- 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/features/fixtures/docker-compose.yml b/features/fixtures/docker-compose.yml index 444f1e32..a48ece35 100644 --- a/features/fixtures/docker-compose.yml +++ b/features/fixtures/docker-compose.yml @@ -5,31 +5,11 @@ services: dockerfile: ./features/fixtures/app/Dockerfile args: - GO_VERSION + ports: + - "4512:4512" environment: - DEFAULT_MAZE_ADDRESS - - API_KEY - ERROR_CLASS - - BUGSNAG_ENDPOINT - - APP_VERSION - - APP_TYPE - - AUTO_CAPTURE_SESSIONS - - HOSTNAME - - NOTIFY_RELEASE_STAGES - - RELEASE_STAGE - - PARAMS_FILTERS - - SYNCHRONOUS - - SERVER_PORT - - BUGSNAG_SOURCE_ROOT - - BUGSNAG_PROJECT_PACKAGES - restart: "no" - - autoconfigure: - build: - context: . - dockerfile: autoconfigure/Dockerfile - args: - - GO_VERSION - environment: - BUGSNAG_API_KEY - BUGSNAG_APP_TYPE - BUGSNAG_APP_VERSION @@ -51,33 +31,6 @@ services: - BUGSNAG_METADATA_fruit_Tomato - BUGSNAG_METADATA_snacks_Carrot restart: "no" - command: go run . - - nethttp: - build: - context: . - dockerfile: net_http/Dockerfile - args: - - GO_VERSION - ports: - - "4512:4512" - environment: - - API_KEY - - ERROR_CLASS - - BUGSNAG_ENDPOINT - - APP_VERSION - - APP_TYPE - - HOSTNAME - - NOTIFY_RELEASE_STAGES - - RELEASE_STAGE - - PARAMS_FILTERS - - AUTO_CAPTURE_SESSIONS - - SYNCHRONOUS - - SERVER_PORT - - BUGSNAG_SOURCE_ROOT - - BUGSNAG_PROJECT_PACKAGES - restart: "no" - command: go run main.go gin: build: From ea2077b66a8e30412461807f1ef01b2ac78f0519 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 20:26:37 +0200 Subject: [PATCH 10/16] Rewrite basic features to new steps --- features/apptype.feature | 24 ++--- features/appversion.feature | 25 +++-- features/autonotify.feature | 15 +-- features/configuration.feature | 103 +++++++++++---------- features/endpoint.feature | 16 ---- features/handled.feature | 65 +++++++------ features/hostname.feature | 27 +++--- features/metadata.feature | 15 +-- features/multieventsession.feature | 21 ++--- features/onbeforenotify.feature | 17 ++-- features/paramfilters.feature | 31 +++---- features/plain_features/panics.feature | 25 ++--- features/recover.feature | 14 +-- features/releasestage.feature | 98 ++++++++++---------- features/sessioncontext.feature | 22 ++--- features/steps/go_steps.rb | 121 ------------------------- features/synchronous.feature | 20 ---- features/user.feature | 17 +--- 18 files changed, 227 insertions(+), 449 deletions(-) delete mode 100644 features/endpoint.feature delete mode 100644 features/synchronous.feature diff --git a/features/apptype.feature b/features/apptype.feature index efe897fc..0a48b079 100644 --- a/features/apptype.feature +++ b/features/apptype.feature @@ -1,22 +1,18 @@ Feature: Configuring app type Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "APP_TYPE" to "background-queue" - And I have built the service "app" + Given I set environment variable "BUGSNAG_APP_TYPE" to "background-queue" Scenario: An error report contains the configured app type when running a go app - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "app.type" equals "background-queue" Scenario: An session report contains the configured app type when running a go app - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I run the go service "app" with the test case "session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "app.type" equals "background-queue" - + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "SendSessionScenario" + And I wait to receive a session + And the session payload field "app.type" equals "background-queue" diff --git a/features/appversion.feature b/features/appversion.feature index 805bf940..1b66737c 100644 --- a/features/appversion.feature +++ b/features/appversion.feature @@ -1,21 +1,18 @@ Feature: Configuring app version Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "APP_VERSION" to "3.1.2" - And I have built the service "app" + And I set environment variable "BUGSNAG_APP_VERSION" to "3.1.2" Scenario: An error report contains the configured app type when running a go app - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "app.version" equals "3.1.2" -Scenario: An session report contains the configured app type when running a go app - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I run the go service "app" with the test case "session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "app.version" equals "3.1.2" +Scenario: A session report contains the configured app type when running a go app + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "SendSessionScenario" + And I wait to receive a session + And the session payload field "app.version" equals "3.1.2" \ No newline at end of file diff --git a/features/autonotify.feature b/features/autonotify.feature index 9a79dcfa..62dc508a 100644 --- a/features/autonotify.feature +++ b/features/autonotify.feature @@ -1,13 +1,8 @@ Feature: Using auto notify -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report is sent when an AutoNotified crash occurs which later gets recovered - When I run the go service "app" with the test case "autonotify" - Then I wait for 3 seconds - And the request 1 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the exception "errorClass" equals "*errors.errorString" for request 1 - And the exception "message" equals "Go routine killed with auto notify" for request 1 + When I start the service "app" + And I run "AutonotifyPanicScenario" + And I wait to receive an error + And the exception "errorClass" equals "*errors.errorString" + And the exception "message" equals "Go routine killed with auto notify" \ No newline at end of file diff --git a/features/configuration.feature b/features/configuration.feature index a5e374eb..6c3c1139 100644 --- a/features/configuration.feature +++ b/features/configuration.feature @@ -5,92 +5,97 @@ Feature: Configure integration with environment variables Background: Given I set environment variable "BUGSNAG_API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I set environment variable "BUGSNAG_NOTIFY_ENDPOINT" to the notify endpoint - And I set environment variable "BUGSNAG_SESSIONS_ENDPOINT" to the sessions endpoint - And I have built the service "autoconfigure" Scenario Outline: Adding content to handled events through env variables Given I set environment variable "" to "" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - When I run the go service "autoconfigure" with the test case "" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "" + And I wait to receive an error And the event "" equals "" Examples: | testcase | variable | value | field | - | panic | BUGSNAG_APP_VERSION | 1.4.34 | app.version | - | panic | BUGSNAG_APP_TYPE | mailer-daemon | app.type | - | panic | BUGSNAG_RELEASE_STAGE | beta1 | app.releaseStage | - | panic | BUGSNAG_HOSTNAME | dream-machine-2 | device.hostname | - | panic | BUGSNAG_METADATA_device_instance | kube2-33-A | metaData.device.instance | - | panic | BUGSNAG_METADATA_framework_version | v3.1.0 | metaData.framework.version | - | panic | BUGSNAG_METADATA_device_runtime_level | 1C | metaData.device.runtime_level | - | panic | BUGSNAG_METADATA_Carrot | orange | metaData.custom.Carrot | + | AutoconfigPanicScenario | BUGSNAG_APP_VERSION | 1.4.34 | app.version | + | AutoconfigPanicScenario | BUGSNAG_APP_TYPE | mailer-daemon | app.type | + | AutoconfigPanicScenario | BUGSNAG_RELEASE_STAGE | beta1 | app.releaseStage | + | AutoconfigPanicScenario | BUGSNAG_HOSTNAME | dream-machine-2 | device.hostname | + | AutoconfigPanicScenario | BUGSNAG_METADATA_device_instance | kube2-33-A | metaData.device.instance | + | AutoconfigPanicScenario | BUGSNAG_METADATA_framework_version | v3.1.0 | metaData.framework.version | + | AutoconfigPanicScenario | BUGSNAG_METADATA_device_runtime_level | 1C | metaData.device.runtime_level | + | AutoconfigPanicScenario | BUGSNAG_METADATA_Carrot | orange | metaData.custom.Carrot | - | handled | BUGSNAG_APP_VERSION | 1.4.34 | app.version | - | handled | BUGSNAG_APP_TYPE | mailer-daemon | app.type | - | handled | BUGSNAG_RELEASE_STAGE | beta1 | app.releaseStage | - | handled | BUGSNAG_HOSTNAME | dream-machine-2 | device.hostname | - | handled | BUGSNAG_METADATA_device_instance | kube2-33-A | metaData.device.instance | - | handled | BUGSNAG_METADATA_framework_version | v3.1.0 | metaData.framework.version | - | handled | BUGSNAG_METADATA_device_runtime_level | 1C | metaData.device.runtime_level | - | handled | BUGSNAG_METADATA_Carrot | orange | metaData.custom.Carrot | + | AutoconfigHandledScenario | BUGSNAG_APP_VERSION | 1.4.34 | app.version | + | AutoconfigHandledScenario | BUGSNAG_APP_TYPE | mailer-daemon | app.type | + | AutoconfigHandledScenario | BUGSNAG_RELEASE_STAGE | beta1 | app.releaseStage | + | AutoconfigHandledScenario | BUGSNAG_HOSTNAME | dream-machine-2 | device.hostname | + | AutoconfigHandledScenario | BUGSNAG_METADATA_device_instance | kube2-33-A | metaData.device.instance | + | AutoconfigHandledScenario | BUGSNAG_METADATA_framework_version | v3.1.0 | metaData.framework.version | + | AutoconfigHandledScenario | BUGSNAG_METADATA_device_runtime_level | 1C | metaData.device.runtime_level | + | AutoconfigHandledScenario | BUGSNAG_METADATA_Carrot | orange | metaData.custom.Carrot | Scenario: Configuring project packages Given I set environment variable "BUGSNAG_PROJECT_PACKAGES" to "main,test" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - When I run the go service "autoconfigure" with the test case "panic" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the in-project frames of the stacktrace are: - | file | method | lineNumber | - | cases.go | explicitPanic | 22 | - | main.go | main | 11 | + When I start the service "app" + And I run "AutoconfigPanicScenario" + And I wait to receive an error + And the "file" of stack frame 0 equals "features/fixtures/app/autoconfig_scenario.go" + And the "method" of stack frame 0 equals "AutoconfigPanicScenario.func1" + And the "lineNumber" of stack frame 0 equals 11 + And the "file" of stack frame 1 equals "features/fixtures/app/main.go" + And the "method" of stack frame 1 equals "main" + And the "lineNumber" of stack frame 1 equals 65 Scenario: Configuring source root - Given I set environment variable "BUGSNAG_SOURCE_ROOT" to the app directory + Given I set environment variable "BUGSNAG_SOURCE_ROOT" to "/app/src/features/fixtures/app/" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - And I run the go service "autoconfigure" with the test case "panic" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the in-project frames of the stacktrace are: - | file | method | lineNumber | - | cases.go | explicitPanic | 22 | - | main.go | main | 11 | + When I start the service "app" + And I run "AutoconfigPanicScenario" + And I wait to receive an error + And the "file" of stack frame 0 equals "autoconfig_scenario.go" + And the "method" of stack frame 0 equals "AutoconfigPanicScenario.func1" + And the "lineNumber" of stack frame 0 equals 11 + And the "file" of stack frame 1 equals "main.go" + And the "method" of stack frame 1 equals "main" + And the "lineNumber" of stack frame 1 equals 65 Scenario: Delivering events filtering through notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "prod,beta" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "beta" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - And I run the go service "autoconfigure" with the test case "panic" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "AutoconfigPanicScenario" + And I wait to receive an error Scenario: Suppressing events through notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "prod,beta" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "dev" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - And I run the go service "autoconfigure" with the test case "panic" - Then 0 requests were received + When I start the service "app" + And I run "AutoconfigPanicScenario" + Then I should receive no errors Scenario: Suppressing events using panic handler Given I set environment variable "BUGSNAG_DISABLE_PANIC_HANDLER" to "1" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - And I run the go service "autoconfigure" with the test case "panic" + When I start the service "app" + And I run "AutoconfigPanicScenario" And I wait for 2 seconds - Then 0 requests were received + Then I should receive no errors Scenario: Enabling synchronous event delivery Given I set environment variable "BUGSNAG_SYNCHRONOUS" to "1" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - When I run the go service "autoconfigure" with the test case "handled" - Then 1 request was received + When I start the service "app" + And I run "AutoconfigHandledScenario" + And I wait to receive an error Scenario: Filtering metadata Given I set environment variable "BUGSNAG_PARAMS_FILTERS" to "tomato,pears" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" - When I run the go service "autoconfigure" with the test case "handled-metadata" - Then I wait to receive a request + When I start the service "app" + And I run "AutoconfigMetadataScenario" + And I wait to receive an error And the event "metaData.fruit.Tomato" equals "[FILTERED]" - And the event "metaData.snacks.Carrot" equals "4" + And the event "metaData.snacks.Carrot" equals "4" \ No newline at end of file diff --git a/features/endpoint.feature b/features/endpoint.feature deleted file mode 100644 index 803f6f4b..00000000 --- a/features/endpoint.feature +++ /dev/null @@ -1,16 +0,0 @@ -Feature: Configuring endpoint - -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - -Scenario: An error report is sent successfully using the notify endpoint only - When I run the go service "app" with the test case "endpoint-notify" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - -Scenario: Configuring Bugsnag will panic if the sessions endpoint is configured without the notify endpoint - When I run the go service "app" with the test case "endpoint-session" - And I wait for 3 second - Then I should receive no requests diff --git a/features/handled.feature b/features/handled.feature index a7797a8a..2a69b66e 100644 --- a/features/handled.feature +++ b/features/handled.feature @@ -1,70 +1,67 @@ Feature: Plain handled errors Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - Given I set environment variable "BUGSNAG_SOURCE_ROOT" to the app directory - And I configure the bugsnag endpoint - And I have built the service "app" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_SOURCE_ROOT" to "/app/src/features/fixtures/app/" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" Scenario: A handled error sends a report - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "warning" And the event "severityReason.type" equals "handledError" - And the exception is a PathError for request 0 - And the "file" of stack frame 0 equals "main.go" + And the exception "errorClass" equals "*fs.PathError" + And the "file" of stack frame 0 equals "handled_scenario.go" Scenario: A handled error sends a report with a custom name Given I set environment variable "ERROR_CLASS" to "MyCustomErrorClass" - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "warning" And the event "severityReason.type" equals "handledError" And the exception "errorClass" equals "MyCustomErrorClass" - And the "file" of stack frame 0 equals "main.go" + And the "file" of stack frame 0 equals "handled_scenario.go" Scenario: Sending an event using a callback to modify report contents - When I run the go service "app" with the test case "handled-with-callback" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "HandledCallbackErrorScenario" + And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "info" And the event "severityReason.type" equals "userCallbackSetSeverity" And the event "context" equals "nonfatal.go:14" - And the "file" of stack frame 0 equals "main.go" - And stack frame 0 contains a local function spanning 245 to 253 + And the "file" of stack frame 0 equals "handled_scenario.go" + And the "lineNumber" of stack frame 0 equals 59 And the "file" of stack frame 1 equals ">insertion<" And the "lineNumber" of stack frame 1 equals 0 Scenario: Marking an error as unhandled in a callback - When I run the go service "app" with the test case "make-unhandled-with-callback" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "HandledToUnhandledScenario" + And I wait to receive an error And the event "unhandled" is true And the event "severity" equals "error" And the event "severityReason.type" equals "userCallbackSetSeverity" And the event "severityReason.unhandledOverridden" is true - And the "file" of stack frame 0 equals "main.go" - And stack frame 0 contains a local function spanning 257 to 262 + And the "file" of stack frame 0 equals "handled_scenario.go" + And the "lineNumber" of stack frame 0 equals 72 Scenario: Unwrapping the causes of a handled error - When I run the go service "app" with the test case "nested-error" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "NestedErrorScenario" + And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "warning" And the event "exceptions.0.message" equals "terminate process" - And the "lineNumber" of stack frame 0 equals 295 - And the "file" of stack frame 0 equals "main.go" - And the "method" of stack frame 0 equals "nestedHandledError" + And the "lineNumber" of stack frame 0 equals 40 + And the "file" of stack frame 0 equals "handled_scenario.go" + And the "method" of stack frame 0 equals "NestedHandledErrorScenario.func1" And the event "exceptions.1.message" equals "login failed" - And the event "exceptions.1.stacktrace.0.file" equals "main.go" - And the event "exceptions.1.stacktrace.0.lineNumber" equals 315 + And the event "exceptions.1.stacktrace.0.file" equals "utils.go" + And the event "exceptions.1.stacktrace.0.lineNumber" equals 39 And the event "exceptions.2.message" equals "invalid token" - And the event "exceptions.2.stacktrace.0.file" equals "main.go" - And the event "exceptions.2.stacktrace.0.lineNumber" equals 323 + And the event "exceptions.2.stacktrace.0.file" equals "utils.go" + And the event "exceptions.2.stacktrace.0.lineNumber" equals 47 \ No newline at end of file diff --git a/features/hostname.feature b/features/hostname.feature index 14c72c90..f05e7fef 100644 --- a/features/hostname.feature +++ b/features/hostname.feature @@ -1,22 +1,17 @@ Feature: Configuring hostname -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report contains the configured hostname - Given I set environment variable "HOSTNAME" to "server-1a" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I run the go service "app" with the test case "handled" - And I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_HOSTNAME" to "server-1a" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "device.hostname" equals "server-1a" Scenario: An session report contains the configured hostname - Given I set environment variable "HOSTNAME" to "server-1a" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I run the go service "app" with the test case "session" - And I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "device.hostname" equals "server-1a" + Given I set environment variable "BUGSNAG_HOSTNAME" to "server-1a" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "SendSessionScenario" + And I wait to receive a session + And the session payload field "device.hostname" equals "server-1a" \ No newline at end of file diff --git a/features/metadata.feature b/features/metadata.feature index 94a8bbf6..a2995445 100644 --- a/features/metadata.feature +++ b/features/metadata.feature @@ -1,15 +1,10 @@ Feature: Sending meta data -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report contains custom meta data - When I run the go service "app" with the test case "metadata" - And I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I start the service "app" + And I run "MetadataScenario" + And I wait to receive an error And the event "metaData.Scheme.Customer.Name" equals "Joe Bloggs" And the event "metaData.Scheme.Customer.Age" equals "21" - And the event "metaData.Scheme.Level" equals "Blue" + And the event "metaData.Scheme.Level" equals "Blue" \ No newline at end of file diff --git a/features/multieventsession.feature b/features/multieventsession.feature index e9e4dbc1..91478eba 100644 --- a/features/multieventsession.feature +++ b/features/multieventsession.feature @@ -1,23 +1,18 @@ Feature: Reporting multiple handled and unhandled errors in the same session Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" Scenario: Handled errors know about previous reported handled errors - When I run the go service "app" with the test case "multiple-handled" - And I wait to receive 2 requests - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the request 1 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "MultipleHandledScenario" + And I wait to receive 2 errors And the event handled sessions count equals 1 for request 0 And the event handled sessions count equals 2 for request 1 Scenario: Unhandled errors know about previous reported handled errors - When I run the go service "app" with the test case "multiple-unhandled" - And I wait to receive 2 requests - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the request 1 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "MultipleUnhandledScenario" + And I wait to receive 2 errors And the event unhandled sessions count equals 1 for request 0 - And the event unhandled sessions count equals 2 for request 1 + And the event unhandled sessions count equals 2 for request 1 \ No newline at end of file diff --git a/features/onbeforenotify.feature b/features/onbeforenotify.feature index 7b4b332f..a53fe1f0 100644 --- a/features/onbeforenotify.feature +++ b/features/onbeforenotify.feature @@ -1,14 +1,9 @@ Feature: Configuring on before notify -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: Send three bugsnags and use on before notify to drop one and modify the message of another - When I run the go service "app" with the test case "onbeforenotify" - Then I wait to receive 2 requests after the start up session - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the exception "message" equals "Don't ignore this error" for request 0 - And the request 1 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the exception "message" equals "Error message was changed" for request 1 + When I start the service "app" + And I run "OnBeforeNotifyScenario" + And I wait to receive 2 errors + And the exception "message" equals "don't ignore this error" + And I discard the oldest error + And the exception "message" equals "error message was changed" \ No newline at end of file diff --git a/features/paramfilters.feature b/features/paramfilters.feature index d1b714b8..58f2c7d8 100644 --- a/features/paramfilters.feature +++ b/features/paramfilters.feature @@ -1,29 +1,22 @@ Feature: Configuring param filters -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report containing meta data is not filtered when the param filters are set but do not match - Given I set environment variable "PARAMS_FILTERS" to "Name" - When I run the go service "app" with the test case "filtered" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_PARAMS_FILTERS" to "Name" + When I start the service "app" + And I run "FilteredMetadataScenario" + And I wait to receive an error And the event "metaData.Account.Price(dollars)" equals "1 Million" Scenario: An error report containing meta data is filtered when the param filters are set and completely match - Given I set environment variable "PARAMS_FILTERS" to "Price(dollars)" - When I run the go service "app" with the test case "filtered" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_PARAMS_FILTERS" to "Price(dollars)" + When I start the service "app" + And I run "FilteredMetadataScenario" + And I wait to receive an error And the event "metaData.Account.Price(dollars)" equals "[FILTERED]" Scenario: An error report containing meta data is filtered when the param filters are set and partially match - Given I set environment variable "PARAMS_FILTERS" to "Price" - When I run the go service "app" with the test case "filtered" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_PARAMS_FILTERS" to "Price" + When I start the service "app" + And I run "FilteredMetadataScenario" + And I wait to receive an error And the event "metaData.Account.Price(dollars)" equals "[FILTERED]" - diff --git a/features/plain_features/panics.feature b/features/plain_features/panics.feature index 2f239a3b..6e9e3174 100644 --- a/features/plain_features/panics.feature +++ b/features/plain_features/panics.feature @@ -1,24 +1,19 @@ Feature: Panic handling Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - Given I set environment variable "BUGSNAG_SOURCE_ROOT" to the app directory - And I configure the bugsnag endpoint - And I have built the service "app" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_SOURCE_ROOT" to "/app/src/features/fixtures/app/" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" Scenario: Capturing a panic - When I run the go service "app" with the test case "unhandled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "UnhandledScenario" + And I wait to receive an error And the event "unhandled" is true And the event "severity" equals "error" And the event "severityReason.type" equals "unhandledPanic" And the exception "errorClass" equals "panic" - And the exception "message" is one of: - | interface conversion: interface is struct {}, not string | - | interface conversion: interface {} is struct {}, not string | - And the in-project frames of the stacktrace are: - | file | method | - | main.go | unhandledCrash.func1 | - | main.go | unhandledCrash | + And the exception "message" matches "^interface conversion: interface.*?is struct {}, not string" + And the "file" of stack frame 0 equals "unhandled_scenario.go" + And the "method" of stack frame 0 equals "UnhandledCrashScenario.func1.1" + And the "file" of stack frame 1 equals "unhandled_scenario.go" + And the "method" of stack frame 1 equals "UnhandledCrashScenario.func1" \ No newline at end of file diff --git a/features/recover.feature b/features/recover.feature index cbdb1f55..8df1bf2a 100644 --- a/features/recover.feature +++ b/features/recover.feature @@ -1,14 +1,8 @@ Feature: Using recover -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report is sent when a go routine crashes but recovers - When I run the go service "app" with the test case "recover" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "RecoverAfterPanicScenario" + And I wait to receive an error And the exception "errorClass" equals "*errors.errorString" - And the exception "message" equals "Go routine killed but recovered" + And the exception "message" equals "Go routine killed but recovered" \ No newline at end of file diff --git a/features/releasestage.feature b/features/releasestage.feature index 6b16ee48..e5dd56c8 100644 --- a/features/releasestage.feature +++ b/features/releasestage.feature @@ -1,71 +1,65 @@ Feature: Configuring release stages and notify release stages -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report is sent when release stage matches notify release stages - Given I set environment variable "NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I set environment variable "RELEASE_STAGE" to "stage2" - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "app.releaseStage" equals "stage2" Scenario: An error report is sent when no notify release stages are specified - Given I set environment variable "RELEASE_STAGE" to "stage2" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error And the event "app.releaseStage" equals "stage2" Scenario: An error report is sent regardless of notify release stages if release stage is not set - Given I set environment variable "NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I run the go service "app" with the test case "handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HandledScenario" + And I wait to receive an error Scenario: An error report is not sent if the release stage does not match the notify release stages - Given I set environment variable "NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I set environment variable "RELEASE_STAGE" to "stage4" - When I run the go service "app" with the test case "handled" - And I wait for 3 second - Then I should receive no requests + Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage4" + When I start the service "app" + And I run "HandledScenario" + And I should receive no errors Scenario: An session report is sent when release stage matches notify release stages - Given I set environment variable "NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - And I set environment variable "RELEASE_STAGE" to "stage2" - When I run the go service "app" with the test case "session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "app.releaseStage" equals "stage2" + Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" + When I start the service "app" + And I run "SendSessionScenario" + And I wait to receive a session + And the session payload field "app.releaseStage" equals "stage2" Scenario: An session report is sent when no notify release stages are specified - Given I set environment variable "RELEASE_STAGE" to "stage2" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I run the go service "app" with the test case "session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "app.releaseStage" equals "stage2" + Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "SendSessionScenario" + And I wait to receive a session + And the session payload field "app.releaseStage" equals "stage2" Scenario: An session report is sent regardless of notify release stages if release stage is not set - Given I set environment variable "NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I run the go service "app" with the test case "session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "SendSessionScenario" + And I wait to receive a session Scenario: An session report is not sent if the release stage does not match the notify release stages - Given I set environment variable "NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - And I set environment variable "RELEASE_STAGE" to "stage4" - When I run the go service "app" with the test case "session" - And I wait for 3 second - Then I should receive no requests - + Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage4" + When I start the service "app" + And I run "SendSessionScenario" + And I should receive no sessions diff --git a/features/sessioncontext.feature b/features/sessioncontext.feature index 0b986395..8cc09a14 100644 --- a/features/sessioncontext.feature +++ b/features/sessioncontext.feature @@ -1,15 +1,13 @@ Feature: Session data inside an error report using a session context -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report contains a session count when part of a session - When I run the go service "app" with the test case "session-and-error" - Then I wait to receive 2 requests after the start up session - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the request 1 is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the event handled sessions count equals 1 for request 0 - And the event unhandled sessions count equals 0 for request 0 - And the number of sessions started equals 1 for request 1 + When I start the service "app" + And I run "SessionAndErrorScenario" + Then I wait to receive 1 error + # one session is created on start + And I wait to receive 2 session + And the error is valid for the error reporting API version "4" for the "Bugsnag Go" notifier + And the session is valid for the session reporting API version "1.0" for the "Bugsnag Go" notifier + And I discard the oldest session + And the session is valid for the session reporting API version "1.0" for the "Bugsnag Go" notifier + And the session payload has a valid sessions array \ No newline at end of file diff --git a/features/steps/go_steps.rb b/features/steps/go_steps.rb index 001a5ca9..cdc1678f 100644 --- a/features/steps/go_steps.rb +++ b/features/steps/go_steps.rb @@ -40,124 +40,3 @@ def local_ip ip_list.captures.first end end - -Given("I set environment variable {string} to the app directory") do |key| - step("I set environment variable \"#{key}\" to \"/app/src/test/\"") -end - -Given("I set environment variable {string} to the notify endpoint") do |key| - step("I set environment variable \"#{key}\" to \"http://#{current_ip}:#{MOCK_API_PORT}\"") -end - -Given("I set environment variable {string} to the sessions endpoint") do |key| - # they're the same picture dot gif - # split them out for the future endpoint splitting work - step("I set environment variable \"#{key}\" to \"http://#{current_ip}:#{MOCK_API_PORT}\"") -end - -Then(/^the request(?: (\d+))? is a valid error report with api key "(.*)"$/) do |request_index, api_key| - request_index ||= 0 - steps %Q{ - And the request #{request_index} is valid for the error reporting API - And the "bugsnag-api-key" header equals "#{api_key}" for request #{request_index} - And the payload field "apiKey" equals "#{api_key}" for request #{request_index} - } -end - -Then(/^the exception is a PathError for request (\d+)$/) do |request_index| - body = find_request(request_index)[:body] - error_class = body["events"][0]["exceptions"][0]["errorClass"] - if ['1.11', '1.12', '1.13', '1.14', '1.15'].include? ENV['GO_VERSION'] - assert_equal(error_class, '*os.PathError') - else - assert_equal(error_class, '*fs.PathError') - end -end - -Then(/^the request(?: (\d+))? is a valid session report with api key "(.*)"$/) do |request_index, api_key| - request_index ||= 0 - steps %Q{ - And the request #{request_index} is valid for the session tracking API - And the "bugsnag-api-key" header equals "#{api_key}" for request #{request_index} - } -end - -Then(/^the event unhandled sessions count equals (\d+) for request (\d+)$/) do |count, request_index| - step "the payload field \"events.0.session.events.unhandled\" equals #{count} for request #{request_index}" -end - -Then(/^the event handled sessions count equals (\d+) for request (\d+)$/) do |count, request_index| - step "the payload field \"events.0.session.events.handled\" equals #{count} for request #{request_index}" -end - -Then(/^the number of sessions started equals (\d+) for request (\d+)$/) do |count, request_index| - step "the payload field \"sessionCounts.0.sessionsStarted\" equals #{count} for request #{request_index}" -end - -When("I run the go service {string} with the test case {string}") do |service, testcase| - run_service_with_command(service, "./run.sh go run . -test=\"#{testcase}\"") -end - -Then(/^I wait to receive a request after the start up session$/) do - step "I wait to receive 1 requests after the start up session" -end - -Then(/^I wait to receive (\d+) requests after the start up session?$/) do |request_count| - max_attempts = 50 - attempts = 0 - start_up_message_received = false - start_up_message_removed = false - received = false - until (attempts >= max_attempts) || received - attempts += 1 - start_up_message_received ||= (stored_requests.size == 1) - if start_up_message_received && !start_up_message_removed - step 'the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa"' - stored_requests.shift - start_up_message_removed = true - next - end - received = (stored_requests.size == request_count) - sleep 0.2 - end - raise "Requests not received in 10s (received #{stored_requests.size})" unless received - # Wait an extra second to ensure there are no further requests - sleep 1 - assert_equal(request_count, stored_requests.size, "#{stored_requests.size} requests received") -end - -Then(/^(\d+) requests? (?:was|were) received$/) do |request_count| - sleep 1 - assert_equal(request_count, stored_requests.size, "#{stored_requests.size} requests received") -end - -Then("the in-project frames of the stacktrace are:") do |table| - body = find_request(0)[:body] - stacktrace = body["events"][0]["exceptions"][0]["stacktrace"] - found = 0 # counts matching frames and ensures ordering is correct - expected = table.hashes.length - stacktrace.each do |frame| - if found < expected and frame["inProject"] and - frame["file"] == table.hashes[found]["file"] and - frame["method"] == table.hashes[found]["method"] - found = found + 1 - end - end - assert_equal(found, expected, "expected #{expected} matching frames but found #{found}. stacktrace:\n#{stacktrace}") -end - -Then("stack frame {int} contains a local function spanning {int} to {int}") do |frame, val, old_val| - # Old versions of Go put the line number on the end of the function - if ['1.7', '1.8'].include? ENV['GO_VERSION'] - step "the \"lineNumber\" of stack frame #{frame} equals #{old_val}" - else - step "the \"lineNumber\" of stack frame #{frame} equals #{val}" - end -end - -Then("the exception {string} is one of:") do |key, table| - body = find_request(0)[:body] - exception = body["events"][0]["exceptions"][0] - options = table.raw.flatten - assert(options.include?(exception[key]), "expected '#{key}' to be one of #{options}") -end diff --git a/features/synchronous.feature b/features/synchronous.feature deleted file mode 100644 index 0a132c48..00000000 --- a/features/synchronous.feature +++ /dev/null @@ -1,20 +0,0 @@ -Feature: Configuring synchronous flag - -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I configure the bugsnag endpoint - And I have built the service "app" - -Scenario: An error report is sent asynchrously but exits immediately so is not sent - Given I set environment variable "SYNCHRONOUS" to "false" - When I run the go service "app" with the test case "send-and-exit" - And I wait for 3 second - Then I should receive no requests - -Scenario: An error report is report synchronously so it will send before exiting - Given I set environment variable "SYNCHRONOUS" to "true" - When I run the go service "app" with the test case "send-and-exit" - Then I wait to receive 1 requests - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - diff --git a/features/user.feature b/features/user.feature index 49040ac1..4cae7234 100644 --- a/features/user.feature +++ b/features/user.feature @@ -1,18 +1,9 @@ Feature: Sending user data -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - And I configure the bugsnag endpoint - And I have built the service "app" - Scenario: An error report contains custom user data - Given I set environment variable "USER_ID" to "test-user-id" - And I set environment variable "USER_NAME" to "test-user-name" - And I set environment variable "USER_EMAIL" to "test-user-email" - When I run the go service "app" with the test case "user" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I start the service "app" + And I run "SetUserScenario" + And I wait to receive an error And the event "user.id" equals "test-user-id" And the event "user.name" equals "test-user-name" - And the event "user.email" equals "test-user-email" + And the event "user.email" equals "test-user-email" \ No newline at end of file From 6ae818368099a40ea7323fd39360be415aa7c6c0 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Tue, 20 Aug 2024 20:32:41 +0200 Subject: [PATCH 11/16] Rewrite nethttp features to new steps --- features/net-http/appversion.feature | 31 +++++++------- features/net-http/autocapturesessions.feature | 24 ----------- features/net-http/autonotify.feature | 27 +++++------- features/net-http/handled.feature | 42 +++++++++---------- features/net-http/onbeforenotify.feature | 20 ++++----- features/net-http/recover.feature | 18 +++----- features/net-http/releasestage.feature | 30 +++++++------ features/net-http/request.feature | 16 +++---- features/net-http/user.feature | 19 +++------ 9 files changed, 82 insertions(+), 145 deletions(-) delete mode 100644 features/net-http/autocapturesessions.feature diff --git a/features/net-http/appversion.feature b/features/net-http/appversion.feature index 06e9f61e..c7759362 100644 --- a/features/net-http/appversion.feature +++ b/features/net-http/appversion.feature @@ -1,28 +1,27 @@ Feature: Configuring app version Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "APP_VERSION" to "3.1.2" - And I set environment variable "SERVER_PORT" to "4512" + And I set environment variable "BUGSNAG_APP_VERSION" to "3.1.2" Scenario: A error report contains the configured app type when using a net http app - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I start the service "nethttp" - And I wait for the app to open port "4512" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + And I wait to receive an error + And I should receive no sessions + And the error is valid for the error reporting API version "4" for the "Bugsnag Go" notifier And the event "app.version" equals "3.1.2" Scenario: A session report contains the configured app type when using a net http app - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I start the service "nethttp" - And I wait for the app to open port "4512" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "app.version" equals "3.1.2" - + And I wait to receive a session + And the session is valid for the session reporting API version "1.0" for the "Bugsnag Go" notifier + And the session payload field "sessions.0.app.version" equals "3.1.2" diff --git a/features/net-http/autocapturesessions.feature b/features/net-http/autocapturesessions.feature deleted file mode 100644 index b7f00bb4..00000000 --- a/features/net-http/autocapturesessions.feature +++ /dev/null @@ -1,24 +0,0 @@ -Feature: Configure auto capture sessions - -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - -Scenario: A session is not sent if auto capture sessions is off - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I start the service "nethttp" - And I wait for the app to open port "4512" - And I wait for 2 seconds - And I open the URL "http://localhost:4512/session" - And I wait for 2 seconds - Then I should receive no requests - -Scenario: A session is sent if auto capture sessions is on - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I start the service "nethttp" - And I wait for the app to open port "4512" - And I wait for 2 seconds - And I open the URL "http://localhost:4512/session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" diff --git a/features/net-http/autonotify.feature b/features/net-http/autonotify.feature index baf4198c..997a741c 100644 --- a/features/net-http/autonotify.feature +++ b/features/net-http/autonotify.feature @@ -1,30 +1,25 @@ Feature: Using auto notify -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - Scenario: An error report is sent when an AutoNotified crash occurs which later gets recovered - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I start the service "nethttp" - And I wait for the app to open port "4512" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/autonotify-then-recover" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Then I wait to receive an error And the event "unhandled" is true And the exception "errorClass" equals "*runtime.TypeAssertionError" And the exception "message" matches "interface conversion: interface ({} )?is struct {}, not string" Scenario: An error report is sent when a go routine crashes which is reported through auto notify - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I start the service "nethttp" - And I wait for the app to open port "4512" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/autonotify" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Then I wait to receive an error And the event "unhandled" is true And the exception "errorClass" equals "*errors.errorString" - And the exception "message" equals "Go routine killed with auto notify" + And the exception "message" equals "Go routine killed with auto notify" \ No newline at end of file diff --git a/features/net-http/handled.feature b/features/net-http/handled.feature index 4c9eb4cc..f84dd335 100644 --- a/features/net-http/handled.feature +++ b/features/net-http/handled.feature @@ -1,35 +1,31 @@ Feature: Handled errors Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - Given I set environment variable "BUGSNAG_SOURCE_ROOT" to the app directory - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_SOURCE_ROOT" to "/app/src/features/fixtures/app/" Scenario: A handled error sends a report - When I start the service "nethttp" - And I wait for the app to open port "4512" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" - Then I wait to receive a request - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the event "unhandled" is false for request 0 - And the event "severity" equals "warning" for request 0 - And the event "severityReason.type" equals "handledError" for request 0 - And the exception is a PathError for request 0 - And the "file" of stack frame 0 equals "main.go" for request 0 + Then I wait to receive an error + And the event "unhandled" is false + And the event "severity" equals "warning" + And the event "severityReason.type" equals "handledError" + And the exception "errorClass" equals "*os.PathError" + And the "file" of stack frame 0 equals "nethttp_scenario.go" Scenario: A handled error sends a report with a custom name Given I set environment variable "ERROR_CLASS" to "MyCustomErrorClass" - When I start the service "nethttp" - And I wait for the app to open port "4512" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" - Then I wait to receive a request - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the event "unhandled" is false for request 0 - And the event "severity" equals "warning" for request 0 - And the event "severityReason.type" equals "handledError" for request 0 - And the exception "errorClass" equals "MyCustomErrorClass" for request 0 - And the "file" of stack frame 0 equals "main.go" for request 0 + Then I wait to receive an error + And the event "unhandled" is false + And the event "severity" equals "warning" + And the event "severityReason.type" equals "handledError" + And the exception "errorClass" equals "MyCustomErrorClass" + And the "file" of stack frame 0 equals "nethttp_scenario.go" \ No newline at end of file diff --git a/features/net-http/onbeforenotify.feature b/features/net-http/onbeforenotify.feature index d0b519c4..46c02412 100644 --- a/features/net-http/onbeforenotify.feature +++ b/features/net-http/onbeforenotify.feature @@ -1,18 +1,12 @@ Feature: Configuring on before notify -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - Scenario: Send three bugsnags and use on before notify to drop one and modify the message of another - When I start the service "nethttp" - And I wait for the app to open port "4512" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/onbeforenotify" - Then I wait to receive 2 requests - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the exception "message" equals "Don't ignore this error" for request 0 - And the request 1 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the exception "message" equals "Error message was changed" for request 1 + Then I wait to receive 2 errors + And the exception "message" equals "Don't ignore this error" + And I discard the oldest error + And the exception "message" equals "Error message was changed" \ No newline at end of file diff --git a/features/net-http/recover.feature b/features/net-http/recover.feature index 5f64d78b..d5f5f10c 100644 --- a/features/net-http/recover.feature +++ b/features/net-http/recover.feature @@ -1,17 +1,11 @@ Feature: Using recover -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - Scenario: An error report is sent when request crashes but is recovered - When I start the service "nethttp" - And I wait for the app to open port "4512" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/recover" - Then I wait to receive a request - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the exception "errorClass" equals "*errors.errorString" for request 0 - And the exception "message" equals "Request killed but recovered" for request 0 + Then I wait to receive an error + And the exception "errorClass" equals "*errors.errorString" + And the exception "message" equals "Request killed but recovered" \ No newline at end of file diff --git a/features/net-http/releasestage.feature b/features/net-http/releasestage.feature index e1b50169..17771eca 100644 --- a/features/net-http/releasestage.feature +++ b/features/net-http/releasestage.feature @@ -1,27 +1,25 @@ Feature: Configuring release stage Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - And I set environment variable "RELEASE_STAGE" to "my-stage" + Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "my-stage" Scenario: An error report is sent with configured release stage - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I start the service "nethttp" - And I wait for the app to open port "4512" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" - Then I wait to receive a request - And the request 0 is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the event "app.releaseStage" equals "my-stage" for request 0 + Then I wait to receive an error + And the event "app.releaseStage" equals "my-stage" Scenario: A session report contains the configured app type - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "true" - When I start the service "nethttp" - And I wait for the app to open port "4512" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/session" - Then I wait to receive a request after the start up session - And the request is a valid session report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the payload field "app.releaseStage" equals "my-stage" + Then I wait to receive a session + And I wait to receive an error + And the session payload field "sessions.0.app.releaseStage" equals "my-stage" \ No newline at end of file diff --git a/features/net-http/request.feature b/features/net-http/request.feature index ecf7f347..559db0c1 100644 --- a/features/net-http/request.feature +++ b/features/net-http/request.feature @@ -1,20 +1,14 @@ Feature: Capturing request information automatically -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - Scenario: An error report will automatically contain request information - Given I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - When I start the service "nethttp" - And I wait for the app to open port "4512" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Then I wait to receive an error And the event "request.clientIp" is not null And the event "request.headers.User-Agent" equals "Ruby" And the event "request.httpMethod" equals "GET" And the event "request.url" ends with "/handled" - And the event "request.url" starts with "http://" + And the event "request.url" starts with "http://" \ No newline at end of file diff --git a/features/net-http/user.feature b/features/net-http/user.feature index dd03d9cd..c1c67c8b 100644 --- a/features/net-http/user.feature +++ b/features/net-http/user.feature @@ -1,21 +1,12 @@ Feature: Sending user data -Background: - Given I set environment variable "API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" - And I configure the bugsnag endpoint - And I set environment variable "SERVER_PORT" to "4512" - And I set environment variable "AUTO_CAPTURE_SESSIONS" to "false" - Scenario: An error report contains custom user data - Given I set environment variable "USER_ID" to "test-user-id" - And I set environment variable "USER_NAME" to "test-user-name" - And I set environment variable "USER_EMAIL" to "test-user-email" - When I start the service "nethttp" - And I wait for the app to open port "4512" + When I start the service "app" + And I run "HttpServerScenario" + And I wait for the host "localhost" to open port "4512" And I wait for 2 seconds And I open the URL "http://localhost:4512/user" - Then I wait to receive a request - And the request is a valid error report with api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + Then I wait to receive an error And the event "user.id" equals "test-user-id" And the event "user.name" equals "test-user-name" - And the event "user.email" equals "test-user-email" + And the event "user.email" equals "test-user-email" \ No newline at end of file From 97aa5f1c6ab8ea3777b4c47fc9ddd6e451164b9c Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Wed, 21 Aug 2024 13:20:21 +0200 Subject: [PATCH 12/16] Fix auto session value in tests - number instead of string --- features/apptype.feature | 4 ++-- features/appversion.feature | 4 ++-- features/autonotify.feature | 7 +++++-- features/configuration.feature | 1 - features/handled.feature | 4 ++-- features/hostname.feature | 4 ++-- features/metadata.feature | 2 +- features/multieventsession.feature | 2 +- features/net-http/appversion.feature | 8 +++----- features/net-http/autonotify.feature | 6 ++---- features/net-http/handled.feature | 2 -- features/net-http/onbeforenotify.feature | 1 - features/net-http/recover.feature | 1 - features/net-http/releasestage.feature | 9 +++------ features/net-http/request.feature | 1 - features/net-http/user.feature | 1 - features/plain_features/panics.feature | 2 +- features/releasestage.feature | 16 ++++++++-------- 18 files changed, 32 insertions(+), 43 deletions(-) diff --git a/features/apptype.feature b/features/apptype.feature index 0a48b079..0a408717 100644 --- a/features/apptype.feature +++ b/features/apptype.feature @@ -4,14 +4,14 @@ Background: Given I set environment variable "BUGSNAG_APP_TYPE" to "background-queue" Scenario: An error report contains the configured app type when running a go app - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HandledScenario" And I wait to receive an error And the event "app.type" equals "background-queue" Scenario: An session report contains the configured app type when running a go app - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" And I wait to receive a session diff --git a/features/appversion.feature b/features/appversion.feature index 1b66737c..ffda5546 100644 --- a/features/appversion.feature +++ b/features/appversion.feature @@ -4,14 +4,14 @@ Background: And I set environment variable "BUGSNAG_APP_VERSION" to "3.1.2" Scenario: An error report contains the configured app type when running a go app - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HandledScenario" And I wait to receive an error And the event "app.version" equals "3.1.2" Scenario: A session report contains the configured app type when running a go app - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" And I wait to receive a session diff --git a/features/autonotify.feature b/features/autonotify.feature index 62dc508a..5dad68f1 100644 --- a/features/autonotify.feature +++ b/features/autonotify.feature @@ -3,6 +3,9 @@ Feature: Using auto notify Scenario: An error report is sent when an AutoNotified crash occurs which later gets recovered When I start the service "app" And I run "AutonotifyPanicScenario" - And I wait to receive an error + And I wait to receive 2 errors And the exception "errorClass" equals "*errors.errorString" - And the exception "message" equals "Go routine killed with auto notify" \ No newline at end of file + And the exception "message" equals "Go routine killed with auto notify" + And I discard the oldest error + And the exception "errorClass" equals "panic" + And the exception "message" equals "Go routine killed with auto notify [recovered]" \ No newline at end of file diff --git a/features/configuration.feature b/features/configuration.feature index 6c3c1139..f5f58591 100644 --- a/features/configuration.feature +++ b/features/configuration.feature @@ -81,7 +81,6 @@ Feature: Configure integration with environment variables And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "AutoconfigPanicScenario" - And I wait for 2 seconds Then I should receive no errors Scenario: Enabling synchronous event delivery diff --git a/features/handled.feature b/features/handled.feature index 2a69b66e..2d524982 100644 --- a/features/handled.feature +++ b/features/handled.feature @@ -2,7 +2,7 @@ Feature: Plain handled errors Background: Given I set environment variable "BUGSNAG_SOURCE_ROOT" to "/app/src/features/fixtures/app/" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" Scenario: A handled error sends a report When I start the service "app" @@ -11,7 +11,7 @@ Scenario: A handled error sends a report And the event "unhandled" is false And the event "severity" equals "warning" And the event "severityReason.type" equals "handledError" - And the exception "errorClass" equals "*fs.PathError" + And the exception "errorClass" equals "*os.PathError" And the "file" of stack frame 0 equals "handled_scenario.go" Scenario: A handled error sends a report with a custom name diff --git a/features/hostname.feature b/features/hostname.feature index f05e7fef..29726e6c 100644 --- a/features/hostname.feature +++ b/features/hostname.feature @@ -2,7 +2,7 @@ Feature: Configuring hostname Scenario: An error report contains the configured hostname Given I set environment variable "BUGSNAG_HOSTNAME" to "server-1a" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HandledScenario" And I wait to receive an error @@ -10,7 +10,7 @@ Scenario: An error report contains the configured hostname Scenario: An session report contains the configured hostname Given I set environment variable "BUGSNAG_HOSTNAME" to "server-1a" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" And I wait to receive a session diff --git a/features/metadata.feature b/features/metadata.feature index a2995445..acdc1411 100644 --- a/features/metadata.feature +++ b/features/metadata.feature @@ -1,7 +1,7 @@ Feature: Sending meta data Scenario: An error report contains custom meta data - When I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + When I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" And I start the service "app" And I run "MetadataScenario" And I wait to receive an error diff --git a/features/multieventsession.feature b/features/multieventsession.feature index 91478eba..aab87327 100644 --- a/features/multieventsession.feature +++ b/features/multieventsession.feature @@ -1,7 +1,7 @@ Feature: Reporting multiple handled and unhandled errors in the same session Background: - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" Scenario: Handled errors know about previous reported handled errors When I start the service "app" diff --git a/features/net-http/appversion.feature b/features/net-http/appversion.feature index c7759362..c2d10ade 100644 --- a/features/net-http/appversion.feature +++ b/features/net-http/appversion.feature @@ -4,11 +4,10 @@ Background: And I set environment variable "BUGSNAG_APP_VERSION" to "3.1.2" Scenario: A error report contains the configured app type when using a net http app - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" And I wait to receive an error And I should receive no sessions @@ -16,12 +15,11 @@ Scenario: A error report contains the configured app type when using a net http And the event "app.version" equals "3.1.2" Scenario: A session report contains the configured app type when using a net http app - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/session" And I wait to receive a session And the session is valid for the session reporting API version "1.0" for the "Bugsnag Go" notifier - And the session payload field "sessions.0.app.version" equals "3.1.2" + And the session payload field "app.version" equals "3.1.2" diff --git a/features/net-http/autonotify.feature b/features/net-http/autonotify.feature index 997a741c..cbea77d3 100644 --- a/features/net-http/autonotify.feature +++ b/features/net-http/autonotify.feature @@ -1,11 +1,10 @@ Feature: Using auto notify Scenario: An error report is sent when an AutoNotified crash occurs which later gets recovered - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/autonotify-then-recover" Then I wait to receive an error And the event "unhandled" is true @@ -13,11 +12,10 @@ Scenario: An error report is sent when an AutoNotified crash occurs which later And the exception "message" matches "interface conversion: interface ({} )?is struct {}, not string" Scenario: An error report is sent when a go routine crashes which is reported through auto notify - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/autonotify" Then I wait to receive an error And the event "unhandled" is true diff --git a/features/net-http/handled.feature b/features/net-http/handled.feature index f84dd335..70722556 100644 --- a/features/net-http/handled.feature +++ b/features/net-http/handled.feature @@ -7,7 +7,6 @@ Scenario: A handled error sends a report When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" Then I wait to receive an error And the event "unhandled" is false @@ -21,7 +20,6 @@ Scenario: A handled error sends a report with a custom name When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" Then I wait to receive an error And the event "unhandled" is false diff --git a/features/net-http/onbeforenotify.feature b/features/net-http/onbeforenotify.feature index 46c02412..15d58b22 100644 --- a/features/net-http/onbeforenotify.feature +++ b/features/net-http/onbeforenotify.feature @@ -4,7 +4,6 @@ Scenario: Send three bugsnags and use on before notify to drop one and modify th When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/onbeforenotify" Then I wait to receive 2 errors And the exception "message" equals "Don't ignore this error" diff --git a/features/net-http/recover.feature b/features/net-http/recover.feature index d5f5f10c..8517bfda 100644 --- a/features/net-http/recover.feature +++ b/features/net-http/recover.feature @@ -4,7 +4,6 @@ Scenario: An error report is sent when request crashes but is recovered When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/recover" Then I wait to receive an error And the exception "errorClass" equals "*errors.errorString" diff --git a/features/net-http/releasestage.feature b/features/net-http/releasestage.feature index 17771eca..f303c765 100644 --- a/features/net-http/releasestage.feature +++ b/features/net-http/releasestage.feature @@ -4,22 +4,19 @@ Background: Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "my-stage" Scenario: An error report is sent with configured release stage - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" Then I wait to receive an error And the event "app.releaseStage" equals "my-stage" Scenario: A session report contains the configured app type - Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/session" Then I wait to receive a session - And I wait to receive an error - And the session payload field "sessions.0.app.releaseStage" equals "my-stage" \ No newline at end of file + And the session payload field "app.releaseStage" equals "my-stage" \ No newline at end of file diff --git a/features/net-http/request.feature b/features/net-http/request.feature index 559db0c1..b6d4067d 100644 --- a/features/net-http/request.feature +++ b/features/net-http/request.feature @@ -4,7 +4,6 @@ Scenario: An error report will automatically contain request information When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/handled" Then I wait to receive an error And the event "request.clientIp" is not null diff --git a/features/net-http/user.feature b/features/net-http/user.feature index c1c67c8b..78468002 100644 --- a/features/net-http/user.feature +++ b/features/net-http/user.feature @@ -4,7 +4,6 @@ Scenario: An error report contains custom user data When I start the service "app" And I run "HttpServerScenario" And I wait for the host "localhost" to open port "4512" - And I wait for 2 seconds And I open the URL "http://localhost:4512/user" Then I wait to receive an error And the event "user.id" equals "test-user-id" diff --git a/features/plain_features/panics.feature b/features/plain_features/panics.feature index 6e9e3174..2a9c52eb 100644 --- a/features/plain_features/panics.feature +++ b/features/plain_features/panics.feature @@ -2,7 +2,7 @@ Feature: Panic handling Background: Given I set environment variable "BUGSNAG_SOURCE_ROOT" to "/app/src/features/fixtures/app/" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" Scenario: Capturing a panic When I start the service "app" diff --git a/features/releasestage.feature b/features/releasestage.feature index e5dd56c8..dfcbb4c6 100644 --- a/features/releasestage.feature +++ b/features/releasestage.feature @@ -2,7 +2,7 @@ Feature: Configuring release stages and notify release stages Scenario: An error report is sent when release stage matches notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" When I start the service "app" And I run "HandledScenario" @@ -11,7 +11,7 @@ Scenario: An error report is sent when release stage matches notify release stag Scenario: An error report is sent when no notify release stages are specified Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HandledScenario" And I wait to receive an error @@ -19,14 +19,14 @@ Scenario: An error report is sent when no notify release stages are specified Scenario: An error report is sent regardless of notify release stages if release stage is not set Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" And I run "HandledScenario" And I wait to receive an error Scenario: An error report is not sent if the release stage does not match the notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "false" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage4" When I start the service "app" And I run "HandledScenario" @@ -34,7 +34,7 @@ Scenario: An error report is not sent if the release stage does not match the no Scenario: An session report is sent when release stage matches notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" When I start the service "app" And I run "SendSessionScenario" @@ -43,7 +43,7 @@ Scenario: An session report is sent when release stage matches notify release st Scenario: An session report is sent when no notify release stages are specified Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" And I wait to receive a session @@ -51,14 +51,14 @@ Scenario: An session report is sent when no notify release stages are specified Scenario: An session report is sent regardless of notify release stages if release stage is not set Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" And I wait to receive a session Scenario: An session report is not sent if the release stage does not match the notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" - And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "true" + And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage4" When I start the service "app" And I run "SendSessionScenario" From 41c675e98c93b6e31a21cf729ad7287677c2b1b0 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Wed, 21 Aug 2024 14:40:18 +0200 Subject: [PATCH 13/16] Consider startup session in session count in tests --- features/apptype.feature | 2 +- features/appversion.feature | 2 +- features/handled.feature | 2 +- features/hostname.feature | 4 ++-- features/multieventsession.feature | 10 ++++++---- features/net-http/handled.feature | 2 +- features/releasestage.feature | 14 +++++++------- features/steps/go_steps.rb | 9 +++++++++ 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/features/apptype.feature b/features/apptype.feature index 0a408717..a454b67a 100644 --- a/features/apptype.feature +++ b/features/apptype.feature @@ -14,5 +14,5 @@ Scenario: An session report contains the configured app type when running a go a Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" - And I wait to receive a session + And I wait to receive 2 sessions And the session payload field "app.type" equals "background-queue" diff --git a/features/appversion.feature b/features/appversion.feature index ffda5546..e5dfaf51 100644 --- a/features/appversion.feature +++ b/features/appversion.feature @@ -14,5 +14,5 @@ Scenario: A session report contains the configured app type when running a go ap Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" - And I wait to receive a session + And I wait to receive 2 sessions And the session payload field "app.version" equals "3.1.2" \ No newline at end of file diff --git a/features/handled.feature b/features/handled.feature index 2d524982..7415b7b4 100644 --- a/features/handled.feature +++ b/features/handled.feature @@ -11,7 +11,7 @@ Scenario: A handled error sends a report And the event "unhandled" is false And the event "severity" equals "warning" And the event "severityReason.type" equals "handledError" - And the exception "errorClass" equals "*os.PathError" + And the exception "errorClass" matches "\*os.PathError|\*fs.PathError" And the "file" of stack frame 0 equals "handled_scenario.go" Scenario: A handled error sends a report with a custom name diff --git a/features/hostname.feature b/features/hostname.feature index 29726e6c..ccd3fcb8 100644 --- a/features/hostname.feature +++ b/features/hostname.feature @@ -8,10 +8,10 @@ Scenario: An error report contains the configured hostname And I wait to receive an error And the event "device.hostname" equals "server-1a" -Scenario: An session report contains the configured hostname +Scenario: A session report contains the configured hostname Given I set environment variable "BUGSNAG_HOSTNAME" to "server-1a" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" - And I wait to receive a session + And I wait to receive 2 sessions And the session payload field "device.hostname" equals "server-1a" \ No newline at end of file diff --git a/features/multieventsession.feature b/features/multieventsession.feature index aab87327..46461dfb 100644 --- a/features/multieventsession.feature +++ b/features/multieventsession.feature @@ -7,12 +7,14 @@ Scenario: Handled errors know about previous reported handled errors When I start the service "app" And I run "MultipleHandledScenario" And I wait to receive 2 errors - And the event handled sessions count equals 1 for request 0 - And the event handled sessions count equals 2 for request 1 + And the event handled sessions count equals 1 + And I discard the oldest error + And the event handled sessions count equals 2 Scenario: Unhandled errors know about previous reported handled errors When I start the service "app" And I run "MultipleUnhandledScenario" And I wait to receive 2 errors - And the event unhandled sessions count equals 1 for request 0 - And the event unhandled sessions count equals 2 for request 1 \ No newline at end of file + And the event unhandled sessions count equals 1 + And I discard the oldest error + And the event unhandled sessions count equals 2 \ No newline at end of file diff --git a/features/net-http/handled.feature b/features/net-http/handled.feature index 70722556..c450db0d 100644 --- a/features/net-http/handled.feature +++ b/features/net-http/handled.feature @@ -12,7 +12,7 @@ Scenario: A handled error sends a report And the event "unhandled" is false And the event "severity" equals "warning" And the event "severityReason.type" equals "handledError" - And the exception "errorClass" equals "*os.PathError" + And the exception "errorClass" matches "\*os.PathError|\*fs.PathError" And the "file" of stack frame 0 equals "nethttp_scenario.go" Scenario: A handled error sends a report with a custom name diff --git a/features/releasestage.feature b/features/releasestage.feature index dfcbb4c6..3aa11d87 100644 --- a/features/releasestage.feature +++ b/features/releasestage.feature @@ -32,31 +32,31 @@ Scenario: An error report is not sent if the release stage does not match the no And I run "HandledScenario" And I should receive no errors -Scenario: An session report is sent when release stage matches notify release stages +Scenario: A session report is sent when release stage matches notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" When I start the service "app" And I run "SendSessionScenario" - And I wait to receive a session + And I wait to receive 2 sessions And the session payload field "app.releaseStage" equals "stage2" -Scenario: An session report is sent when no notify release stages are specified +Scenario: A session report is sent when no notify release stages are specified Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" - And I wait to receive a session + And I wait to receive 2 sessions And the session payload field "app.releaseStage" equals "stage2" -Scenario: An session report is sent regardless of notify release stages if release stage is not set +Scenario: A session report is sent regardless of notify release stages if release stage is not set Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" When I start the service "app" And I run "SendSessionScenario" - And I wait to receive a session + And I wait to receive 2 sessions -Scenario: An session report is not sent if the release stage does not match the notify release stages +Scenario: A session report is not sent if the release stage does not match the notify release stages Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "1" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage4" diff --git a/features/steps/go_steps.rb b/features/steps/go_steps.rb index cdc1678f..b8d5e398 100644 --- a/features/steps/go_steps.rb +++ b/features/steps/go_steps.rb @@ -11,6 +11,15 @@ ) end +Then('the event unhandled sessions count equals {int}') do |count| + step "the error payload field \"events.0.session.events.unhandled\" equals #{count}" +end + +Then('the event handled sessions count equals {int}') do |count| + step "the error payload field \"events.0.session.events.handled\" equals #{count}" +end + + def execute_command(action, scenario_name = '') address = $address ? $address : "#{local_ip}:9339" From 54313af48b0af34326a12874d865e757f120d409 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Wed, 21 Aug 2024 14:43:13 +0200 Subject: [PATCH 14/16] Unify scenario names with scenario func names --- features/apptype.feature | 2 +- features/appversion.feature | 2 +- features/fixtures/app/main.go | 38 +++++++++++++------------- features/handled.feature | 6 ++-- features/hostname.feature | 2 +- features/multieventsession.feature | 4 +-- features/plain_features/panics.feature | 2 +- features/releasestage.feature | 8 +++--- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/features/apptype.feature b/features/apptype.feature index a454b67a..26ec346f 100644 --- a/features/apptype.feature +++ b/features/apptype.feature @@ -6,7 +6,7 @@ Background: Scenario: An error report contains the configured app type when running a go app Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "app.type" equals "background-queue" diff --git a/features/appversion.feature b/features/appversion.feature index e5dfaf51..c08916ef 100644 --- a/features/appversion.feature +++ b/features/appversion.feature @@ -6,7 +6,7 @@ Background: Scenario: An error report contains the configured app type when running a go app Given I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "app.version" equals "3.1.2" diff --git a/features/fixtures/app/main.go b/features/fixtures/app/main.go index 7332a1a0..a86e4ce4 100644 --- a/features/fixtures/app/main.go +++ b/features/fixtures/app/main.go @@ -9,25 +9,25 @@ import ( ) var scenariosMap = map[string]func(Command) func(){ - "UnhandledScenario": UnhandledCrashScenario, - "HandledScenario": HandledErrorScenario, - "MultipleUnhandledScenario": MultipleUnhandledErrorsScenario, - "MultipleHandledScenario": MultipleHandledErrorsScenario, - "NestedErrorScenario": NestedHandledErrorScenario, - "MetadataScenario": MetadataScenario, - "FilteredMetadataScenario": FilteredMetadataScenario, - "HandledCallbackErrorScenario": HandledCallbackErrorScenario, - "SendSessionScenario": SendSessionScenario, - "HandledToUnhandledScenario": HandledToUnhandledScenario, - "SetUserScenario": SetUserScenario, - "RecoverAfterPanicScenario": RecoverAfterPanicScenario, - "AutonotifyPanicScenario": AutonotifyPanicScenario, - "SessionAndErrorScenario": SessionAndErrorScenario, - "OnBeforeNotifyScenario": OnBeforeNotifyScenario, - "AutoconfigPanicScenario": AutoconfigPanicScenario, - "AutoconfigHandledScenario": AutoconfigHandledScenario, - "AutoconfigMetadataScenario": AutoconfigMetadataScenario, - "HttpServerScenario": HttpServerScenario, + "UnhandledCrashScenario": UnhandledCrashScenario, + "HandledErrorScenario": HandledErrorScenario, + "MultipleUnhandledErrorsScenario": MultipleUnhandledErrorsScenario, + "MultipleHandledErrorsScenario": MultipleHandledErrorsScenario, + "NestedHandledErrorScenario": NestedHandledErrorScenario, + "MetadataScenario": MetadataScenario, + "FilteredMetadataScenario": FilteredMetadataScenario, + "HandledCallbackErrorScenario": HandledCallbackErrorScenario, + "SendSessionScenario": SendSessionScenario, + "HandledToUnhandledScenario": HandledToUnhandledScenario, + "SetUserScenario": SetUserScenario, + "RecoverAfterPanicScenario": RecoverAfterPanicScenario, + "AutonotifyPanicScenario": AutonotifyPanicScenario, + "SessionAndErrorScenario": SessionAndErrorScenario, + "OnBeforeNotifyScenario": OnBeforeNotifyScenario, + "AutoconfigPanicScenario": AutoconfigPanicScenario, + "AutoconfigHandledScenario": AutoconfigHandledScenario, + "AutoconfigMetadataScenario": AutoconfigMetadataScenario, + "HttpServerScenario": HttpServerScenario, } func main() { diff --git a/features/handled.feature b/features/handled.feature index 7415b7b4..c5b98cdf 100644 --- a/features/handled.feature +++ b/features/handled.feature @@ -6,7 +6,7 @@ Background: Scenario: A handled error sends a report When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "warning" @@ -17,7 +17,7 @@ Scenario: A handled error sends a report Scenario: A handled error sends a report with a custom name Given I set environment variable "ERROR_CLASS" to "MyCustomErrorClass" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "warning" @@ -51,7 +51,7 @@ Scenario: Marking an error as unhandled in a callback Scenario: Unwrapping the causes of a handled error When I start the service "app" - And I run "NestedErrorScenario" + And I run "NestedHandledErrorScenario" And I wait to receive an error And the event "unhandled" is false And the event "severity" equals "warning" diff --git a/features/hostname.feature b/features/hostname.feature index ccd3fcb8..ddd44368 100644 --- a/features/hostname.feature +++ b/features/hostname.feature @@ -4,7 +4,7 @@ Scenario: An error report contains the configured hostname Given I set environment variable "BUGSNAG_HOSTNAME" to "server-1a" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "device.hostname" equals "server-1a" diff --git a/features/multieventsession.feature b/features/multieventsession.feature index 46461dfb..bb9039dc 100644 --- a/features/multieventsession.feature +++ b/features/multieventsession.feature @@ -5,7 +5,7 @@ Background: Scenario: Handled errors know about previous reported handled errors When I start the service "app" - And I run "MultipleHandledScenario" + And I run "MultipleHandledErrorsScenario" And I wait to receive 2 errors And the event handled sessions count equals 1 And I discard the oldest error @@ -13,7 +13,7 @@ Scenario: Handled errors know about previous reported handled errors Scenario: Unhandled errors know about previous reported handled errors When I start the service "app" - And I run "MultipleUnhandledScenario" + And I run "MultipleUnhandledErrorsScenario" And I wait to receive 2 errors And the event unhandled sessions count equals 1 And I discard the oldest error diff --git a/features/plain_features/panics.feature b/features/plain_features/panics.feature index 2a9c52eb..691a007e 100644 --- a/features/plain_features/panics.feature +++ b/features/plain_features/panics.feature @@ -6,7 +6,7 @@ Feature: Panic handling Scenario: Capturing a panic When I start the service "app" - And I run "UnhandledScenario" + And I run "UnhandledCrashScenario" And I wait to receive an error And the event "unhandled" is true And the event "severity" equals "error" diff --git a/features/releasestage.feature b/features/releasestage.feature index 3aa11d87..2652b0c5 100644 --- a/features/releasestage.feature +++ b/features/releasestage.feature @@ -5,7 +5,7 @@ Scenario: An error report is sent when release stage matches notify release stag And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "app.releaseStage" equals "stage2" @@ -13,7 +13,7 @@ Scenario: An error report is sent when no notify release stages are specified Given I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage2" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error And the event "app.releaseStage" equals "stage2" @@ -21,7 +21,7 @@ Scenario: An error report is sent regardless of notify release stages if release Given I set environment variable "BUGSNAG_NOTIFY_RELEASE_STAGES" to "stage1,stage2,stage3" And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I wait to receive an error Scenario: An error report is not sent if the release stage does not match the notify release stages @@ -29,7 +29,7 @@ Scenario: An error report is not sent if the release stage does not match the no And I set environment variable "BUGSNAG_AUTO_CAPTURE_SESSIONS" to "0" And I set environment variable "BUGSNAG_RELEASE_STAGE" to "stage4" When I start the service "app" - And I run "HandledScenario" + And I run "HandledErrorScenario" And I should receive no errors Scenario: A session report is sent when release stage matches notify release stages From f4ca7ebf30017e0582bb0ecc08606a3bd5e3a108 Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Wed, 21 Aug 2024 14:43:44 +0200 Subject: [PATCH 15/16] Enable ubuntu tests in CI --- .github/workflows/test-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index d51eec2a..392fda7c 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - os: [windows] + os: [ubuntu, windows] go-version: ['1.11', '1.12', '1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22'] steps: From d71919308821256aef0f569bcbdae0cff6351fac Mon Sep 17 00:00:00 2001 From: Daria Bialobrzeska Date: Thu, 22 Aug 2024 13:06:16 +0200 Subject: [PATCH 16/16] Remove Bugsnag-Integrity header, server side notifiers don't have to handle it --- features/support/env.rb | 13 +++++++------ v2/headers/prefixed.go | 6 +----- v2/headers/prefixed_test.go | 7 ++----- v2/payload.go | 11 +---------- v2/sessions/publisher.go | 11 +---------- 5 files changed, 12 insertions(+), 36 deletions(-) diff --git a/features/support/env.rb b/features/support/env.rb index d55c94b1..d806b189 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,7 +1,8 @@ Before do - $address = nil - $api_key = "166f5ad3590596f9aa8d601ea89af845" - steps %( - When I configure the base endpoint - ) - end \ No newline at end of file + Maze.config.enforce_bugsnag_integrity = false + $address = nil + $api_key = "166f5ad3590596f9aa8d601ea89af845" + steps %( + When I configure the base endpoint + ) +end \ No newline at end of file diff --git a/v2/headers/prefixed.go b/v2/headers/prefixed.go index 8a518e80..ea93f6b6 100644 --- a/v2/headers/prefixed.go +++ b/v2/headers/prefixed.go @@ -1,20 +1,16 @@ package headers import ( - "fmt" "time" ) // PrefixedHeaders returns a map of Content-Type and the 'Bugsnag-' headers for // API key, payload version, and the time at which the request is being sent. -func PrefixedHeaders(apiKey, payloadVersion, sha1 string) map[string]string { - integrityHeader := fmt.Sprintf("sha1 %v", sha1) - +func PrefixedHeaders(apiKey, payloadVersion string) map[string]string { return map[string]string{ "Content-Type": "application/json", "Bugsnag-Api-Key": apiKey, "Bugsnag-Payload-Version": payloadVersion, "Bugsnag-Sent-At": time.Now().UTC().Format(time.RFC3339), - "Bugsnag-Integrity": integrityHeader, } } diff --git a/v2/headers/prefixed_test.go b/v2/headers/prefixed_test.go index 1df826d4..739d9e4f 100644 --- a/v2/headers/prefixed_test.go +++ b/v2/headers/prefixed_test.go @@ -1,7 +1,6 @@ package headers import ( - "fmt" "strings" "testing" "time" @@ -9,10 +8,9 @@ import ( const APIKey = "abcd1234abcd1234" const testPayloadVersion = "3" -const testSHA = "5e13ae4640ae4ae0e09c05b7bb060f544dabd042" func TestConstantBugsnagPrefixedHeaders(t *testing.T) { - headers := PrefixedHeaders(APIKey, testPayloadVersion, testSHA) + headers := PrefixedHeaders(APIKey, testPayloadVersion) testCases := []struct { header string expected string @@ -20,7 +18,6 @@ func TestConstantBugsnagPrefixedHeaders(t *testing.T) { {header: "Content-Type", expected: "application/json"}, {header: "Bugsnag-Api-Key", expected: APIKey}, {header: "Bugsnag-Payload-Version", expected: testPayloadVersion}, - {header: "Bugsnag-Integrity", expected: fmt.Sprintf("sha1 %v", testSHA)}, } for _, tc := range testCases { t.Run(tc.header, func(st *testing.T) { @@ -32,7 +29,7 @@ func TestConstantBugsnagPrefixedHeaders(t *testing.T) { } func TestTimeDependentBugsnagPrefixedHeaders(t *testing.T) { - headers := PrefixedHeaders(APIKey, testPayloadVersion, testSHA) + headers := PrefixedHeaders(APIKey, testPayloadVersion) sentAtString := headers["Bugsnag-Sent-At"] if !strings.HasSuffix(sentAtString, "Z") { t.Errorf("Error when setting Bugsnag-Sent-At header: %s, doesn't end with a Z", sentAtString) diff --git a/v2/payload.go b/v2/payload.go index 4d1a0e8e..1379fea7 100644 --- a/v2/payload.go +++ b/v2/payload.go @@ -2,8 +2,6 @@ package bugsnag import ( "bytes" - "crypto/sha1" - "encoding/hex" "encoding/json" "fmt" "net/http" @@ -38,13 +36,6 @@ func (p *payload) deliver() error { return fmt.Errorf("bugsnag/payload.deliver: %v", err) } - hasher := sha1.New() - _, err = hasher.Write(buf) - if err != nil { - return fmt.Errorf("bugsnag/payload.deliver: %v", err) - } - sha1_hash := hex.EncodeToString(hasher.Sum(nil)) - client := http.Client{ Transport: p.Transport, } @@ -52,7 +43,7 @@ func (p *payload) deliver() error { if err != nil { return fmt.Errorf("bugsnag/payload.deliver unable to create request: %v", err) } - for k, v := range headers.PrefixedHeaders(p.APIKey, notifyPayloadVersion, sha1_hash) { + for k, v := range headers.PrefixedHeaders(p.APIKey, notifyPayloadVersion) { req.Header.Add(k, v) } resp, err := client.Do(req) diff --git a/v2/sessions/publisher.go b/v2/sessions/publisher.go index bdb658ff..5d636f47 100644 --- a/v2/sessions/publisher.go +++ b/v2/sessions/publisher.go @@ -2,8 +2,6 @@ package sessions import ( "bytes" - "crypto/sha1" - "encoding/hex" "encoding/json" "fmt" "net/http" @@ -63,19 +61,12 @@ func (p *publisher) publish(sessions []*Session) error { return fmt.Errorf("bugsnag/sessions/publisher.publish unable to marshal json: %v", err) } - hasher := sha1.New() - _, err = hasher.Write(buf) - if err != nil { - return fmt.Errorf("bugsnag/payload.deliver: %v", err) - } - sha1_hash := hex.EncodeToString(hasher.Sum(nil)) - req, err := http.NewRequest("POST", p.config.Endpoint, bytes.NewBuffer(buf)) if err != nil { return fmt.Errorf("bugsnag/sessions/publisher.publish unable to create request: %v", err) } - for k, v := range headers.PrefixedHeaders(p.config.APIKey, sessionPayloadVersion, sha1_hash) { + for k, v := range headers.PrefixedHeaders(p.config.APIKey, sessionPayloadVersion) { req.Header.Add(k, v) }