specjour 0.3.0.rc8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.markdown +16 -9
- data/README.markdown +9 -0
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/specjour.rb +19 -6
- data/lib/specjour/cli.rb +8 -0
- data/lib/specjour/connection.rb +1 -0
- data/lib/specjour/cucumber.rb +11 -0
- data/lib/specjour/cucumber/distributed_formatter.rb +12 -10
- data/lib/specjour/cucumber/final_report.rb +4 -1
- data/lib/specjour/cucumber/main_ext.rb +3 -0
- data/lib/specjour/cucumber/preloader.rb +33 -12
- data/lib/specjour/cucumber/runner.rb +20 -0
- data/lib/specjour/db_scrub.rb +2 -0
- data/lib/specjour/dispatcher.rb +16 -6
- data/lib/specjour/manager.rb +18 -4
- data/lib/specjour/printer.rb +28 -4
- data/lib/specjour/rspec.rb +9 -1
- data/lib/specjour/rspec2/distributed_formatter.rb +11 -1
- data/lib/specjour/rspec2/final_report.rb +17 -4
- data/lib/specjour/rspec2/runner.rb +2 -2
- data/lib/specjour/rspec2/shared_example_group_ext.rb +9 -0
- data/lib/specjour/worker.rb +10 -8
- data/sample/features/fail.feature +31 -0
- data/sample/features/pass.feature +31 -0
- data/sample/features/step_definitions/sample_steps.rb +26 -0
- data/sample/features/undefined.feature +17 -0
- data/specjour.gemspec +13 -3
- metadata +35 -15
data/History.markdown
CHANGED
@@ -1,16 +1,26 @@
|
|
1
1
|
History
|
2
2
|
=======
|
3
3
|
|
4
|
-
## 0.3.0
|
4
|
+
## 0.3.0 / 2010-10-14
|
5
|
+
|
6
|
+
* [fixed] Cucumber output for scenario outlines (delitescere & supaspoida)
|
7
|
+
* [fixed] Undefined shared examples in Rspec2
|
8
|
+
* [fixed] INT signal sent to managers and workers, sets wants\_to\_quit where
|
9
|
+
appropriate for Rspec2 and Cucumber
|
10
|
+
* [fixed] Error reporting for failed steps within a Background
|
11
|
+
* [added] Cucumber 0.9.x compatibility
|
12
|
+
* [added] RSpec 2.0.0 compatibility
|
13
|
+
|
14
|
+
|
15
|
+
## 0.3.0.rc8 / 2010-09-13
|
5
16
|
|
6
17
|
* [fixed] Custom hooks now load in Ruby 1.9.2
|
7
18
|
* [fixed] Specjour prepare correctly recreates the db
|
8
|
-
|
9
19
|
* [added] Support for loading test DB from SQL file
|
10
|
-
(config.
|
20
|
+
(config.active\_record.schema\_format = :sql)
|
11
21
|
* [added] Rsync failures raise Specjour::Error
|
12
22
|
|
13
|
-
## 0.3.0.rc7 / 2010-
|
23
|
+
## 0.3.0.rc7 / 2010-09-09
|
14
24
|
|
15
25
|
* [fixed] Distributing absolute paths to remote machines.
|
16
26
|
|
@@ -20,11 +30,11 @@ History
|
|
20
30
|
|
21
31
|
* [changed] Decreased timeout to 2 seconds when searching for remote managers
|
22
32
|
|
23
|
-
## 0.3.0.rc6 / 2010-
|
33
|
+
## 0.3.0.rc6 / 2010-09-07
|
24
34
|
|
25
35
|
* [fixed] Ruby 1.9.2 support through minor changes and DNSSD upgrade
|
26
36
|
* [fixed] DbScrub.drop actually invokes the db:drop rake task
|
27
|
-
* [fixed] Prepare task ignores rspec's
|
37
|
+
* [fixed] Prepare task ignores rspec's at\_exit callback, disabling the test
|
28
38
|
suite from running after the prepare task completes.
|
29
39
|
|
30
40
|
## 0.3.0.rc5 / 2010-07-30
|
@@ -94,9 +104,6 @@ History
|
|
94
104
|
|
95
105
|
$ specjour listen --projects foo bar
|
96
106
|
|
97
|
-
|
98
|
-
## 0.2.6 / master
|
99
|
-
|
100
107
|
* [fixed] Rsync copies symbolic links. gh-6
|
101
108
|
* [fixed] DbScrub explicitly requires its dependencies and no longer loads the
|
102
109
|
Rakefile. gh-10
|
data/README.markdown
CHANGED
@@ -102,6 +102,15 @@ By default, the dispatcher looks for managers matching the project's directory n
|
|
102
102
|
~/bizconf $ specjour listen -p bizconf_09
|
103
103
|
~/bizconf $ specjour -a bizconf_09
|
104
104
|
|
105
|
+
## Compatibility
|
106
|
+
|
107
|
+
* RSpec 1.3.x
|
108
|
+
* RSpec 2.0.0
|
109
|
+
* Cucumber 0.8.5
|
110
|
+
* Cucumber 0.9.2
|
111
|
+
* Rails 2
|
112
|
+
* Rails 3
|
113
|
+
|
105
114
|
## Thanks
|
106
115
|
|
107
116
|
* shayarnett - Cucumber support, pairing and other various patches
|
data/Rakefile
CHANGED
@@ -14,6 +14,7 @@ begin
|
|
14
14
|
gem.add_dependency "thor", ">=0.14.0"
|
15
15
|
gem.add_development_dependency "rspec", "1.3.0"
|
16
16
|
gem.add_development_dependency "rr", ">=0.10.11"
|
17
|
+
gem.add_development_dependency "cucumber", ">=0.9.0"
|
17
18
|
gem.add_development_dependency "yard", ">=0.5.3"
|
18
19
|
gem.add_development_dependency "jeweler", ">=1.4.0"
|
19
20
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.0
|
1
|
+
0.3.0
|
data/lib/specjour.rb
CHANGED
@@ -8,6 +8,7 @@ autoload :Benchmark, 'benchmark'
|
|
8
8
|
autoload :Logger, 'logger'
|
9
9
|
autoload :Socket, 'socket'
|
10
10
|
autoload :StringIO, 'stringio'
|
11
|
+
autoload :OpenStruct, 'ostruct'
|
11
12
|
|
12
13
|
module Specjour
|
13
14
|
autoload :CLI, 'specjour/cli'
|
@@ -17,7 +18,6 @@ module Specjour
|
|
17
18
|
autoload :DbScrub, 'specjour/db_scrub'
|
18
19
|
autoload :Dispatcher, 'specjour/dispatcher'
|
19
20
|
autoload :Manager, 'specjour/manager'
|
20
|
-
autoload :OpenStruct, 'ostruct'
|
21
21
|
autoload :Printer, 'specjour/printer'
|
22
22
|
autoload :Protocol, 'specjour/protocol'
|
23
23
|
autoload :QuietFork, 'specjour/quiet_fork'
|
@@ -28,12 +28,17 @@ module Specjour
|
|
28
28
|
autoload :Cucumber, 'specjour/cucumber'
|
29
29
|
autoload :Rspec, 'specjour/rspec'
|
30
30
|
|
31
|
-
VERSION = "0.3.0
|
31
|
+
VERSION = "0.3.0".freeze
|
32
32
|
HOOKS_PATH = "./.specjour/hooks.rb"
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
def self.interrupted?
|
35
|
+
@interrupted
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.interrupted=(bool)
|
39
|
+
Cucumber.wants_to_quit
|
40
|
+
Rspec.wants_to_quit
|
41
|
+
@interrupted = bool
|
37
42
|
end
|
38
43
|
|
39
44
|
def self.logger
|
@@ -54,10 +59,18 @@ module Specjour
|
|
54
59
|
require HOOKS_PATH if File.exists?(HOOKS_PATH)
|
55
60
|
end
|
56
61
|
|
62
|
+
def self.trap_interrupt
|
63
|
+
Signal.trap('INT') do
|
64
|
+
self.interrupted = true
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
57
69
|
Error = Class.new(StandardError)
|
58
70
|
PROGRAM_NAME = $PROGRAM_NAME # keep a reference of the original program name
|
59
71
|
|
60
72
|
GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
|
61
73
|
|
62
|
-
|
74
|
+
trap_interrupt
|
75
|
+
|
63
76
|
end
|
data/lib/specjour/cli.rb
CHANGED
@@ -34,6 +34,7 @@ module Specjour
|
|
34
34
|
handle_logging
|
35
35
|
handle_workers
|
36
36
|
args[:registered_projects] = args.delete(:projects) || [File.basename(Dir.pwd)]
|
37
|
+
append_to_program_name "listen"
|
37
38
|
Specjour::Manager.new(args).start
|
38
39
|
end
|
39
40
|
|
@@ -44,6 +45,7 @@ module Specjour
|
|
44
45
|
handle_logging
|
45
46
|
handle_workers
|
46
47
|
handle_dispatcher(path)
|
48
|
+
append_to_program_name "dispatch"
|
47
49
|
Specjour::Dispatcher.new(args).start
|
48
50
|
end
|
49
51
|
|
@@ -59,6 +61,7 @@ module Specjour
|
|
59
61
|
handle_workers
|
60
62
|
handle_dispatcher(path)
|
61
63
|
args[:worker_task] = 'prepare'
|
64
|
+
append_to_program_name "prepare"
|
62
65
|
Specjour::Dispatcher.new(args).start
|
63
66
|
end
|
64
67
|
|
@@ -77,11 +80,16 @@ module Specjour
|
|
77
80
|
method_option :quiet, :type => :boolean
|
78
81
|
def work
|
79
82
|
handle_logging
|
83
|
+
append_to_program_name "work"
|
80
84
|
Specjour::Worker.new(args).start
|
81
85
|
end
|
82
86
|
|
83
87
|
protected
|
84
88
|
|
89
|
+
def append_to_program_name(command)
|
90
|
+
$PROGRAM_NAME = "#{$PROGRAM_NAME} #{command}"
|
91
|
+
end
|
92
|
+
|
85
93
|
def args
|
86
94
|
@args ||= options.dup
|
87
95
|
end
|
data/lib/specjour/connection.rb
CHANGED
data/lib/specjour/cucumber.rb
CHANGED
@@ -7,9 +7,20 @@ module Specjour
|
|
7
7
|
require 'specjour/cucumber/distributed_formatter'
|
8
8
|
require 'specjour/cucumber/final_report'
|
9
9
|
require 'specjour/cucumber/preloader'
|
10
|
+
require 'specjour/cucumber/main_ext'
|
11
|
+
require 'specjour/cucumber/runner'
|
10
12
|
|
13
|
+
CUCUMBER_09x = ::Cucumber::VERSION =~ /0\.9\.\d/
|
11
14
|
::Cucumber::Cli::Options.class_eval { def print_profile_information; end }
|
12
15
|
rescue LoadError
|
13
16
|
end
|
17
|
+
|
18
|
+
class << self; attr_accessor :runtime; end
|
19
|
+
|
20
|
+
def self.wants_to_quit
|
21
|
+
if defined?(::Cucumber) && ::Cucumber.respond_to?(:wants_to_quit=)
|
22
|
+
::Cucumber.wants_to_quit = true
|
23
|
+
end
|
24
|
+
end
|
14
25
|
end
|
15
26
|
end
|
@@ -17,15 +17,17 @@ module Specjour::Cucumber
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def prepare_failures
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@failing_scenarios << failure_message
|
20
|
+
step_mother.scenarios(:failed).select do |s|
|
21
|
+
s.is_a?(Cucumber::Ast::Scenario) || s.is_a?(Cucumber::Ast::OutlineTable::ExampleRow)
|
22
|
+
end.map do |failure|
|
23
|
+
if failure.is_a?(Cucumber::Ast::Scenario)
|
24
|
+
failure
|
25
|
+
elsif failure.is_a?(Cucumber::Ast::OutlineTable::ExampleRow)
|
26
|
+
failure.scenario_outline
|
28
27
|
end
|
28
|
+
end.each do |failure|
|
29
|
+
@failing_scenarios << format_string("cucumber " + failure.file_colon_line[2..-1], :failed) +
|
30
|
+
format_string(" # Scenario: " + failure.name, :comment)
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
@@ -43,12 +45,12 @@ module Specjour::Cucumber
|
|
43
45
|
output += format_string(element.backtrace_line, status)
|
44
46
|
output += "\n"
|
45
47
|
end
|
46
|
-
@step_summary << output unless output.
|
48
|
+
@step_summary << output unless output.nil? || output.empty?
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
52
|
def prepare_steps(type)
|
51
|
-
prepare_elements(step_mother.
|
53
|
+
prepare_elements(step_mother.steps(type), type, 'steps')
|
52
54
|
end
|
53
55
|
|
54
56
|
def print_exception(e, status, indent)
|
@@ -60,9 +60,12 @@ module Specjour
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def summarize
|
63
|
-
if @summarizer.
|
63
|
+
if @summarizer.steps(:failed).any?
|
64
64
|
puts "\n\n"
|
65
65
|
@summarizer.step_summary.each {|f| puts f }
|
66
|
+
end
|
67
|
+
|
68
|
+
if @summarizer.failing_scenarios.any?
|
66
69
|
puts "\n\n"
|
67
70
|
puts format_string("Failing Scenarios:", :failed)
|
68
71
|
@summarizer.failing_scenarios.each {|f| puts f }
|
@@ -1,14 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
module Specjour
|
2
|
+
module Cucumber
|
3
|
+
module Preloader
|
4
|
+
def self.load(feature_file)
|
5
|
+
if CUCUMBER_09x
|
6
|
+
load_09x
|
7
|
+
else
|
8
|
+
load_08x
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def self.load_08x
|
15
|
+
cli = ::Cucumber::Cli::Main.new []
|
16
|
+
step_mother = cli.class.step_mother
|
17
|
+
|
18
|
+
step_mother.log = cli.configuration.log
|
19
|
+
step_mother.options = cli.configuration.options
|
20
|
+
step_mother.load_code_files(cli.configuration.support_to_load)
|
21
|
+
step_mother.after_configuration(cli.configuration)
|
22
|
+
features = step_mother.load_plain_text_features(cli.configuration.feature_files)
|
23
|
+
step_mother.load_code_files(cli.configuration.step_defs_to_load)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.load_09x
|
27
|
+
configuration = ::Cucumber::Cli::Configuration.new
|
28
|
+
configuration.parse! []
|
29
|
+
runtime = ::Cucumber::Runtime.new(configuration)
|
30
|
+
runtime.send :load_step_definitions
|
31
|
+
Cucumber.runtime = runtime
|
32
|
+
end
|
33
|
+
end
|
13
34
|
end
|
14
35
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Specjour
|
2
|
+
module Cucumber
|
3
|
+
module Runner
|
4
|
+
def self.run(feature, output)
|
5
|
+
cli = ::Cucumber::Cli::Main.new(['--format', 'Specjour::Cucumber::DistributedFormatter', feature], output)
|
6
|
+
|
7
|
+
if CUCUMBER_09x
|
8
|
+
Cucumber.runtime.instance_variable_set(:@configuration, cli.configuration)
|
9
|
+
Cucumber.runtime.instance_eval do
|
10
|
+
tree_walker = @configuration.build_tree_walker(self)
|
11
|
+
self.visitor = tree_walker
|
12
|
+
tree_walker.visit_features(features)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
cli.execute!(::Cucumber::Cli::Main.step_mother)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/specjour/db_scrub.rb
CHANGED
@@ -9,6 +9,7 @@ module Specjour
|
|
9
9
|
load 'tasks/misc.rake'
|
10
10
|
load 'tasks/databases.rake'
|
11
11
|
Rake::Task["db:structure:dump"].clear
|
12
|
+
Rake::Task["environment"].clear
|
12
13
|
end
|
13
14
|
|
14
15
|
extend self
|
@@ -31,6 +32,7 @@ module Specjour
|
|
31
32
|
|
32
33
|
def connect_to_database
|
33
34
|
ActiveRecord::Base.remove_connection
|
35
|
+
ActiveRecord::Base.establish_connection
|
34
36
|
connection
|
35
37
|
rescue # assume the database doesn't exist
|
36
38
|
Rake::Task['db:create'].invoke
|
data/lib/specjour/dispatcher.rb
CHANGED
@@ -18,7 +18,7 @@ module Specjour
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def start
|
21
|
-
abort("#{project_path} doesn't exist") unless File.
|
21
|
+
abort("#{project_path} doesn't exist") unless File.directory?(project_path)
|
22
22
|
gather_managers
|
23
23
|
rsync_daemon.start
|
24
24
|
dispatch_work
|
@@ -69,7 +69,7 @@ module Specjour
|
|
69
69
|
puts "#{manager.hostname} (#{manager.worker_size})"
|
70
70
|
end
|
71
71
|
printer.worker_size = worker_size
|
72
|
-
command_managers(true) { |m| m.dispatch }
|
72
|
+
command_managers(true) { |m| m.dispatch rescue DRb::DRbConnError }
|
73
73
|
end
|
74
74
|
|
75
75
|
def dispatching_tests?
|
@@ -77,7 +77,7 @@ module Specjour
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def fetch_manager(uri)
|
80
|
-
Timeout.timeout(
|
80
|
+
Timeout.timeout(0.5) do
|
81
81
|
manager = DRbObject.new_with_uri(uri.to_s)
|
82
82
|
if !managers.include?(manager) && manager.available_for?(project_alias)
|
83
83
|
add_manager(manager)
|
@@ -95,7 +95,11 @@ module Specjour
|
|
95
95
|
manager_options = {:worker_size => options[:worker_size], :registered_projects => [project_alias]}
|
96
96
|
manager = Manager.start_quietly manager_options
|
97
97
|
fetch_manager(manager.drb_uri)
|
98
|
-
at_exit
|
98
|
+
at_exit do
|
99
|
+
unless Specjour.interrupted?
|
100
|
+
Process.kill('TERM', manager.pid) rescue Errno::ESRCH
|
101
|
+
end
|
102
|
+
end
|
99
103
|
end
|
100
104
|
|
101
105
|
def gather_managers
|
@@ -107,7 +111,7 @@ module Specjour
|
|
107
111
|
|
108
112
|
def gather_remote_managers
|
109
113
|
browser = DNSSD::Service.new
|
110
|
-
Timeout.timeout(
|
114
|
+
Timeout.timeout(3) do
|
111
115
|
browser.browse '_druby._tcp' do |reply|
|
112
116
|
if reply.flags.add?
|
113
117
|
resolve_reply(reply)
|
@@ -162,7 +166,13 @@ module Specjour
|
|
162
166
|
manager.preload_spec = all_tests.detect {|f| f =~ /_spec\.rb$/}
|
163
167
|
manager.preload_feature = all_tests.detect {|f| f =~ /\.feature$/}
|
164
168
|
manager.worker_task = worker_task
|
165
|
-
at_exit
|
169
|
+
at_exit do
|
170
|
+
begin
|
171
|
+
manager.interrupted = Specjour.interrupted?
|
172
|
+
manager.kill_worker_processes
|
173
|
+
rescue DRb::DRbConnError
|
174
|
+
end
|
175
|
+
end
|
166
176
|
end
|
167
177
|
|
168
178
|
def wait_on_managers
|
data/lib/specjour/manager.rb
CHANGED
@@ -8,12 +8,13 @@ module Specjour
|
|
8
8
|
include SocketHelper
|
9
9
|
|
10
10
|
attr_accessor :project_name, :preload_spec, :preload_feature, :worker_task, :pid
|
11
|
-
attr_reader :worker_size, :dispatcher_uri, :registered_projects, :
|
11
|
+
attr_reader :worker_size, :dispatcher_uri, :registered_projects, :worker_pids, :options
|
12
12
|
|
13
13
|
def self.start_quietly(options)
|
14
14
|
manager = new options.merge(:quiet => true)
|
15
15
|
manager.drb_uri
|
16
16
|
manager.pid = QuietFork.fork { manager.start }
|
17
|
+
sleep 0.2
|
17
18
|
manager
|
18
19
|
end
|
19
20
|
|
@@ -69,8 +70,16 @@ module Specjour
|
|
69
70
|
Dir.chdir(project_path, &block)
|
70
71
|
end
|
71
72
|
|
73
|
+
def interrupted=(bool)
|
74
|
+
Specjour.interrupted = bool
|
75
|
+
end
|
76
|
+
|
72
77
|
def kill_worker_processes
|
73
|
-
|
78
|
+
if Specjour.interrupted?
|
79
|
+
Process.kill('INT', *worker_pids) rescue Errno::ESRCH
|
80
|
+
else
|
81
|
+
Process.kill('TERM', *worker_pids) rescue Errno::ESRCH
|
82
|
+
end
|
74
83
|
end
|
75
84
|
|
76
85
|
def pid
|
@@ -86,7 +95,6 @@ module Specjour
|
|
86
95
|
puts "Workers ready: #{worker_size}."
|
87
96
|
puts "Listening for #{registered_projects.join(', ')}"
|
88
97
|
bonjour_announce
|
89
|
-
Signal.trap('INT') { puts; puts "Shutting down manager..."; exit 1 }
|
90
98
|
DRb.thread.join
|
91
99
|
end
|
92
100
|
|
@@ -103,7 +111,13 @@ module Specjour
|
|
103
111
|
protected
|
104
112
|
|
105
113
|
def bonjour_announce
|
106
|
-
|
114
|
+
unless quiet?
|
115
|
+
bonjour_service.register "specjour_manager_#{object_id}", "_#{drb_uri.scheme}._tcp", nil, drb_uri.port
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def bonjour_service
|
120
|
+
@bonjour_service = DNSSD::Service.new
|
107
121
|
end
|
108
122
|
|
109
123
|
def cmd(command)
|
data/lib/specjour/printer.rb
CHANGED
@@ -10,7 +10,7 @@ module Specjour
|
|
10
10
|
new(specs_to_run).start
|
11
11
|
end
|
12
12
|
|
13
|
-
attr_accessor :worker_size, :specs_to_run, :completed_workers, :disconnections
|
13
|
+
attr_accessor :worker_size, :specs_to_run, :completed_workers, :disconnections, :profiler
|
14
14
|
|
15
15
|
def initialize(specs_to_run)
|
16
16
|
super(
|
@@ -23,7 +23,8 @@ module Specjour
|
|
23
23
|
)
|
24
24
|
@completed_workers = 0
|
25
25
|
@disconnections = 0
|
26
|
-
|
26
|
+
@profiler = {}
|
27
|
+
self.specs_to_run = run_order(specs_to_run)
|
27
28
|
end
|
28
29
|
|
29
30
|
def serve(client)
|
@@ -56,13 +57,18 @@ module Specjour
|
|
56
57
|
cucumber_report.add(summary)
|
57
58
|
end
|
58
59
|
|
60
|
+
def add_to_profiler(client, args)
|
61
|
+
test, time = *args
|
62
|
+
self.profiler[test] = time
|
63
|
+
end
|
64
|
+
|
59
65
|
protected
|
60
66
|
|
61
67
|
def disconnecting(client_port)
|
62
|
-
self.disconnections += 1
|
68
|
+
synchronize { self.disconnections += 1 }
|
63
69
|
if disconnections == worker_size
|
64
70
|
shutdown
|
65
|
-
stop unless
|
71
|
+
stop unless Specjour.interrupted?
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
@@ -83,6 +89,15 @@ module Specjour
|
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
92
|
+
def run_order(specs_to_run)
|
93
|
+
if File.exist?('.specjour/performance')
|
94
|
+
ordered_specs = File.readlines('.specjour/performance').map {|l| l.chop.split(':')[1]}
|
95
|
+
(specs_to_run - ordered_specs) | (ordered_specs & specs_to_run)
|
96
|
+
else
|
97
|
+
specs_to_run
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
86
101
|
def rspec_report
|
87
102
|
@rspec_report ||= Rspec::FinalReport.new
|
88
103
|
end
|
@@ -91,6 +106,14 @@ module Specjour
|
|
91
106
|
@cucumber_report ||= Cucumber::FinalReport.new
|
92
107
|
end
|
93
108
|
|
109
|
+
def record_performance
|
110
|
+
File.open('.specjour/performance', 'w') do |file|
|
111
|
+
ordered_specs = profiler.to_a.sort_by {|a| -a[1].to_f}.map do |test, time|
|
112
|
+
file.puts "%6f:%s" % [time, test]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
94
117
|
def reporters
|
95
118
|
[@rspec_report, @cucumber_report].compact
|
96
119
|
end
|
@@ -98,6 +121,7 @@ module Specjour
|
|
98
121
|
def stopping
|
99
122
|
summarize_reports
|
100
123
|
warn_if_workers_deserted
|
124
|
+
record_performance unless Specjour.interrupted?
|
101
125
|
end
|
102
126
|
|
103
127
|
def summarize_reports
|
data/lib/specjour/rspec.rb
CHANGED
@@ -13,13 +13,16 @@ module Specjour
|
|
13
13
|
|
14
14
|
def self.load_rspec2
|
15
15
|
require 'rspec/core'
|
16
|
-
|
16
|
+
require 'rspec/core/formatters/progress_formatter'
|
17
17
|
|
18
18
|
require 'specjour/rspec/marshalable_exception'
|
19
19
|
require 'specjour/rspec/preloader'
|
20
20
|
require 'specjour/rspec2/distributed_formatter'
|
21
21
|
require 'specjour/rspec2/final_report'
|
22
22
|
require 'specjour/rspec2/runner'
|
23
|
+
require 'specjour/rspec2/shared_example_group_ext'
|
24
|
+
|
25
|
+
::Rspec::Core::Runner.disable_autorun!
|
23
26
|
end
|
24
27
|
|
25
28
|
begin
|
@@ -28,5 +31,10 @@ module Specjour
|
|
28
31
|
load_rspec1
|
29
32
|
end
|
30
33
|
|
34
|
+
def self.wants_to_quit
|
35
|
+
if defined?(::RSpec) && ::RSpec.respond_to?(:wants_to_quit=)
|
36
|
+
::RSpec.wants_to_quit = true
|
37
|
+
end
|
38
|
+
end
|
31
39
|
end
|
32
40
|
end
|
@@ -15,16 +15,26 @@ module Specjour::Rspec
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def noop
|
18
|
+
def noop(*args)
|
19
19
|
end
|
20
20
|
alias dump_pending noop
|
21
21
|
alias dump_failures noop
|
22
22
|
alias start_dump noop
|
23
|
+
alias message noop
|
24
|
+
|
25
|
+
def color_enabled?
|
26
|
+
true
|
27
|
+
end
|
23
28
|
|
24
29
|
def dump_summary(*args)
|
25
30
|
output.send_message :rspec_summary=, metadata_for_examples
|
26
31
|
end
|
27
32
|
|
33
|
+
def close
|
34
|
+
@examples = []
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
28
38
|
protected
|
29
39
|
|
30
40
|
def marshalable_execution_result(execution_result)
|
@@ -6,6 +6,8 @@ module Specjour::Rspec
|
|
6
6
|
def initialize
|
7
7
|
@examples = []
|
8
8
|
@duration = 0.0
|
9
|
+
::Rspec.configuration.color_enabled = true
|
10
|
+
::Rspec.configuration.output_stream = $stdout
|
9
11
|
end
|
10
12
|
|
11
13
|
def add(data)
|
@@ -28,6 +30,9 @@ module Specjour::Rspec
|
|
28
30
|
examples.concat(
|
29
31
|
metadata_collection.map do |partial_metadata|
|
30
32
|
example = ::Rspec::Core::Example.allocate
|
33
|
+
example.instance_variable_set(:@example_group_class,
|
34
|
+
OpenStruct.new(:metadata => {}, :ancestors => [])
|
35
|
+
)
|
31
36
|
metadata = ::Rspec::Core::Metadata.new
|
32
37
|
metadata.merge! partial_metadata
|
33
38
|
example.instance_variable_set(:@metadata, metadata)
|
@@ -36,24 +41,32 @@ module Specjour::Rspec
|
|
36
41
|
)
|
37
42
|
end
|
38
43
|
|
44
|
+
def pending_examples
|
45
|
+
::RSpec.world.find(examples, :execution_result => { :status => 'pending' })
|
46
|
+
end
|
47
|
+
|
48
|
+
def failed_examples
|
49
|
+
::RSpec.world.find(examples, :execution_result => { :status => 'failed' })
|
50
|
+
end
|
51
|
+
|
39
52
|
def formatter
|
40
53
|
@formatter ||= new_progress_formatter
|
41
54
|
end
|
42
55
|
|
43
56
|
def summarize
|
44
57
|
if examples.size > 0
|
45
|
-
formatter.
|
58
|
+
formatter.start_dump
|
46
59
|
formatter.dump_pending
|
47
60
|
formatter.dump_failures
|
61
|
+
formatter.dump_summary(duration, examples.size, failed_examples.size, pending_examples.size)
|
48
62
|
end
|
49
63
|
end
|
50
64
|
|
51
65
|
protected
|
52
66
|
def new_progress_formatter
|
53
67
|
new_formatter = ::Rspec::Core::Formatters::ProgressFormatter.new($stdout)
|
54
|
-
new_formatter.instance_variable_set(:@
|
55
|
-
new_formatter.instance_variable_set(:@
|
56
|
-
Rspec.configuration.color_enabled = true
|
68
|
+
new_formatter.instance_variable_set(:@failed_examples, failed_examples)
|
69
|
+
new_formatter.instance_variable_set(:@pending_examples, pending_examples)
|
57
70
|
new_formatter
|
58
71
|
end
|
59
72
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Specjour::Rspec::Runner
|
2
2
|
def self.run(spec, output)
|
3
3
|
reset
|
4
|
-
|
5
|
-
::Rspec::Core::Runner.
|
4
|
+
args = ['--format=Specjour::Rspec::DistributedFormatter', spec]
|
5
|
+
::Rspec::Core::Runner.run_in_process args, $stderr, output
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.reset
|
data/lib/specjour/worker.rb
CHANGED
@@ -40,7 +40,7 @@ module Specjour
|
|
40
40
|
while test = connection.next_test
|
41
41
|
print_status(test)
|
42
42
|
time = Benchmark.realtime { run_test test }
|
43
|
-
|
43
|
+
profile(test, time)
|
44
44
|
run_times[test_type(test)] += time
|
45
45
|
end
|
46
46
|
|
@@ -63,11 +63,9 @@ module Specjour
|
|
63
63
|
Rspec::Preloader.load(preload_spec) if preload_spec
|
64
64
|
Cucumber::Preloader.load(preload_feature) if preload_feature
|
65
65
|
rescue StandardError => exception
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
]
|
70
|
-
$stderr.puts msg.join("\n")
|
66
|
+
$stderr.puts "Caught exception: #{exception.class} #{exception.message}"
|
67
|
+
Specjour.logger.debug exception.backtrace.join("\n")
|
68
|
+
$stderr.puts "Proceeding... you may need to re-run the dispatcher."
|
71
69
|
end
|
72
70
|
|
73
71
|
def printer_connection
|
@@ -84,6 +82,11 @@ module Specjour
|
|
84
82
|
printf "[#{ENV['TEST_ENV_NUMBER']}] Finished #{test} in %.4f\n", time
|
85
83
|
end
|
86
84
|
|
85
|
+
def profile(test, time)
|
86
|
+
connection.send_message(:add_to_profiler, [test, time])
|
87
|
+
print_time_for(test, time)
|
88
|
+
end
|
89
|
+
|
87
90
|
def run_test(test)
|
88
91
|
if test_type(test) == :cucumber
|
89
92
|
run_feature test
|
@@ -93,8 +96,7 @@ module Specjour
|
|
93
96
|
end
|
94
97
|
|
95
98
|
def run_feature(feature)
|
96
|
-
|
97
|
-
cli.execute!(::Cucumber::Cli::Main.step_mother)
|
99
|
+
Specjour::Cucumber::Runner.run(feature, connection)
|
98
100
|
end
|
99
101
|
|
100
102
|
def run_spec(spec)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Feature: Failing sample
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given anything
|
5
|
+
|
6
|
+
Scenario: Winning
|
7
|
+
When I do something good
|
8
|
+
Then fail
|
9
|
+
|
10
|
+
Scenario: Losing
|
11
|
+
When I do something bad
|
12
|
+
Then fail
|
13
|
+
|
14
|
+
Scenario Outline: Passing wins
|
15
|
+
When I do something good with <thing>
|
16
|
+
Then fail
|
17
|
+
|
18
|
+
Examples:
|
19
|
+
| thing |
|
20
|
+
| money |
|
21
|
+
| time |
|
22
|
+
|
23
|
+
Scenario Outline: Passing flops
|
24
|
+
When I do something bad with <thing>
|
25
|
+
Then fail
|
26
|
+
|
27
|
+
Examples:
|
28
|
+
| thing |
|
29
|
+
| money |
|
30
|
+
| time |
|
31
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Feature: Passing sample
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given anything
|
5
|
+
|
6
|
+
Scenario: Winning
|
7
|
+
When I do something good
|
8
|
+
Then I should be successful
|
9
|
+
|
10
|
+
Scenario: Losing
|
11
|
+
When I do something bad
|
12
|
+
Then I should not be successful
|
13
|
+
|
14
|
+
Scenario Outline: Passing wins
|
15
|
+
When I do something good with <thing>
|
16
|
+
Then I should be successful
|
17
|
+
|
18
|
+
Examples:
|
19
|
+
| thing |
|
20
|
+
| money |
|
21
|
+
| time |
|
22
|
+
|
23
|
+
Scenario Outline: Passing flops
|
24
|
+
When I do something bad with <thing>
|
25
|
+
Then I should not be successful
|
26
|
+
|
27
|
+
Examples:
|
28
|
+
| thing |
|
29
|
+
| money |
|
30
|
+
| time |
|
31
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Given /^anything$/ do
|
2
|
+
end
|
3
|
+
|
4
|
+
When /^I do something good$/ do
|
5
|
+
end
|
6
|
+
|
7
|
+
When /^I do something bad$/ do
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^I do something good with (.+)$/ do |thing|
|
11
|
+
end
|
12
|
+
|
13
|
+
When /^I do something bad with (.+)$/ do |thing|
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^I should not be successful$/ do
|
17
|
+
false.should_not == true
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^I should be successful$/ do
|
21
|
+
true.should == true
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^fail$/ do
|
25
|
+
false.should == true
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: Undefined step definitions sample
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given anything
|
5
|
+
|
6
|
+
Scenario:
|
7
|
+
When I have this undefined step definition
|
8
|
+
Then fail
|
9
|
+
|
10
|
+
Scenario Outline:
|
11
|
+
When I have this undefined step definition
|
12
|
+
Then fail
|
13
|
+
|
14
|
+
Examples:
|
15
|
+
| thing |
|
16
|
+
| money |
|
17
|
+
| time |
|
data/specjour.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{specjour}
|
8
|
-
s.version = "0.3.0
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Sandro Turriate"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-14}
|
13
13
|
s.default_executable = %q{specjour}
|
14
14
|
s.description = %q{Distribute your spec suite amongst your LAN via Bonjour.}
|
15
15
|
s.email = %q{sandro.turriate@gmail.com}
|
@@ -37,7 +37,9 @@ Gem::Specification.new do |s|
|
|
37
37
|
"lib/specjour/cucumber.rb",
|
38
38
|
"lib/specjour/cucumber/distributed_formatter.rb",
|
39
39
|
"lib/specjour/cucumber/final_report.rb",
|
40
|
+
"lib/specjour/cucumber/main_ext.rb",
|
40
41
|
"lib/specjour/cucumber/preloader.rb",
|
42
|
+
"lib/specjour/cucumber/runner.rb",
|
41
43
|
"lib/specjour/db_scrub.rb",
|
42
44
|
"lib/specjour/dispatcher.rb",
|
43
45
|
"lib/specjour/manager.rb",
|
@@ -54,9 +56,14 @@ Gem::Specification.new do |s|
|
|
54
56
|
"lib/specjour/rspec2/distributed_formatter.rb",
|
55
57
|
"lib/specjour/rspec2/final_report.rb",
|
56
58
|
"lib/specjour/rspec2/runner.rb",
|
59
|
+
"lib/specjour/rspec2/shared_example_group_ext.rb",
|
57
60
|
"lib/specjour/rsync_daemon.rb",
|
58
61
|
"lib/specjour/socket_helper.rb",
|
59
62
|
"lib/specjour/worker.rb",
|
63
|
+
"sample/features/fail.feature",
|
64
|
+
"sample/features/pass.feature",
|
65
|
+
"sample/features/step_definitions/sample_steps.rb",
|
66
|
+
"sample/features/undefined.feature",
|
60
67
|
"spec/spec.opts",
|
61
68
|
"spec/spec_helper.rb",
|
62
69
|
"spec/specjour/cli_spec.rb",
|
@@ -93,6 +100,7 @@ Gem::Specification.new do |s|
|
|
93
100
|
s.add_runtime_dependency(%q<thor>, [">= 0.14.0"])
|
94
101
|
s.add_development_dependency(%q<rspec>, ["= 1.3.0"])
|
95
102
|
s.add_development_dependency(%q<rr>, [">= 0.10.11"])
|
103
|
+
s.add_development_dependency(%q<cucumber>, [">= 0.9.0"])
|
96
104
|
s.add_development_dependency(%q<yard>, [">= 0.5.3"])
|
97
105
|
s.add_development_dependency(%q<jeweler>, [">= 1.4.0"])
|
98
106
|
else
|
@@ -100,6 +108,7 @@ Gem::Specification.new do |s|
|
|
100
108
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
101
109
|
s.add_dependency(%q<rspec>, ["= 1.3.0"])
|
102
110
|
s.add_dependency(%q<rr>, [">= 0.10.11"])
|
111
|
+
s.add_dependency(%q<cucumber>, [">= 0.9.0"])
|
103
112
|
s.add_dependency(%q<yard>, [">= 0.5.3"])
|
104
113
|
s.add_dependency(%q<jeweler>, [">= 1.4.0"])
|
105
114
|
end
|
@@ -108,6 +117,7 @@ Gem::Specification.new do |s|
|
|
108
117
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
109
118
|
s.add_dependency(%q<rspec>, ["= 1.3.0"])
|
110
119
|
s.add_dependency(%q<rr>, [">= 0.10.11"])
|
120
|
+
s.add_dependency(%q<cucumber>, [">= 0.9.0"])
|
111
121
|
s.add_dependency(%q<yard>, [">= 0.5.3"])
|
112
122
|
s.add_dependency(%q<jeweler>, [">= 1.4.0"])
|
113
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: specjour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
9
|
- 0
|
10
|
-
|
11
|
-
version: 0.3.0.rc8
|
10
|
+
version: 0.3.0
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- Sandro Turriate
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2010-
|
18
|
+
date: 2010-10-14 00:00:00 -04:00
|
20
19
|
default_executable: specjour
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -84,9 +83,25 @@ dependencies:
|
|
84
83
|
type: :development
|
85
84
|
version_requirements: *id004
|
86
85
|
- !ruby/object:Gem::Dependency
|
87
|
-
name:
|
86
|
+
name: cucumber
|
88
87
|
prerelease: false
|
89
88
|
requirement: &id005 !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 59
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
- 9
|
97
|
+
- 0
|
98
|
+
version: 0.9.0
|
99
|
+
type: :development
|
100
|
+
version_requirements: *id005
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
name: yard
|
103
|
+
prerelease: false
|
104
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
90
105
|
none: false
|
91
106
|
requirements:
|
92
107
|
- - ">="
|
@@ -98,11 +113,11 @@ dependencies:
|
|
98
113
|
- 3
|
99
114
|
version: 0.5.3
|
100
115
|
type: :development
|
101
|
-
version_requirements: *
|
116
|
+
version_requirements: *id006
|
102
117
|
- !ruby/object:Gem::Dependency
|
103
118
|
name: jeweler
|
104
119
|
prerelease: false
|
105
|
-
requirement: &
|
120
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
106
121
|
none: false
|
107
122
|
requirements:
|
108
123
|
- - ">="
|
@@ -114,7 +129,7 @@ dependencies:
|
|
114
129
|
- 0
|
115
130
|
version: 1.4.0
|
116
131
|
type: :development
|
117
|
-
version_requirements: *
|
132
|
+
version_requirements: *id007
|
118
133
|
description: Distribute your spec suite amongst your LAN via Bonjour.
|
119
134
|
email: sandro.turriate@gmail.com
|
120
135
|
executables:
|
@@ -143,7 +158,9 @@ files:
|
|
143
158
|
- lib/specjour/cucumber.rb
|
144
159
|
- lib/specjour/cucumber/distributed_formatter.rb
|
145
160
|
- lib/specjour/cucumber/final_report.rb
|
161
|
+
- lib/specjour/cucumber/main_ext.rb
|
146
162
|
- lib/specjour/cucumber/preloader.rb
|
163
|
+
- lib/specjour/cucumber/runner.rb
|
147
164
|
- lib/specjour/db_scrub.rb
|
148
165
|
- lib/specjour/dispatcher.rb
|
149
166
|
- lib/specjour/manager.rb
|
@@ -160,9 +177,14 @@ files:
|
|
160
177
|
- lib/specjour/rspec2/distributed_formatter.rb
|
161
178
|
- lib/specjour/rspec2/final_report.rb
|
162
179
|
- lib/specjour/rspec2/runner.rb
|
180
|
+
- lib/specjour/rspec2/shared_example_group_ext.rb
|
163
181
|
- lib/specjour/rsync_daemon.rb
|
164
182
|
- lib/specjour/socket_helper.rb
|
165
183
|
- lib/specjour/worker.rb
|
184
|
+
- sample/features/fail.feature
|
185
|
+
- sample/features/pass.feature
|
186
|
+
- sample/features/step_definitions/sample_steps.rb
|
187
|
+
- sample/features/undefined.feature
|
166
188
|
- spec/spec.opts
|
167
189
|
- spec/spec_helper.rb
|
168
190
|
- spec/specjour/cli_spec.rb
|
@@ -194,14 +216,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
194
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
217
|
none: false
|
196
218
|
requirements:
|
197
|
-
- - "
|
219
|
+
- - ">="
|
198
220
|
- !ruby/object:Gem::Version
|
199
|
-
hash:
|
221
|
+
hash: 3
|
200
222
|
segments:
|
201
|
-
-
|
202
|
-
|
203
|
-
- 1
|
204
|
-
version: 1.3.1
|
223
|
+
- 0
|
224
|
+
version: "0"
|
205
225
|
requirements: []
|
206
226
|
|
207
227
|
rubyforge_project:
|