cucumber support

This commit is contained in:
Nick Gauthier 2010-03-30 13:45:10 -04:00
parent 24f550f62c
commit 2fd871ed9b
8 changed files with 186 additions and 25 deletions

View File

@ -20,9 +20,12 @@ In your rakefile:
require 'hydra/tasks'
Hydra::TestTask.new('hydra') do |t|
# test unit
t.add_files 'test/unit/**/*_test.rb'
t.add_files 'test/functional/**/*_test.rb'
t.add_files 'test/integration/**/*_test.rb'
# cucumber
t.add_files 'features/**/*.feature'
end
Run:
@ -32,6 +35,16 @@ Run:
Hydra defaults to Single Core mode, so you may want to configure it
to use two (or more) of your cores if you have a multi-processing machine.
== Supported frameworks
Right now hydra only supports a few frameworks:
* Test::Unit
* Cucumber
We're working on adding more frameworks, and if you'd like to help, please
send me a message and I'll show you where to code!
== Running Remote Tasks
You can run tasks across all of your remote workers easily with Hydra. In your rake file, add:

View File

@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Nick Gauthier"]
s.date = %q{2010-03-25}
s.date = %q{2010-03-30}
s.description = %q{Spread your tests over multiple machines to test your code faster.}
s.email = %q{nick@smartlogicsolutions.com}
s.extra_rdoc_files = [
@ -30,6 +30,7 @@ Gem::Specification.new do |s|
"hydra.gemspec",
"hydra_gray.png",
"lib/hydra.rb",
"lib/hydra/cucumber/formatter.rb",
"lib/hydra/hash.rb",
"lib/hydra/listener/abstract.rb",
"lib/hydra/listener/minimal_output.rb",
@ -52,6 +53,8 @@ Gem::Specification.new do |s|
"lib/hydra/worker.rb",
"test/fixtures/assert_true.rb",
"test/fixtures/config.yml",
"test/fixtures/features/step_definitions.rb",
"test/fixtures/features/write_file.feature",
"test/fixtures/hello_world.rb",
"test/fixtures/slow.rb",
"test/fixtures/sync_test.rb",
@ -78,6 +81,7 @@ Gem::Specification.new do |s|
"test/fixtures/sync_test.rb",
"test/fixtures/assert_true.rb",
"test/fixtures/hello_world.rb",
"test/fixtures/features/step_definitions.rb",
"test/master_test.rb",
"test/worker_test.rb",
"test/runner_test.rb",

View File

@ -0,0 +1,31 @@
require 'cucumber/formatter/console'
require 'cucumber/formatter/io'
module Cucumber #:nodoc:
module Formatter #:nodoc:
# Hydra formatter for cucumber.
# Stifles all output except error messages
# Based on the
class Hydra < Cucumber::Formatter::Progress
# Removed the extra newlines here
def after_features(features)
print_summary(features)
end
private
# Removed the file statistics
def print_summary(features)
print_steps(:pending)
print_steps(:failed)
print_snippets(@options)
print_passing_wip(@options)
print_tag_limit_warnings(features)
end
# Removed all progress output
def progress(status)
end
end
end
end

View File

@ -33,29 +33,17 @@ module Hydra #:nodoc:
# Run a test file and report the results
def run_file(file)
trace "Running file: #{file}"
begin
require file
rescue LoadError => ex
trace "#{file} does not exist [#{ex.to_s}]"
@io.write Results.new(:output => ex.to_s, :file => file)
return
end
output = []
@result = Test::Unit::TestResult.new
@result.add_listener(Test::Unit::TestResult::FAULT) do |value|
output << value
output = ""
if file =~ /.rb$/
output = run_ruby_file(file)
elsif file =~ /.feature$/
output = run_cucumber_file(file)
end
klasses = Runner.find_classes_in_file(file)
begin
klasses.each{|klass| klass.suite.run(@result){|status, name| ;}}
rescue => ex
output << ex.to_s
end
output = "." if output == ""
output << '.' if output.empty?
@io.write Results.new(:output => output.join("\n"), :file => file)
@io.write Results.new(:output => output, :file => file)
end
# Stop running
@ -86,6 +74,94 @@ module Hydra #:nodoc:
end
end
# Run a ruby file (ending in .rb)
def run_ruby_file(file)
run_test_unit_file(file) + run_rspec_file(file)
end
# Run all the Test::Unit Suites in a ruby file
def run_test_unit_file(file)
begin
require file
rescue LoadError => ex
trace "#{file} does not exist [#{ex.to_s}]"
return ex.to_s
end
output = []
@result = Test::Unit::TestResult.new
@result.add_listener(Test::Unit::TestResult::FAULT) do |value|
output << value
end
klasses = Runner.find_classes_in_file(file)
begin
klasses.each{|klass| klass.suite.run(@result){|status, name| ;}}
rescue => ex
output << ex.to_s
end
return output.join("\n")
end
# run all the Specs in an RSpec file (NOT IMPLEMENTED)
def run_rspec_file(file)
#TODO
# Given the file
# return "" if all the tests passed
# or return the error messages for the entire file
return ""
end
# run all the scenarios in a cucumber feature file
def run_cucumber_file(file)
require 'cucumber'
require 'cucumber/formatter/progress'
require 'hydra/cucumber/formatter'
def tag_excess(features, limits)
limits.map do |tag_name, tag_limit|
tag_locations = features.tag_locations(tag_name)
if tag_limit && (tag_locations.length > tag_limit)
[tag_name, tag_limit, tag_locations]
else
nil
end
end.compact
end
files = [file]
dev_null = StringIO.new
options = Cucumber::Cli::Options.new
configuration = Cucumber::Cli::Configuration.new(dev_null, dev_null)
configuration.parse!([]+files)
step_mother = Cucumber::StepMother.new
step_mother.options = configuration.options
step_mother.log = configuration.log
step_mother.load_code_files(configuration.support_to_load)
step_mother.after_configuration(configuration)
features = step_mother.load_plain_text_features(files)
step_mother.load_code_files(configuration.step_defs_to_load)
tag_excess = tag_excess(features, configuration.options[:tag_expression].limits)
configuration.options[:tag_excess] = tag_excess
hydra_response = StringIO.new
formatter = Cucumber::Formatter::Hydra.new(
step_mother, hydra_response, configuration.options
)
runner = Cucumber::Ast::TreeWalker.new(
step_mother, [formatter], configuration.options, dev_null
)
step_mother.visitor = runner
runner.visit_features(features)
hydra_response.rewind
return hydra_response.read
end
# find all the test unit classes in a given file, so we can run their suites
def self.find_classes_in_file(f)
code = ""
File.open(f) {|buffer| code = buffer.read}

View File

@ -0,0 +1,17 @@
Given /^a target file$/ do
@target_file = File.expand_path(File.join(Dir.tmpdir, 'hydra_test.txt'))
end
When /^I write "([^\"]*)" to the file$/ do |text|
f = File.new(@target_file, 'w')
f.write text
f.flush
f.close
end
Then /^"([^\"]*)" should be written in the file$/ do |text|
f = File.new(@target_file, 'r')
raise 'Did not write to file' unless text == f.read
f.close
end

View File

@ -0,0 +1,7 @@
Feature: Write a file
Scenario: Write to hydra_test.txt
Given a target file
When I write "HYDRA" to the file
Then "HYDRA" should be written in the file

View File

@ -18,7 +18,7 @@ class RunnerTest < Test::Unit::TestCase
# coverage output
pipe = Hydra::Pipe.new
parent = Process.fork do
request_a_file_and_verify_completion(pipe)
request_a_file_and_verify_completion(pipe, test_file)
end
run_the_runner(pipe)
Process.wait(parent)
@ -31,10 +31,19 @@ class RunnerTest < Test::Unit::TestCase
child = Process.fork do
run_the_runner(pipe)
end
request_a_file_and_verify_completion(pipe)
request_a_file_and_verify_completion(pipe, test_file)
Process.wait(child)
end
should "run a cucumber test" do
pipe = Hydra::Pipe.new
parent = Process.fork do
request_a_file_and_verify_completion(pipe, cucumber_feature_file)
end
run_the_runner(pipe)
Process.wait(parent)
end
should "be able to run a runner over ssh" do
ssh = Hydra::SSH.new(
'localhost',
@ -62,12 +71,12 @@ class RunnerTest < Test::Unit::TestCase
end
module RunnerTestHelper
def request_a_file_and_verify_completion(pipe)
def request_a_file_and_verify_completion(pipe, file)
pipe.identify_as_parent
# make sure it asks for a file, then give it one
assert pipe.gets.is_a?(Hydra::Messages::Runner::RequestFile)
pipe.write(Hydra::Messages::Worker::RunFile.new(:file => test_file))
pipe.write(Hydra::Messages::Worker::RunFile.new(:file => file))
# grab its response. This makes us wait for it to finish
response = pipe.gets

View File

@ -18,6 +18,10 @@ class Test::Unit::TestCase
def test_file
File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'write_file.rb'))
end
def cucumber_feature_file
File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'features', 'write_file.feature'))
end
end
module Hydra #:nodoc: