appsignal 3.9.1-java → 3.9.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3135 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +58 -0
  6. data/Rakefile +79 -64
  7. data/appsignal.gemspec +1 -1
  8. data/build_matrix.yml +109 -179
  9. data/ext/base.rb +1 -1
  10. data/gemfiles/hanami-2.1.gemfile +7 -0
  11. data/lib/appsignal/cli/diagnose.rb +1 -1
  12. data/lib/appsignal/config.rb +1 -1
  13. data/lib/appsignal/demo.rb +0 -1
  14. data/lib/appsignal/environment.rb +5 -1
  15. data/lib/appsignal/extension/jruby.rb +1 -1
  16. data/lib/appsignal/helpers/instrumentation.rb +3 -3
  17. data/lib/appsignal/hooks/active_job.rb +2 -1
  18. data/lib/appsignal/integrations/action_cable.rb +1 -1
  19. data/lib/appsignal/integrations/grape.rb +19 -47
  20. data/lib/appsignal/integrations/hanami.rb +27 -41
  21. data/lib/appsignal/integrations/padrino.rb +46 -43
  22. data/lib/appsignal/integrations/railtie.rb +1 -4
  23. data/lib/appsignal/integrations/resque.rb +1 -1
  24. data/lib/appsignal/integrations/sidekiq.rb +2 -4
  25. data/lib/appsignal/integrations/sinatra.rb +7 -2
  26. data/lib/appsignal/probes/gvl.rb +24 -2
  27. data/lib/appsignal/probes/sidekiq.rb +1 -1
  28. data/lib/appsignal/probes.rb +1 -1
  29. data/lib/appsignal/rack/abstract_middleware.rb +62 -28
  30. data/lib/appsignal/rack/event_handler.rb +37 -26
  31. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  32. data/lib/appsignal/rack/hanami_middleware.rb +20 -0
  33. data/lib/appsignal/rack/rails_instrumentation.rb +14 -56
  34. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  35. data/lib/appsignal/utils.rb +1 -0
  36. data/lib/appsignal/version.rb +1 -1
  37. data/lib/appsignal.rb +34 -33
  38. data/spec/.rubocop.yml +1 -1
  39. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  40. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  41. data/spec/lib/appsignal/config_spec.rb +7 -5
  42. data/spec/lib/appsignal/demo_spec.rb +38 -41
  43. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  44. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  45. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  46. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  47. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  48. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  49. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  50. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  51. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  52. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  53. data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
  54. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  55. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  56. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  57. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  58. data/spec/lib/appsignal/integrations/hanami_spec.rb +126 -64
  59. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  60. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  61. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  62. data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
  63. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  64. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  65. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  66. data/spec/lib/appsignal/integrations/sinatra_spec.rb +8 -3
  67. data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
  68. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  69. data/spec/lib/appsignal/probes_spec.rb +7 -4
  70. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
  71. data/spec/lib/appsignal/rack/event_handler_spec.rb +151 -69
  72. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
  73. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  74. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +36 -0
  75. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  76. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  77. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
  78. data/spec/lib/appsignal/transaction_spec.rb +79 -93
  79. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  80. data/spec/lib/appsignal_spec.rb +363 -342
  81. data/spec/support/hanami/hanami_app.rb +1 -3
  82. data/spec/support/helpers/dependency_helper.rb +6 -1
  83. data/spec/support/helpers/std_streams_helper.rb +1 -1
  84. data/spec/support/helpers/transaction_helpers.rb +8 -0
  85. data/spec/support/matchers/transaction.rb +185 -0
  86. data/spec/support/mocks/dummy_app.rb +20 -0
  87. data/spec/support/shared_examples/instrument.rb +17 -12
  88. data/spec/support/testing.rb +18 -9
  89. metadata +17 -10
  90. data/.semaphore/semaphore.yml +0 -2347
  91. data/script/lint_git +0 -22
  92. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  93. data/spec/support/matchers/be_completed.rb +0 -5
  94. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -53,20 +53,14 @@ describe Appsignal::Hooks::ResqueHook do
53
53
  perform_rescue_job(ResqueTestJob)
54
54
 
55
55
  transaction = last_transaction
