specjour 0.2.5 → 0.3.0.rc1

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.
Files changed (40) hide show
  1. data/History.markdown +51 -20
  2. data/README.markdown +53 -26
  3. data/Rakefile +3 -5
  4. data/VERSION +1 -1
  5. data/bin/specjour +1 -48
  6. data/lib/specjour/cli.rb +97 -0
  7. data/lib/specjour/configuration.rb +73 -0
  8. data/lib/specjour/connection.rb +1 -1
  9. data/lib/specjour/cucumber/distributed_formatter.rb +2 -5
  10. data/lib/specjour/cucumber/preloader.rb +13 -0
  11. data/lib/specjour/cucumber.rb +3 -2
  12. data/lib/specjour/db_scrub.rb +8 -1
  13. data/lib/specjour/dispatcher.rb +99 -36
  14. data/lib/specjour/manager.rb +63 -37
  15. data/lib/specjour/printer.rb +33 -11
  16. data/lib/specjour/quiet_fork.rb +11 -0
  17. data/lib/specjour/rspec/distributed_formatter.rb +4 -15
  18. data/lib/specjour/rspec/preloader.rb +8 -0
  19. data/lib/specjour/rspec.rb +1 -0
  20. data/lib/specjour/rsync_daemon.rb +1 -1
  21. data/lib/specjour/socket_helper.rb +28 -0
  22. data/lib/specjour/worker.rb +42 -25
  23. data/lib/specjour.rb +13 -5
  24. data/spec/spec_helper.rb +12 -0
  25. data/spec/specjour/cli_spec.rb +104 -0
  26. data/spec/specjour/configuration_spec.rb +112 -0
  27. data/spec/{cpu_spec.rb → specjour/cpu_spec.rb} +0 -0
  28. data/spec/{manager_spec.rb → specjour/manager_spec.rb} +2 -2
  29. data/spec/specjour/printer_spec.rb +101 -0
  30. data/spec/{rsync_daemon_spec.rb → specjour/rsync_daemon_spec.rb} +2 -0
  31. data/spec/specjour_spec.rb +13 -2
  32. data/specjour.gemspec +33 -26
  33. metadata +69 -31
  34. data/lib/specjour/cucumber/dispatcher.rb +0 -18
  35. data/lib/specjour/cucumber/printer.rb +0 -9
  36. data/lib/specjour/socket_helpers.rb +0 -11
  37. data/lib/specjour/tasks/dispatch.rake +0 -21
  38. data/lib/specjour/tasks/specjour.rb +0 -1
  39. data/rails/init.rb +0 -6
  40. data/spec/lib/specjour/worker_spec.rb +0 -14
@@ -2,39 +2,65 @@ module Specjour
2
2
  class Dispatcher
3
3
  require 'dnssd'
4
4
  Thread.abort_on_exception = true
5
- include SocketHelpers
5
+ include SocketHelper
6
6
 
7
7
  class << self
8
8
  attr_accessor :interrupted
9
9
  alias interrupted? interrupted
10
10
  end
11
11
 
12
- attr_reader :project_path, :managers, :manager_threads, :hosts
13
- attr_accessor :worker_size
12
+ attr_reader :project_alias, :managers, :manager_threads, :hosts, :options, :all_tests
13
+ attr_accessor :worker_size, :project_path
14
14
 
15
- def initialize(project_path)
16
- @project_path = project_path
17
- @managers = []
15
+ def initialize(options = {})
16
+ @options = options
17
+ @project_path = File.expand_path options[:project_path]
18
18
  @worker_size = 0
19
- reset_manager_threads
19
+ @managers = []
20
+ find_tests
21
+ clear_manager_threads
20
22
  end
21
23
 
22
24
  def start
23
- rsync_daemon.start
25
+ abort("#{project_path} doesn't exist") unless File.exists?(project_path)
24
26
  gather_managers
27
+ rsync_daemon.start
25
28
  dispatch_work
