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' require 'hydra/tasks'
Hydra::TestTask.new('hydra') do |t| Hydra::TestTask.new('hydra') do |t|
# test unit
t.add_files 'test/unit/**/*_test.rb' t.add_files 'test/unit/**/*_test.rb'
t.add_files 'test/functional/**/*_test.rb' t.add_files 'test/functional/**/*_test.rb'
t.add_files 'test/integration/**/*_test.rb' t.add_files 'test/integration/**/*_test.rb'
# cucumber
t.add_files 'features/**/*.feature'
end end
Run: Run:
@ -32,6 +35,16 @@ Run:
Hydra defaults to Single Core mode, so you may want to configure it 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. 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 == Running Remote Tasks
You can run tasks across all of your remote workers easily with Hydra. In your rake file, add: 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.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Nick Gauthier"] 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.description = %q{Spread your tests over multiple machines to test your code faster.}
s.email = %q{nick@smartlogicsolutions.com} s.email = %q{nick@smartlogicsolutions.com}
s.extra_rdoc_files = [ s.extra_rdoc_files = [
@ -30,6 +30,7 @@ Gem::Specification.new do |s|
"hydra.gemspec", "hydra.gemspec",
"hydra_gray.png", "hydra_gray.png",
"lib/hydra.rb", "lib/hydra.rb",
"lib/hydra/cucumber/formatter.rb",
"lib/hydra/hash.rb", "lib/hydra/hash.rb",
"lib/hydra/listener/abstract.rb", "lib/hydra/listener/abstract.rb",
"lib/hydra/listener/minimal_output.rb", "lib/hydra/listener/minimal_output.rb",
@ -52,6 +53,8 @@ Gem::Specification.new do |s|
"lib/hydra/worker.rb", "lib/hydra/worker.rb",
"test/fixtures/assert_true.rb", "test/fixtures/assert_true.rb",
"test/fixtures/config.yml", "test/fixtures/config.yml",
"test/fixtures/features/step_definitions.rb",
"test/fixtures/features/write_file.feature",
"test/fixtures/hello_world.rb", "test/fixtures/hello_world.rb",
"test/fixtures/slow.rb", "test/fixtures/slow.rb",
"test/fixtures/sync_test.rb", "test/fixtures/sync_test.rb",
@ -78,6 +81,7 @@ Gem::Specification.new do |s|
"test/fixtures/sync_test.rb", "test/fixtures/sync_test.rb",
"test/fixtures/assert_true.rb", "test/fixtures/assert_true.rb",
"test/fixtures/hello_world.rb", "test/fixtures/hello_world.rb",
"test/fixtures/features/step_definitions.rb",
"test/master_test.rb", "test/master_test.rb",
"test/worker_test.rb", "test/worker_test.rb",
"test/runner_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 # Run a test file and report the results
def run_file(file) def run_file(file)
trace "Running file: #{file}" trace "Running file: #{file}"
begin
require file output = ""
rescue LoadError => ex if file =~ /.rb$/
trace "#{file} does not exist [#{ex.to_s}]" output = run_ruby_file(file)
@io.write Results.new(:output => ex.to_s, :file => file) elsif file =~ /.feature$/
return output = run_cucumber_file(file)
end
output = []
@result = Test::Unit::TestResult.new
@result.add_listener(Test::Unit::TestResult::FAULT) do |value|
output << value
end end
klasses = Runner.find_classes_in_file(file) output = "." if output == ""
begin
klasses.each{|klass| klass.suite.run(@result){|status, name| ;}}
rescue => ex
output << ex.to_s
end
output << '.' if output.empty? @io.write Results.new(:output => output, :file => file)
@io.write Results.new(:output => output.join("\n"), :file => file)
end end
# Stop running # Stop running
@ -86,6 +74,94 @@ module Hydra #:nodoc:
end end
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) def self.find_classes_in_file(f)
code = "" code = ""
File.open(f) {|buffer| code = buffer.read} 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 # coverage output
pipe = Hydra::Pipe.new pipe = Hydra::Pipe.new
parent = Process.fork do parent = Process.fork do
request_a_file_and_verify_completion(pipe) request_a_file_and_verify_completion(pipe, test_file)
end end
run_the_runner(pipe) run_the_runner(pipe)
Process.wait(parent) Process.wait(parent)
@ -31,10 +31,19 @@ class RunnerTest < Test::Unit::TestCase
child = Process.fork do child = Process.fork do
run_the_runner(pipe) run_the_runner(pipe)
end end
request_a_file_and_verify_completion(pipe) request_a_file_and_verify_completion(pipe, test_file)
Process.wait(child) Process.wait(child)
end 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 should "be able to run a runner over ssh" do
ssh = Hydra::SSH.new( ssh = Hydra::SSH.new(
'localhost', 'localhost',
@ -62,12 +71,12 @@ class RunnerTest < Test::Unit::TestCase
end end
module RunnerTestHelper module RunnerTestHelper
def request_a_file_and_verify_completion(pipe) def request_a_file_and_verify_completion(pipe, file)
pipe.identify_as_parent pipe.identify_as_parent
# make sure it asks for a file, then give it one # make sure it asks for a file, then give it one
assert pipe.gets.is_a?(Hydra::Messages::Runner::RequestFile) 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 # grab its response. This makes us wait for it to finish
response = pipe.gets response = pipe.gets

View File

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