56
- transaction_hash = transaction.to_h
57
- expect(transaction_hash).to include(
58
- "id" => kind_of(String),
59
- "action" => "ResqueTestJob#perform",
60
- "error" => nil,
61
- "namespace" => namespace,
62
- "metadata" => {},
63
- "sample_data" => {
64
- "breadcrumbs" => [],
65
- "tags" => { "queue" => queue }
66
- }
67
- )
68
- expect(transaction_hash["events"].map { |e| e["name"] })
69
- .to eql(["perform.resque"])
56
+ expect(transaction).to have_id
57
+ expect(transaction).to have_namespace(namespace)
58
+ expect(transaction).to have_action("ResqueTestJob#perform")
59
+ expect(transaction).to_not have_error
60
+ expect(transaction).to_not include_metadata
61
+ expect(transaction).to_not include_breadcrumbs
62
+ expect(transaction).to include_tags("queue" => queue)
63
+ expect(transaction).to include_event("name" => "perform.resque")
70
64
  end
71
65
 
72
66
  context "with error" do
@@ -76,22 +70,14 @@ describe Appsignal::Hooks::ResqueHook do
76
70
  end.to raise_error(RuntimeError, "resque job error")
77
71
 
78
72
  transaction = last_transaction
79
- transaction_hash = transaction.to_h
80
- expect(transaction_hash).to include(
81
- "id" => kind_of(String),
82
- "action" => "ResqueErrorTestJob#perform",
83
- "error" => {
84
- "name" => "RuntimeError",
85
- "message" => "resque job error",
86
- "backtrace" => kind_of(String)
87
- },
88
- "namespace" => namespace,
89
- "metadata" => {},
90
- "sample_data" => {
91
- "breadcrumbs" => [],
92
- "tags" => { "queue" => queue }
93
- }
94
- )
73
+ expect(transaction).to have_id
74
+ expect(transaction).to have_namespace(namespace)
75
+ expect(transaction).to have_action("ResqueErrorTestJob#perform")
76
+ expect(transaction).to have_error("RuntimeError", "resque job error")
77
+ expect(transaction).to_not include_metadata
78
+ expect(transaction).to_not include_breadcrumbs
79
+ expect(transaction).to include_tags("queue" => queue)
80
+ expect(transaction).to include_event("name" => "perform.resque")
95
81
  end
96
82
  end
97
83
 
@@ -115,25 +101,23 @@ describe Appsignal::Hooks::ResqueHook do
115
101
  )
116
102
 
117
103
  transaction = last_transaction
118
- transaction_hash = transaction.to_h
119
- expect(transaction_hash).to include(
120
- "id" => kind_of(String),
121
- "action" => "ResqueTestJob#perform",
122
- "error" => nil,
123
- "namespace" => namespace,
124
- "metadata" => {},
125
- "sample_data" => {
126
- "tags" => { "queue" => queue },
127
- "breadcrumbs" => [],
128
- "params" => [
129
- "foo",
130
- {
131
- "foo" => "[FILTERED]",
132
- "bar" => "Bar",
133
- "baz" => { "1" => "foo" }
134
- }
135
- ]
136
- }
104
+ expect(transaction).to have_id
105
+ expect(transaction).to have_namespace(namespace)
106
+ expect(transaction).to have_action("ResqueTestJob#perform")
107
+ expect(transaction).to_not have_error
108
+ expect(transaction).to_not include_metadata
109
+ expect(transaction).to_not include_breadcrumbs
110
+ expect(transaction).to include_tags("queue" => queue)
111
+ expect(transaction).to include_event("name" => "perform.resque")
112
+ expect(transaction).to include_params(
113
+ [
114
+ "foo",
115
+ {
116
+ "foo" => "[FILTERED]",
117
+ "bar" => "Bar",
118
+ "baz" => { "1" => "foo" }
119
+ }
120
+ ]
137
121
  )
138
122
  end
139
123
  end
@@ -173,19 +157,15 @@ describe Appsignal::Hooks::ResqueHook do
173
157
  )
174
158
 
175
159
  transaction = last_transaction
176
- transaction_hash = transaction.to_h
177
- expect(transaction_hash).to include(
178
- "id" => kind_of(String),
179
- "action" => "ResqueTestJobByActiveJob#perform",
180
- "error" => nil,
181
- "namespace" => namespace,
182
- "metadata" => {},
183
- "sample_data" => {
184
- "breadcrumbs" => [],
185
- "tags" => { "queue" => queue }
186
- # Params will be set by the ActiveJob integration
187
- }
188
- )
160
+ expect(transaction).to have_id
161
+ expect(transaction).to have_namespace(namespace)
162
+ expect(transaction).to have_action("ResqueTestJobByActiveJob#perform")
163
+ expect(transaction).to_not have_error
164
+ expect(transaction).to_not include_metadata
165
+ expect(transaction).to_not include_breadcrumbs
166
+ expect(transaction).to include_tags("queue" => queue)
167
+ expect(transaction).to include_event("name" => "perform.resque")
168
+ expect(transaction).to_not include_params
189
169
  end