26
- printer.join
29
+ Signal.trap('INT') { Dispatcher.interrupted = true; exit 1 }
30
+ printer.join if dispatching_tests?
31
+ wait_on_managers
27
32
  exit printer.exit_status
28
33
  end
29
34
 
30
35
  protected
31
36
 
32
- def all_specs
33
- @all_specs ||= Dir.chdir(project_path) do
34
- Dir["spec/**/**/*_spec.rb"].sort
37
+ def find_tests
38
+ if project_path.match(/(.+)\/((spec|features)(?:\/\w+)*)$/)
39
+ self.project_path = $1
40
+ @all_tests = $3 == 'spec' ? all_specs($2) : all_features($2)
41
+ else
42
+ @all_tests = Array(all_specs) | Array(all_features)
35
43
  end
36
44
  end
37
45
 
46
+ def all_specs(tests_path = 'spec')
47
+ Dir.chdir(project_path) do
48
+ Dir[File.join(tests_path, "**/*_spec.rb")].sort
49
+ end if File.exists? File.join(project_path, tests_path)
50
+ end
51
+
52
+ def all_features(tests_path = 'features')
53
+ Dir.chdir(project_path) do
54
+ Dir[File.join(tests_path, "**/*.feature")].sort
55
+ end if File.exists? File.join(project_path, tests_path)
56
+ end
57
+
58
+ def add_manager(manager)
59
+ set_up_manager(manager)
60
+ managers << manager
61
+ self.worker_size += manager.worker_size
62
+ end
63
+
38
64
  def command_managers(async = false, &block)
39
65
  managers.each do |manager|
40
66
  manager_threads << Thread.new(manager, &block)
@@ -42,53 +68,83 @@ module Specjour
42
68
  wait_on_managers unless async
43
69
  end
44
70
 
71
+ def dispatcher_uri
72
+ @dispatcher_uri ||= URI::Generic.build :scheme => "specjour", :host => hostname, :port => printer.port
73
+ end
74
+
45
75
  def dispatch_work
76
+ puts "Managers found: #{managers.size}"
77
+ puts "Workers found: #{worker_size}"
78
+ printer.worker_size = worker_size
46
79
  command_managers(true) { |m| m.dispatch }
47
80
  end
48
81
 
82
+ def dispatching_tests?
83
+ worker_task == 'run_tests'
84
+ end
85
+
49
86
  def fetch_manager(uri)
50
87
  Timeout.timeout(8) do
51
88
  manager = DRbObject.new_with_uri(uri.to_s)
52
- if !managers.include?(manager) && manager.available_for?(project_name)
53
- set_up_manager(manager, uri)
54
- managers << manager
55
- self.worker_size += manager.worker_size
89
+ if !managers.include?(manager) && manager.available_for?(project_alias)
90
+ add_manager(manager)
56
91
  end
57
92
  end
58
93
  rescue Timeout::Error
59
94
  Specjour.logger.debug "Couldn't work with manager at #{uri}"
95
+ rescue DRb::DRbConnError
96
+ retry
97
+ end
98
+
99
+ def fork_local_manager
100
+ puts "No remote managers found, starting a local manager..."
101
+ manager_options = {:worker_size => options[:worker_size], :registered_projects => [project_alias]}
102
+ manager = Manager.start_quietly manager_options
103
+ fetch_manager(manager.drb_uri)
104
+ at_exit { Process.kill('TERM', manager.pid) rescue Errno::ESRCH }
60
105
  end
61
106
 
62
107
  def gather_managers
63
- puts "Waiting for managers"
64
- Signal.trap('INT') { self.class.interrupted = true; exit }
108
+ puts "Looking for managers..."
109
+ gather_remote_managers
110
+ fork_local_manager if local_manager_needed?
111
+ abort "No managers found" if managers.size.zero?
112
+ end
113
+
114
+ def gather_remote_managers
65
115
  browser = DNSSD::Service.new
