diff options
Diffstat (limited to 'packages/chef-server/autotest/merb_rspec.rb')
-rw-r--r-- | packages/chef-server/autotest/merb_rspec.rb | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/packages/chef-server/autotest/merb_rspec.rb b/packages/chef-server/autotest/merb_rspec.rb new file mode 100644 index 0000000000..9ff1f7263b --- /dev/null +++ b/packages/chef-server/autotest/merb_rspec.rb @@ -0,0 +1,223 @@ +# Adapted from Autotest::Rails, RSpec's autotest class, as well as merb-core's. +require 'autotest' + +class RspecCommandError < StandardError; end + +class Autotest::MerbRspec < Autotest + + # +model_tests_dir+:: the directory to find model-centric tests + # +controller_tests_dir+:: the directory to find controller-centric tests + # +view_tests_dir+:: the directory to find view-centric tests + # +fixtures_dir+:: the directory to find fixtures in + attr_accessor :model_tests_dir, :controller_tests_dir, :view_tests_dir, :fixtures_dir + + def initialize # :nodoc: + super + + initialize_test_layout + + # Ignore any happenings in these directories + add_exception %r%^\./(?:doc|log|public|tmp)% + + # Ignore any mappings that Autotest may have already set up + clear_mappings + + # Any changes to a file in the root of the 'lib' directory will run any + # model test with a corresponding name. + add_mapping %r%^lib\/.*\.rb% do |filename, _| + files_matching %r%#{model_test_for(filename)}$% + end + + add_mapping %r%^spec/(spec_helper|shared/.*)\.rb$% do + files_matching %r%^spec/.*_spec\.rb$% + end + + # Any changes to a fixture will run corresponding view, controller and + # model tests + add_mapping %r%^#{fixtures_dir}/(.*)s.yml% do |_, m| + [ + model_test_for(m[1]), + controller_test_for(m[1]), + view_test_for(m[1]) + ] + end + + # Any change to a test or spec will cause it to be run + add_mapping %r%^spec/(unit|models|integration|controllers|views|functional)/.*rb$% do |filename, _| + filename + end + + # Any change to a model will cause it's corresponding test to be run + add_mapping %r%^app/models/(.*)\.rb$% do |_, m| + model_test_for(m[1]) + end + + # Any change to the global helper will result in all view and controller + # tests being run + add_mapping %r%^app/helpers/global_helpers.rb% do + files_matching %r%^spec/(views|functional|controllers)/.*_spec\.rb$% + end + + # Any change to a helper will run it's corresponding view and controller + # tests, unless the helper is the global helper. Changes to the global + # helper run all view and controller tests. + add_mapping %r%^app/helpers/(.*)_helper(s)?.rb% do |_, m| + if m[1] == "global" then + files_matching %r%^spec/(views|functional|controllers)/.*_spec\.rb$% + else + [ + view_test_for(m[1]), + controller_test_for(m[1]) + ] + end + end + + # Changes to views result in their corresponding view and controller test + # being run + add_mapping %r%^app/views/(.*)/% do |_, m| + [ + view_test_for(m[1]), + controller_test_for(m[1]) + ] + end + + # Changes to a controller result in its corresponding test being run. If + # the controller is the exception or application controller, all + # controller tests are run. + add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m| + if ["application", "exception"].include?(m[1]) + files_matching %r%^spec/(controllers|views|functional)/.*_spec\.rb$% + else + controller_test_for(m[1]) + end + end + + # If a change is made to the router, run all controller and view tests + add_mapping %r%^config/router.rb$% do # FIX + files_matching %r%^spec/(controllers|views|functional)/.*_spec\.rb$% + end + + # If any of the major files governing the environment are altered, run + # everything + add_mapping %r%^spec/spec_helper.rb|config/(init|rack|environments/test.rb|database.yml)% do # FIX + files_matching %r%^spec/(unit|models|controllers|views|functional)/.*_spec\.rb$% + end + end + + def failed_results(results) + results.scan(/^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m) + end + + def handle_results(results) + @failures = failed_results(results) + @files_to_test = consolidate_failures @failures + unless $TESTING + if @files_to_test.empty? + hook :green + else + hook :red + end + end + @tainted = true unless @files_to_test.empty? + end + + def consolidate_failures(failed) + filters = Hash.new { |h,k| h[k] = [] } + failed.each do |spec, failed_trace| + find_files.keys.select { |f| f =~ /spec\// }.each do |f| + if failed_trace =~ Regexp.new(f) + filters[f] << spec + break + end + end + end + filters + end + + def make_test_cmd(files_to_test) + [ + ruby, + "-S", + spec_command, + add_options_if_present, + files_to_test.keys.flatten.join(' ') + ].join(" ") + end + + def add_options_if_present + File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : "" + end + + # Finds the proper spec command to use. Precendence is set in the + # lazily-evaluated method spec_commands. Alias + Override that in + # ~/.autotest to provide a different spec command then the default + # paths provided. + def spec_command(separator=File::ALT_SEPARATOR) + unless defined? @spec_command then + @spec_command = spec_commands.find { |cmd| File.exists? cmd } + + raise RspecCommandError, "No spec command could be found!" unless @spec_command + + @spec_command.gsub!(File::SEPARATOR, separator) if separator + end + @spec_command + end + + # Autotest will look for spec commands in the following + # locations, in this order: + # + # * default spec bin/loader installed in Rubygems + # * any spec command found in PATH + def spec_commands + [ File.join(Config::CONFIG['bindir'], 'spec'), 'spec' ] + end + +private + + # Determines the paths we can expect tests or specs to reside, as well as + # corresponding fixtures. + def initialize_test_layout + self.model_tests_dir = "spec/models" + self.controller_tests_dir = "spec/controllers" + self.view_tests_dir = "spec/views" + self.fixtures_dir = "spec/fixtures" + end + + # Given a filename and the test type, this method will return the + # corresponding test's or spec's name. + # + # ==== Arguments + # +filename+<String>:: the file name of the model, view, or controller + # +kind_of_test+<Symbol>:: the type of test we that we should run + # + # ==== Returns + # String:: the name of the corresponding test or spec + # + # ==== Example + # + # > test_for("user", :model) + # => "user_test.rb" + # > test_for("login", :controller) + # => "login_controller_test.rb" + # > test_for("form", :view) + # => "form_view_spec.rb" # If you're running a RSpec-like suite + def test_for(filename, kind_of_test) # :nodoc: + name = [filename] + name << kind_of_test.to_s if kind_of_test == :view + name << "spec" + return name.join("_") + ".rb" + end + + def model_test_for(filename) + [model_tests_dir, test_for(filename, :model)].join("/") + end + + def controller_test_for(filename) + [controller_tests_dir, test_for(filename, :controller)].join("/") + end + + def view_test_for(filename) + [view_tests_dir, test_for(filename, :view)].join("/") + end + +end |