190
170
  end
191
171
  end
@@ -37,37 +37,25 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
37
37
  expect { perform_shoryuken_job }.to change { created_transactions.length }.by(1)
38
38
 
39
39
  transaction = last_transaction
40
- expect(transaction).to be_completed
41
- transaction_hash = transaction.to_h
42
- expect(transaction_hash).to include(
43
- "action" => "DemoShoryukenWorker#perform",
44
- "id" => kind_of(String), # AppSignal generated id
45
- "namespace" => Appsignal::Transaction::BACKGROUND_JOB,
46
- "error" => nil
47
- )
48
- expect(transaction_hash["events"].first).to include(
49
- "allocation_count" => kind_of(Integer),
40
+ expect(transaction).to have_id
41
+ expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
42
+ expect(transaction).to have_action("DemoShoryukenWorker#perform")
43
+ expect(transaction).to_not have_error
44
+ expect(transaction).to include_event(
50
45
  "body" => "",
51
46
  "body_format" => Appsignal::EventFormatter::DEFAULT,
52
- "child_allocation_count" => kind_of(Integer),
53
- "child_duration" => kind_of(Float),
54
- "child_gc_duration" => kind_of(Float),
55
47
  "count" => 1,
56
- "gc_duration" => kind_of(Float),
57
- "start" => kind_of(Float),
58
- "duration" => kind_of(Float),
59
48
  "name" => "perform_job.shoryuken",
60
49
  "title" => ""
61
50
  )
62
- expect(transaction_hash["sample_data"]).to include(
63
- "params" => { "foo" => "Foo", "bar" => "Bar" },
64
- "metadata" => {
65
- "message_id" => "msg1",
66
- "queue" => queue,
67
- "SentTimestamp" => sent_timestamp
68
- }
51
+ expect(transaction).to include_params("foo" => "Foo", "bar" => "Bar")
52
+ expect(transaction).to include_sample_metadata(
53
+ "message_id" => "msg1",
54
+ "queue" => queue,
55
+ "SentTimestamp" => sent_timestamp
69
56
  )
70
- expect(transaction).to have_received(:set_queue_start).with(sent_timestamp)
57
+ expect(transaction).to have_queue_start(sent_timestamp)
58
+ expect(transaction).to be_completed
71
59
  end
72
60
 
73
61
  context "with parameter filtering" do
@@ -82,10 +70,7 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
82
70
  it "filters selected arguments" do
83
71
  perform_shoryuken_job
84
72
 
85
- transaction_hash = last_transaction.to_h
86
- expect(transaction_hash["sample_data"]).to include(
87
- "params" => { "foo" => "[FILTERED]", "bar" => "Bar" }
88
- )
73
+ expect(last_transaction).to include_params("foo" => "[FILTERED]", "bar" => "Bar")
89
74
  end
90
75
  end
91
76
  end
@@ -96,10 +81,7 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
96
81
  it "handles string arguments" do
97
82
  perform_shoryuken_job
98
83
 
99
- transaction_hash = last_transaction.to_h
100
- expect(transaction_hash["sample_data"]).to include(
101
- "params" => { "params" => body }
102
- )
84
+ expect(last_transaction).to include_params("params" => body)
103
85
  end
104
86
  end
105
87
 
@@ -109,10 +91,7 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
109
91
  it "handles primitive types as arguments" do
110
92
  perform_shoryuken_job
111
93
 
112
- transaction_hash = last_transaction.to_h
113
- expect(transaction_hash["sample_data"]).to include(
114
- "params" => { "params" => body }
115
- )
94
+ expect(last_transaction).to include_params("params" => body)
116
95
  end
117
96
  end
118
97
  end
@@ -126,18 +105,11 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
126
105
  end.to change { created_transactions.length }.by(1)
127
106
 
128
107
  transaction = last_transaction
108
+ expect(transaction).to have_id
109
+ expect(transaction).to have_action("DemoShoryukenWorker#perform")
110
+ expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
111
+ expect(transaction).to have_error("ExampleException", "error message")
129
112
  expect(transaction).to be_completed
130
- transaction_hash = transaction.to_h
131
- expect(transaction_hash).to include(
132
- "action" => "DemoShoryukenWorker#perform",
133
- "id" => kind_of(String), # AppSignal generated id
134
- "namespace" => Appsignal::Transaction::BACKGROUND_JOB,
135
- "error" => {
136
- "name" => "ExampleException",
137
- "message" => "error message",
138
- "backtrace" => kind_of(String)
139
- }
140
- )
141
113
  end
142
114
  end
143
115
 
@@ -171,41 +143,28 @@ describe Appsignal::Hooks::ShoryukenMiddleware do
171
143
  end.to change { created_transactions.length }.by(1)
172
144
 
173
145
  transaction = last_transaction
174
- expect(transaction).to be_completed
175
- transaction_hash = transaction.to_h
176
- expect(transaction_hash).to include(
177
- "action" => "DemoShoryukenWorker#perform",
178
- "id" => kind_of(String), # AppSignal generated id
179
- "namespace" => Appsignal::Transaction::BACKGROUND_JOB,
180
- "error" => nil
181
- )
182
- expect(transaction_hash["events"].first).to include(
183
- "allocation_count" => kind_of(Integer),
146
+ expect(transaction).to have_id
147
+ expect(transaction).to have_action("DemoShoryukenWorker#perform")
148
+ expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
149
+ expect(transaction).to_not have_error
150
+ expect(transaction).to include_event(
184
151
  "body" => "",
185
152
  "body_format" => Appsignal::EventFormatter::DEFAULT,
186
- "child_allocation_count" => kind_of(Integer),
187
- "child_duration" => kind_of(Float),
188
- "child_gc_duration" => kind_of(Float),
189
153
  "count" => 1,
190
- "gc_duration" => kind_of(Float),
191
- "start" => kind_of(Float),
192
- "duration" => kind_of(Float),
193
154
  "name" => "perform_job.shoryuken",
194
155
  "title" => ""
195
156
  )
196
- expect(transaction_hash["sample_data"]).to include(
197
- "params" => {
198
- "msg2" => "foo bar",
199
- "msg1" => { "id" => "123", "foo" => "Foo", "bar" => "Bar" }
200
- },
201
- "metadata" => {
202
- "batch" => true,
203
- "queue" => "some-funky-queue-name",
204
- "SentTimestamp" => sent_timestamp.to_s # Earliest/oldest timestamp from messages
205
- }
157
+ expect(transaction).to include_params(
158
+ "msg2" => "foo bar",
159
+ "msg1" => { "id" => "123", "foo" => "Foo", "bar" => "Bar" }
160
+ )
161
+ expect(transaction).to include_sample_metadata(
162
+ "batch" => true,
163
+ "queue" => "some-funky-queue-name",
164
+ "SentTimestamp" => sent_timestamp.to_s # Earliest/oldest timestamp from messages
206
165
  )
207
166
  # Queue time based on earliest/oldest timestamp from messages
208
- expect(transaction).to have_received(:set_queue_start).with(sent_timestamp)
167
+ expect(transaction).to have_queue_start(sent_timestamp)
209
168
  end
210
169
  end
211
170
  end
@@ -5,32 +5,106 @@ if DependencyHelper.hanami2_present?
5
5
  require "appsignal/integrations/hanami"
6
6
 
7
7
  before do
8
- allow(Appsignal).to receive(:active?).and_return(true)
9
- allow(Appsignal).to receive(:start).and_return(true)
10
- allow(Appsignal).to receive(:start_logger).and_return(true)
8
+ Appsignal.config = nil
9
+ allow(::Hanami::Action).to receive(:prepend)
10
+ uninstall_hanami_middleware
11
+ ENV["APPSIGNAL_APP_NAME"] = "hanamia-test-app"
12
+ ENV["APPSIGNAL_APP_ENV"] = "test"
13
+ ENV["APPSIGNAL_PUSH_API_KEY"] = "0000"
14
+ end
15
+
16
+ def uninstall_hanami_middleware
17
+ middleware_stack = ::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX]
18
+ middleware_stack.delete_if do |middleware|
19
+ middleware.first == Appsignal::Rack::HanamiMiddleware ||
20
+ middleware.first == Rack::Events
21
+ end
11
22
  end
12
23
 
13
24
  describe Appsignal::Integrations::HanamiPlugin do
14
25
  it "starts AppSignal on init" do
15
- expect(Appsignal).to receive(:start)
26
+ expect(Appsignal.active?).to be_falsey
27
+
28
+ Appsignal::Integrations::HanamiPlugin.init
29
+
30
+ expect(Appsignal.active?).to be_truthy
16
31
  end
17
32
 
18
- it "starts the logger on init" do
19
- expect(Appsignal).to receive(:start_logger)
33
+ it "prepends the integration to Hanami::Action" do
34
+ Appsignal::Integrations::HanamiPlugin.init
35
+
36
+ expect(::Hanami::Action)
37
+ .to have_received(:prepend).with(Appsignal::Integrations::HanamiIntegration)
20
38
  end
21
39
 
22
- it "prepends the integration to Hanami" do
23
- expect(::Hanami::Action).to receive(:prepend)
24
- .with(Appsignal::Integrations::HanamiIntegration)
40
+ it "adds middleware to the Hanami app" do
41
+ Appsignal::Integrations::HanamiPlugin.init
42
+
43
+ expect(::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX])
44
+ .to include(
45
+ [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], *hanami_middleware_options],
46
+ [Appsignal::Rack::HanamiMiddleware, [], *hanami_middleware_options]
47
+ )
25
48
  end
26
49
 
27
50
  context "when not active" do
28
- before { allow(Appsignal).to receive(:active?).and_return(false) }
51
+ before do
52
+ ENV.delete("APPSIGNAL_APP_NAME")
53
+ ENV.delete("APPSIGNAL_APP_ENV")
54
+ ENV.delete("APPSIGNAL_PUSH_API_KEY")
55
+ end
56
+
57
+ it "does not prepend the integration to Hanami::Action" do
58
+ Appsignal::Integrations::HanamiPlugin.init
29
59
 
30
- it "does not prepend the integration" do
31
- expect(::Hanami::Action).to_not receive(:prepend)
60
+ expect(::Hanami::Action).to_not have_received(:prepend)
32
61
  .with(Appsignal::Integrations::HanamiIntegration)
33
62
  end
63
+
64
+ it "does not add the middleware to the Hanami app" do
65
+ Appsignal::Integrations::HanamiPlugin.init
66
+
67
+ middleware_stack = ::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX]
68
+ expect(middleware_stack).to_not include(
69
+ [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], *hanami_middleware_options]
70
+ )
71
+ expect(middleware_stack).to_not include(
72
+ [Appsignal::Rack::HanamiMiddleware, [], *hanami_middleware_options]
73
+ )
74
+ end
75
+ end
76
+
77
+ context "when AppSignal is already active" do
78
+ before do
79
+ expect(Appsignal).to receive(:active?).at_least(1).and_return(true)
80
+ end
81
+
82
+ it "does not initialize AppSignal again" do
83
+ expect(Appsignal).to_not receive(:start)
84
+
85
+ Appsignal::Integrations::HanamiPlugin.init
86
+ end
87
+
88
+ it "prepends the integration to Hanami::Action" do
89
+ Appsignal::Integrations::HanamiPlugin.init
90
+
91
+ expect(::Hanami::Action)
92
+ .to have_received(:prepend).with(Appsignal::Integrations::HanamiIntegration)
93
+ end
94
+
95
+ it "adds middleware to the Hanami app" do
96
+ Appsignal::Integrations::HanamiPlugin.init
97
+
98
+ expect(::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX])
99
+ .to include(
100
+ [
101
+ Rack::Events,
102
+ [[kind_of(Appsignal::Rack::EventHandler)]],
103
+ *hanami_middleware_options
104
+ ],
105
+ [Appsignal::Rack::HanamiMiddleware, [], *hanami_middleware_options]
106
+ )
107
+ end
34
108
  end
