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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +43 -0
- data/.dockerignore +5 -0
- data/.gitignore +23 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +82 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +33 -0
- data/Dockerfile +41 -0
- data/Dockerfile_test +66 -0
- data/Gemfile +41 -0
- data/LICENSE +193 -0
- data/README.md +351 -0
- data/Rakefile +202 -0
- data/Vagrantfile +67 -0
- data/appoptics_apm.gemspec +55 -0
- data/build_gems.sh +15 -0
- data/docker-compose.yml +73 -0
- data/examples/DNT.md +35 -0
- data/examples/carrying_context.rb +220 -0
- data/examples/instrumenting_metal_controller.rb +8 -0
- data/examples/puma_on_heroku_config.rb +17 -0
- data/examples/tracing_async_threads.rb +124 -0
- data/examples/tracing_background_jobs.rb +53 -0
- data/examples/tracing_forked_processes.rb +99 -0
- data/examples/unicorn_on_heroku_config.rb +28 -0
- data/ext/oboe_metal/extconf.rb +54 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0.so.0.0.0 +0 -0
- data/ext/oboe_metal/noop/noop.c +7 -0
- data/ext/oboe_metal/src/VERSION +1 -0
- data/ext/oboe_metal/src/bson/bson.h +221 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/oboe.h +883 -0
- data/ext/oboe_metal/src/oboe.hpp +793 -0
- data/ext/oboe_metal/src/oboe_debug.h +50 -0
- data/ext/oboe_metal/src/oboe_wrap.cxx +6088 -0
- data/ext/oboe_metal/tests/test.rb +11 -0
- data/gemfiles/delayed_job.gemfile +36 -0
- data/gemfiles/frameworks.gemfile +44 -0
- data/gemfiles/instrumentation_mocked.gemfile +29 -0
- data/gemfiles/libraries.gemfile +85 -0
- data/gemfiles/rails23.gemfile +39 -0
- data/gemfiles/rails30.gemfile +42 -0
- data/gemfiles/rails31.gemfile +44 -0
- data/gemfiles/rails32.gemfile +54 -0
- data/gemfiles/rails40.gemfile +27 -0
- data/gemfiles/rails41.gemfile +27 -0
- data/gemfiles/rails42.gemfile +35 -0
- data/gemfiles/rails50.gemfile +44 -0
- data/gemfiles/rails51.gemfile +44 -0
- data/get_version.rb +5 -0
- data/init.rb +4 -0
- data/lib/appoptics_apm/api/layerinit.rb +39 -0
- data/lib/appoptics_apm/api/logging.rb +359 -0
- data/lib/appoptics_apm/api/memcache.rb +34 -0
- data/lib/appoptics_apm/api/profiling.rb +201 -0
- data/lib/appoptics_apm/api/tracing.rb +152 -0
- data/lib/appoptics_apm/api/util.rb +128 -0
- data/lib/appoptics_apm/api.rb +18 -0
- data/lib/appoptics_apm/base.rb +252 -0
- data/lib/appoptics_apm/config.rb +281 -0
- data/lib/appoptics_apm/frameworks/grape.rb +93 -0
- data/lib/appoptics_apm/frameworks/padrino/templates.rb +58 -0
- data/lib/appoptics_apm/frameworks/padrino.rb +52 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +106 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller2.rb +61 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +58 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view_2x.rb +56 -0
- data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
- data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +120 -0
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +101 -0
- data/lib/appoptics_apm/frameworks/rails.rb +116 -0
- data/lib/appoptics_apm/frameworks/sinatra/templates.rb +56 -0
- data/lib/appoptics_apm/frameworks/sinatra.rb +71 -0
- data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
- data/lib/appoptics_apm/inst/bunny-consumer.rb +92 -0
- data/lib/appoptics_apm/inst/curb.rb +329 -0
- data/lib/appoptics_apm/inst/dalli.rb +85 -0
- data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
- data/lib/appoptics_apm/inst/em-http-request.rb +105 -0
- data/lib/appoptics_apm/inst/excon.rb +130 -0
- data/lib/appoptics_apm/inst/faraday.rb +77 -0
- data/lib/appoptics_apm/inst/http.rb +83 -0
- data/lib/appoptics_apm/inst/httpclient.rb +176 -0
- data/lib/appoptics_apm/inst/memcache.rb +102 -0
- data/lib/appoptics_apm/inst/memcached.rb +94 -0
- data/lib/appoptics_apm/inst/mongo.rb +242 -0
- data/lib/appoptics_apm/inst/mongo2.rb +225 -0
- data/lib/appoptics_apm/inst/moped.rb +466 -0
- data/lib/appoptics_apm/inst/rack.rb +146 -0
- data/lib/appoptics_apm/inst/redis.rb +275 -0
- data/lib/appoptics_apm/inst/resque.rb +151 -0
- data/lib/appoptics_apm/inst/rest-client.rb +50 -0
- data/lib/appoptics_apm/inst/sequel.rb +178 -0
- data/lib/appoptics_apm/inst/sidekiq-client.rb +53 -0
- data/lib/appoptics_apm/inst/sidekiq-worker.rb +67 -0
- data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
- data/lib/appoptics_apm/inst/typhoeus.rb +113 -0
- data/lib/appoptics_apm/instrumentation.rb +22 -0
- data/lib/appoptics_apm/legacy_method_profiling.rb +97 -0
- data/lib/appoptics_apm/loading.rb +66 -0
- data/lib/appoptics_apm/logger.rb +41 -0
- data/lib/appoptics_apm/method_profiling.rb +33 -0
- data/lib/appoptics_apm/ruby.rb +35 -0
- data/lib/appoptics_apm/support.rb +135 -0
- data/lib/appoptics_apm/test.rb +94 -0
- data/lib/appoptics_apm/thread_local.rb +26 -0
- data/lib/appoptics_apm/util.rb +312 -0
- data/lib/appoptics_apm/version.rb +15 -0
- data/lib/appoptics_apm/xtrace.rb +103 -0
- data/lib/appoptics_apm.rb +72 -0
- data/lib/joboe_metal.rb +214 -0
- data/lib/oboe/README +2 -0
- data/lib/oboe/backward_compatibility.rb +80 -0
- data/lib/oboe/inst/rack.rb +11 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +187 -0
- data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +222 -0
- data/ruby_setup.sh +47 -0
- data/run_docker_build_gem_upload_to_packagecloud.sh +20 -0
- data/run_tests_docker.rb +32 -0
- data/test/benchmark/README.md +65 -0
- data/test/benchmark/logging_bench.rb +54 -0
- data/test/benchmark/with_libraries_gemfile/bunny_bench.rb +69 -0
- data/test/benchmark/with_rails5x_gemfile/action_controller5x_bench.rb +43 -0
- data/test/frameworks/apps/grape_nested.rb +33 -0
- data/test/frameworks/apps/grape_simple.rb +80 -0
- data/test/frameworks/apps/padrino_simple.rb +80 -0
- data/test/frameworks/apps/sinatra_simple.rb +55 -0
- data/test/frameworks/grape_test.rb +286 -0
- data/test/frameworks/padrino_test.rb +222 -0
- data/test/frameworks/rails3x_test.rb +554 -0
- data/test/frameworks/rails4x_test.rb +570 -0
- data/test/frameworks/rails5x_api_test.rb +210 -0
- data/test/frameworks/rails5x_test.rb +376 -0
- data/test/frameworks/rails_shared_tests.rb +172 -0
- data/test/frameworks/sinatra_test.rb +140 -0
- data/test/instrumentation/bunny_client_test.rb +276 -0
- data/test/instrumentation/bunny_consumer_test.rb +204 -0
- data/test/instrumentation/curb_test.rb +398 -0
- data/test/instrumentation/dalli_test.rb +177 -0
- data/test/instrumentation/em_http_request_test.rb +89 -0
- data/test/instrumentation/excon_test.rb +231 -0
- data/test/instrumentation/faraday_test.rb +228 -0
- data/test/instrumentation/http_test.rb +143 -0
- data/test/instrumentation/httpclient_test.rb +320 -0
- data/test/instrumentation/memcache_test.rb +260 -0
- data/test/instrumentation/memcached_test.rb +229 -0
- data/test/instrumentation/mongo_v1_test.rb +479 -0
- data/test/instrumentation/mongo_v2_index_test.rb +124 -0
- data/test/instrumentation/mongo_v2_test.rb +584 -0
- data/test/instrumentation/mongo_v2_view_test.rb +435 -0
- data/test/instrumentation/moped_test.rb +517 -0
- data/test/instrumentation/rack_test.rb +165 -0
- data/test/instrumentation/redis_hashes_test.rb +268 -0
- data/test/instrumentation/redis_keys_test.rb +321 -0
- data/test/instrumentation/redis_lists_test.rb +310 -0
- data/test/instrumentation/redis_misc_test.rb +163 -0
- data/test/instrumentation/redis_sets_test.rb +296 -0
- data/test/instrumentation/redis_sortedsets_test.rb +328 -0
- data/test/instrumentation/redis_strings_test.rb +349 -0
- data/test/instrumentation/resque_test.rb +185 -0
- data/test/instrumentation/rest-client_test.rb +288 -0
- data/test/instrumentation/sequel_mysql2_test.rb +353 -0
- data/test/instrumentation/sequel_mysql_test.rb +334 -0
- data/test/instrumentation/sequel_pg_test.rb +336 -0
- data/test/instrumentation/sidekiq-client_test.rb +159 -0
- data/test/instrumentation/sidekiq-worker_test.rb +180 -0
- data/test/instrumentation/twitter-cassandra_test.rb +424 -0
- data/test/instrumentation/typhoeus_test.rb +284 -0
- data/test/jobs/delayed_job/db_worker_job.rb +29 -0
- data/test/jobs/delayed_job/error_worker_job.rb +10 -0
- data/test/jobs/delayed_job/remote_call_worker_job.rb +20 -0
- data/test/jobs/resque/db_worker_job.rb +29 -0
- data/test/jobs/resque/error_worker_job.rb +10 -0
- data/test/jobs/resque/remote_call_worker_job.rb +20 -0
- data/test/jobs/sidekiq/db_worker_job.rb +29 -0
- data/test/jobs/sidekiq/error_worker_job.rb +10 -0
- data/test/jobs/sidekiq/remote_call_worker_job.rb +20 -0
- data/test/minitest_helper.rb +276 -0
- data/test/mocked/curb_mocked_test.rb +311 -0
- data/test/mocked/excon_mocked_test.rb +166 -0
- data/test/mocked/faraday_mocked_test.rb +93 -0
- data/test/mocked/http_mocked_test.rb +129 -0
- data/test/mocked/httpclient_mocked_test.rb +245 -0
- data/test/mocked/rest_client_mocked_test.rb +103 -0
- data/test/mocked/typhoeus_mocked_test.rb +192 -0
- data/test/models/widget.rb +36 -0
- data/test/profiling/legacy_method_profiling_test.rb +201 -0
- data/test/profiling/method_profiling_test.rb +631 -0
- data/test/queues/delayed_job-client_test.rb +95 -0
- data/test/queues/delayed_job-worker_test.rb +91 -0
- data/test/reporter/reporter_test.rb +14 -0
- data/test/servers/delayed_job.rb +107 -0
- data/test/servers/rackapp_8101.rb +29 -0
- data/test/servers/rails3x_8140.rb +96 -0
- data/test/servers/rails4x_8140.rb +96 -0
- data/test/servers/rails5x_8140.rb +95 -0
- data/test/servers/rails5x_api_8150.rb +78 -0
- data/test/servers/sidekiq.rb +29 -0
- data/test/servers/sidekiq.yml +7 -0
- data/test/servers/sidekiq_initializer.rb +25 -0
- data/test/settings +0 -0
- data/test/support/auto_tracing_test.rb +50 -0
- data/test/support/backcompat_test.rb +276 -0
- data/test/support/config_test.rb +149 -0
- data/test/support/dnt_test.rb +98 -0
- data/test/support/init_report_test.rb +25 -0
- data/test/support/liboboe_settings_test.rb +110 -0
- data/test/support/logging_test.rb +130 -0
- data/test/support/noop_test.rb +88 -0
- data/test/support/sql_sanitize_test.rb +55 -0
- data/test/support/tracing_mode_test.rb +33 -0
- data/test/support/tvalias_test.rb +15 -0
- data/test/support/xtrace_test.rb +41 -0
- 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
|
+
|