66
- begin
67
- Timeout.timeout(10) do
68
- browser.browse '_druby._tcp' do |reply|
69
- if reply.flags.add?
70
- resolve_reply(reply)
71
- end
72
- browser.stop unless reply.flags.more_coming?
116
+ Timeout.timeout(10) do
117
+ browser.browse '_druby._tcp' do |reply|
118
+ if reply.flags.add?
119
+ resolve_reply(reply)
73
120
  end
121
+ browser.stop unless reply.flags.more_coming?
74
122
  end
75
- rescue Timeout::Error
76
123
  end
77
- puts "Managers found: #{managers.size}"
78
- abort unless managers.size > 0
79
- puts "Workers found: #{worker_size}"
80
- printer.worker_size = worker_size
124
+ rescue Timeout::Error
125
+ end
126
+
127
+ def local_manager_needed?
128
+ options[:worker_size] > 0 && no_local_managers?
129
+ end
130
+
131
+ def no_local_managers?
132
+ !managers.any? {|m| m.hostname == hostname}
81
133
  end
82
134
 
83
135
  def printer
84
- @printer ||= Printer.start(all_specs)
136
+ @printer ||= Printer.start(all_tests)
137
+ end
138
+
139
+ def project_alias
140
+ @project_alias ||= options[:project_alias] || project_name
85
141
  end
86
142
 
87
143
  def project_name
88
144
  @project_name ||= File.basename(project_path)
89
145
  end
90
146
 
91
- def reset_manager_threads
147
+ def clear_manager_threads
92
148
  @manager_threads = []
93
149
  end
94
150
 
@@ -105,15 +161,22 @@ module Specjour
105
161
  @rsync_daemon ||= RsyncDaemon.new(project_path, project_name)
106
162
  end
107
163
 
108
- def set_up_manager(manager, uri)
164
+ def set_up_manager(manager)
109
165
  manager.project_name = project_name
110
- manager.dispatcher_uri = URI::Generic.build :scheme => "specjour", :host => hostname, :port => printer.port
111
- at_exit { manager.kill_worker_processes }
166
+ manager.dispatcher_uri = dispatcher_uri
167
+ manager.preload_spec = all_tests.detect {|f| f =~ /_spec\.rb$/}
168
+ manager.preload_feature = all_tests.detect {|f| f =~ /\.feature$/}
169
+ manager.worker_task = worker_task
170
+ at_exit { manager.kill_worker_processes rescue DRb::DRbConnError }
112
171
  end
113
172
 
114
173
  def wait_on_managers
115
174
  manager_threads.each {|t| t.join; t.exit}
116
- reset_manager_threads
175
+ clear_manager_threads
176
+ end
177
+
178
+ def worker_task
179
+ options[:worker_task] || 'run_tests'
117
180
  end
118
181
  end
119
182
  end
@@ -1,29 +1,33 @@
1
1
  module Specjour
2
2
  class Manager
3
3
  require 'dnssd'
4
+ require 'specjour/rspec'
5
+ require 'specjour/cucumber'
6
+
4
7
  include DRbUndumped
5
- include SocketHelpers
8
+ include SocketHelper
9
+
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
6
12
 
7
- attr_accessor :project_name, :specs_to_run
8
- attr_reader :worker_size, :batch_size, :dispatcher_uri, :registered_projects, :bonjour_service, :worker_pids
13
+ def self.start_quietly(options)
14
+ manager = new options.merge(:quiet => true)
15
+ manager.drb_uri
16
+ manager.pid = QuietFork.fork { manager.start }
17
+ manager
18
+ end
9
19
 
10
20
  def initialize(options = {})
21
+ @options = options
11
22
  @worker_size = options[:worker_size]
12
- @batch_size = options[:batch_size]
23
+ @worker_task = options[:worker_task]
13
24
  @registered_projects = options[:registered_projects]
14
25
  @worker_pids = []
26
+ at_exit { kill_worker_processes }
15
27
  end