35
109
 
36
110
  context "when APPSIGNAL_APP_ENV ENV var is provided" do
@@ -52,72 +126,60 @@ if DependencyHelper.hanami2_present?
52
126
  expect(Appsignal.config.env).to eq("test")
53
127
  end
54
128
  end
55
-
56
- after { Appsignal::Integrations::HanamiPlugin.init }
57
129
  end
58
130
 
59
- describe "Hanami Actions" do
60
- let(:env) do
61
- Rack::MockRequest.env_for(
62
- "/books",
63
- "router.params" => router_params,
64
- :method => "GET"
65
- )
131
+ describe Appsignal::Integrations::HanamiIntegration do
132
+ let(:transaction) { http_request_transaction }
133
+ let(:app) do
134
+ Class.new(HanamiApp::Actions::Books::Index) do
135
+ def self.name
136
+ "HanamiApp::Actions::Books::Index::TestClass"
137
+ end
138
+ end
139
+ end
140
+ around { |example| keep_transactions { example.run } }
141
+ before do
142
+ ENV["APPSIGNAL_APP_NAME"] = "hanamia-test-app"
143
+ ENV["APPSIGNAL_APP_ENV"] = "test"
144
+ ENV["APPSIGNAL_PUSH_API_KEY"] = "0000"
145
+ Appsignal::Integrations::HanamiPlugin.init
146
+ allow(app).to receive(:prepend).and_call_original
147
+ app.prepend(Appsignal::Integrations::HanamiIntegration)
66
148
  end
