appoptics_apm 4.0.2

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 (226) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +43 -0
  3. data/.dockerignore +5 -0
  4. data/.gitignore +23 -0
  5. data/.rubocop.yml +5 -0
  6. data/.travis.yml +82 -0
  7. data/CHANGELOG.md +769 -0
  8. data/CONFIG.md +33 -0
  9. data/Dockerfile +41 -0
  10. data/Dockerfile_test +66 -0
  11. data/Gemfile +41 -0
  12. data/LICENSE +193 -0
  13. data/README.md +351 -0
  14. data/Rakefile +202 -0
  15. data/Vagrantfile +67 -0
  16. data/appoptics_apm.gemspec +55 -0
  17. data/build_gems.sh +15 -0
  18. data/docker-compose.yml +73 -0
  19. data/examples/DNT.md +35 -0
  20. data/examples/carrying_context.rb +220 -0
  21. data/examples/instrumenting_metal_controller.rb +8 -0
  22. data/examples/puma_on_heroku_config.rb +17 -0
  23. data/examples/tracing_async_threads.rb +124 -0
  24. data/examples/tracing_background_jobs.rb +53 -0
  25. data/examples/tracing_forked_processes.rb +99 -0
  26. data/examples/unicorn_on_heroku_config.rb +28 -0
  27. data/ext/oboe_metal/extconf.rb +54 -0
  28. data/ext/oboe_metal/lib/.keep +0 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0.so.0.0.0 +0 -0
  30. data/ext/oboe_metal/noop/noop.c +7 -0
  31. data/ext/oboe_metal/src/VERSION +1 -0
  32. data/ext/oboe_metal/src/bson/bson.h +221 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/oboe.h +883 -0
  35. data/ext/oboe_metal/src/oboe.hpp +793 -0
  36. data/ext/oboe_metal/src/oboe_debug.h +50 -0
  37. data/ext/oboe_metal/src/oboe_wrap.cxx +6088 -0
  38. data/ext/oboe_metal/tests/test.rb +11 -0
  39. data/gemfiles/delayed_job.gemfile +36 -0
  40. data/gemfiles/frameworks.gemfile +44 -0
  41. data/gemfiles/instrumentation_mocked.gemfile +29 -0
  42. data/gemfiles/libraries.gemfile +85 -0
  43. data/gemfiles/rails23.gemfile +39 -0
  44. data/gemfiles/rails30.gemfile +42 -0
  45. data/gemfiles/rails31.gemfile +44 -0
  46. data/gemfiles/rails32.gemfile +54 -0
  47. data/gemfiles/rails40.gemfile +27 -0
  48. data/gemfiles/rails41.gemfile +27 -0
  49. data/gemfiles/rails42.gemfile +35 -0
  50. data/gemfiles/rails50.gemfile +44 -0
  51. data/gemfiles/rails51.gemfile +44 -0
  52. data/get_version.rb +5 -0
  53. data/init.rb +4 -0
  54. data/lib/appoptics_apm/api/layerinit.rb +39 -0
  55. data/lib/appoptics_apm/api/logging.rb +359 -0
  56. data/lib/appoptics_apm/api/memcache.rb +34 -0
  57. data/lib/appoptics_apm/api/profiling.rb +201 -0
  58. data/lib/appoptics_apm/api/tracing.rb +152 -0
  59. data/lib/appoptics_apm/api/util.rb +128 -0
  60. data/lib/appoptics_apm/api.rb +18 -0
  61. data/lib/appoptics_apm/base.rb +252 -0
  62. data/lib/appoptics_apm/config.rb +281 -0
  63. data/lib/appoptics_apm/frameworks/grape.rb +93 -0
  64. data/lib/appoptics_apm/frameworks/padrino/templates.rb +58 -0
  65. data/lib/appoptics_apm/frameworks/padrino.rb +52 -0
  66. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +106 -0
  67. data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +61 -0
  68. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +58 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +56 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  75. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  76. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  77. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +120 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +101 -0
  81. data/lib/appoptics_apm/frameworks/rails.rb +116 -0
  82. data/lib/appoptics_apm/frameworks/sinatra/templates.rb +56 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +71 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +92 -0
  86. data/lib/appoptics_apm/inst/curb.rb +329 -0
  87. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  88. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  89. data/lib/appoptics_apm/inst/em-http-request.rb +105 -0
  90. data/lib/appoptics_apm/inst/excon.rb +130 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +77 -0
  92. data/lib/appoptics_apm/inst/http.rb +83 -0
  93. data/lib/appoptics_apm/inst/httpclient.rb +176 -0
  94. data/lib/appoptics_apm/inst/memcache.rb +102 -0
  95. data/lib/appoptics_apm/inst/memcached.rb +94 -0
  96. data/lib/appoptics_apm/inst/mongo.rb +242 -0
  97. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  98. data/lib/appoptics_apm/inst/moped.rb +466 -0
  99. data/lib/appoptics_apm/inst/rack.rb +146 -0
  100. data/lib/appoptics_apm/inst/redis.rb +275 -0
  101. data/lib/appoptics_apm/inst/resque.rb +151 -0
  102. data/lib/appoptics_apm/inst/rest-client.rb +50 -0
  103. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  104. data/lib/appoptics_apm/inst/sidekiq-client.rb +53 -0
  105. data/lib/appoptics_apm/inst/sidekiq-worker.rb +67 -0
  106. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  107. data/lib/appoptics_apm/inst/typhoeus.rb +113 -0
  108. data/lib/appoptics_apm/instrumentation.rb +22 -0
  109. data/lib/appoptics_apm/legacy_method_profiling.rb +97 -0
  110. data/lib/appoptics_apm/loading.rb +66 -0
  111. data/lib/appoptics_apm/logger.rb +41 -0
  112. data/lib/appoptics_apm/method_profiling.rb +33 -0
  113. data/lib/appoptics_apm/ruby.rb +35 -0
  114. data/lib/appoptics_apm/support.rb +135 -0
  115. data/lib/appoptics_apm/test.rb +94 -0
  116. data/lib/appoptics_apm/thread_local.rb +26 -0
  117. data/lib/appoptics_apm/util.rb +312 -0
  118. data/lib/appoptics_apm/version.rb +15 -0
  119. data/lib/appoptics_apm/xtrace.rb +103 -0
  120. data/lib/appoptics_apm.rb +72 -0
  121. data/lib/joboe_metal.rb +214 -0
  122. data/lib/oboe/README +2 -0
  123. data/lib/oboe/backward_compatibility.rb +80 -0
  124. data/lib/oboe/inst/rack.rb +11 -0
  125. data/lib/oboe.rb +7 -0
  126. data/lib/oboe_metal.rb +187 -0
  127. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  128. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +222 -0
  129. data/ruby_setup.sh +47 -0
  130. data/run_docker_build_gem_upload_to_packagecloud.sh +20 -0
  131. data/run_tests_docker.rb +32 -0
  132. data/test/benchmark/README.md +65 -0
  133. data/test/benchmark/logging_bench.rb +54 -0
  134. data/test/benchmark/with_libraries_gemfile/bunny_bench.rb +69 -0
  135. data/test/benchmark/with_rails5x_gemfile/action_controller5x_bench.rb +43 -0
  136. data/test/frameworks/apps/grape_nested.rb +33 -0
  137. data/test/frameworks/apps/grape_simple.rb +80 -0
  138. data/test/frameworks/apps/padrino_simple.rb +80 -0
  139. data/test/frameworks/apps/sinatra_simple.rb +55 -0
  140. data/test/frameworks/grape_test.rb +286 -0
  141. data/test/frameworks/padrino_test.rb +222 -0
  142. data/test/frameworks/rails3x_test.rb +554 -0
  143. data/test/frameworks/rails4x_test.rb +570 -0
  144. data/test/frameworks/rails5x_api_test.rb +210 -0
  145. data/test/frameworks/rails5x_test.rb +376 -0
  146. data/test/frameworks/rails_shared_tests.rb +172 -0
  147. data/test/frameworks/sinatra_test.rb +140 -0
  148. data/test/instrumentation/bunny_client_test.rb +276 -0
  149. data/test/instrumentation/bunny_consumer_test.rb +204 -0
  150. data/test/instrumentation/curb_test.rb +398 -0
  151. data/test/instrumentation/dalli_test.rb +177 -0
  152. data/test/instrumentation/em_http_request_test.rb +89 -0
  153. data/test/instrumentation/excon_test.rb +231 -0
  154. data/test/instrumentation/faraday_test.rb +228 -0
  155. data/test/instrumentation/http_test.rb +143 -0
  156. data/test/instrumentation/httpclient_test.rb +320 -0
  157. data/test/instrumentation/memcache_test.rb +260 -0
  158. data/test/instrumentation/memcached_test.rb +229 -0
  159. data/test/instrumentation/mongo_v1_test.rb +479 -0
  160. data/test/instrumentation/mongo_v2_index_test.rb +124 -0
  161. data/test/instrumentation/mongo_v2_test.rb +584 -0
  162. data/test/instrumentation/mongo_v2_view_test.rb +435 -0
  163. data/test/instrumentation/moped_test.rb +517 -0
  164. data/test/instrumentation/rack_test.rb +165 -0
  165. data/test/instrumentation/redis_hashes_test.rb +268 -0
  166. data/test/instrumentation/redis_keys_test.rb +321 -0
  167. data/test/instrumentation/redis_lists_test.rb +310 -0
  168. data/test/instrumentation/redis_misc_test.rb +163 -0
  169. data/test/instrumentation/redis_sets_test.rb +296 -0
  170. data/test/instrumentation/redis_sortedsets_test.rb +328 -0
  171. data/test/instrumentation/redis_strings_test.rb +349 -0
  172. data/test/instrumentation/resque_test.rb +185 -0
  173. data/test/instrumentation/rest-client_test.rb +288 -0
  174. data/test/instrumentation/sequel_mysql2_test.rb +353 -0
  175. data/test/instrumentation/sequel_mysql_test.rb +334 -0
  176. data/test/instrumentation/sequel_pg_test.rb +336 -0
  177. data/test/instrumentation/sidekiq-client_test.rb +159 -0
  178. data/test/instrumentation/sidekiq-worker_test.rb +180 -0
  179. data/test/instrumentation/twitter-cassandra_test.rb +424 -0
  180. data/test/instrumentation/typhoeus_test.rb +284 -0
  181. data/test/jobs/delayed_job/db_worker_job.rb +29 -0
  182. data/test/jobs/delayed_job/error_worker_job.rb +10 -0
  183. data/test/jobs/delayed_job/remote_call_worker_job.rb +20 -0
  184. data/test/jobs/resque/db_worker_job.rb +29 -0
  185. data/test/jobs/resque/error_worker_job.rb +10 -0
  186. data/test/jobs/resque/remote_call_worker_job.rb +20 -0
  187. data/test/jobs/sidekiq/db_worker_job.rb +29 -0
  188. data/test/jobs/sidekiq/error_worker_job.rb +10 -0
  189. data/test/jobs/sidekiq/remote_call_worker_job.rb +20 -0
  190. data/test/minitest_helper.rb +276 -0
  191. data/test/mocked/curb_mocked_test.rb +311 -0
  192. data/test/mocked/excon_mocked_test.rb +166 -0
  193. data/test/mocked/faraday_mocked_test.rb +93 -0
  194. data/test/mocked/http_mocked_test.rb +129 -0
  195. data/test/mocked/httpclient_mocked_test.rb +245 -0
  196. data/test/mocked/rest_client_mocked_test.rb +103 -0
  197. data/test/mocked/typhoeus_mocked_test.rb +192 -0
  198. data/test/models/widget.rb +36 -0
  199. data/test/profiling/legacy_method_profiling_test.rb +201 -0
  200. data/test/profiling/method_profiling_test.rb +631 -0
  201. data/test/queues/delayed_job-client_test.rb +95 -0
  202. data/test/queues/delayed_job-worker_test.rb +91 -0
  203. data/test/reporter/reporter_test.rb +14 -0
  204. data/test/servers/delayed_job.rb +107 -0
  205. data/test/servers/rackapp_8101.rb +29 -0
  206. data/test/servers/rails3x_8140.rb +96 -0
  207. data/test/servers/rails4x_8140.rb +96 -0
  208. data/test/servers/rails5x_8140.rb +95 -0
  209. data/test/servers/rails5x_api_8150.rb +78 -0
  210. data/test/servers/sidekiq.rb +29 -0
  211. data/test/servers/sidekiq.yml +7 -0
  212. data/test/servers/sidekiq_initializer.rb +25 -0
  213. data/test/settings +0 -0
  214. data/test/support/auto_tracing_test.rb +50 -0
  215. data/test/support/backcompat_test.rb +276 -0
  216. data/test/support/config_test.rb +149 -0
  217. data/test/support/dnt_test.rb +98 -0
  218. data/test/support/init_report_test.rb +25 -0
  219. data/test/support/liboboe_settings_test.rb +110 -0
  220. data/test/support/logging_test.rb +130 -0
  221. data/test/support/noop_test.rb +88 -0
  222. data/test/support/sql_sanitize_test.rb +55 -0
  223. data/test/support/tracing_mode_test.rb +33 -0
  224. data/test/support/tvalias_test.rb +15 -0
  225. data/test/support/xtrace_test.rb +41 -0
  226. metadata +475 -0