16
28
 
17
29
  def available_for?(project_name)
18
- registered_projects ? registered_projects.include?(project_name) : true
19
- end
20
-
21
- def bundle_install
22
- Dir.chdir(project_path) do
23
- unless system('bundle check > /dev/null')
24
- system("bundle install --relock > /dev/null")
25
- end
26
- end
30
+ registered_projects ? registered_projects.include?(project_name) : false
27
31
  end
28
32
 
29
33
  def dispatcher_uri=(uri)
@@ -31,50 +35,67 @@ module Specjour
31
35
  @dispatcher_uri = uri
32
36
  end
33
37
 
34
- def kill_worker_processes
35
- Process.kill('TERM', *worker_pids) rescue nil
36
- end
37
-
38
- def project_path
39
- File.join("/tmp", project_name)
40
- end
41
-
42
38
  def dispatch
43
39
  suspend_bonjour do
44
40
  sync
45
- bundle_install
41
+ in_project { Configuration.before_fork.call }
46
42
  dispatch_workers
47
43
  end
48
44
  end
49
45
 
46
+ def drb_start
47
+ DRb.start_service drb_uri.to_s, self
48
+ at_exit { DRb.stop_service }
49
+ end
50
+
51
+ def drb_uri
52
+ @drb_uri ||= begin
53
+ current_uri.scheme = "druby"
54
+ current_uri
55
+ end
56
+ end
57
+
50
58
  def dispatch_workers
51
- GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
59
+ worker_pids.clear
52
60
  (1..worker_size).each do |index|
53
61
  worker_pids << fork do
54
- exec("specjour --batch-size #{batch_size} #{'--log' if Specjour.log?} --do-work #{project_path},#{dispatcher_uri},#{index}")
55
- Kernel.exit!
62
+ exec "specjour work #{worker_options(index)}"
56
63
  end
57
64
  end
58
- at_exit { kill_worker_processes }
59
65
  Process.waitall
60
66
  end
61
67
 
68
+ def in_project(&block)
69
+ Dir.chdir(project_path, &block)
70
+ end
71
+
72
+ def kill_worker_processes
73
+ Process.kill('TERM', *worker_pids) rescue Errno::ESRCH
74
+ end
75
+
76
+ def pid
77
+ @pid || Process.pid
78
+ end
79
+
80
+ def project_path
81
+ File.join("/tmp", project_name)
82
+ end
83
+
62
84
  def start
63
85
  drb_start
64
- puts "Workers ready: #{worker_size}"
86
+ puts "Workers ready: #{worker_size}."
87
+ puts "Listening for #{registered_projects.join(', ')}"
65
88
  bonjour_announce
66
- Signal.trap('INT') { puts; puts "Shutting down manager..."; exit }
89
+ Signal.trap('INT') { puts; puts "Shutting down manager..."; exit 1 }
67
90
  DRb.thread.join
68
91
  end
69
92
 
70
- def drb_start
71
- DRb.start_service nil, self
72
- puts "Manager started at #{drb_uri}"
73
- at_exit { DRb.stop_service }
93
+ def quiet?
94
+ options.has_key? :quiet
74
95
  end
75
96
 
76
97
  def sync
77
- cmd "rsync -a --delete --port=8989 #{dispatcher_uri.host}::#{project_name} #{project_path}"
98
+ cmd "rsync -aL --delete --port=8989 #{dispatcher_uri.host}::#{project_name} #{project_path}"
78
99
  end
79
100
 
80
101
  protected
@@ -88,14 +109,19 @@ module Specjour
88
109
  system command
89
110
  end
90
111
 
91
- def drb_uri
92
- @drb_uri ||= URI.parse(DRb.uri)
93
- end
94
-
95
112
  def suspend_bonjour(&block)
96
113
  bonjour_service.stop
97
114
  block.call
98
115
  bonjour_announce
99
116
  end
