appoptics_apm 4.0.2

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