67
149
 
68
- let(:router_params) { { :foo => "bar", :baz => "qux" } }
69
-
70
- describe "#call", :error => false do
71
- it "sets params" do
72
- expect_any_instance_of(Appsignal::Transaction).to receive(:params=).with(router_params)
73
- end
150
+ def make_request(env)
151
+ action = app.new
152
+ action.call(env)
153
+ end
74
154
 
75
- it "sets the action name" do
76
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil)
77
- .with("HanamiApp::Actions::Books::Index")
78
- end
155
+ describe "#call" do
156
+ context "without an active transaction" do
157
+ let(:env) { {} }
79
158
 
80
- it "sets the metadata" do
81
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
82
- .with("status", "200")
83
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
84
- .with("path", "/books")
85
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
86
- .with("method", "GET")
87
- end
159
+ it "does not set the action name" do
160
+ make_request(env)
88
161
 
89
- it "sets the queue start" do
90
- expect_any_instance_of(Appsignal::Transaction)
91
- .to receive(:set_http_or_background_queue_start)
162
+ expect(transaction).to_not have_action
163
+ end
92
164
  end
93
165
 
94
- context "with error", :error => true do
95
- let(:error) { HanamiApp::ExampleError }
166
+ context "with an active transaction" do
167
+ let(:env) { { Appsignal::Rack::APPSIGNAL_TRANSACTION => transaction } }
96
168
 
