diff --git a/.travis.yml b/.travis.yml index d21b397809..44b04262e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,8 @@ language: ruby sudo: required before_install: - - ./test/script/before_install/revert_rubygems.sh - gem --version - ./test/script/before_install/gemstash_mirror.sh - - ./test/script/before_install/update_bundler.sh - bundle --version install: bundle install diff --git a/lib/new_relic/agent.rb b/lib/new_relic/agent.rb index 6174d563e4..83cf285924 100644 --- a/lib/new_relic/agent.rb +++ b/lib/new_relic/agent.rb @@ -369,8 +369,7 @@ def add_instrumentation(file_pattern) # # @api public def require_test_helper - path = File.join(__FILE__, '..', '..', '..', 'test', 'agent_helper') - require File.expand_path(path) + require File.expand_path('../../../test/agent_helper', __FILE__) end # This method sets the block sent to this method as a sql diff --git a/test/helpers/logging.rb b/test/helpers/logging.rb new file mode 100644 index 0000000000..9270702900 --- /dev/null +++ b/test/helpers/logging.rb @@ -0,0 +1,37 @@ +# encoding: utf-8 +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. + +def with_verbose_logging + orig_logger = NewRelic::Agent.logger + $stderr.puts '', '---', '' + new_logger = NewRelic::Agent::AgentLogger.new('', Logger.new($stderr) ) + NewRelic::Agent.logger = new_logger + + with_config(:log_level => 'debug') do + yield + end +ensure + NewRelic::Agent.logger = orig_logger +end + +# Need to be a bit sloppy when testing against the logging--let everything +# through, but check we (at least) get our particular message we care about +def expects_logging(level, *with_params) + ::NewRelic::Agent.logger.stubs(level) + ::NewRelic::Agent.logger.expects(level).with(*with_params).once +end + +def expects_no_logging(level) + ::NewRelic::Agent.logger.expects(level).never +end + +# Sometimes need to test cases where we muddle with the global logger +# If so, use this method to ensure it gets restored after we're done +def without_logger + logger = ::NewRelic::Agent.logger + ::NewRelic::Agent.logger = nil + yield +ensure + ::NewRelic::Agent.logger = logger +end diff --git a/test/helpers/minitest.rb b/test/helpers/minitest.rb new file mode 100644 index 0000000000..5b8075ae71 --- /dev/null +++ b/test/helpers/minitest.rb @@ -0,0 +1,50 @@ +# encoding: utf-8 +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. + +unless defined?(Minitest::Test) + Minitest::Test = MiniTest::Unit::TestCase +end + +# Set up a watcher for leaking agent threads out of tests. It'd be nice to +# disable the threads everywhere, but not all tests have newrelic.yml loaded to +# us to rely on, so instead we'll just watch for it. +class Minitest::Test + + def before_setup + if self.respond_to?(:name) + test_method_name = self.name + else + test_method_name = self.__name__ + end + + NewRelic::Agent.logger.info("*** #{self.class}##{test_method_name} **") + + @__thread_count = ruby_threads.count + super + end + + def after_teardown + unfreeze_time + + threads = ruby_threads + if @__thread_count != threads.count + backtraces = threads.map do |thread| + trace = Hometown.for(thread) + trace.backtrace.join("\n ") + end.join("\n\n") + + fail "Thread count changed in this test from #{@__thread_count} to #{threads.count}\n#{backtraces}" + end + + super + end + + # We only want to count threads that were spun up from Ruby (i.e. + # Thread.new) JRuby has system threads we don't care to track. + def ruby_threads + Thread.list.select { |t| Hometown.for(t) } + end + +end + diff --git a/test/helpers/misc.rb b/test/helpers/misc.rb new file mode 100644 index 0000000000..72e1367234 --- /dev/null +++ b/test/helpers/misc.rb @@ -0,0 +1,87 @@ +# encoding: utf-8 +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. + +def default_service(stubbed_method_overrides = {}) + service = stub + stubbed_method_defaults = { + :connect => {}, + :shutdown => nil, + :agent_id= => nil, + :agent_id => nil, + :collector => stub_everything, + :request_timeout= => nil, + :metric_data => nil, + :error_data => nil, + :transaction_sample_data => nil, + :sql_trace_data => nil, + :get_agent_commands => [], + :agent_command_results => nil, + :analytic_event_data => nil, + :valid_to_marshal? => true + } + + service.stubs(stubbed_method_defaults.merge(stubbed_method_overrides)) + + # When session gets called yield to the given block. + service.stubs(:session).yields + service +end + +def fixture_tcp_socket( response ) + # Don't actually talk to Google. + socket = stub("socket") do + stubs(:closed?).returns(false) + stubs(:close) + stubs(:setsockopt) + + # Simulate a bunch of socket-ey stuff since Mocha doesn't really + # provide any other way to do it + class << self + attr_accessor :response, :write_checker + end + + def self.check_write + self.write_checker = Proc.new + end + + def self.write( buf ) + self.write_checker.call( buf ) if self.write_checker + buf.length + end + + def self.sysread( size, buf='' ) + @data ||= response.to_s + raise EOFError if @data.empty? + buf.replace @data.slice!( 0, size ) + buf + end + class << self + alias_method :read_nonblock, :sysread + end + + end + + socket.response = response + TCPSocket.stubs( :open ).returns( socket ) + + return socket +end + +def dummy_mysql_explain_result(hash=nil) + hash ||= { + 'Id' => '1', + 'Select Type' => 'SIMPLE', + 'Table' => 'sandwiches', + 'Type' => 'range', + 'Possible Keys' => 'PRIMARY', + 'Key' => 'PRIMARY', + 'Key Length' => '4', + 'Ref' => '', + 'Rows' => '1', + 'Extra' => 'Using index' + } + explain_result = mock('explain result') + explain_result.stubs(:each_hash).yields(hash) + explain_result +end diff --git a/test/helpers/transaction_sample_test.rb b/test/helpers/transaction_sample_test.rb new file mode 100644 index 0000000000..23b6a516ae --- /dev/null +++ b/test/helpers/transaction_sample_test.rb @@ -0,0 +1,44 @@ +# encoding: utf-8 +# This file is distributed under New Relic's license terms. +# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. + +module TransactionSampleTestHelper + module_function + def make_sql_transaction(*sql) + sampler = nil + state = NewRelic::Agent::TransactionState.tl_get + + in_transaction('/path') do + sampler = NewRelic::Agent.instance.transaction_sampler + sampler.notice_push_frame(state, "a") + explainer = NewRelic::Agent::Instrumentation::ActiveRecord::EXPLAINER + sql.each {|sql_statement| sampler.notice_sql(sql_statement, {:adapter => "mysql"}, 0, state, explainer) } + sleep 0.02 + yield if block_given? + sampler.notice_pop_frame(state, "a") + end + + return sampler.last_sample + end + + def run_sample_trace(path='/path') + sampler = nil + state = NewRelic::Agent::TransactionState.tl_get + + request = stub(:path => path) + + in_transaction("Controller/sandwiches/index", :request => request) do + sampler = NewRelic::Agent.instance.transaction_sampler + sampler.notice_sql("SELECT * FROM sandwiches WHERE bread = 'wheat'", {}, 0, state) + sampler.notice_push_frame(state, "ab") + sampler.notice_sql("SELECT * FROM sandwiches WHERE bread = 'white'", {}, 0, state) + yield sampler if block_given? + sampler.notice_pop_frame(state, "ab") + sampler.notice_push_frame(state, "lew") + sampler.notice_sql("SELECT * FROM sandwiches WHERE bread = 'french'", {}, 0, state) + sampler.notice_pop_frame(state, "lew") + end + + return sampler.last_sample + end +end diff --git a/test/new_relic/agent/sampled_buffer_test.rb b/test/new_relic/agent/sampled_buffer_test.rb index b60e64e6f1..395d280177 100644 --- a/test/new_relic/agent/sampled_buffer_test.rb +++ b/test/new_relic/agent/sampled_buffer_test.rb @@ -2,8 +2,8 @@ # This file is distributed under New Relic's license terms. # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. -require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper')) -require 'test/new_relic/agent/event_buffer_test_cases' +require File.expand_path '../../../test_helper', __FILE__ +require 'new_relic/agent/event_buffer_test_cases' module NewRelic::Agent class SampledBufferTest < Minitest::Test diff --git a/test/new_relic/agent/sized_buffer_test.rb b/test/new_relic/agent/sized_buffer_test.rb index e6e30e3dc1..23ff6ded5b 100644 --- a/test/new_relic/agent/sized_buffer_test.rb +++ b/test/new_relic/agent/sized_buffer_test.rb @@ -3,7 +3,7 @@ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper')) -require 'test/new_relic/agent/event_buffer_test_cases' +require 'new_relic/agent/event_buffer_test_cases' require 'new_relic/agent/sized_buffer' module NewRelic::Agent diff --git a/test/new_relic/agent/synthetics_event_buffer_test.rb b/test/new_relic/agent/synthetics_event_buffer_test.rb index 7dc450d7eb..878d17e153 100644 --- a/test/new_relic/agent/synthetics_event_buffer_test.rb +++ b/test/new_relic/agent/synthetics_event_buffer_test.rb @@ -3,7 +3,7 @@ # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper')) -require 'test/new_relic/agent/event_buffer_test_cases' +require 'new_relic/agent/event_buffer_test_cases' require 'new_relic/agent/synthetics_event_buffer' module NewRelic::Agent diff --git a/test/new_relic/rack/deferred_instrumentation_test.rb b/test/new_relic/rack/deferred_instrumentation_test.rb deleted file mode 100644 index 3aaaac2627..0000000000 --- a/test/new_relic/rack/deferred_instrumentation_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -# encoding: utf-8 -# This file is distributed under New Relic's license terms. -# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. - -require File.expand_path(File.join(File.dirname(__FILE__),'..','..','test_helper')) - -class NewRelic::Rack::DeferredInstrumentationTest < Minitest::Test - class TestApp - def call(env) - [200, {}, ["whatever"]] - end - end - - def test_to_app_does_not_blow_up_when_rack_instrumentation_required_multiple_times - # We want to use two different paths to require the rack instrumentation here - # in order to simulate a situation that might arise where a user is - # explicitly requiring our rack instrumentation file, and then the agent - # automatically requires it as well, via a different path. - # On Ruby 1.8.7, this will cause the file to be evaluated multiple times. - path1 = "new_relic/agent/instrumentation/rack" - path2 = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'new_relic', 'agent', 'instrumentation', 'rack')) - refute_equal(path2, path1) - - require path1 - require path2 - - builder = ::Rack::Builder.new do - run(::NewRelic::Rack::DeferredInstrumentationTest::TestApp.new) - end - - builder.to_app - end -end diff --git a/test/script/before_install/revert_rubygems.sh b/test/script/before_install/revert_rubygems.sh deleted file mode 100755 index 9dcac1a808..0000000000 --- a/test/script/before_install/revert_rubygems.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# -# revert to older rubygems version for ruby versions prior to 2.0 -# -# TODO: remove when older rubies are deprecated, RUBY-1668 - -set -ev - -if [[ `ruby --version` =~ ^ruby\ 1\. ]]; then - if [ -n "$GEMSTASH_MIRROR" ]; then - gem update --clear-sources --source $GEMSTASH_MIRROR --system 1.8.25 - else - gem update --system 1.8.25 - fi -fi diff --git a/test/script/before_install/update_bundler.sh b/test/script/before_install/update_bundler.sh deleted file mode 100755 index 10aa9e7714..0000000000 --- a/test/script/before_install/update_bundler.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# -# ruby-1.9.3 travis has bundler 1.7.6 installed, which pulls in dm-types-1.2.0 -# during the datamapper multiverse suite. this causes a dep conflict on json -# gem. updating bundler to latest on that version pulls in dm-types-1.2.2 -# and does not cause a conflict. - -set -ev - -if [[ `ruby --version` =~ ^ruby\ 1\.9\.3 ]]; then - gem install bundler -fi diff --git a/test/test_helper.rb b/test/test_helper.rb index f11613cd25..5576625546 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,15 +2,15 @@ # This file is distributed under New Relic's license terms. # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details. +# define special constant so DefaultSource.framework can return :test module NewRelic; TEST = true; end unless defined? NewRelic::TEST + ENV['RAILS_ENV'] = 'test' -NEWRELIC_PLUGIN_DIR = File.expand_path(File.join(File.dirname(__FILE__),"..")) -$LOAD_PATH << '.' -$LOAD_PATH << '../../..' -$LOAD_PATH << File.join(NEWRELIC_PLUGIN_DIR,"lib") -$LOAD_PATH << File.join(NEWRELIC_PLUGIN_DIR,"test") -$LOAD_PATH << File.join(NEWRELIC_PLUGIN_DIR,"ui/helpers") -$LOAD_PATH.uniq! + +$: << File.expand_path('../../lib', __FILE__) +$: << File.expand_path('../../test', __FILE__) +$: << File.expand_path('../../ui/helpers', __FILE__) # TODO remove after #1493 merges +$:.uniq! require 'rubygems' require 'rake' @@ -18,58 +18,10 @@ module NewRelic; TEST = true; end unless defined? NewRelic::TEST require 'minitest/autorun' require 'mocha/setup' -unless defined?(Minitest::Test) - Minitest::Test = MiniTest::Unit::TestCase -end - require 'hometown' Hometown.watch(::Thread) -# Set up a watcher for leaking agent threads out of tests. It'd be nice to -# disable the threads everywhere, but not all tests have newrelic.yml loaded to -# us to rely on, so instead we'll just watch for it. -class Minitest::Test - def before_setup - if self.respond_to?(:name) - test_method_name = self.name - else - test_method_name = self.__name__ - end - - NewRelic::Agent.logger.info("*** #{self.class}##{test_method_name} **") - - @__thread_count = ruby_threads.count - super - end - - def after_teardown - unfreeze_time - - threads = ruby_threads - if @__thread_count != threads.count - backtraces = threads.map do |thread| - trace = Hometown.for(thread) - trace.backtrace.join("\n ") - end.join("\n\n") - - fail "Thread count changed in this test from #{@__thread_count} to #{threads.count}\n#{backtraces}" - end - - super - end - - # We only want to count threads that were spun up from Ruby (i.e. - # Thread.new) JRuby has system threads we don't care to track. - def ruby_threads - Thread.list.select { |t| Hometown.for(t) } - end -end - -Dir.glob('test/helpers/*').each { |f| require f } - -Dir.glob(File.join(NEWRELIC_PLUGIN_DIR,'test/helpers/*.rb')).each do |helper| - require helper -end +Dir[File.expand_path('../helpers/*', __FILE__)].each {|f| require f.sub(/.*test\//,'')} # We can speed things up in tests that don't need to load rails. # You can also run the tests in a mode without rails. Many tests @@ -79,7 +31,7 @@ def ruby_threads require 'newrelic_rpm' else begin - require 'config/environment' + require './config/environment' require 'newrelic_rpm' rescue LoadError puts "Running tests in standalone mode." @@ -105,162 +57,3 @@ class MyApp < Rails::Application # This is the public method recommended for plugin developers to share our # agent helpers. Use it so we don't accidentally break it. NewRelic::Agent.require_test_helper - -def default_service(stubbed_method_overrides = {}) - service = stub - stubbed_method_defaults = { - :connect => {}, - :shutdown => nil, - :agent_id= => nil, - :agent_id => nil, - :collector => stub_everything, - :request_timeout= => nil, - :metric_data => nil, - :error_data => nil, - :transaction_sample_data => nil, - :sql_trace_data => nil, - :get_agent_commands => [], - :agent_command_results => nil, - :analytic_event_data => nil, - :valid_to_marshal? => true - } - - service.stubs(stubbed_method_defaults.merge(stubbed_method_overrides)) - - # When session gets called yield to the given block. - service.stubs(:session).yields - service -end - -def with_verbose_logging - orig_logger = NewRelic::Agent.logger - $stderr.puts '', '---', '' - new_logger = NewRelic::Agent::AgentLogger.new('', Logger.new($stderr) ) - NewRelic::Agent.logger = new_logger - - with_config(:log_level => 'debug') do - yield - end -ensure - NewRelic::Agent.logger = orig_logger -end - -# Need to be a bit sloppy when testing against the logging--let everything -# through, but check we (at least) get our particular message we care about -def expects_logging(level, *with_params) - ::NewRelic::Agent.logger.stubs(level) - ::NewRelic::Agent.logger.expects(level).with(*with_params).once -end - -def expects_no_logging(level) - ::NewRelic::Agent.logger.expects(level).never -end - -# Sometimes need to test cases where we muddle with the global logger -# If so, use this method to ensure it gets restored after we're done -def without_logger - logger = ::NewRelic::Agent.logger - ::NewRelic::Agent.logger = nil - yield -ensure - ::NewRelic::Agent.logger = logger -end - -def fixture_tcp_socket( response ) - # Don't actually talk to Google. - socket = stub("socket") do - stubs(:closed?).returns(false) - stubs(:close) - stubs(:setsockopt) - - # Simulate a bunch of socket-ey stuff since Mocha doesn't really - # provide any other way to do it - class << self - attr_accessor :response, :write_checker - end - - def self.check_write - self.write_checker = Proc.new - end - - def self.write( buf ) - self.write_checker.call( buf ) if self.write_checker - buf.length - end - - def self.sysread( size, buf='' ) - @data ||= response.to_s - raise EOFError if @data.empty? - buf.replace @data.slice!( 0, size ) - buf - end - class << self - alias_method :read_nonblock, :sysread - end - - end - - socket.response = response - TCPSocket.stubs( :open ).returns( socket ) - - return socket -end - -def dummy_mysql_explain_result(hash=nil) - hash ||= { - 'Id' => '1', - 'Select Type' => 'SIMPLE', - 'Table' => 'sandwiches', - 'Type' => 'range', - 'Possible Keys' => 'PRIMARY', - 'Key' => 'PRIMARY', - 'Key Length' => '4', - 'Ref' => '', - 'Rows' => '1', - 'Extra' => 'Using index' - } - explain_result = mock('explain result') - explain_result.stubs(:each_hash).yields(hash) - explain_result -end - -module TransactionSampleTestHelper - module_function - def make_sql_transaction(*sql) - sampler = nil - state = NewRelic::Agent::TransactionState.tl_get - - in_transaction('/path') do - sampler = NewRelic::Agent.instance.transaction_sampler - sampler.notice_push_frame(state, "a") - explainer = NewRelic::Agent::Instrumentation::ActiveRecord::EXPLAINER - sql.each {|sql_statement| sampler.notice_sql(sql_statement, {:adapter => "mysql"}, 0, state, explainer) } - sleep 0.02 - yield if block_given? - sampler.notice_pop_frame(state, "a") - end - - return sampler.last_sample - end - - def run_sample_trace(path='/path') - sampler = nil - state = NewRelic::Agent::TransactionState.tl_get - - request = stub(:path => path) - - in_transaction("Controller/sandwiches/index", :request => request) do - sampler = NewRelic::Agent.instance.transaction_sampler - sampler.notice_sql("SELECT * FROM sandwiches WHERE bread = 'wheat'", {}, 0, state) - sampler.notice_push_frame(state, "ab") - sampler.notice_sql("SELECT * FROM sandwiches WHERE bread = 'white'", {}, 0, state) - yield sampler if block_given? - sampler.notice_pop_frame(state, "ab") - sampler.notice_push_frame(state, "lew") - sampler.notice_sql("SELECT * FROM sandwiches WHERE bread = 'french'", {}, 0, state) - sampler.notice_pop_frame(state, "lew") - end - - return sampler.last_sample - end -end