specjour 0.3.0.rc8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,26 @@
1
1
  History
2
2
  =======
3
3
 
4
- ## 0.3.0.rc8 / 2010-08-13
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.active_record.schema_format = :sql)
20
+ (config.active\_record.schema\_format = :sql)
11
21
  * [added] Rsync failures raise Specjour::Error
12
22
 
13
- ## 0.3.0.rc7 / 2010-08-09
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-08-07
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 at_exit callback, disabling the test
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
@@ -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.rc8
1
+ 0.3.0
@@ -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.rc8".freeze
31
+ VERSION = "0.3.0".freeze
32
32
  HOOKS_PATH = "./.specjour/hooks.rb"
33
33
 
34
- class << self
35
- attr_accessor :interrupted
36
- alias interrupted? interrupted
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
- Signal.trap('INT') { Specjour.interrupted = true; exit 1 }
74
+ trap_interrupt
75
+
63
76
  end
@@ -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
@@ -67,6 +67,7 @@ module Specjour
67
67
  @socket = TCPSocket.open(uri.host, uri.port)
68
68
  rescue Errno::ECONNREFUSED => error
69
69
  Specjour.logger.debug "Could not connect to #{uri.to_s}\n#{error.inspect}"
70
+ sleep 0.1
70
71
  retry
71
72
  end
72
73
 
@@ -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
- @failures = step_mother.scenarios(:failed).select { |s| s.is_a?(Cucumber::Ast::Scenario) }
21
-
22
- if !@failures.empty?
23
- @failures.each do |failure|
24
- failure_message = ''
25
- failure_message += format_string("cucumber " + failure.file_colon_line, :failed) +
26
- failure_message += format_string(" # Scenario: " + failure.name, :comment)
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.blank?
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.scenarios(type), type, 'steps')
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.failing_scenarios.any?
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 }
@@ -0,0 +1,3 @@
1
+ Cucumber::Cli::Main.class_eval do
2
+ def trap_interrupt; end
3
+ end
@@ -1,14 +1,35 @@
1
- class Specjour::Cucumber::Preloader
2
- def self.load(feature_file)
3
- # preload all features
4
- cli = ::Cucumber::Cli::Main.new []
5
- step_mother = cli.class.step_mother
6
-
7
- step_mother.log = cli.configuration.log
8
- step_mother.options = cli.configuration.options
9
- step_mother.load_code_files(cli.configuration.support_to_load)
10
- step_mother.after_configuration(cli.configuration)
11
- features = step_mother.load_plain_text_features(cli.configuration.feature_files)
12
- step_mother.load_code_files(cli.configuration.step_defs_to_load)
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
@@ -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
@@ -18,7 +18,7 @@ module Specjour
18
18
  end
19
19
 
20
20
  def start
21
- abort("#{project_path} doesn't exist") unless File.exists?(project_path)
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(1) do
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 { Process.kill('TERM', manager.pid) rescue Errno::ESRCH }
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(1) do
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 { manager.kill_worker_processes rescue DRb::DRbConnError }
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
@@ -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, :bonjour_service, :worker_pids, :options
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
- Process.kill('TERM', *worker_pids) rescue Errno::ESRCH
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
- @bonjour_service = DNSSD.register! "specjour_manager_#{object_id}", "_#{drb_uri.scheme}._tcp", nil, drb_uri.port
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)
@@ -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
- self.specs_to_run = specs_to_run
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 stopped?
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
@@ -13,13 +13,16 @@ module Specjour
13
13
 
14
14
  def self.load_rspec2
15
15
  require 'rspec/core'
16
- ::Rspec::Core::Runner.disable_autorun!
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.dump_summary(duration, formatter.example_count, formatter.failure_count, formatter.pending_count)
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(:@examples, examples)
55
- new_formatter.instance_variable_set(:@example_count, examples.size)
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
- options = ['--format=Specjour::Rspec::DistributedFormatter', spec]
5
- ::Rspec::Core::Runner.run options, $stderr, output
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
@@ -0,0 +1,9 @@
1
+ Rspec::Core::SharedExampleGroup.class_eval do
2
+
3
+ def ensure_shared_example_group_name_not_taken(name)
4
+ if RSpec.world.shared_example_groups.has_key?(name)
5
+ Specjour.logger.debug "Shared example group '#{name}' already exists"
6
+ end
7
+ end
8
+
9
+ end
@@ -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
- print_time_for(test, time)
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
- msg = [
67
- "Caught exception: #{exception.class} #{exception.message}",
68
- "Proceeding... you may need to re-run the dispatcher."
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
- cli = ::Cucumber::Cli::Main.new(['--format', 'Specjour::Cucumber::DistributedFormatter', feature], connection)
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 |
@@ -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.rc8"
8
+ s.version = "0.3.0"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
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-09-13}
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: 977940561
5
- prerelease: true
4
+ hash: 19
5
+ prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
9
  - 0
10
- - rc8
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-09-13 00:00:00 -04:00
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: yard
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: *id005
116
+ version_requirements: *id006
102
117
  - !ruby/object:Gem::Dependency
103
118
  name: jeweler
104
119
  prerelease: false
105
- requirement: &id006 !ruby/object:Gem::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: *id006
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: 25
221
+ hash: 3
200
222
  segments:
201
- - 1
202
- - 3
203
- - 1
204
- version: 1.3.1
223
+ - 0
224
+ version: "0"
205
225
  requirements: []
206
226
 
207
227
  rubyforge_project: