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,276 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+ require 'minitest/spec'
7
+ require 'minitest/autorun'
8
+ require 'minitest/reporters'
9
+ require 'minitest/debugger' if ENV['DEBUG']
10
+
11
+ if ENV['TEST_RUNS_TO_FILE']
12
+ # write to STDOUT as well as file (comes in handy with docker runs)
13
+ FileUtils.mkdir_p('log') # create if it doesn't exist
14
+ $out_file = File.new("log/test_runs_#{Time.now.strftime("%Y_%m_%d")}.log", 'a')
15
+ $out_file.sync = true
16
+ $stdout.sync = true
17
+ def $stdout.write string
18
+ $out_file.write string
19
+ super
20
+ end
21
+ end
22
+
23
+ puts "\n\033[1m=== TEST RUN: #{ENV['RVM_TEST']} #{ENV['BUNDLE_GEMFILE']} #{Time.now.strftime("%Y-%m-%d %H:%M")} ===\033[0m\n"
24
+
25
+ ENV['RACK_ENV'] = 'test'
26
+ ENV['APPOPTICS_GEM_TEST'] = 'true'
27
+
28
+ #
29
+ # ENV['APPOPTICS_GEM_VERBOSE'] = 'true'
30
+
31
+ # FIXME: Temp hack to fix padrino-core calling RUBY_ENGINE when it's not defined under Ruby 1.9.3
32
+ RUBY_ENGINE = 'ruby' unless defined?(RUBY_ENGINE)
33
+
34
+ Minitest::Spec.new 'pry'
35
+
36
+ MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
37
+
38
+ if defined?(JRUBY_VERSION)
39
+ ENV['JAVA_OPTS'] = "-J-javaagent:/usr/local/tracelytics/tracelyticsagent.jar"
40
+ end
41
+
42
+ Bundler.require(:default, :test)
43
+
44
+ # Configure AppOpticsAPM
45
+ AppOpticsAPM::Config[:verbose] = true
46
+ AppOpticsAPM::Config[:tracing_mode] = "always"
47
+ AppOpticsAPM::Config[:sample_rate] = 1000000
48
+ AppOpticsAPM.logger.level = Logger::DEBUG
49
+
50
+ # Pre-create test databases (see also .travis.yml)
51
+ # puts "Pre-creating test databases"
52
+ # puts %x{mysql -u root -e 'create database travis_ci_test;'}
53
+ # puts %x{psql -c 'create database travis_ci_test;' -U postgres}
54
+
55
+ # Our background Rack-app for http client testing
56
+ require './test/servers/rackapp_8101'
57
+
58
+ # Conditionally load other background servers
59
+ # depending on what we're testing
60
+ #
61
+ case File.basename(ENV['BUNDLE_GEMFILE'])
62
+ when /delayed_job/
63
+ require './test/servers/delayed_job'
64
+
65
+ when /rails5/
66
+ require './test/servers/rails5x_8140'
67
+ require './test/servers/rails5x_api_8150'
68
+
69
+ when /rails4/
70
+ require './test/servers/rails4x_8140'
71
+
72
+ when /rails3/
73
+ require './test/servers/rails3x_8140'
74
+
75
+ when /frameworks/
76
+ when /libraries/
77
+ if RUBY_VERSION >= '2.0'
78
+ # Load Sidekiq if TEST isn't defined or if it is, it calls
79
+ # out the sidekiq tests
80
+ if !ENV.key?('TEST') || ENV['TEST'] =~ /sidekiq/
81
+ # Background Sidekiq thread
82
+ require './test/servers/sidekiq.rb'
83
+ end
84
+ end
85
+ end
86
+
87
+ ##
88
+ # clear_all_traces
89
+ #
90
+ # Truncates the trace output file to zero
91
+ #
92
+ def clear_all_traces
93
+ if AppOpticsAPM.loaded
94
+ AppOpticsAPM::Context.clear
95
+ AppOpticsAPM::Reporter.clear_all_traces
96
+ sleep 0.2 # it seems like the docker file system needs a bit of time to clear the file
97
+ end
98
+ end
99
+
100
+ ##
101
+ # get_all_traces
102
+ #
103
+ # Retrieves all traces written to the trace file
104
+ #
105
+ def get_all_traces
106
+ if AppOpticsAPM.loaded
107
+ AppOpticsAPM::Reporter.get_all_traces
108
+ else
109
+ []
110
+ end
111
+ end
112
+
113
+ ##
114
+ # validate_outer_layers
115
+ #
116
+ # Validates that the KVs in kvs are present
117
+ # in event
118
+ #
119
+ def validate_outer_layers(traces, layer)
120
+ traces.first['Layer'].must_equal layer
121
+ traces.first['Label'].must_equal 'entry'
122
+ traces.last['Layer'].must_equal layer
123
+ traces.last['Label'].must_equal 'exit'
124
+ end
125
+
126
+ ##
127
+ # validate_event_keys
128
+ #
129
+ # Validates that the KVs in kvs are present
130
+ # in event
131
+ #
132
+ def validate_event_keys(event, kvs)
133
+ kvs.each do |k, v|
134
+ assert_equal true, event.key?(k), "#{k} is missing"
135
+ assert event[k] == v, "#{k} != #{v} (#{event[k]})"
136
+ end
137
+ end
138
+
139
+ ##
140
+ # has_edge?
141
+ #
142
+ # Searches the array of <tt>traces</tt> for
143
+ # <tt>edge</tt>
144
+ #
145
+ def has_edge?(edge, traces)
146
+ traces.each do |t|
147
+ if AppOpticsAPM::XTrace.edge_id(t["X-Trace"]) == edge
148
+ return true
149
+ end
150
+ end
151
+ AppOpticsAPM.logger.debug "[oboe/debug] edge #{edge} not found in traces."
152
+ false
153
+ end
154
+
155
+ ##
156
+ # valid_edges?
157
+ #
158
+ # Runs through the array of <tt>traces</tt> to validate
159
+ # that all edges connect.
160
+ #
161
+ # Not that this won't work for external cross-app tracing
162
+ # since we won't have those remote traces to validate
163
+ # against.
164
+ #
165
+ def valid_edges?(traces)
166
+ traces.reverse.each do |t|
167
+ if t.key?("Edge")
168
+ unless has_edge?(t["Edge"], traces)
169
+ return false
170
+ end
171
+ end
172
+ end
173
+ true
174
+ end
175
+
176
+ ##
177
+ # layer_has_key
178
+ #
179
+ # Checks an array of trace events if a specific layer (regardless of event type)
180
+ # has he specified key
181
+ #
182
+ def layer_has_key(traces, layer, key)
183
+ return false if traces.empty?
184
+ has_key = false
185
+
186
+ traces.each do |t|
187
+ if t["Layer"] == layer and t.has_key?(key)
188
+ has_key = true
189
+
190
+ (t["Backtrace"].length > 0).must_equal true
191
+ end
192
+ end
193
+
194
+ has_key.must_equal true
195
+ end
196
+
197
+ ##
198
+ # layer_doesnt_have_key
199
+ #
200
+ # Checks an array of trace events to assure that a specific layer
201
+ # (regardless of event type) doesn't have the specified key
202
+ #
203
+ def layer_doesnt_have_key(traces, layer, key)
204
+ return false if traces.empty?
205
+ has_key = false
206
+
207
+ traces.each do |t|
208
+ has_key = true if t["Layer"] == layer and t.has_key?(key)
209
+ end
210
+
211
+ has_key.must_equal false
212
+ end
213
+
214
+ ##
215
+ # Checks if the transaction name corresponds to Controller.Action
216
+ # if there are multiple events with Controller and/or Action, then they all have to match
217
+ #
218
+ def assert_controller_action(test_action)
219
+ traces = get_all_traces
220
+ traces.select { |tr| tr['Controller'] || tr['Action'] }.map do |tr|
221
+ assert_equal(test_action, [tr['Controller'], tr['Action']].join('.'))
222
+ end
223
+ end
224
+
225
+ def not_sampled?(xtrace)
226
+ xtrace[59].to_i & 1 == 0
227
+ end
228
+
229
+ def sampled?(xtrace)
230
+ xtrace[59].to_i & 1 == 1
231
+ end
232
+
233
+ def print_traces(traces, more_keys = [])
234
+ indent = ''
235
+ traces.each do |trace|
236
+ indent += ' ' if trace["Label"] == "entry"
237
+
238
+ puts "#{indent}X-Trace: #{trace["X-Trace"]}"
239
+ puts "#{indent}Label: #{trace["Label"]}"
240
+ puts "#{indent}Layer: #{trace["Layer"]}"
241
+
242
+ more_keys.each { |key| puts "#{indent}#{key}: #{trace[key]}"}
243
+
244
+ indent = indent[0...-2] if trace["Label"] == "exit"
245
+ end
246
+ nil
247
+ end
248
+
249
+ if (File.basename(ENV['BUNDLE_GEMFILE']) =~ /^frameworks/) == 0
250
+ require "sinatra"
251
+ ##
252
+ # Sinatra and Padrino Related Helpers
253
+ #
254
+ # Taken from padrino-core gem
255
+ #
256
+ class Sinatra::Base
257
+ # Allow assertions in request context
258
+ include MiniTest::Assertions
259
+ end
260
+
261
+
262
+ class MiniTest::Spec
263
+ include Rack::Test::Methods
264
+
265
+ # Sets up a Sinatra::Base subclass defined with the block
266
+ # given. Used in setup or individual spec methods to establish
267
+ # the application.
268
+ def mock_app(base=Padrino::Application, &block)
269
+ @app = Sinatra.new(base, &block)
270
+ end
271
+
272
+ def app
273
+ Rack::Lint.new(@app)
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,311 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ if !defined?(JRUBY_VERSION)
5
+
6
+ require 'minitest_helper'
7
+ require 'webmock/minitest'
8
+ require 'mocha/mini_test'
9
+ WebMock.allow_net_connect!
10
+
11
+ class CurbMockedTest < Minitest::Test
12
+
13
+ def setup
14
+ WebMock.enable!
15
+ WebMock.disable_net_connect!
16
+ AppOpticsAPM.config_lock.synchronize {
17
+ @tm = AppOpticsAPM::Config[:tracing_mode]
18
+ @sample_rate = AppOpticsAPM::Config[:sample_rate]
19
+ }
20
+ end
21
+
22
+ def teardown
23
+ AppOpticsAPM.config_lock.synchronize {
24
+ AppOpticsAPM::Config[:tracing_mode] = @tm
25
+ AppOpticsAPM::Config[:blacklist] = []
26
+ AppOpticsAPM::Config[:sample_rate] = @sample_rate
27
+ }
28
+ WebMock.reset!
29
+ WebMock.allow_net_connect!
30
+ WebMock.disable!
31
+ end
32
+
33
+ def test_xtrace_tracing
34
+ stub_request(:get, "http://127.0.0.9:8101/").to_return(status: 200, body: "", headers: {})
35
+
36
+ AppOpticsAPM::API.start_trace('curb_tests') do
37
+ ::Curl.get("http://127.0.0.9:8101/")
38
+ end
39
+
40
+ assert_requested :get, "http://127.0.0.9:8101/", times: 1
41
+ assert_requested :get, "http://127.0.0.9:8101/", headers: {'X-Trace'=>/^2B[0-9,A-F]*01$/}, times: 1
42
+ end
43
+
44
+ def test_xtrace_sample_rate_0
45
+ stub_request(:get, "http://127.0.0.4:8101/").to_return(status: 200, body: "", headers: {})
46
+
47
+ AppOpticsAPM.config_lock.synchronize do
48
+ AppOpticsAPM::Config[:sample_rate] = 0
49
+ AppOpticsAPM::API.start_trace('curb_tests') do
50
+ ::Curl.get("http://127.0.0.4:8101/")
51
+ end
52
+ end
53
+
54
+ assert_requested :get, "http://127.0.0.4:8101/", times: 1
55
+ assert_requested :get, "http://127.0.0.4:8101/", headers: {'X-Trace'=>/^2B[0-9,A-F]*00$/}, times: 1
56
+ assert_not_requested :get, "http://127.0.0.4:8101/", headers: {'X-Trace'=>/^2B0*$/}
57
+ end
58
+
59
+ def test_xtrace_no_trace
60
+ stub_request(:get, "http://127.0.0.6:8101/").to_return(status: 200, body: "", headers: {})
61
+
62
+ ::Curl.get("http://127.0.0.6:8101/")
63
+
64
+ assert_requested :get, "http://127.0.0.6:8101/", times: 1
65
+ assert_not_requested :get, "http://127.0.0.6:8101/", headers: {'X-Trace'=>/^.*$/}
66
+ end
67
+
68
+ def test_blacklisted
69
+ stub_request(:get, "http://127.0.0.2:8101/").to_return(status: 200, body: "", headers: {})
70
+
71
+ AppOpticsAPM.config_lock.synchronize do
72
+ AppOpticsAPM::Config.blacklist << '127.0.0.2'
73
+ AppOpticsAPM::API.start_trace('curb_test') do
74
+ ::Curl.get("http://127.0.0.2:8101/")
75
+ end
76
+ end
77
+
78
+ assert_requested :get, "http://127.0.0.2:8101/", times: 1
79
+ assert_not_requested :get, "http://127.0.0.2:8101/", headers: {'X-Trace'=>/^.*/}
80
+ end
81
+
82
+ def test_multi_get_no_trace
83
+ WebMock.disable!
84
+
85
+ Curl::Multi.expects(:http_without_appoptics).with do |url_confs, _multi_options|
86
+ assert_equal 3, url_confs.size
87
+ url_confs.each do |conf|
88
+ refute conf[:headers] && conf[:headers]['X-Trace']
89
+ end
90
+ true
91
+ end
92
+
93
+ easy_options = {:follow_location => true}
94
+ multi_options = {:pipeline => false}
95
+
96
+ urls = []
97
+ urls << "http://127.0.0.7:8101/?one=1"
98
+ urls << "http://127.0.0.7:8101/?two=2"
99
+ urls << "http://127.0.0.7:8101/?three=3"
100
+
101
+ Curl::Multi.get(urls, easy_options, multi_options)
102
+ end
103
+
104
+ def test_multi_get_tracing
105
+ WebMock.disable!
106
+
107
+ Curl::Multi.expects(:http_without_appoptics).with do |url_confs, _multi_options|
108
+ assert_equal 3, url_confs.size
109
+ url_confs.each do |conf|
110
+ headers = conf[:headers] || {}
111
+ assert headers['X-Trace']
112
+ assert headers['Custom']
113
+ assert_match /specialvalue/, headers['Custom']
114
+ assert sampled?(headers['X-Trace'])
115
+ end
116
+ true
117
+ end
118
+
119
+ easy_options = {:follow_location => true, :headers => { 'Custom' => 'specialvalue' }}
120
+ multi_options = {:pipeline => false}
121
+
122
+ urls = []
123
+ urls << "http://127.0.0.7:8101/?one=1"
124
+ urls << "http://127.0.0.7:8101/?two=2"
125
+ urls << "http://127.0.0.7:8101/?three=3"
126
+
127
+ AppOpticsAPM::API.start_trace('curb_tests') do
128
+ Curl::Multi.get(urls, easy_options, multi_options)
129
+ end
130
+ end
131
+
132
+ def test_multi_get_tracing_not_sampling
133
+ WebMock.disable!
134
+
135
+ Curl::Multi.expects(:http_without_appoptics).with do |url_confs, _multi_options|
136
+ assert_equal 3, url_confs.size
137
+ url_confs.each do |conf|
138
+ headers = conf[:headers] || {}
139
+ assert headers['X-Trace']
140
+ assert not_sampled?(headers['X-Trace'])
141
+ end
142
+ true
143
+ end
144
+
145
+ easy_options = {:follow_location => true}
146
+ multi_options = {:pipeline => false}
147
+
148
+ urls = []
149
+ urls << "http://127.0.0.7:8101/?one=1"
150
+ urls << "http://127.0.0.7:8101/?two=2"
151
+ urls << "http://127.0.0.7:8101/?three=3"
152
+
153
+ AppOpticsAPM.config_lock.synchronize do
154
+ AppOpticsAPM::Config[:sample_rate] = 0
155
+ AppOpticsAPM::API.start_trace('curb_tests') do
156
+ Curl::Multi.get(urls, easy_options, multi_options)
157
+ end
158
+ end
159
+ end
160
+
161
+ def test_multi_perform_no_trace
162
+ WebMock.disable!
163
+
164
+ urls = []
165
+ urls << "http://127.0.0.1:8101/?one=1"
166
+ urls << "http://127.0.0.1:8101/?two=2"
167
+ urls << "http://127.0.0.1:8101/?three=3"
168
+
169
+ m = Curl::Multi.new
170
+ urls.each do |url|
171
+ cu = Curl::Easy.new(url) do |curl|
172
+ curl.follow_location = true
173
+ end
174
+ m.add cu
175
+ end
176
+
177
+ m.perform do
178
+ m.requests.each do |request|
179
+ refute request.headers && request.headers['X-Trace']
180
+ end
181
+ end
182
+ end
183
+
184
+ def test_multi_perform_tracing
185
+ WebMock.disable!
186
+
187
+ urls = []
188
+ urls << "http://127.0.0.1:8101/?one=1"
189
+ urls << "http://127.0.0.1:8101/?two=2"
190
+ urls << "http://127.0.0.1:8101/?three=3"
191
+
192
+ AppOpticsAPM::API.start_trace('curb_tests') do
193
+ m = Curl::Multi.new
194
+ urls.each do |url|
195
+ cu = Curl::Easy.new(url) do |curl|
196
+ curl.follow_location = true
197
+ curl.headers = { 'Custom' => 'specialvalue' }
198
+ end
199
+ m.add cu
200
+ end
201
+
202
+ m.perform do
203
+ m.requests.each do |request|
204
+ assert request.headers['X-Trace']
205
+ assert request.headers['Custom']
206
+ assert sampled?(request.headers['X-Trace'])
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ def test_multi_perform_tracing_not_sampling
213
+ WebMock.disable!
214
+
215
+ urls = []
216
+ urls << "http://127.0.0.1:8101/?one=1"
217
+ urls << "http://127.0.0.1:8101/?two=2"
218
+ urls << "http://127.0.0.1:8101/?three=3"
219
+
220
+ AppOpticsAPM.config_lock.synchronize do
221
+ AppOpticsAPM::Config[:sample_rate] = 0
222
+ AppOpticsAPM::API.start_trace('curb_tests') do
223
+ m = Curl::Multi.new
224
+ urls.each do |url|
225
+ cu = Curl::Easy.new(url) do |curl|
226
+ curl.follow_location = true
227
+ end
228
+ m.add cu
229
+ end
230
+
231
+ m.perform do
232
+ m.requests.each do |request|
233
+ assert request.headers['X-Trace']
234
+ assert not_sampled?(request.headers['X-Trace'])
235
+ refute_match /^2B0*$/, request.headers['X-Trace']
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ # preserve custom headers
243
+ #
244
+ # this calls Curl::Easy.http
245
+ def test_preserves_custom_headers_on_get
246
+ stub_request(:get, "http://127.0.0.6:8101/").to_return(status: 200, body: "", headers: {})
247
+
248
+ AppOpticsAPM::API.start_trace('curb_tests') do
249
+ Curl.get("http://127.0.0.6:8101/") do |curl|
250
+ curl.headers = { 'Custom' => 'specialvalue' }
251
+ end
252
+ end
253
+
254
+ assert_requested :get, "http://127.0.0.6:8101/", headers: {'Custom'=>'specialvalue'}, times: 1
255
+ end
256
+
257
+ # The following test can't use WebMock because it interferes with our instrumentation
258
+ def test_preserves_custom_headers_on_http_put
259
+ WebMock.disable!
260
+
261
+ curl = Curl::Easy.new("http://127.0.0.1:8101/")
262
+ curl.headers = { 'Custom' => 'specialvalue4' }
263
+
264
+ AppOpticsAPM::API.start_trace('curb_tests') do
265
+ curl.http_put nil
266
+ end
267
+
268
+ assert curl.headers
269
+ assert curl.headers['X-Trace']
270
+ assert curl.headers['Custom']
271
+ assert_match /^2B[0-9,A-F]*01$/, curl.headers['X-Trace']
272
+ assert_match /specialvalue4/, curl.headers['Custom']
273
+ end
274
+
275
+ def test_preserves_custom_headers_on_http_post
276
+ WebMock.disable!
277
+
278
+ curl = Curl::Easy.new("http://127.0.0.1:8101/")
279
+ curl.headers = { 'Custom' => 'specialvalue4' }
280
+
281
+ AppOpticsAPM::API.start_trace('curb_tests') do
282
+ curl.http_post
283
+ end
284
+
285
+ assert curl.headers
286
+ assert curl.headers['X-Trace']
287
+ assert curl.headers['Custom']
288
+ assert_match /^2B[0-9,A-F]*01$/, curl.headers['X-Trace']
289
+ assert_match /specialvalue4/, curl.headers['Custom']
290
+ end
291
+
292
+ def test_preserves_custom_headers_on_perform
293
+ WebMock.disable!
294
+
295
+ curl = Curl::Easy.new("http://127.0.0.1:8101/")
296
+ curl.headers = { 'Custom' => 'specialvalue4' }
297
+
298
+ AppOpticsAPM::API.start_trace('curb_tests') do
299
+ curl.perform
300
+ end
301
+
302
+ assert curl.headers
303
+ assert curl.headers['X-Trace']
304
+ assert curl.headers['Custom']
305
+ assert_match /^2B[0-9,A-F]*01$/, curl.headers['X-Trace']
306
+ assert_match /specialvalue4/, curl.headers['Custom']
307
+ end
308
+
309
+ end
310
+ end
311
+