@@ -10,28 +10,44 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do
10
10
def perform ( % Oban.Job { } ) , do: :ok
11
11
end
12
12
13
+ @ worker_as_string "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker"
14
+
13
15
describe "handle_event/4" do
14
16
test "reports the correct error to Sentry" do
15
- # Any worker is okay here, this is just an easier way to get a job struct.
16
- job =
17
- % { "id" => "123" , "entity" => "user" , "type" => "delete" }
18
- |> MyWorker . new ( )
19
- |> Ecto.Changeset . apply_action! ( :validate )
20
- |> Map . replace! ( :unsaved_error , % {
21
- reason: % RuntimeError { message: "oops" } ,
22
- kind: :error ,
23
- stacktrace: [ ]
24
- } )
17
+ Sentry.Test . start_collecting ( )
18
+
19
+ emit_telemetry_for_failed_job ( :error , % RuntimeError { message: "oops" } , [ ] )
20
+
21
+ assert [ event ] = Sentry.Test . pop_sentry_reports ( )
22
+ assert event . original_exception == % RuntimeError { message: "oops" }
23
+ assert [ % { stacktrace: % { frames: [ stacktrace ] } } = exception ] = event . exception
24
+
25
+ assert exception . type == "RuntimeError"
26
+ assert exception . value == "oops"
27
+ assert exception . mechanism . handled == true
28
+ assert stacktrace . module == MyWorker
29
+
30
+ assert stacktrace . function ==
31
+ "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker.process/1"
32
+
33
+ assert event . tags . oban_queue == "default"
34
+ assert event . tags . oban_state == "available"
35
+ assert event . tags . oban_worker == "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker"
36
+ assert % { job: % Oban.Job { } } = event . integration_meta . oban
25
37
38
+ assert event . fingerprint == [ @ worker_as_string , "{{ default }}" ]
39
+ end
40
+
41
+ test "unwraps Oban.PerformErrors and reports the wrapped error" do
26
42
Sentry.Test . start_collecting ( )
27
43
28
- assert :ok =
29
- ErrorReporter . handle_event (
30
- [ :oban , :job , :exception ] ,
31
- % { } ,
32
- % { job: job } ,
33
- :no_config
34
- )
44
+ emit_telemetry_for_failed_job (
45
+ :error ,
46
+ % Oban.PerformError {
47
+ reason: { :error , % RuntimeError { message: "oops" } }
48
+ } ,
49
+ [ ]
50
+ )
35
51
36
52
assert [ event ] = Sentry.Test . pop_sentry_reports ( )
37
53
assert event . original_exception == % RuntimeError { message: "oops" }
@@ -49,50 +65,67 @@ defmodule Sentry.Integrations.Oban.ErrorReporterTest do
49
65
assert event . tags . oban_state == "available"
50
66
assert event . tags . oban_worker == "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker"
51
67
assert % { job: % Oban.Job { } } = event . integration_meta . oban
68
+
69
+ assert event . fingerprint == [ @ worker_as_string , "{{ default }}" ]
52
70
end
53
71
54
72
test "reports non-exception errors to Sentry" do
55
- job =
56
- % { "id" => "123" , "entity" => "user" , "type" => "delete" }
57
- |> MyWorker . new ( )
58
- |> Ecto.Changeset . apply_action! ( :validate )
59
- |> Map . replace! ( :unsaved_error , % {
60
- reason: :undef ,
61
- kind: :error ,
62
- stacktrace: [ ]
63
- } )
64
-
65
73
Sentry.Test . start_collecting ( )
66
74
67
- assert :ok =
68
- ErrorReporter . handle_event (
69
- [ :oban , :job , :exception ] ,
70
- % { } ,
71
- % { job: job } ,
72
- :no_config
73
- )
75
+ emit_telemetry_for_failed_job ( :error , :undef , [ ] )
74
76
75
77
assert [ event ] = Sentry.Test . pop_sentry_reports ( )
76
78
assert % { job: % Oban.Job { } } = event . integration_meta . oban
77
79
78
80
assert event . message == % Sentry.Interfaces.Message {
79
- formatted:
80
- "Oban job Sentry.Integrations.Oban.ErrorReporterTest.MyWorker errored out: :undef" ,
81
- message:
82
- "Oban job Sentry.Integrations.Oban.ErrorReporterTest.MyWorker errored out: %s" ,
81
+ formatted: "Oban job #{ @ worker_as_string } errored out: :undef" ,
82
+ message: "Oban job #{ @ worker_as_string } errored out: %s" ,
83
83
params: [ ":undef" ]
84
84
}
85
85
86
86
assert [ % Sentry.Interfaces.Thread { stacktrace: % { frames: [ stacktrace ] } } ] = event . threads
87
-
88
87
assert stacktrace . module == MyWorker
89
-
90
- assert stacktrace . function ==
91
- "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker.process/1"
88
+ assert stacktrace . function == "#{ @ worker_as_string } .process/1"
92
89
93
90
assert event . tags . oban_queue == "default"
94
91
assert event . tags . oban_state == "available"
95
- assert event . tags . oban_worker == "Sentry.Integrations.Oban.ErrorReporterTest.MyWorker"
92
+ assert event . tags . oban_worker == @ worker_as_string
93
+
94
+ assert event . fingerprint == [ @ worker_as_string , "{{ default }}" ]
96
95
end
96
+
97
+ for reason <- [ :cancel , :discard ] do
98
+ test "doesn't report Oban.PerformError with reason #{ inspect ( reason ) } " do
99
+ Sentry.Test . start_collecting ( )
100
+
101
+ emit_telemetry_for_failed_job (
102
+ :error ,
103
+ % Oban.PerformError { reason: { unquote ( reason ) , "nah" } } ,
104
+ [ ]
105
+ )
106
+
107
+ assert Sentry.Test . pop_sentry_reports ( ) == [ ]
108
+ end
109
+ end
110
+ end
111
+
112
+ ## Helpers
113
+
114
+ defp emit_telemetry_for_failed_job ( kind , reason , stacktrace ) do
115
+ job =
116
+ % { "id" => "123" , "entity" => "user" , "type" => "delete" }
117
+ |> MyWorker . new ( )
118
+ |> Ecto.Changeset . apply_action! ( :validate )
119
+ |> Map . replace! ( :unsaved_error , % { kind: kind , reason: reason , stacktrace: stacktrace } )
120
+
121
+ assert :ok =
122
+ ErrorReporter . handle_event (
123
+ [ :oban , :job , :exception ] ,
124
+ % { } ,
125
+ % { job: job } ,
126
+ :no_config
127
+ )
128
+
129
+ job
97
130
end
98
131
end
0 commit comments