97
- it "records the exception" do
98
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
99
- end
169
+ it "sets action name on the transaction" do
170
+ make_request(env)
100
171
 
101
- it "sets the status to 500" do
102
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata)
103
- .with("status", "500")
104
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).twice
172
+ expect(transaction).to have_action("HanamiApp::Actions::Books::Index::TestClass")
105
173
  end
106
174
  end
175
+ end
176
+ end
107
177
 
108
- after(:error => false) do
109
- Appsignal::Integrations::HanamiPlugin.init
110
-
111
- action = HanamiApp::Actions::Books::Index.new
112
- action.call(env)
113
- end
114
-
115
- after(:error => true) do
116
- Appsignal::Integrations::HanamiPlugin.init
117
-
118
- action = HanamiApp::Actions::Books::Error.new
119
- expect { action.call(env) }.to raise_error(error)
120
- end
178
+ def hanami_middleware_options
179
+ if DependencyHelper.hanami2_1_present?
180
+ [{}, nil]
181
+ else
182
+ [nil]
121
183
  end
122
184
  end
123
185
  end
@@ -23,9 +23,8 @@ if DependencyHelper.http_present?
23
23
 
24
24
  HTTP.get("http://www.google.com")
25
25
 
26
- transaction_hash = transaction.to_h
27
- expect(transaction_hash).to include("namespace" => Appsignal::Transaction::HTTP_REQUEST)
28
- expect(transaction_hash["events"].first).to include(
26
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
27
+ expect(transaction).to include_event(
29
28
  "body" => "",
30
29
  "body_format" => Appsignal::EventFormatter::DEFAULT,
31
30
  "name" => "request.http_rb",
@@ -38,9 +37,8 @@ if DependencyHelper.http_present?
38
37
 
39
38
  HTTP.get("https://www.google.com")
40
39
 
41
- transaction_hash = transaction.to_h
42
- expect(transaction_hash).to include("namespace" => Appsignal::Transaction::HTTP_REQUEST)
43
- expect(transaction_hash["events"].first).to include(
40
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
41
+ expect(transaction).to include_event(
44
42
  "body" => "",
45
43
  "body_format" => Appsignal::EventFormatter::DEFAULT,
46
44
  "name" => "request.http_rb",
@@ -54,7 +52,7 @@ if DependencyHelper.http_present?
54
52
 
55
53
  HTTP.get("https://www.google.com", :params => { :q => "Appsignal" })
56
54
 
57
- expect(transaction.to_h["events"].first).to include(
55
+ expect(transaction).to include_event(
58
56
  "body" => "",
59
57
  "title" => "GET https://www.google.com"
60
58
  )
@@ -66,7 +64,7 @@ if DependencyHelper.http_present?
66
64
 
67
65
  HTTP.post("https://www.google.com", :json => { :q => "Appsignal" })
68
66
 
69
- expect(transaction.to_h["events"].first).to include(
67
+ expect(transaction).to include_event(
70
68
  "body" => "",
71
69
  "title" => "POST https://www.google.com"
72
70
  )
@@ -83,20 +81,14 @@ if DependencyHelper.http_present?
83
81
  HTTP.get("https://www.google.com")
84
82
  end.to raise_error(ExampleException)
85
83
 
86
- transaction_hash = transaction.to_h
87
- expect(transaction_hash).to include("namespace" => Appsignal::Transaction::HTTP_REQUEST)
88
- expect(transaction_hash["events"].first).to include(
84
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
85
+ expect(transaction).to include_event(
89
86
  "body" => "",
90
87
  "body_format" => Appsignal::EventFormatter::DEFAULT,
91
88
  "name" => "request.http_rb",
92
89
  "title" => "GET https://www.google.com"
93
90
  )
94
-
95
- expect(transaction_hash["error"]).to include(
96
- "backtrace" => kind_of(String),
97
- "name" => error.class.name,
98
- "message" => error.message
99
- )
91
+ expect(transaction).to have_error(error.class.name, error.message)
100
92
  end
101
93
  end
102
94
 
@@ -112,7 +104,7 @@ if DependencyHelper.http_present?
112
104
 
113
105
  HTTP.get(request_uri.new("http://www.google.com"))
114
106
 
115
- expect(transaction.to_h["events"].first).to include(
107
+ expect(transaction).to include_event(
116
108
  "name" => "request.http_rb",
117
109
  "title" => "GET http://www.google.com"
118
110
  )
@@ -123,7 +115,7 @@ if DependencyHelper.http_present?
123
115
 
124
116
  HTTP.get(URI("http://www.google.com"))
125
117
 
126
- expect(transaction.to_h["events"].first).to include(
118
+ expect(transaction).to include_event(
127
119
  "name" => "request.http_rb",
128
120
  "title" => "GET http://www.google.com"
129
121
  )
@@ -134,7 +126,7 @@ if DependencyHelper.http_present?
134
126
 
135
127
  HTTP.get("http://www.google.com")
136
128
 
137
- expect(transaction.to_h["events"].first).to include(
129
+ expect(transaction).to include_event(
138
130
  "name" => "request.http_rb",
139
131
  "title" => "GET http://www.google.com"
140
132
  )
@@ -0,0 +1,33 @@
1
+ require "appsignal/integrations/net_http"
2
+
3
+ describe Appsignal::Integrations::NetHttpIntegration do
4
+ let(:transaction) { http_request_transaction }
5
+ before(:context) { start_agent }
6
+ before { set_current_transaction transaction }
7
+ around { |example| keep_transactions { example.run } }
8
+
9
+ it "instruments a http request" do
10
+ stub_request(:any, "http://www.google.com/")
11
+
12
+ Net::HTTP.get_response(URI.parse("http://www.google.com"))
13
+
14
+ expect(transaction).to include_event(
15
+ "name" => "request.net_http",
16
+ "title" => "GET http://www.google.com"
17
+ )
18
+ end
19
+
20
+ it "instruments a https request" do
21
+ stub_request(:any, "https://www.google.com/")
22
+
23
+ uri = URI.parse("https://www.google.com")
24
+ http = Net::HTTP.new(uri.host, uri.port)
25
+ http.use_ssl = true
26
+ http.get(uri.request_uri)
27
+
28
+ expect(transaction).to include_event(
29
+ "name" => "request.net_http",
30
+ "title" => "GET https://www.google.com"
31
+ )
32
+ end
33
+ end