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,147 @@
1
+ describe Appsignal::Rack::JSExceptionCatcher do
2
+ let(:app) { double(:call => true) }
3
+ let(:options) { nil }
4
+ let(:config_options) { { :enable_frontend_error_catching => true } }
5
+ let(:config) { project_fixture_config("production", config_options) }
6
+ before { Appsignal.config = config }
7
+
8
+ describe "#initialize" do
9
+ it "logs to the logger" do
10
+ expect(Appsignal.logger).to receive(:debug)
11
+ .with("Initializing Appsignal::Rack::JSExceptionCatcher")
12
+
13
+ Appsignal::Rack::JSExceptionCatcher.new(app, options)
14
+ end
15
+ end
16
+
17
+ describe "#call" do
18
+ let(:catcher) { Appsignal::Rack::JSExceptionCatcher.new(app, options) }
19
+ after { catcher.call(env) }
20
+
21
+ context "when path is not frontend_error_catching_path" do
22
+ let(:env) { { "PATH_INFO" => "/foo" } }
23
+
24
+ context "when AppSignal is not active" do
25
+ before { config[:active] = false }
26
+
27
+ it "calls the next middleware" do
28
+ expect(app).to receive(:call).with(env)
29
+ end
30
+ end
31
+
32
+ context "when AppSignal is active" do
33
+ before { config[:active] = true }
34
+
35
+ it "calls the next middleware" do
36
+ expect(app).to receive(:call).with(env)
37
+ end
38
+ end
39
+ end
40
+
41
+ context "when path is frontend_error_catching_path" do
42
+ let(:transaction) { double(:complete! => true) }
43
+ let(:env) do
44
+ {
45
+ "PATH_INFO" => "/appsignal_error_catcher",
46
+ "rack.input" => double(:read => '{"name": "error"}')
47
+ }
48
+ end
49
+
50
+ context "when AppSignal is not active" do
51
+ before { config[:active] = false }
52
+
53
+ it "doesn't create an AppSignal transaction" do
54
+ expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
55
+ end
56
+
57
+ it "returns a 202 status" do
58
+ expect(catcher.call(env)).to eq(
59
+ [202, {}, ["AppSignal JavaScript error catching endpoint is not active."]]
60
+ )
61
+ end
62
+ end
63
+
64
+ context "when AppSignal is active" do
65
+ before { config[:active] = true }
66
+
67
+ it "creates a JSExceptionTransaction" do
68
+ expect(Appsignal::JSExceptionTransaction).to receive(:new)
69
+ .with("name" => "error")
70
+ .and_return(transaction)
71
+
72
+ expect(transaction).to receive(:complete!)
73
+ end
74
+
75
+ it "returns 200" do
76
+ allow(Appsignal::JSExceptionTransaction).to receive(:new)
77
+ .and_return(transaction)
78
+
79
+ expect(catcher.call(env)).to eq([200, {}, []])
80
+ end
81
+
82
+ context "when request payload is empty" do
83
+ let(:env) do
84
+ {
85
+ "PATH_INFO" => "/appsignal_error_catcher",
86
+ "rack.input" => double(:read => "")
87
+ }
88
+ end
89
+
90
+ it "does not create a transaction" do
91
+ expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
92
+ end
93
+
94
+ it "returns 400" do
95
+ expect(catcher.call(env)).to eq([400, {}, ["Request payload is not valid JSON."]])
96
+ end
97
+ end
98
+
99
+ context "when `frontend_error_catching_path` is different" do
100
+ let(:config_options) { { :frontend_error_catching_path => "/foo" } }
101
+
102
+ it "does not create a transaction" do
103
+ expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
104
+ end
105
+
106
+ it "calls the next middleware" do
107
+ expect(app).to receive(:call).with(env)
108
+ end
109
+ end
110
+
111
+ context "when `name` is empty" do
112
+ let(:env) do
113
+ {
114
+ "PATH_INFO" => "/appsignal_error_catcher",
115
+ "rack.input" => double(:read => '{"name": ""}')
116
+ }
117
+ end
118
+
119
+ it "does not create a transaction" do
120
+ expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
121
+ end
122
+
123
+ it "returns 422" do
124
+ expect(catcher.call(env)).to eq([422, {}, []])
125
+ end
126
+ end
127
+
128
+ context "when `name` doesn't exist" do
129
+ let(:env) do
130
+ {
131
+ "PATH_INFO" => "/appsignal_error_catcher",
132
+ "rack.input" => double(:read => '{"foo": ""}')
133
+ }
134
+ end
135
+
136
+ it "does not create a transaction" do
137
+ expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
138
+ end
139
+
140
+ it "returns 422" do
141
+ expect(catcher.call(env)).to eq([422, {}, []])
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,117 @@
1
+ if DependencyHelper.rails_present?
2
+ class MockController
3
+ end
4
+
5
+ describe Appsignal::Rack::RailsInstrumentation do
6
+ before :context do
7
+ start_agent
8
+ end
9
+
10
+ let(:app) { double(:call => true) }
11
+ let(:env) do
12
+ http_request_env_with_data("action_dispatch.request_id" => "1").tap do |request|
13
+ request["action_controller.instance"] = double(
14
+ :class => MockController,
15
+ :action_name => "index"
16
+ )
17
+ end
18
+ end
19
+ let(:middleware) { Appsignal::Rack::RailsInstrumentation.new(app, {}) }
20
+
21
+ describe "#call" do
22
+ before do
23
+ allow(middleware).to receive(:raw_payload).and_return({})
24
+ end
25
+
26
+ context "when appsignal is active" do
27
+ before { allow(Appsignal).to receive(:active?).and_return(true) }
28
+
29
+ it "should call with monitoring" do
30
+ expect(middleware).to receive(:call_with_appsignal_monitoring).with(env)
31
+ end
32
+ end
33
+
34
+ context "when appsignal is not active" do
35
+ before { allow(Appsignal).to receive(:active?).and_return(false) }
36
+
37
+ it "should not call with monitoring" do
38
+ expect(middleware).to_not receive(:call_with_appsignal_monitoring)
39
+ end
40
+
41
+ it "should call the app" do
42
+ expect(app).to receive(:call).with(env)
43
+ end
44
+ end
45
+
46
+ after { middleware.call(env) }
47
+ end
48
+
49
+ describe "#call_with_appsignal_monitoring", :error => false do
50
+ it "should create a transaction" do
51
+ expect(Appsignal::Transaction).to receive(:create).with(
52
+ "1",
53
+ Appsignal::Transaction::HTTP_REQUEST,
54
+ kind_of(ActionDispatch::Request),
55
+ :params_method => :filtered_parameters
56
+ ).and_return(
57
+ instance_double(
58
+ "Appsignal::Transaction",
59
+ :set_action => nil,
60
+ :set_action_if_nil => nil,
61
+ :set_http_or_background_queue_start => nil,
62
+ :set_metadata => nil
63
+ )
64
+ )
65
+ end
66
+
67
+ it "should call the app" do
68
+ expect(app).to receive(:call).with(env)
69
+ end
70
+
71
+ context "with an exception", :error => true do
72
+ let(:error) { ExampleException }
73
+ let(:app) do
74
+ double.tap do |d|
75
+ allow(d).to receive(:call).and_raise(error)
76
+ end
77
+ end
78
+
79
+ it "records the exception" do
80
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
81
+ end
82
+ end
83
+
84
+ it "should set metadata" do
85
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).twice
86
+ end
87
+
88
+ it "should set the action and queue start" do
89
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil).with("MockController#index")
90
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_http_or_background_queue_start)
91
+ end
92
+
93
+ after(:error => false) { middleware.call(env) }
94
+ after(:error => true) { expect { middleware.call(env) }.to raise_error(error) }
95
+ end
96
+
97
+ describe "#request_id" do
98
+ subject { middleware.request_id(env) }
99
+
100
+ context "with request id present" do
101
+ let(:env) { { "action_dispatch.request_id" => "id" } }
102
+
103
+ it "returns the present id" do
104
+ is_expected.to eq "id"
105
+ end
106
+ end
107
+
108
+ context "with request id not present" do
109
+ let(:env) { {} }
110
+
111
+ it "sets a new id" do
112
+ expect(subject.length).to eq 36
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,213 @@
1
+ if DependencyHelper.sinatra_present?
2
+ require "appsignal/integrations/sinatra"
3
+
4
+ describe Appsignal::Rack::SinatraInstrumentation do
5
+ let(:settings) { double(:raise_errors => false) }
6
+ let(:app) { double(:call => true, :settings => settings) }
7
+ let(:env) { { "sinatra.route" => "GET /", :path => "/", :method => "GET" } }
8
+ let(:middleware) { Appsignal::Rack::SinatraInstrumentation.new(app) }
9
+
10
+ describe "#call" do
11
+ before do
12
+ start_agent
13
+ allow(middleware).to receive(:raw_payload).and_return({})
14
+ allow(Appsignal).to receive(:active?).and_return(true)
15
+ end
16
+
17
+ it "should call without monitoring" do
18
+ expect(Appsignal::Transaction).to_not receive(:create)
19
+ end
20
+
21
+ after { middleware.call(env) }
22
+ end
23
+
24
+ describe ".settings" do
25
+ subject { middleware.settings }
26
+
27
+ it "should return the app's settings" do
28
+ expect(subject).to eq(app.settings)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe Appsignal::Rack::SinatraBaseInstrumentation do
34
+ before :context do
35
+ start_agent
36
+ end
37
+
38
+ let(:settings) { double(:raise_errors => false) }
39
+ let(:app) { double(:call => true, :settings => settings) }
40
+ let(:env) { { "sinatra.route" => "GET /", :path => "/", :method => "GET" } }
41
+ let(:options) { {} }
42
+ let(:middleware) { Appsignal::Rack::SinatraBaseInstrumentation.new(app, options) }
43
+
44
+ describe "#initialize" do
45
+ context "with no settings method in the Sinatra app" do
46
+ let(:app) { double(:call => true) }
47
+
48
+ it "should not raise errors" do
49
+ expect(middleware.raise_errors_on).to be(false)
50
+ end
51
+ end
52
+
53
+ context "with no raise_errors setting in the Sinatra app" do
54
+ let(:app) { double(:call => true, :settings => double) }
55
+
56
+ it "should not raise errors" do
57
+ expect(middleware.raise_errors_on).to be(false)
58
+ end
59
+ end
60
+
61
+ context "with raise_errors turned off in the Sinatra app" do
62
+ let(:app) { double(:call => true, :settings => double(:raise_errors => false)) }
63
+
64
+ it "should raise errors" do
65
+ expect(middleware.raise_errors_on).to be(false)
66
+ end
67
+ end
68
+
69
+ context "with raise_errors turned on in the Sinatra app" do
70
+ let(:app) { double(:call => true, :settings => double(:raise_errors => true)) }
71
+
72
+ it "should raise errors" do
73
+ expect(middleware.raise_errors_on).to be(true)
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "#call" do
79
+ before do
80
+ allow(middleware).to receive(:raw_payload).and_return({})
81
+ end
82
+
83
+ context "when appsignal is active" do
84
+ before { allow(Appsignal).to receive(:active?).and_return(true) }
85
+
86
+ it "should call with monitoring" do
87
+ expect(middleware).to receive(:call_with_appsignal_monitoring).with(env)
88
+ end
89
+ end
90
+
91
+ context "when appsignal is not active" do
92
+ before { allow(Appsignal).to receive(:active?).and_return(false) }
93
+
94
+ it "should not call with monitoring" do
95
+ expect(middleware).to_not receive(:call_with_appsignal_monitoring)
96
+ end
97
+
98
+ it "should call the stack" do
99
+ expect(app).to receive(:call).with(env)
100
+ end
101
+ end
102
+
103
+ after { middleware.call(env) }
104
+ end
105
+
106
+ describe "#call_with_appsignal_monitoring", :error => false do
107
+ it "should create a transaction" do
108
+ expect(Appsignal::Transaction).to receive(:create).with(
109
+ kind_of(String),
110
+ Appsignal::Transaction::HTTP_REQUEST,
111
+ kind_of(Sinatra::Request),
112
+ kind_of(Hash)
113
+ ).and_return(double(:set_action_if_nil => nil, :set_http_or_background_queue_start => nil, :set_metadata => nil))
114
+ end
115
+
116
+ it "should call the app" do
117
+ expect(app).to receive(:call).with(env)
118
+ end
119
+
120
+ context "with an error", :error => true do
121
+ let(:error) { ExampleException }
122
+ let(:app) do
123
+ double.tap do |d|
124
+ allow(d).to receive(:call).and_raise(error)
125
+ allow(d).to receive(:settings).and_return(settings)
126
+ end
127
+ end
128
+
129
+ it "records the exception" do
130
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
131
+ end
132
+ end
133
+
134
+ context "with an error in sinatra.error" do
135
+ let(:error) { ExampleException }
136
+ let(:env) { { "sinatra.error" => error } }
137
+
138
+ it "records the exception" do
139
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
140
+ end
141
+
142
+ context "when raise_errors is on" do
143
+ let(:settings) { double(:raise_errors => true) }
144
+
145
+ it "does not record the error" do
146
+ expect_any_instance_of(Appsignal::Transaction).to_not receive(:set_error)
147
+ end
148
+ end
149
+
150
+ context "if sinatra.skip_appsignal_error is set" do
151
+ let(:env) { { "sinatra.error" => error, "sinatra.skip_appsignal_error" => true } }
152
+
153
+ it "does not record the error" do
154
+ expect_any_instance_of(Appsignal::Transaction).to_not receive(:set_error)
155
+ end
156
+ end
157
+ end
158
+
159
+ describe "action name" do
160
+ it "should set the action" do
161
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil).with("GET /")
162
+ end
163
+
164
+ context "without 'sinatra.route' env" do
165
+ let(:env) { { :path => "/", :method => "GET" } }
166
+
167
+ it "returns nil" do
168
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil).with(nil)
169
+ end
170
+ end
171
+
172
+ context "with mounted modular application" do
173
+ before { env["SCRIPT_NAME"] = "/api" }
174
+
175
+ it "should call set_action with an application prefix path" do
176
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil).with("GET /api/")
177
+ end
178
+
179
+ context "without 'sinatra.route' env" do
180
+ let(:env) { { :path => "/", :method => "GET" } }
181
+
182
+ it "returns nil" do
183
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_action_if_nil).with(nil)
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ it "should set metadata" do
190
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_metadata).twice
191
+ end
192
+
193
+ it "should set the queue start" do
194
+ expect_any_instance_of(Appsignal::Transaction).to receive(:set_http_or_background_queue_start)
195
+ end
196
+
197
+ context "with overridden request class and params method" do
198
+ let(:options) { { :request_class => ::Rack::Request, :params_method => :filtered_params } }
199
+
200
+ it "should use the overridden request class and params method" do
201
+ request = ::Rack::Request.new(env)
202
+ expect(::Rack::Request).to receive(:new)
203
+ .with(env.merge(:params_method => :filtered_params))
204
+ .at_least(:once)
205
+ .and_return(request)
206
+ end
207
+ end
208
+
209
+ after(:error => false) { middleware.call(env) }
210
+ after(:error => true) { expect { middleware.call(env) }.to raise_error(error) }
211
+ end
212
+ end
213
+ end