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.
@@ -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: