appsignal 2.5.0.alpha.1-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 (211) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rspec +4 -0
  4. data/.rubocop.yml +66 -0
  5. data/.rubocop_todo.yml +124 -0
  6. data/.travis.yml +72 -0
  7. data/.yardopts +8 -0
  8. data/CHANGELOG.md +639 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE +20 -0
  11. data/README.md +264 -0
  12. data/Rakefile +214 -0
  13. data/appsignal.gemspec +42 -0
  14. data/benchmark.rake +77 -0
  15. data/bin/appsignal +13 -0
  16. data/ext/Rakefile +27 -0
  17. data/ext/agent.yml +64 -0
  18. data/ext/appsignal_extension.c +692 -0
  19. data/ext/base.rb +79 -0
  20. data/ext/extconf.rb +35 -0
  21. data/gemfiles/capistrano2.gemfile +7 -0
  22. data/gemfiles/capistrano3.gemfile +7 -0
  23. data/gemfiles/grape.gemfile +7 -0
  24. data/gemfiles/no_dependencies.gemfile +5 -0
  25. data/gemfiles/padrino.gemfile +7 -0
  26. data/gemfiles/que.gemfile +5 -0
  27. data/gemfiles/rails-3.2.gemfile +6 -0
  28. data/gemfiles/rails-4.0.gemfile +6 -0
  29. data/gemfiles/rails-4.1.gemfile +6 -0
  30. data/gemfiles/rails-4.2.gemfile +10 -0
  31. data/gemfiles/rails-5.0.gemfile +5 -0
  32. data/gemfiles/rails-5.1.gemfile +5 -0
  33. data/gemfiles/resque.gemfile +12 -0
  34. data/gemfiles/sequel-435.gemfile +11 -0
  35. data/gemfiles/sequel.gemfile +11 -0
  36. data/gemfiles/sinatra.gemfile +6 -0
  37. data/gemfiles/webmachine.gemfile +5 -0
  38. data/lib/appsignal.rb +804 -0
  39. data/lib/appsignal/auth_check.rb +65 -0
  40. data/lib/appsignal/capistrano.rb +10 -0
  41. data/lib/appsignal/cli.rb +108 -0
  42. data/lib/appsignal/cli/demo.rb +63 -0
  43. data/lib/appsignal/cli/diagnose.rb +500 -0
  44. data/lib/appsignal/cli/helpers.rb +72 -0
  45. data/lib/appsignal/cli/install.rb +277 -0
  46. data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
  47. data/lib/appsignal/config.rb +287 -0
  48. data/lib/appsignal/demo.rb +107 -0
  49. data/lib/appsignal/event_formatter.rb +74 -0
  50. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
  51. data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
  52. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
  53. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
  54. data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
  55. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
  56. data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
  57. data/lib/appsignal/extension.rb +63 -0
  58. data/lib/appsignal/extension/jruby.rb +460 -0
  59. data/lib/appsignal/garbage_collection_profiler.rb +48 -0
  60. data/lib/appsignal/hooks.rb +105 -0
  61. data/lib/appsignal/hooks/action_cable.rb +113 -0
  62. data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
  63. data/lib/appsignal/hooks/celluloid.rb +30 -0
  64. data/lib/appsignal/hooks/data_mapper.rb +18 -0
  65. data/lib/appsignal/hooks/delayed_job.rb +19 -0
  66. data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
  67. data/lib/appsignal/hooks/net_http.rb +29 -0
  68. data/lib/appsignal/hooks/passenger.rb +22 -0
  69. data/lib/appsignal/hooks/puma.rb +35 -0
  70. data/lib/appsignal/hooks/que.rb +21 -0
  71. data/lib/appsignal/hooks/rake.rb +39 -0
  72. data/lib/appsignal/hooks/redis.rb +30 -0
  73. data/lib/appsignal/hooks/sequel.rb +60 -0
  74. data/lib/appsignal/hooks/shoryuken.rb +43 -0
  75. data/lib/appsignal/hooks/sidekiq.rb +144 -0
  76. data/lib/appsignal/hooks/unicorn.rb +40 -0
  77. data/lib/appsignal/hooks/webmachine.rb +23 -0
  78. data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
  79. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
  80. data/lib/appsignal/integrations/data_mapper.rb +33 -0
  81. data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
  82. data/lib/appsignal/integrations/grape.rb +53 -0
  83. data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
  84. data/lib/appsignal/integrations/object.rb +35 -0
  85. data/lib/appsignal/integrations/padrino.rb +84 -0
  86. data/lib/appsignal/integrations/que.rb +43 -0
  87. data/lib/appsignal/integrations/railtie.rb +41 -0
  88. data/lib/appsignal/integrations/rake.rb +2 -0
  89. data/lib/appsignal/integrations/resque.rb +20 -0
  90. data/lib/appsignal/integrations/resque_active_job.rb +30 -0
  91. data/lib/appsignal/integrations/sinatra.rb +17 -0
  92. data/lib/appsignal/integrations/webmachine.rb +38 -0
  93. data/lib/appsignal/js_exception_transaction.rb +54 -0
  94. data/lib/appsignal/marker.rb +63 -0
  95. data/lib/appsignal/minutely.rb +42 -0
  96. data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
  97. data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
  98. data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
  99. data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
  100. data/lib/appsignal/rack/streaming_listener.rb +73 -0
  101. data/lib/appsignal/system.rb +81 -0
  102. data/lib/appsignal/transaction.rb +498 -0
  103. data/lib/appsignal/transmitter.rb +107 -0
  104. data/lib/appsignal/utils.rb +127 -0
  105. data/lib/appsignal/utils/params_sanitizer.rb +59 -0
  106. data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
  107. data/lib/appsignal/version.rb +3 -0
  108. data/lib/sequel/extensions/appsignal_integration.rb +3 -0
  109. data/resources/appsignal.yml.erb +39 -0
  110. data/resources/cacert.pem +3866 -0
  111. data/spec/.rubocop.yml +7 -0
  112. data/spec/lib/appsignal/auth_check_spec.rb +80 -0
  113. data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
  114. data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
  115. data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
  116. data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
  117. data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
  118. data/spec/lib/appsignal/cli/install_spec.rb +632 -0
  119. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
  120. data/spec/lib/appsignal/cli_spec.rb +56 -0
  121. data/spec/lib/appsignal/config_spec.rb +637 -0
  122. data/spec/lib/appsignal/demo_spec.rb +87 -0
  123. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
  124. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
  125. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
  126. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
  127. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
  128. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
  129. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
  130. data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
  131. data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
  132. data/spec/lib/appsignal/extension_spec.rb +137 -0
  133. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
  134. data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
  135. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
  136. data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
  137. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
  138. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
  139. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
  140. data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
  141. data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
  142. data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
  143. data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
  144. data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
  145. data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
  146. data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
  147. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
  148. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
  149. data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
  150. data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
  151. data/spec/lib/appsignal/hooks_spec.rb +195 -0
  152. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
  153. data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
  154. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
  155. data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
  156. data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
  157. data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
  158. data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
  159. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
  160. data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
  161. data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
  162. data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
  163. data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
  164. data/spec/lib/appsignal/marker_spec.rb +51 -0
  165. data/spec/lib/appsignal/minutely_spec.rb +50 -0
  166. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
  167. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
  168. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
  169. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
  170. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
  171. data/spec/lib/appsignal/system_spec.rb +131 -0
  172. data/spec/lib/appsignal/transaction_spec.rb +1146 -0
  173. data/spec/lib/appsignal/transmitter_spec.rb +152 -0
  174. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
  175. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
  176. data/spec/lib/appsignal/utils_spec.rb +150 -0
  177. data/spec/lib/appsignal_spec.rb +1049 -0
  178. data/spec/spec_helper.rb +116 -0
  179. data/spec/support/fixtures/containers/cgroups/docker +14 -0
  180. data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
  181. data/spec/support/fixtures/containers/cgroups/lxc +10 -0
  182. data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
  183. data/spec/support/fixtures/containers/cgroups/none +1 -0
  184. data/spec/support/fixtures/generated_config.yml +24 -0
  185. data/spec/support/fixtures/uploaded_file.txt +0 -0
  186. data/spec/support/helpers/api_request_helper.rb +19 -0
  187. data/spec/support/helpers/cli_helpers.rb +26 -0
  188. data/spec/support/helpers/config_helpers.rb +21 -0
  189. data/spec/support/helpers/dependency_helper.rb +73 -0
  190. data/spec/support/helpers/directory_helper.rb +27 -0
  191. data/spec/support/helpers/env_helpers.rb +33 -0
  192. data/spec/support/helpers/example_exception.rb +13 -0
  193. data/spec/support/helpers/example_standard_error.rb +13 -0
  194. data/spec/support/helpers/log_helpers.rb +22 -0
  195. data/spec/support/helpers/std_streams_helper.rb +66 -0
  196. data/spec/support/helpers/system_helpers.rb +8 -0
  197. data/spec/support/helpers/time_helpers.rb +11 -0
  198. data/spec/support/helpers/transaction_helpers.rb +37 -0
  199. data/spec/support/matchers/contains_log.rb +7 -0
  200. data/spec/support/mocks/fake_gc_profiler.rb +19 -0
  201. data/spec/support/mocks/mock_extension.rb +6 -0
  202. data/spec/support/project_fixture/config/application.rb +0 -0
  203. data/spec/support/project_fixture/config/appsignal.yml +32 -0
  204. data/spec/support/project_fixture/config/environments/development.rb +0 -0
  205. data/spec/support/project_fixture/config/environments/production.rb +0 -0
  206. data/spec/support/project_fixture/config/environments/test.rb +0 -0
  207. data/spec/support/project_fixture/log/.gitkeep +0 -0
  208. data/spec/support/rails/my_app.rb +6 -0
  209. data/spec/support/shared_examples/instrument.rb +43 -0
  210. data/spec/support/stubs/delayed_job.rb +0 -0
  211. metadata +483 -0
@@ -0,0 +1,419 @@
1
+ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
2
+ class DelayedTestClass; end
3
+
4
+ let(:namespace) { Appsignal::Transaction::BACKGROUND_JOB }
5
+ let(:worker) { anything }
6
+ let(:queue) { anything }
7
+ let(:given_args) do
8
+ [
9
+ "foo",
10
+ {
11
+ :foo => "Foo",
12
+ :bar => "Bar",
13
+ "baz" => { 1 => :foo }
14
+ }
15
+ ]
16
+ end
17
+ let(:expected_args) do
18
+ [
19
+ "foo",
20
+ {
21
+ "foo" => "Foo",
22
+ "bar" => "Bar",
23
+ "baz" => { "1" => "foo" }
24
+ }
25
+ ]
26
+ end
27
+ let(:job_class) { "TestClass" }
28
+ let(:item) do
29
+ {
30
+ "jid" => "b4a577edbccf1d805744efa9",
31
+ "class" => job_class,
32
+ "retry_count" => 0,
33
+ "queue" => "default",
34
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
35
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
36
+ "args" => given_args,
37
+ "extra" => "data"
38
+ }
39
+ end
40
+ let(:plugin) { Appsignal::Hooks::SidekiqPlugin.new }
41
+ let(:test_store) { {} }
42
+ let(:log) { StringIO.new }
43
+ before do
44
+ start_agent
45
+ Appsignal.logger = test_logger(log)
46
+
47
+ # Stub calls to extension, because that would remove the transaction
48
+ # from the extension.
49
+ allow_any_instance_of(Appsignal::Extension::Transaction).to receive(:finish).and_return(true)
50
+ allow_any_instance_of(Appsignal::Extension::Transaction).to receive(:complete)
51
+
52
+ # Stub removal of current transaction from current thread so we can fetch
53
+ # it later.
54
+ expect(Appsignal::Transaction).to receive(:clear_current_transaction!) do
55
+ transaction = Thread.current[:appsignal_transaction]
56
+ test_store[:transaction] = transaction if transaction
57
+ end
58
+ end
59
+ after :with_yaml_parse_error => false do
60
+ expect(log_contents(log)).to_not contains_log(:warn, "Unable to load YAML")
61
+ end
62
+ after { clear_current_transaction! }
63
+
64
+ shared_examples "sidekiq metadata" do
65
+ describe "internal Sidekiq job values" do
66
+ it "does not save internal Sidekiq values as metadata on transaction" do
67
+ perform_job
68
+
69
+ transaction_hash = transaction.to_h
70
+ expect(transaction_hash["metadata"].keys)
71
+ .to_not include(*Appsignal::Hooks::SidekiqPlugin::JOB_KEYS)
72
+ end
73
+ end
74
+
75
+ context "with parameter filtering" do
76
+ before do
77
+ Appsignal.config = project_fixture_config("production")
78
+ Appsignal.config[:filter_parameters] = ["foo"]
79
+ end
80
+
81
+ it "filters selected arguments" do
82
+ perform_job
83
+
84
+ transaction_hash = transaction.to_h
85
+ expect(transaction_hash["sample_data"]).to include(
86
+ "params" => [
87
+ "foo",
88
+ {
89
+ "foo" => "[FILTERED]",
90
+ "bar" => "Bar",
91
+ "baz" => { "1" => "foo" }
92
+ }
93
+ ]
94
+ )
95
+ end
96
+ end
97
+
98
+ context "with encrypted arguments" do
99
+ before do
100
+ item["encrypt"] = true
101
+ item["args"] << "super secret value" # Last argument will be replaced
102
+ end
103
+
104
+ it "replaces the last argument (the secret bag) with an [encrypted data] string" do
105
+ perform_job
106
+
107
+ transaction_hash = transaction.to_h
108
+ expect(transaction_hash["sample_data"]).to include(
109
+ "params" => expected_args << "[encrypted data]"
110
+ )
111
+ end
112
+ end
113
+
114
+ context "when using the Sidekiq delayed extension" do
115
+ let(:item) do
116
+ {
117
+ "jid" => "efb140489485999d32b5504c",
118
+ "class" => "Sidekiq::Extensions::DelayedClass",
119
+ "queue" => "default",
120
+ "args" => [
121
+ "---\n- !ruby/class 'DelayedTestClass'\n- :foo_method\n- - :bar: baz\n"
122
+ ],
123
+ "retry" => true,
124
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
125
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
126
+ "extra" => "data"
127
+ }
128
+ end
129
+
130
+ it "uses the delayed class and method name for the action" do
131
+ perform_job
132
+
133
+ transaction_hash = transaction.to_h
134
+ expect(transaction_hash["action"]).to eq("DelayedTestClass.foo_method")
135
+ expect(transaction_hash["sample_data"]).to include(
136
+ "params" => ["bar" => "baz"]
137
+ )
138
+ end
139
+
140
+ context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
141
+ before { item["args"] = [] }
142
+
143
+ it "logs a warning and uses the default argument" do
144
+ perform_job
145
+
146
+ transaction_hash = transaction.to_h
147
+ expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedClass#perform")
148
+ expect(transaction_hash["sample_data"]).to include("params" => [])
149
+ expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
150
+ end
151
+ end
152
+ end
153
+
154
+ context "when using ActiveJob" do
155
+ let(:item) do
156
+ {
157
+ "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
158
+ "wrapped" => "ActiveJobTestClass",
159
+ "queue" => "default",
160
+ "args" => [{
161
+ "job_class" => "ActiveJobTestJob",
162
+ "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
163
+ "queue_name" => "default",
164
+ "arguments" => [
165
+ "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
166
+ ]
167
+ }],
168
+ "retry" => true,
169
+ "jid" => "efb140489485999d32b5504c",
170
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
171
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f
172
+ }
173
+ end
174
+
175
+ it "creates a transaction with events" do
176
+ perform_job
177
+
178
+ transaction_hash = transaction.to_h
179
+ expect(transaction_hash).to include(
180
+ "id" => kind_of(String),
181
+ "action" => "ActiveJobTestClass#perform",
182
+ "error" => nil,
183
+ "namespace" => namespace,
184
+ "metadata" => {
185
+ "queue" => "default"
186
+ },
187
+ "sample_data" => {
188
+ "environment" => {},
189
+ "params" => [
190
+ "foo",
191
+ {
192
+ "foo" => "Foo",
193
+ "bar" => "Bar",
194
+ "baz" => { "1" => "bar" }
195
+ }
196
+ ],
197
+ "tags" => {}
198
+ }
199
+ )
200
+ # TODO: Not available in transaction.to_h yet.
201
+ # https://github.com/appsignal/appsignal-agent/issues/293
202
+ expect(transaction.request.env).to eq(
203
+ :queue_start => Time.parse("2001-01-01 10:00:00UTC").to_f
204
+ )
205
+ expect_transaction_to_have_sidekiq_event(transaction_hash)
206
+ end
207
+
208
+ context "with ActionMailer job" do
209
+ let(:item) do
210
+ {
211
+ "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
212
+ "wrapped" => "ActionMailer::DeliveryJob",
213
+ "queue" => "default",
214
+ "args" => [{
215
+ "job_class" => "ActiveMailerTestJob",
216
+ "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
217
+ "queue_name" => "default",
218
+ "arguments" => [
219
+ "MailerClass", "mailer_method", "deliver_now",
220
+ "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
221
+ ]
222
+ }],
223
+ "retry" => true,
224
+ "jid" => "efb140489485999d32b5504c",
225
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
226
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f
227
+ }
228
+ end
229
+
230
+ it "creates a transaction for the ActionMailer class" do
231
+ perform_job
232
+
233
+ transaction_hash = transaction.to_h
234
+ expect(transaction_hash).to include(
235
+ "id" => kind_of(String),
236
+ "action" => "MailerClass#mailer_method",
237
+ "error" => nil,
238
+ "namespace" => namespace,
239
+ "metadata" => {
240
+ "queue" => "default"
241
+ },
242
+ "sample_data" => {
243
+ "environment" => {},
244
+ "params" => [
245
+ "foo",
246
+ {
247
+ "foo" => "Foo",
248
+ "bar" => "Bar",
249
+ "baz" => { "1" => "bar" }
250
+ }
251
+ ],
252
+ "tags" => {}
253
+ }
254
+ )
255
+ end
256
+ end
257
+
258
+ context "with parameter filtering" do
259
+ before do
260
+ Appsignal.config = project_fixture_config("production")
261
+ Appsignal.config[:filter_parameters] = ["foo"]
262
+ end
263
+
264
+ it "filters selected arguments" do
265
+ perform_job
266
+
267
+ transaction_hash = transaction.to_h
268
+ expect(transaction_hash["sample_data"]).to include(
269
+ "params" => [
270
+ "foo",
271
+ {
272
+ "foo" => "[FILTERED]",
273
+ "bar" => "Bar",
274
+ "baz" => { "1" => "bar" }
275
+ }
276
+ ]
277
+ )
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ context "with an error" do
284
+ let(:error) { ExampleException }
285
+
286
+ it "creates a transaction and adds the error" do
287
+ expect do
288
+ perform_job { raise error, "uh oh" }
289
+ end.to raise_error(error)
290
+
291
+ transaction_hash = transaction.to_h
292
+ expect(transaction_hash).to include(
293
+ "id" => kind_of(String),
294
+ "action" => "TestClass#perform",
295
+ "error" => {
296
+ "name" => "ExampleException",
297
+ "message" => "uh oh",
298
+ # TODO: backtrace should be an Array of Strings
299
+ # https://github.com/appsignal/appsignal-agent/issues/294
300
+ "backtrace" => kind_of(String)
301
+ },
302
+ "metadata" => {
303
+ "extra" => "data",
304
+ "queue" => "default",
305
+ "retry_count" => "0"
306
+ },
307
+ "namespace" => namespace,
308
+ "sample_data" => {
309
+ "environment" => {},
310
+ "params" => expected_args,
311
+ "tags" => {}
312
+ }
313
+ )
314
+ expect_transaction_to_have_sidekiq_event(transaction_hash)
315
+ end
316
+
317
+ include_examples "sidekiq metadata"
318
+ end
319
+
320
+ context "without an error" do
321
+ it "creates a transaction with events" do
322
+ perform_job
323
+
324
+ transaction_hash = transaction.to_h
325
+ expect(transaction_hash).to include(
326
+ "id" => kind_of(String),
327
+ "action" => "TestClass#perform",
328
+ "error" => nil,
329
+ "metadata" => {
330
+ "extra" => "data",
331
+ "queue" => "default",
332
+ "retry_count" => "0"
333
+ },
334
+ "namespace" => namespace,
335
+ "sample_data" => {
336
+ "environment" => {},
337
+ "params" => expected_args,
338
+ "tags" => {}
339
+ }
340
+ )
341
+ # TODO: Not available in transaction.to_h yet.
342
+ # https://github.com/appsignal/appsignal-agent/issues/293
343
+ expect(transaction.request.env).to eq(
344
+ :queue_start => Time.parse("2001-01-01 10:00:00UTC").to_f
345
+ )
346
+ expect_transaction_to_have_sidekiq_event(transaction_hash)
347
+ end
348
+
349
+ include_examples "sidekiq metadata"
350
+ end
351
+
352
+ def perform_job
353
+ Timecop.freeze(Time.parse("2001-01-01 10:01:00UTC")) do
354
+ plugin.call(worker, item, queue) do
355
+ yield if block_given?
356
+ end
357
+ end
358
+ end
359
+
360
+ def transaction
361
+ test_store[:transaction]
362
+ end
363
+
364
+ def expect_transaction_to_have_sidekiq_event(transaction_hash)
365
+ events = transaction_hash["events"]
366
+ expect(events.count).to eq(1)
367
+ expect(events.first).to include(
368
+ "name" => "perform_job.sidekiq",
369
+ "title" => "",
370
+ "count" => 1,
371
+ "body" => "",
372
+ "body_format" => Appsignal::EventFormatter::DEFAULT
373
+ )
374
+ end
375
+ end
376
+
377
+ describe Appsignal::Hooks::SidekiqHook do
378
+ describe "#dependencies_present?" do
379
+ subject { described_class.new.dependencies_present? }
380
+
381
+ context "when Sidekiq constant is found" do
382
+ before { Object.const_set("Sidekiq", 1) }
383
+ after { Object.send(:remove_const, "Sidekiq") }
384
+
385
+ it { is_expected.to be_truthy }
386
+ end
387
+
388
+ context "when Sidekiq constant is not found" do
389
+ before { Object.send(:remove_const, "Sidekiq") if defined?(Sidekiq) }
390
+
391
+ it { is_expected.to be_falsy }
392
+ end
393
+ end
394
+
395
+ describe "#install" do
396
+ before do
397
+ class Sidekiq
398
+ def self.middlewares
399
+ @middlewares ||= Set.new
400
+ end
401
+
402
+ def self.configure_server
403
+ yield self
404
+ end
405
+
406
+ def self.server_middleware
407
+ yield middlewares
408
+ end
409
+ end
410
+ end
411
+ after { Object.send(:remove_const, "Sidekiq") }
412
+
413
+ it "adds the AppSignal SidekiqPlugin to the Sidekiq middleware chain" do
414
+ described_class.new.install
415
+
416
+ expect(Sidekiq.middlewares).to include(Appsignal::Hooks::SidekiqPlugin)
417
+ end
418
+ end
419
+ end
@@ -0,0 +1,52 @@
1
+ describe Appsignal::Hooks::UnicornHook do
2
+ context "with unicorn" do
3
+ before :context do
4
+ module Unicorn
5
+ class HttpServer
6
+ def worker_loop(worker)
7
+ end
8
+ end
9
+
10
+ class Worker
11
+ def close
12
+ end
13
+ end
14
+ end
15
+ Appsignal::Hooks::UnicornHook.new.install
16
+ end
17
+ after(:context) { Object.send(:remove_const, :Unicorn) }
18
+
19
+ describe "#dependencies_present?" do
20
+ subject { described_class.new.dependencies_present? }
21
+
22
+ it { is_expected.to be_truthy }
23
+ end
24
+
25
+ it "adds behavior to Unicorn::HttpServer#worker_loop" do
26
+ server = Unicorn::HttpServer.new
27
+ worker = double
28
+
29
+ expect(Appsignal).to receive(:forked)
30
+ expect(server).to receive(:worker_loop_without_appsignal).with(worker)
31
+
32
+ server.worker_loop(worker)
33
+ end
34
+
35
+ it "adds behavior to Unicorn::Worker#close" do
36
+ worker = Unicorn::Worker.new
37
+
38
+ expect(Appsignal).to receive(:stop)
39
+ expect(worker).to receive(:close_without_appsignal)
40
+
41
+ worker.close
42
+ end
43
+ end
44
+
45
+ context "without unicorn" do
46
+ describe "#dependencies_present?" do
47
+ subject { described_class.new.dependencies_present? }
48
+
49
+ it { is_expected.to be_falsy }
50
+ end
51
+ end
52
+ end