@@ -0,0 +1,172 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require "minitest_helper"
5
+ require 'mocha/mini_test'
6
+
7
+
8
+ describe "RailsSharedTests" do
9
+ before do
10
+ clear_all_traces
11
+ AppOpticsAPM.config_lock.synchronize {
12
+ @tm = AppOpticsAPM::Config[:tracing_mode]
13
+ @sample_rate = AppOpticsAPM::Config[:sample_rate]
14
+ }
15
+ end
16
+
17
+ after do
18
+ AppOpticsAPM.config_lock.synchronize {
19
+ AppOpticsAPM::Config[:tracing_mode] = @tm
20
+ AppOpticsAPM::Config[:sample_rate] = @sample_rate
21
+ }
22
+ end
23
+
24
+ it "should NOT trace when tracing is set to :never" do
25
+ AppOpticsAPM.config_lock.synchronize do
26
+ AppOpticsAPM::Config[:tracing_mode] = :never
27
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
28
+ r = Net::HTTP.get_response(uri)
29
+
30
+ traces = get_all_traces
31
+ traces.count.must_equal 0
32
+ end
33
+ end
34
+
35
+ it "should NOT trace when sample_rate is 0" do
36
+ AppOpticsAPM.config_lock.synchronize do
37
+ AppOpticsAPM::Config[:sample_rate] = 0
38
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
39
+ r = Net::HTTP.get_response(uri)
40
+
41
+ traces = get_all_traces
42
+ traces.count.must_equal 0
43
+ end
44
+ end
45
+
46
+ it "should NOT trace when there is no context" do
47
+ response_headers = HelloController.action("world").call(
48
+ "REQUEST_METHOD" => "GET",
49
+ "rack.input" => -> {}
50
+ )[1]
51
+
52
+ response_headers.key?('X-Trace').must_equal false
53
+
54
+ traces = get_all_traces
55
+ traces.count.must_equal 0
56
+ end
57
+
58
+ it "should send inbound metrics" do
59
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
60
+
61
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
62
+ test_action = action
63
+ test_url = url
64
+ test_status = status
65
+ test_method = method
66
+ test_error = error
67
+ end.once
68
+
69
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
70
+ Net::HTTP.get_response(uri)
71
+
72
+ assert_equal "HelloController.world", test_action
73
+ assert_equal "http://127.0.0.1:8140/hello/world", test_url
74
+ assert_equal 200, test_status
75
+ assert_equal "GET", test_method
76
+ assert_equal 0, test_error
77
+
78
+ assert_controller_action(test_action)
79
+ end
80
+
81
+ it "should send inbound metrics when not tracing" do
82
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
83
+ AppOpticsAPM.config_lock.synchronize do
84
+ AppOpticsAPM::Config[:tracing_mode] = :never
85
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
86
+ test_action = action
87
+ test_url = url
88
+ test_status = status
89
+ test_method = method
90
+ test_error = error
91
+ end.once
92
+
93
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
94
+ Net::HTTP.get_response(uri)
95
+ end
96
+
97
+ assert_equal "HelloController.world", test_action
98
+ assert_equal "http://127.0.0.1:8140/hello/world", test_url
99
+ assert_equal 200, test_status
100
+ assert_equal "GET", test_method
101
+ assert_equal 0, test_error
102
+ end
103
+
104
+ it "should send metrics for 500 errors" do
105
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
106
+
107
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
108
+ test_action = action
109
+ test_url = url
110
+ test_status = status
111
+ test_method = method
112
+ test_error = error
113
+ end.once
114
+
115
+ uri = URI.parse('http://127.0.0.1:8140/hello/servererror')
116
+ Net::HTTP.get_response(uri)
117
+
118
+ assert_equal "HelloController.servererror", test_action
119
+ assert_equal "http://127.0.0.1:8140/hello/servererror", test_url
120
+ assert_equal 500, test_status
121
+ assert_equal "GET", test_method
122
+ assert_equal 1, test_error
123
+
124
+ assert_controller_action(test_action)
125
+ end
126
+
127
+ it "should find the controller action for a route with a parameter" do
128
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
129
+
130
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
131
+ test_action = action
132
+ test_url = url
133
+ test_status = status
134
+ test_method = method
135
+ test_error = error
136
+ end.once
137
+
138
+ uri = URI.parse('http://127.0.0.1:8140/hello/15/show')
139
+ Net::HTTP.get_response(uri)
140
+
141
+ assert_equal "HelloController.show", test_action
142
+ assert_equal "http://127.0.0.1:8140/hello/15/show", test_url
143
+ assert_equal 200, test_status
144
+ assert_equal "GET", test_method
145
+ assert_equal 0, test_error
146
+
147
+ assert_controller_action(test_action)
148
+ end
149
+
150
+ it "should find controller action in the metal stack" do
151
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
152
+
153
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
154
+ test_action = action
155
+ test_url = url
156
+ test_status = status
157
+ test_method = method
158
+ test_error = error
159
+ end.once
160
+
161
+ uri = URI.parse('http://127.0.0.1:8140/hello/metal')
162
+ r = Net::HTTP.get_response(uri)
163
+
164
+ assert_equal 200, test_status
165
+ assert_equal "FerroController.world", test_action
166
+ assert_equal "http://127.0.0.1:8140/hello/metal", test_url
167
+ assert_equal "GET", test_method
168
+ assert_equal 0, test_error
169
+
170
+ assert_controller_action(test_action)
171
+ end
172
+ end
@@ -0,0 +1,140 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+
5
+ require "minitest_helper"
6
+ require "mocha/mini_test"
7
+ require File.expand_path(File.dirname(__FILE__) + '/apps/sinatra_simple')
8
+
9
+ describe Sinatra do
10
+ before do
11
+ clear_all_traces
12
+ end
13
+
14
+ it "should trace a request to a simple sinatra stack" do
15
+ @app = SinatraSimple
16
+
17
+ r = get "/render"
18
+
19
+ traces = get_all_traces
20
+
21
+ traces.count.must_equal 9
22
+ valid_edges?(traces).must_equal true
23
+ validate_outer_layers(traces, 'rack')
24
+
25
+ traces[2]['Layer'].must_equal "sinatra"
26
+ traces[4]['Label'].must_equal "profile_entry"
27
+ traces[7]['Controller'].must_equal "SinatraSimple"
28
+ traces[8]['Label'].must_equal "exit"
29
+
30
+ # Validate the existence of the response header
31
+ r.headers.key?('X-Trace').must_equal true
32
+ r.headers['X-Trace'].must_equal traces[8]['X-Trace']
33
+ end
34
+
35
+ it "should not have RUM code in the response" do
36
+ @app = SinatraSimple
37
+
38
+ r = get "/render"
39
+
40
+ (r.body =~ /tly.js/).must_be_nil
41
+ end
42
+
43
+ it "should report the route with :id" do
44
+ @app = SinatraSimple
45
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
46
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
47
+ test_action = action
48
+ test_url = url
49
+ test_status = status
50
+ test_method = method
51
+ test_error = error
52
+ end.once
53
+
54
+ r = get "/render/123304952309747203947"
55
+
56
+ r.body.must_match /123304952309747203947/
57
+
58
+ assert_equal "SinatraSimple.GET /render/:id", test_action
59
+ assert_equal "http://example.org/render/123304952309747203947", test_url
60
+ assert_equal 200, test_status
61
+ assert_equal "GET", test_method
62
+ assert_equal 0, test_error
63
+
64
+ assert_controller_action(test_action)
65
+ end
66
+
67
+ it "should report the route with :id and more" do
68
+ @app = SinatraSimple
69
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
70
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
71
+ test_action = action
72
+ test_url = url
73
+ test_status = status
74
+ test_method = method
75
+ test_error = error
76
+ end.once
77
+
78
+ r = get "/render/123304952309747203947/what"
79
+
80
+ r.body.must_match /WOOT.*123304952309747203947/
81
+
82
+ assert_equal "SinatraSimple.GET /render/:id/what", test_action
83
+ assert_equal "http://example.org/render/123304952309747203947/what", test_url
84
+ assert_equal 200, test_status
85
+ assert_equal "GET", test_method
86
+ assert_equal 0, test_error
87
+
88
+ assert_controller_action(test_action)
89
+ end
90
+
91
+ it "should report the route with splats" do
92
+ @app = SinatraSimple
93
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
94
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
95
+ test_action = action
96
+ test_url = url
97
+ test_status = status
98
+ test_method = method
99
+ test_error = error
100
+ end.once
101
+
102
+ r = get "/say/hello/to/world"
103
+
104
+ r.body.must_match /hello world/
105
+
106
+ assert_equal "SinatraSimple.GET /say/*/to/*", test_action
107
+ assert_equal "http://example.org/say/hello/to/world", test_url
108
+ assert_equal 200, test_status
109
+ assert_equal "GET", test_method
110
+ assert_equal 0, test_error
111
+
112
+ assert_controller_action(test_action)
113
+ end
114
+
115
+ if RUBY_VERSION > '2.2'
116
+ it "should report the route with regex" do
117
+ @app = SinatraSimple
118
+ test_action, test_url, test_status, test_method, test_error = nil, nil, nil, nil, nil
119
+ AppOpticsAPM::Span.expects(:createHttpSpan).with do |action, url, _duration, status, method, error|
120
+ test_action = action
121
+ test_url = url
122
+ test_status = status
123
+ test_method = method
124
+ test_error = error
125
+ end.once
126
+
127
+ r = get "/hello/friend"
128
+
129
+ r.body.must_match /Hello, friend/
130
+
131
+ test_action.must_match "SinatraSimple.GET \\/hello\\/([\\w]+)", test_action
132
+ assert_equal "http://example.org/hello/friend", test_url
133
+ assert_equal 200, test_status
134
+ assert_equal "GET", test_method
135
+ assert_equal 0, test_error
136
+
137
+ assert_controller_action(test_action)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,276 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'minitest_helper'
5
+
6
+ unless defined?(JRUBY_VERSION)
7
+ class BunnyClientTest < Minitest::Test
8
+ def setup
9
+ # Support specific environment variables to support remote rabbitmq servers
10
+ ENV['APPOPTICS_RABBITMQ_SERVER'] = "127.0.0.1" unless ENV['APPOPTICS_RABBITMQ_SERVER']
11
+ ENV['APPOPTICS_RABBITMQ_PORT'] = "5672" unless ENV['APPOPTICS_RABBITMQ_PORT']
12
+ ENV['APPOPTICS_RABBITMQ_USERNAME'] = "guest" unless ENV['APPOPTICS_RABBITMQ_USERNAME']
13
+ ENV['APPOPTICS_RABBITMQ_PASSWORD'] = "guest" unless ENV['APPOPTICS_RABBITMQ_PASSWORD']
14
+ ENV['APPOPTICS_RABBITMQ_VHOST'] = "/" unless ENV['APPOPTICS_RABBITMQ_VHOST']
15
+
16
+ @connection_params = {}
17
+ @connection_params[:host] = ENV['APPOPTICS_RABBITMQ_SERVER']
18
+ @connection_params[:port] = ENV['APPOPTICS_RABBITMQ_PORT']
19
+ @connection_params[:vhost] = ENV['APPOPTICS_RABBITMQ_VHOST']
20
+ @connection_params[:user] = ENV['APPOPTICS_RABBITMQ_USERNAME']
21
+ @connection_params[:pass] = ENV['APPOPTICS_RABBITMQ_PASSWORD']
22
+
23
+ clear_all_traces
24
+ end
25
+
26
+ def test_publish_default_exchange
27
+ @conn = Bunny.new(@connection_params)
28
+ @conn.start
29
+ @ch = @conn.create_channel
30
+ @queue = @ch.queue("tv.ruby.test")
31
+ @exchange = @ch.default_exchange
32
+
33
+ AppOpticsAPM::API.start_trace('bunny_tests') do
34
+ @exchange.publish("The Tortoise and the Hare", :routing_key => @queue.name)
35
+ end
36
+
37
+ traces = get_all_traces
38
+ traces.count.must_equal 4
39
+
40
+ validate_outer_layers(traces, "bunny_tests")
41
+ assert valid_edges?(traces), "Invalid edge in traces"
42
+
43
+ traces[1]['Layer'].must_equal "rabbitmq-client"
44
+ traces[1]['Label'].must_equal "entry"
45
+ traces[2]['Layer'].must_equal "rabbitmq-client"
46
+ traces[2]['Label'].must_equal "exit"
47
+ traces[2]['Spec'].must_equal "pushq"
48
+ traces[2]['Flavor'].must_equal "rabbitmq"
49
+ traces[2]['ExchangeName'].must_equal "default"
50
+ traces[2]['RoutingKey'].must_equal "tv.ruby.test"
51
+ traces[2]['Op'].must_equal "publish"
52
+ traces[2]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
53
+ traces[2]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
54
+ traces[2]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
55
+
56
+ @conn.close
57
+ end
58
+
59
+ def test_publish_fanout_exchange
60
+ @conn = Bunny.new(@connection_params)
61
+ @conn.start
62
+ @ch = @conn.create_channel
63
+ @exchange = @ch.fanout("tv.ruby.fanout.tests")
64
+
65
+ AppOpticsAPM::API.start_trace('bunny_tests') do
66
+ @exchange.publish("The Tortoise and the Hare in the fanout exchange.", :routing_key => 'tv.ruby.test').publish("And another...")
67
+ end
68
+
69
+ traces = get_all_traces
70
+ traces.count.must_equal 6
71
+
72
+ validate_outer_layers(traces, "bunny_tests")
73
+ assert valid_edges?(traces), "Invalid edge in traces"
74
+
75
+ traces[1]['Layer'].must_equal "rabbitmq-client"
76
+ traces[1]['Label'].must_equal "entry"
77
+ traces[2]['Layer'].must_equal "rabbitmq-client"
78
+ traces[2]['Label'].must_equal "exit"
79
+ traces[2]['Spec'].must_equal "pushq"
80
+ traces[2]['Flavor'].must_equal "rabbitmq"
81
+ traces[2]['ExchangeName'].must_equal "tv.ruby.fanout.tests"
82
+ traces[2]['RoutingKey'].must_equal "tv.ruby.test"
83
+ traces[2]['Op'].must_equal "publish"
84
+ traces[2]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
85
+ traces[2]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
86
+ traces[2]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
87
+
88
+ traces[3]['Layer'].must_equal "rabbitmq-client"
89
+ traces[3]['Label'].must_equal "entry"
90
+ traces[4]['Layer'].must_equal "rabbitmq-client"
91
+ traces[4]['Label'].must_equal "exit"
92
+ traces[4]['Spec'].must_equal "pushq"
93
+ traces[4]['Flavor'].must_equal "rabbitmq"
94
+ traces[4]['ExchangeName'].must_equal "tv.ruby.fanout.tests"
95
+ traces[4].key?('RoutingKey').must_equal false
96
+ traces[4]['Op'].must_equal "publish"
97
+ traces[4]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
98
+ traces[4]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
99
+ traces[4]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
100
+
101
+ @conn.close
102
+ end
103
+
104
+ def test_publish_topic_exchange
105
+ @conn = Bunny.new(@connection_params)
106
+ @conn.start
107
+ @ch = @conn.create_channel
108
+ @exchange = @ch.topic("tv.ruby.topic.tests", :auto_delete => true)
109
+
110
+ AppOpticsAPM::API.start_trace('bunny_tests') do
111
+ @exchange.publish("The Tortoise and the Hare in the topic exchange.", :routing_key => 'tv.ruby.test.1').publish("And another...", :routing_key => 'tv.ruby.test.2' )
112
+ end
113
+
114
+ traces = get_all_traces
115
+ traces.count.must_equal 6
116
+
117
+ validate_outer_layers(traces, "bunny_tests")
118
+ assert valid_edges?(traces), "Invalid edge in traces"
119
+
120
+ traces[1]['Layer'].must_equal "rabbitmq-client"
121
+ traces[1]['Label'].must_equal "entry"
122
+ traces[2]['Layer'].must_equal "rabbitmq-client"
123
+ traces[2]['Label'].must_equal "exit"
124
+ traces[2]['Spec'].must_equal "pushq"
125
+ traces[2]['Flavor'].must_equal "rabbitmq"
126
+ traces[2]['ExchangeName'].must_equal "tv.ruby.topic.tests"
127
+ traces[2]['RoutingKey'].must_equal "tv.ruby.test.1"
128
+ traces[2]['Op'].must_equal "publish"
129
+ traces[2]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
130
+ traces[2]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
131
+ traces[2]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
132
+
133
+ traces[3]['Layer'].must_equal "rabbitmq-client"
134
+ traces[3]['Label'].must_equal "entry"
135
+ traces[4]['Layer'].must_equal "rabbitmq-client"
136
+ traces[4]['Label'].must_equal "exit"
137
+ traces[4]['Spec'].must_equal "pushq"
138
+ traces[4]['Flavor'].must_equal "rabbitmq"
139
+ traces[4]['ExchangeName'].must_equal "tv.ruby.topic.tests"
140
+ traces[4]['RoutingKey'].must_equal "tv.ruby.test.2"
141
+ traces[4]['Op'].must_equal "publish"
142
+ traces[4]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
143
+ traces[4]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
144
+ traces[4]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
145
+
146
+ @conn.close
147
+ end
148
+
149
+ def test_publish_error_handling
150
+ @conn = Bunny.new(@connection_params)
151
+ @conn.start
152
+ @ch = @conn.create_channel
153
+
154
+ begin
155
+ AppOpticsAPM::API.start_trace('bunny_tests') do
156
+ @exchange = @ch.topic("tv.ruby.error.1", :auto_delete => true)
157
+ @exchange = @ch.fanout("tv.ruby.error.1", :auto_delete => true)
158
+ @exchange.publish("The Tortoise and the Hare in the topic exchange.", :routing_key => 'tv.ruby.test.1').publish("And another...", :routing_key => 'tv.ruby.test.2' )
159
+ end
160
+ rescue
161
+ # Capture intentional redeclaration error
162
+ end
163
+
164
+ traces = get_all_traces
165
+ assert_equal 3, traces.count
166
+
167
+ validate_outer_layers(traces, "bunny_tests")
168
+ assert valid_edges?(traces), "Invalid edge in traces"
169
+
170
+ traces[1]['Label'].must_equal "error"
171
+ traces[1]['ErrorClass'].must_equal "Bunny::PreconditionFailed"
172
+ traces[1]['ErrorMsg'].must_match(/PRECONDITION_FAILED/)
173
+ traces[1].key?('Backtrace').must_equal true
174
+
175
+ @conn.close
176
+ end
177
+
178
+ def test_delete_exchange
179
+ @conn = Bunny.new(@connection_params)
180
+ @conn.start
181
+ @ch = @conn.create_channel
182
+ @exchange = @ch.fanout("tv.delete_exchange.test")
183
+ @queue = @ch.queue("", :exclusive => true).bind(@exchange)
184
+
185
+ @ch.confirm_select
186
+ @exchange.publish("", :routing_key => 'tv.ruby.test')
187
+
188
+ AppOpticsAPM::API.start_trace('bunny_tests') do
189
+ @exchange.delete
190
+ end
191
+
192
+ traces = get_all_traces
193
+ traces.count.must_equal 4
194
+
195
+ validate_outer_layers(traces, "bunny_tests")
196
+
197
+ traces[2]['Spec'].must_equal "pushq"
198
+ traces[2]['Flavor'].must_equal "rabbitmq"
199
+ traces[2]['ExchangeName'].must_equal "tv.delete_exchange.test"
200
+ traces[2]['ExchangeType'].must_equal "fanout"
201
+ traces[2]['Op'].must_equal "delete"
202
+ traces[2]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
203
+ traces[2]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
204
+ traces[2]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
205
+ end
206
+
207
+ def test_wait_for_confirms
208
+ @conn = Bunny.new(@connection_params)
209
+ @conn.start
210
+ @ch = @conn.create_channel
211
+ @exchange = @ch.fanout("tv.ruby.wait_for_confirm.tests")
212
+ @queue = @ch.queue("", :exclusive => true).bind(@exchange)
213
+
214
+ @ch.confirm_select
215
+
216
+ AppOpticsAPM::API.start_trace('bunny_tests') do
217
+ 1000.times do
218
+ @exchange.publish("", :routing_key => 'tv.ruby.test')
219
+ end
220
+
221
+ @ch.wait_for_confirms
222
+ end
223
+
224
+ traces = get_all_traces
225
+ assert_equal 2004,traces.count
226
+
227
+ validate_outer_layers(traces, "bunny_tests")
228
+
229
+ traces[2000]['Spec'].must_equal "pushq"
230
+ traces[2000]['Flavor'].must_equal "rabbitmq"
231
+ traces[2000]['ExchangeName'].must_equal "tv.ruby.wait_for_confirm.tests"
232
+ traces[2000]['RoutingKey'].must_equal "tv.ruby.test"
233
+ traces[2000]['Op'].must_equal "publish"
234
+ traces[2000]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
235
+ traces[2000]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
236
+ traces[2000]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
237
+
238
+ traces[2001]['Layer'].must_equal "rabbitmq-client"
239
+ traces[2001]['Label'].must_equal "entry"
240
+ traces[2002]['Layer'].must_equal "rabbitmq-client"
241
+ traces[2002]['Label'].must_equal "exit"
242
+ traces[2002]['Spec'].must_equal "pushq"
243
+ traces[2002]['Flavor'].must_equal "rabbitmq"
244
+ traces[2002]['Op'].must_equal "wait_for_confirms"
245
+ traces[2002]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
246
+ traces[2002]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
247
+ traces[2002]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
248
+
249
+ @conn.close
250
+ end
251
+
252
+ def test_channel_queue
253
+ @conn = Bunny.new(@connection_params)
254
+ @conn.start
255
+ @ch = @conn.create_channel
256
+ @exchange = @ch.fanout("tv.queue.test")
257
+
258
+ AppOpticsAPM::API.start_trace('bunny_tests') do
259
+ @queue = @ch.queue("blah", :exclusive => true).bind(@exchange)
260
+ end
261
+
262
+ traces = get_all_traces
263
+ traces.count.must_equal 4
264
+
265
+ validate_outer_layers(traces, "bunny_tests")
266
+
267
+ traces[2]['Spec'].must_equal "pushq"
268
+ traces[2]['Flavor'].must_equal "rabbitmq"
269
+ traces[2]['Op'].must_equal "queue"
270
+ traces[2]['Queue'].must_equal "blah"
271
+ traces[2]['RemoteHost'].must_equal ENV['APPOPTICS_RABBITMQ_SERVER']
272
+ traces[2]['RemotePort'].must_equal ENV['APPOPTICS_RABBITMQ_PORT'].to_i
273
+ traces[2]['VirtualHost'].must_equal ENV['APPOPTICS_RABBITMQ_VHOST']
274
+ end
275
+ end
276
+ end