117
+
118
+ def worker_options(index)
119
+ exec_options = "--project-path #{project_path} --printer-uri #{dispatcher_uri} --number #{index} --task #{worker_task}"
120
+ exec_options << " --preload-spec #{preload_spec}" if preload_spec
121
+ exec_options << " --preload-feature #{preload_feature}" if preload_feature
122
+ exec_options << " --log" if Specjour.log?
123
+ exec_options << " --quiet" if quiet?
124
+ exec_options
125
+ end
100
126
  end
101
127
  end
@@ -1,5 +1,6 @@
1
1
  module Specjour
2
2
  require 'specjour/rspec'
3
+ require 'specjour/cucumber'
3
4
 
4
5
  class Printer < GServer
5
6
  include Protocol
@@ -44,11 +45,15 @@ module Specjour
44
45
  end
45
46
 
46
47
  def exit_status
47
- report.exit_status
48
+ reporters.all? {|r| r.exit_status == true}
48
49
  end
49
50
 
50
- def worker_summary=(client, summary)
51
- report.add(summary)
51
+ def rspec_summary=(client, summary)
52
+ rspec_report.add(summary)
53
+ end
54
+
55
+ def cucumber_summary=(client, summary)
56
+ cucumber_report.add(summary)
52
57
  end
53
58
 
54
59
  protected
@@ -66,7 +71,7 @@ module Specjour
66
71
  end
67
72
 
68
73
  def error(exception)
69
- Specjour.logger.debug exception.inspect
74
+ Specjour.logger.debug "#{exception.inspect}\n#{exception.backtrace.join("\n")}"
70
75
  end
71
76
 
72
77
  def process(message, client)
@@ -78,22 +83,39 @@ module Specjour
78
83
  end
79
84
  end
80
85
 
81
- def report
82
- @report ||= Rspec::FinalReport.new
86
+ def rspec_report
87
+ @rspec_report ||= Rspec::FinalReport.new
88
+ end
89
+
90
+ def cucumber_report
91
+ @cucumber_report ||= Cucumber::FinalReport.new
92
+ end
93
+
94
+ def reporters
95
+ [@rspec_report, @cucumber_report].compact
83
96
  end
84
97
 
85
98
  def stopping
86
- report.summarize
87
- if disconnections != completed_workers && !Specjour::Dispatcher.interrupted?
88
- puts abandoned_worker_message
89
- end
99
+ summarize_reports
100
+ warn_if_workers_deserted
101
+ end
102
+
103
+ def summarize_reports
104
+ reporters.each {|r| r.summarize}
90
105
  end
91
106
 
92
107
  def synchronize(&block)
93
108
  @connectionsMutex.synchronize &block
94
109
  end
95
110
 
96
- def abandoned_worker_message
111
+ def warn_if_workers_deserted
112
+ if disconnections != completed_workers && !Dispatcher.interrupted?
113
+ puts
114
+ puts workers_deserted_message
115
+ end
116
+ end
117
+
118
+ def workers_deserted_message
97
119
  data = "* ERROR: NOT ALL WORKERS COMPLETED PROPERLY *"
98
120
  filler = "*" * data.size
99
121
  [filler, data, filler].join "\n"
@@ -0,0 +1,11 @@
1
+ module Specjour::QuietFork
2
+ extend self
3
+ attr_reader :pid
4
+
5
+ def self.fork(&block)
6
+ @pid = Kernel.fork do
7
+ $stdout = StringIO.new
8
+ block.call
9
+ end
10
+ end
11
+ end
@@ -2,11 +2,6 @@ module Specjour::Rspec
2
2
  class DistributedFormatter < Spec::Runner::Formatter::BaseTextFormatter
3
3
  require 'specjour/rspec/marshalable_rspec_failure'
4
4
 
5
- class << self
6
- attr_accessor :batch_size
7
- end
8
- @batch_size = 1
9
-
10
5
  attr_reader :failing_messages, :passing_messages, :pending_messages, :output
11
6
  attr_reader :duration, :example_count, :failure_count, :pending_count, :pending_examples, :failing_examples
12
7
 
@@ -22,18 +17,18 @@ module Specjour::Rspec
22
17
 
23
18
  def example_failed(example, counter, failure)
24
19
  failing_messages << colorize_failure('F', failure)
25
- batch_print(failing_messages)
20
+ print_and_flush(failing_messages)
26
21
  end
27
22
 
28
23
  def example_passed(example)
29
24
  passing_messages << green('.')
30
- batch_print(passing_messages)
25
+ print_and_flush(passing_messages)
31
26
  end
32
27
 
33
28
  def example_pending(example, message, deprecated_pending_location=nil)
34
29
  super
35
30
  pending_messages << yellow('*')
36
- batch_print(pending_messages)
31
+ print_and_flush(pending_messages)
37
32
  end
38
33
 
39
34
  def dump_summary(duration, example_count, failure_count, pending_count)
@@ -41,7 +36,7 @@ module Specjour::Rspec
41
36
  @example_count = example_count
42
37
  @failure_count = failure_count
43
38
  @pending_count = pending_count
44
- output.send_message(:worker_summary=, to_hash)
39
+ output.send_message(:rspec_summary=, to_hash)
45
40
  end
46
41
 
47
42
  def dump_pending
@@ -68,12 +63,6 @@ module Specjour::Rspec
68
63
 
69
64
  protected
70
65
 
71
- def batch_print(messages)
72
- if messages.size == self.class.batch_size
73
- print_and_flush(messages)
74
- end
75
- end
76
-
77
66
  def print_and_flush(messages)
78
67
  output.print messages.to_s
79
68
  output.flush
@@ -0,0 +1,8 @@
1
+ class Specjour::Rspec::Preloader
2
+ def self.load(spec_file)
3
+ $LOAD_PATH.unshift File.join(Dir.pwd, 'spec')
4
+ require spec_file
5
+ ensure
6
+ $LOAD_PATH.shift
7
+ end
8
+ end
@@ -5,5 +5,6 @@ module Specjour
5
5
 
6
6
  require 'specjour/rspec/distributed_formatter'
7
7
  require 'specjour/rspec/final_report'
8
+ require 'specjour/rspec/preloader'
8
9
  end
9
10
  end
@@ -1,7 +1,7 @@
1
1
  module Specjour
2
2
  class RsyncDaemon
3
3
  require 'fileutils'
4
- include SocketHelpers
4
+ include SocketHelper
5
5
 
6
6
  # Corresponds to the version of specjour that changed the configuration
7
7
  # file.
@@ -0,0 +1,28 @@
1
+ module Specjour
2
+ module SocketHelper
3
+ def ip_from_hostname(hostname)
4
+ Socket.getaddrinfo(hostname, nil, Socket::AF_INET, Socket::SOCK_STREAM).first.fetch(3)
5
+ end
6
+
7
+ def hostname
8
+ @hostname ||= Socket.gethostname
9
+ end
10
+
11
+ def current_uri
12
+ @current_uri ||= new_uri
13
+ end
14
+
15
+ def new_uri
16
+ URI::Generic.build :host => faux_server[2], :port => faux_server[1]
17
+ end
18
+
19
+ protected
20
+
21
+ def faux_server
22
+ server = TCPServer.new('0.0.0.0', nil)
23
+ server.addr
24
+ ensure
25
+ server.close
26
+ end
27
+ end
28
+ end
@@ -1,51 +1,78 @@
1
1
  module Specjour
2
+ require 'specjour/rspec'
2
3
  require 'specjour/cucumber'
3
4
 
4
5
  class Worker
5
6
  include Protocol
6
- include SocketHelpers
7
+ include SocketHelper
7
8
  attr_accessor :printer_uri
