appsignal 2.5.0.alpha.1-java

Sign up to get free protection for your applications and to get access to all the features.
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