appsignal 3.9.2-java → 3.10.0-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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3138 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +130 -0
  6. data/README.md +0 -1
  7. data/Rakefile +80 -65
  8. data/appsignal.gemspec +1 -1
  9. data/build_matrix.yml +112 -184
  10. data/ext/base.rb +1 -1
  11. data/gemfiles/hanami-2.1.gemfile +7 -0
  12. data/gemfiles/webmachine1.gemfile +5 -4
  13. data/lib/appsignal/cli/diagnose.rb +1 -1
  14. data/lib/appsignal/config.rb +5 -1
  15. data/lib/appsignal/demo.rb +0 -1
  16. data/lib/appsignal/environment.rb +11 -2
  17. data/lib/appsignal/extension/jruby.rb +1 -1
  18. data/lib/appsignal/helpers/instrumentation.rb +164 -2
  19. data/lib/appsignal/hooks/active_job.rb +1 -6
  20. data/lib/appsignal/integrations/grape.rb +19 -47
  21. data/lib/appsignal/integrations/hanami.rb +8 -7
  22. data/lib/appsignal/integrations/padrino.rb +51 -52
  23. data/lib/appsignal/integrations/railtie.rb +0 -3
  24. data/lib/appsignal/integrations/rake.rb +46 -12
  25. data/lib/appsignal/integrations/sidekiq.rb +1 -11
  26. data/lib/appsignal/integrations/sinatra.rb +0 -1
  27. data/lib/appsignal/integrations/webmachine.rb +15 -9
  28. data/lib/appsignal/probes/gvl.rb +24 -2
  29. data/lib/appsignal/probes/sidekiq.rb +1 -1
  30. data/lib/appsignal/probes.rb +1 -1
  31. data/lib/appsignal/rack/abstract_middleware.rb +104 -33
  32. data/lib/appsignal/rack/body_wrapper.rb +143 -0
  33. data/lib/appsignal/rack/event_handler.rb +12 -3
  34. data/lib/appsignal/rack/generic_instrumentation.rb +5 -4
  35. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  36. data/lib/appsignal/rack/hanami_middleware.rb +2 -12
  37. data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
  38. data/lib/appsignal/rack/rails_instrumentation.rb +14 -57
  39. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
  40. data/lib/appsignal/rack/streaming_listener.rb +13 -59
  41. data/lib/appsignal/rack.rb +31 -0
  42. data/lib/appsignal/transaction.rb +50 -8
  43. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  44. data/lib/appsignal/utils.rb +1 -0
  45. data/lib/appsignal/version.rb +1 -1
  46. data/lib/appsignal.rb +36 -33
  47. data/spec/.rubocop.yml +1 -1
  48. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  49. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  50. data/spec/lib/appsignal/config_spec.rb +8 -5
  51. data/spec/lib/appsignal/demo_spec.rb +38 -41
  52. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  53. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  54. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  55. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  56. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  57. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  58. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  59. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  60. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  61. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  62. data/spec/lib/appsignal/hooks/rake_spec.rb +107 -34
  63. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  64. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  65. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  66. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  67. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  68. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  69. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  70. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  71. data/spec/lib/appsignal/integrations/padrino_spec.rb +190 -163
  72. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  73. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  74. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  75. data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -3
  76. data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -40
  77. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  78. data/spec/lib/appsignal/probes_spec.rb +7 -4
  79. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +302 -105
  80. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
  81. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  82. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -27
  83. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  84. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  85. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
  86. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  87. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  88. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +44 -139
  89. data/spec/lib/appsignal/transaction_spec.rb +239 -94
  90. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  91. data/spec/lib/appsignal_spec.rb +556 -344
  92. data/spec/support/helpers/dependency_helper.rb +6 -1
  93. data/spec/support/helpers/std_streams_helper.rb +1 -1
  94. data/spec/support/helpers/transaction_helpers.rb +8 -0
  95. data/spec/support/matchers/transaction.rb +185 -0
  96. data/spec/support/mocks/dummy_app.rb +20 -0
  97. data/spec/support/shared_examples/instrument.rb +17 -12
  98. data/spec/support/testing.rb +18 -9
  99. metadata +20 -11
  100. data/.semaphore/semaphore.yml +0 -2347
  101. data/script/lint_git +0 -22
  102. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  103. data/spec/support/matchers/be_completed.rb +0 -5
  104. data/support/check_versions +0 -22
  105. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -88,13 +88,10 @@ describe Appsignal::Hooks::RedisClientHook do
88
88
  connection = RedisClient::RubyConnection.new client_config
89
89
  expect(connection.write([:get, "key"])).to eql("stub_write")
90
90
 
91
- transaction_hash = transaction.to_h
92
- expect(transaction_hash["events"]).to include(
93
- hash_including(
94
- "name" => "query.redis",
95
- "body" => "get ?",
96
- "title" => "stub_id"
97
- )
91
+ expect(transaction).to include_event(
92
+ "name" => "query.redis",
93
+ "body" => "get ?",
94
+ "title" => "stub_id"
98
95
  )
99
96
  end
100
97
 
@@ -103,16 +100,13 @@ describe Appsignal::Hooks::RedisClientHook do
103
100
  script = "return redis.call('set',KEYS[1],ARGV[1])"
104
101
  keys = ["foo"]
105
102
  argv = ["bar"]
106
- expect(connection.write([:eval, script, keys.size, keys,
107
- argv])).to eql("stub_write")
103
+ expect(connection.write([:eval, script, keys.size, keys, argv]))
104
+ .to eql("stub_write")
108
105
 
109
- transaction_hash = transaction.to_h
110
- expect(transaction_hash["events"]).to include(
111
- hash_including(
112
- "name" => "query.redis",
113
- "body" => "#{script} ? ?",
114
- "title" => "stub_id"
115
- )
106
+ expect(transaction).to include_event(
107
+ "name" => "query.redis",
108
+ "body" => "#{script} ? ?",
109
+ "title" => "stub_id"
116
110
  )
117
111
  end
118
112
  end
@@ -181,13 +175,10 @@ describe Appsignal::Hooks::RedisClientHook do
181
175
  connection = RedisClient::HiredisConnection.new client_config
182
176
  expect(connection.write([:get, "key"])).to eql("stub_write")
183
177
 
184
- transaction_hash = transaction.to_h
185
- expect(transaction_hash["events"]).to include(
186
- hash_including(
187
- "name" => "query.redis",
188
- "body" => "get ?",
189
- "title" => "stub_id"
190
- )
178
+ expect(transaction).to include_event(
179
+ "name" => "query.redis",
180
+ "body" => "get ?",
181
+ "title" => "stub_id"
191
182
  )
192
183
  end
193
184
 
@@ -199,13 +190,10 @@ describe Appsignal::Hooks::RedisClientHook do
199
190
  expect(connection.write([:eval, script, keys.size, keys,
200
191
  argv])).to eql("stub_write")
201
192
 
202
- transaction_hash = transaction.to_h
203
- expect(transaction_hash["events"]).to include(
204
- hash_including(
205
- "name" => "query.redis",
206
- "body" => "#{script} ? ?",
207
- "title" => "stub_id"
208
- )
193
+ expect(transaction).to include_event(
194
+ "name" => "query.redis",
195
+ "body" => "#{script} ? ?",
196
+ "title" => "stub_id"
209
197
  )
210
198
  end
211
199
  end
@@ -81,14 +81,11 @@ describe Appsignal::Hooks::RedisHook do
81
81
  client = Redis::Client.new
82
82
  expect(client.write([:get, "key"])).to eql("stub_write")
83
83
 
84
- transaction_hash = transaction.to_h
85
- expect(transaction_hash["events"]).to include(
86
- hash_including(
87
- "name" => "query.redis",
88
- "body" => "get ?",
89
- "title" => "stub_id"
90
- )
91
- )
84
+ expect(transaction).to include_event(
85
+ "name" => "query.redis",
86
+ "body" => "get ?",
87
+ "title" => "stub_id"
88
+ )
92
89
  end
93
90
 
94
91
  it "instrument a redis script call" do
@@ -98,14 +95,11 @@ describe Appsignal::Hooks::RedisHook do
98
95
  argv = ["bar"]
99
96
  expect(client.write([:eval, script, keys.size, keys, argv])).to eql("stub_write")
100
97
 
101
- transaction_hash = transaction.to_h
102
- expect(transaction_hash["events"]).to include(
103
- hash_including(
104
- "name" => "query.redis",
105
- "body" => "#{script} ? ?",
106
- "title" => "stub_id"
107
- )
108
- )
98
+ expect(transaction).to include_event(
99
+ "name" => "query.redis",
100
+ "body" => "#{script} ? ?",
101
+ "title" => "stub_id"
102
+ )
109
103
  end
110
104
  end
111
105
  end
@@ -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,7 +5,12 @@ if DependencyHelper.hanami2_present?
5
5
  require "appsignal/integrations/hanami"
6
6
 
7
7
  before do
8
+ Appsignal.config = nil
9
+ allow(::Hanami::Action).to receive(:prepend)
8
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"
9
14
  end
10
15
 
11
16
  def uninstall_hanami_middleware
@@ -18,35 +23,41 @@ if DependencyHelper.hanami2_present?
18
23
 
19
24
  describe Appsignal::Integrations::HanamiPlugin do
20
25
  it "starts AppSignal on init" do
21
- expect(Appsignal).to receive(:start)
22
- expect(Appsignal).to receive(:start_logger)
26
+ expect(Appsignal.active?).to be_falsey
27
+
23
28
  Appsignal::Integrations::HanamiPlugin.init
29
+
30
+ expect(Appsignal.active?).to be_truthy
24
31
  end
25
32
 
26
33
  it "prepends the integration to Hanami::Action" do
27
- allow(Appsignal).to receive(:active?).and_return(true)
28
34
  Appsignal::Integrations::HanamiPlugin.init
29
- expect(::Hanami::Action.included_modules)
30
- .to include(Appsignal::Integrations::HanamiIntegration)
35
+
36
+ expect(::Hanami::Action)
37
+ .to have_received(:prepend).with(Appsignal::Integrations::HanamiIntegration)
31
38
  end
32
39
 
33
40
  it "adds middleware to the Hanami app" do
34
- allow(Appsignal).to receive(:active?).and_return(true)
35
41
  Appsignal::Integrations::HanamiPlugin.init
36
42
 
37
43
  expect(::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX])
38
44
  .to include(
39
- [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], nil],
40
- [Appsignal::Rack::HanamiMiddleware, [], nil]
45
+ [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], *hanami_middleware_options],
46
+ [Appsignal::Rack::HanamiMiddleware, [], *hanami_middleware_options]
41
47
  )
42
48
  end
43
49
 
44
50
  context "when not active" do
45
- 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
46
56
 
47
57
  it "does not prepend the integration to Hanami::Action" do
48
58
  Appsignal::Integrations::HanamiPlugin.init
49
- expect(::Hanami::Action).to_not receive(:prepend)
59
+
60
+ expect(::Hanami::Action).to_not have_received(:prepend)
50
61
  .with(Appsignal::Integrations::HanamiIntegration)
51
62
  end
52
63
 
@@ -55,14 +66,47 @@ if DependencyHelper.hanami2_present?
55
66
 
56
67
  middleware_stack = ::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX]
57
68
  expect(middleware_stack).to_not include(
58
- [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], nil]
69
+ [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], *hanami_middleware_options]
59
70
  )
60
71
  expect(middleware_stack).to_not include(
61
- [Appsignal::Rack::HanamiMiddleware, [], nil]
72
+ [Appsignal::Rack::HanamiMiddleware, [], *hanami_middleware_options]
62
73
  )
63
74
  end
64
75
  end
65
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
108
+ end
109
+
66
110
  context "when APPSIGNAL_APP_ENV ENV var is provided" do
67
111
  it "uses this as the environment" do
68
112
  ENV["APPSIGNAL_APP_ENV"] = "custom"
@@ -86,14 +130,24 @@ if DependencyHelper.hanami2_present?
86
130
 
87
131
  describe Appsignal::Integrations::HanamiIntegration do
88
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
89
140
  around { |example| keep_transactions { example.run } }
90
- before(:context) { start_agent }
91
141
  before do
92
- allow(Appsignal).to receive(:active?).and_return(true)
142
+ ENV["APPSIGNAL_APP_NAME"] = "hanamia-test-app"
143
+ ENV["APPSIGNAL_APP_ENV"] = "test"
144
+ ENV["APPSIGNAL_PUSH_API_KEY"] = "0000"
93
145
  Appsignal::Integrations::HanamiPlugin.init
146
+ allow(app).to receive(:prepend).and_call_original
147
+ app.prepend(Appsignal::Integrations::HanamiIntegration)
94
148
  end
95
149
 
96
- def make_request(env, app: HanamiApp::Actions::Books::Index)
150
+ def make_request(env)
97
151
  action = app.new
98
152
  action.call(env)
99
153
  end
@@ -105,9 +159,7 @@ if DependencyHelper.hanami2_present?
105
159
  it "does not set the action name" do
106
160
  make_request(env)
107
161
 
108
- expect(transaction.to_h).to include(
109
- "action" => nil
110
- )
162
+ expect(transaction).to_not have_action
111
163
  end
112
164
  end
113
165
 
@@ -117,12 +169,18 @@ if DependencyHelper.hanami2_present?
117
169
  it "sets action name on the transaction" do
118
170
  make_request(env)
119
171
 
120
- expect(transaction.to_h).to include(
121
- "action" => "HanamiApp::Actions::Books::Index"
122
- )
172
+ expect(transaction).to have_action("HanamiApp::Actions::Books::Index::TestClass")
123
173
  end
124
174
  end
125
175
  end
126
176
  end
177
+
178
+ def hanami_middleware_options
179
+ if DependencyHelper.hanami2_1_present?
180
+ [{}, nil]
181
+ else
182
+ [nil]
183
+ end
184
+ end
127
185
  end
128
186
  end