8
- attr_reader :project_path, :specs_to_run, :number, :batch_size
9
-
10
- def initialize(project_path, printer_uri, number, batch_size)
11
- @project_path = project_path
12
- @specs_to_run = specs_to_run
13
- @number = number.to_i
14
- @batch_size = batch_size.to_i
15
- self.printer_uri = printer_uri
16
- Rspec::DistributedFormatter.batch_size = batch_size
9
+ attr_reader :project_path, :number, :preload_spec, :preload_feature, :task
10
+
11
+ def initialize(options = {})
12
+ ARGV.replace []
13
+ $stdout = StringIO.new if options[:quiet]
14
+ @project_path = options[:project_path]
15
+ @number = options[:number].to_i
16
+ @preload_spec = options[:preload_spec]
17
+ @preload_feature = options[:preload_feature]
18
+ @task = options[:task]
19
+ self.printer_uri = options[:printer_uri]
17
20
  set_env_variables
21
+ Dir.chdir(project_path)
18
22
  end
19
23
 
20
24
  def printer_uri=(val)
21
25
  @printer_uri = URI.parse(val)
22
26
  end
23
27
 
24
- def run
28
+ def prepare
29
+ load_app
30
+ Configuration.prepare.call
31
+ end
32
+
33
+ def run_tests
34
+ load_app
35
+ Configuration.after_fork.call
25
36
  run_time = 0
26
- Dir.chdir(project_path)
37
+
27
38
  while test = connection.next_test
28
- run_time += Benchmark.realtime do
39
+ time = Benchmark.realtime do
29
40
  run_test test
30
41
  end
42
+ run_time += time if test =~ /_spec\.rb$/
31
43
  end
32
- connection.send_message(:worker_summary=, {:duration => sprintf("%6f", run_time)})
44
+ connection.send_message(:rspec_summary=, {:duration => sprintf("%6f", run_time)})
33
45
  connection.send_message(:done)
34
46
  connection.disconnect
35
47
  end
36
48
 
49
+ def start
50
+ send task
51
+ end
52
+
37
53
  protected
38
54
 
39
55
  def connection
40
56
  @connection ||= printer_connection
41
57
  end
42
58
 
59
+ def load_app
60
+ Rspec::Preloader.load(preload_spec) if preload_spec
61
+ Cucumber::Preloader.load(preload_feature) if preload_feature
62
+ end
63
+
43
64
  def printer_connection
44
65
  Connection.new printer_uri
45
66
  end
46
67
 
68
+ def print_status(test)
69
+ status = "[#{ENV['TEST_ENV_NUMBER']}] Running #{test}"
70
+ puts status
71
+ $PROGRAM_NAME = "specjour#{status}"
72
+ end
73
+
47
74
  def run_test(test)
48
- puts "[#{ENV['TEST_ENV_NUMBER']}] Running #{test}"
75
+ print_status(test)
49
76
  if test =~ /\.feature$/
50
77
  run_feature test
51
78
  else
@@ -54,7 +81,6 @@ module Specjour
54
81
  end
55
82
 
56
83
  def run_feature(feature)
57
- set_up_cucumber
58
84
  cli = ::Cucumber::Cli::Main.new(['--format', 'Specjour::Cucumber::DistributedFormatter', feature], connection)
59
85
  cli.execute!(::Cucumber::Cli::Main.step_mother)
60
86
  end
@@ -70,17 +96,8 @@ module Specjour
70
96
  end
71
97
 
72
98
  def set_env_variables
73
- ENV['PREPARE_DB'] = 'true'
74
99
  ENV['RSPEC_COLOR'] = 'true'
75
100
  ENV['TEST_ENV_NUMBER'] = number.to_s
76
101
  end
77
-
78
- def set_up_cucumber
79
- unless @cucumber_loaded
80
- Cucumber::DistributedFormatter.batch_size = batch_size
81
- ::Cucumber::Cli::Options.class_eval { def print_profile_information; end }
82
- @cucumber_loaded = true
83
- end
84
- end
85
102
  end
86
103
  end