#!/usr/bin/env ruby # 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. # this is to make sure that the Multiverse environment loads with the # the gem version of Minitest (necessary for Rails 4) and not the one # in standard library. if defined?(gem) gem 'minitest' end require File.expand_path(File.join(File.dirname(__FILE__), 'environment')) module Multiverse class Suite include Color attr_accessor :directory, :include_debugger def initialize(directory, include_debugger=nil) self.directory = directory self.include_debugger = !!include_debugger end def clean_gemfiles FileUtils.rm_rf File.join(directory, 'Gemfile') FileUtils.rm_rf File.join(directory, 'Gemfile.lock') end def environments @environments ||= ( Dir.chdir directory Envfile.new(File.join(directory, 'Envfile')) ) end # load the environment for this suite after we've forked def load_dependencies(gemfile_text) clean_gemfiles begin generate_gemfile(gemfile_text) bundle rescue => e puts "#{e.class}: #{e}" puts "Fast local bundle failed. Attempting to install from rubygems.org" clean_gemfiles generate_gemfile(gemfile_text, false) bundle end print_environment end def bundle require 'rubygems' require 'bundler' bundler_out = `bundle` raise "bundle command failed with (#{$?})" unless $? == 0 puts bundler_out if verbose? Bundler.require end def generate_gemfile(gemfile_text, local = true) gemfile = File.join(Dir.pwd, 'Gemfile') File.open(gemfile,'w') do |f| f.puts ' source :rubygems' unless local f.print gemfile_text f.puts newrelic_gemfile_line unless gemfile_text =~ /^\s*gem .newrelic_rpm./ if RUBY_VERSION > '1.8.7' f.puts " gem 'test-unit', :require => 'test/unit'" f.puts " gem 'debugger'" if include_debugger else f.puts " gem 'ruby-debug'" if include_debugger end end puts yellow("Gemfile set to:") if verbose? puts File.open(gemfile).read if verbose? end def newrelic_gemfile_line line = ENV['NEWRELIC_GEMFILE_LINE'] if ENV['NEWRELIC_GEMFILE_LINE'] path = ENV['NEWRELIC_GEM_PATH'] || '../../../..' line ||= " gem 'newrelic_rpm', :path => '#{path}'" line += ", #{environments.newrelic_gemfile_options}" if environments.newrelic_gemfile_options line end def print_environment puts yellow("Environment loaded with:") if verbose? gems = Bundler.definition.specs.inject([]) do |m, s| next m if s.name == 'bundler' m.push "#{s.name} (#{s.version})" m end.sort puts(gems.join(', ')) end def execute_child_environment(env_index) gemfile_text = environments[env_index] load_dependencies(gemfile_text) execute_ruby_files trigger_test_unit end # Load the test suite's environment and execute it. # # Normally we fork to do this, and wait for the child to exit, to avoid # polluting the parent process with test dependencies. JRuby doesn't # implement #fork so we resort to a hack. We exec this lib file, which # loads a new JVM for the tests to run in. def execute if environments.condition && !environments.condition.call puts yellow("SKIPPED #{directory.inspect}: #{environments.skip_message}") return end puts yellow("\nRunning #{directory.inspect} in #{environments.size} environments") environments.before.call if environments.before environments.each_with_index do |gemfile_text, i| execute_with_pipe(i) end environments.after.call if environments.after end def execute_with_pipe(env) OutputCollector.buffers.push('') IO.popen("#{__FILE__} #{directory} #{env}") do |io| while chars = io.read(8) do OutputCollector.buffers.last << chars print chars end end if $? != 0 OutputCollector.failing_output.push(OutputCollector.buffers.last) end Multiverse::Runner.notice_exit_status $? end # something makes Test::Unit not want to run automatically. Seems like the # at_exit hook may be failing to run due to forking. def trigger_test_unit case when defined? Test::Unit::RunCount # 1.9.3 # JRuby 1.7 doesn't seem to have a problem triggering test unit. In # contrast to MRI triggering it like this causes an error. return if defined?(JRuby) Test::Unit::RunCount.run_once do exit(Test::Unit::Runner.new.run || true) end when defined? MiniTest::Unit # 1.9.2 exit(MiniTest::Unit.new.run) when defined? Test::Unit::AutoRunner # 1.8.7 exit(Test::Unit::AutoRunner.run) else raise "Can't figure out how to trigger Test::Unit" end end def execute_ruby_files Dir.chdir directory Dir[File.join(directory, '*.rb')].each do |file| puts yellow("Executing #{file.inspect}") if verbose? load file end end def verbose? ENV['VERBOSE'] end end end # Exectute the suite. We need this if we want to execute a suite by spawning a # new process instead of forking. if $0 == __FILE__ Multiverse::Suite.new(ARGV[0], ARGV[2]).execute_child_environment(ARGV[1].to_i) end