lib/specjour/loader.rb in specjour-0.7.0 vs lib/specjour/loader.rb in specjour-2.0.0.rc1
- old
+ new
@@ -1,150 +1,86 @@
module Specjour
+ require 'specjour/worker'
class Loader
- include Protocol
- include Fork
+ include Logger
+ include SocketHelper
- attr_reader :test_paths, :printer_uri, :project_path, :task, :worker_size, :worker_pids, :quiet
+ attr_reader \
+ :options,
+ :quiet,
+ :task,
+ :worker_pids
def initialize(options = {})
@options = options
- @printer_uri = options[:printer_uri]
- @test_paths = options[:test_paths]
- @worker_size = options[:worker_size]
@task = options[:task]
@quiet = options[:quiet]
- @project_path = options[:project_path]
@worker_pids = []
- Dir.chdir project_path
- Specjour.load_custom_hooks
end
def start
- load_app
- Configuration.after_load.call
- (1..worker_size).each do |index|
+ Process.setsid
+ $PROGRAM_NAME = "specjour loader"
+ set_up
+ sync
+ Specjour.plugin_manager.send_task(:load_application)
+ Specjour.plugin_manager.send_task(:register_tests_with_printer)
+ fork_workers
+ wait_srv
+ rescue StandardError, ScriptError => e
+ $stderr.puts "RESCUED #{e.class} '#{e.message}'"
+ $stderr.puts e.backtrace
+ $stderr.puts "\n\n"
+ connection.error(e)
+ ensure
+ remove_connection
+ log "Loader killing group #{Process.getsid}"
+ end
+
+ def fork_workers
+ Specjour.plugin_manager.send_task(:before_worker_fork)
+ (1..Specjour.configuration.worker_size).each do |index|
worker_pids << fork do
- Worker.new(
+ remove_connection
+ Specjour.plugin_manager.send_task(:remove_connection)
+ $PROGRAM_NAME = "specjour worker"
+ worker = Worker.new(
:number => index,
- :printer_uri => printer_uri,
:quiet => quiet
- ).send(task)
+ )
+ Specjour.plugin_manager.send_task(:after_worker_fork)
+ worker.send(task)
end
end
- Process.waitall
- ensure
- kill_worker_processes
end
- def spec_files
- @spec_files ||= file_collector(spec_paths) do |path|
- if path == project_path
- Dir["spec/**/*_spec.rb"]
- else
- Dir["**/*_spec.rb"]
+ def wait_srv
+ select [connection.socket]
+ if !connection.socket.eof?
+ signal = connection.get_server_done
+ case signal
+ when "INT"
+ debug "Sending INT to -#{Process.getsid}"
+ Process.kill("INT", -Process.getsid)
end
end
end
- def feature_files
- @feature_files ||= file_collector(feature_paths) do |path|
- if path == project_path
- Dir["features/**/*.feature"]
- else
- Dir["**/*.feature"]
- end
- end
+ def set_up
+ data = connection.ready({hostname: hostname, worker_size: Specjour.configuration.worker_size})
+ Specjour.configuration.project_name = data[:project_name]
+ Specjour.configuration.test_paths = data[:test_paths]
+ Specjour.configuration.project_path = File.expand_path(Specjour.configuration.project_name, Specjour.configuration.tmp_path)
end
- protected
-
- def spec_paths
- @spec_paths ||= test_paths.select {|p| p =~ /spec.*$/}
+ def sync
+ cmd "rsync #{Specjour.configuration.rsync_options} --port=#{Specjour.configuration.rsync_port} #{connection.host}::#{Specjour.configuration.project_name} #{Specjour.configuration.project_path}"
+ Dir.chdir Specjour.configuration.project_path
end
- def feature_paths
- @feature_paths ||= test_paths.select {|p| p =~ /features.*$/}
- end
-
- def file_collector(paths, &globber)
- if spec_paths.empty? && feature_paths.empty?
- globber[project_path]
- else
- paths.map do |path|
- path = File.expand_path(path, project_path)
- if File.directory?(path)
- globber[path]
- else
- path
- end
- end.flatten.uniq
+ def cmd(command)
+ Specjour.benchmark(command) do
+ system *command.split
end
end
-
- def load_app
- RSpec::Preloader.load spec_files if spec_files.any?
- Cucumber::Preloader.load(feature_files, connection) if feature_files.any?
- register_tests_with_printer
- end
-
- def register_tests_with_printer
- tests = rspec_examples | cucumber_scenarios
- connection.send_message :tests=, tests
- end
-
- def rspec_examples
- if spec_files.any?
- filtered_examples
- else
- []
- end
- end
-
- def filtered_examples
- examples = ::RSpec.world.example_groups.map do |g|
- g.descendant_filtered_examples
- end.flatten
- locations = examples.map do |e|
- meta = e.metadata
- groups = e.example_group.parent_groups + [e.example_group]
- shared_group = groups.detect do |group|
- group.metadata[:shared_group_name]
- end
- if shared_group
- meta = shared_group.metadata[:example_group]
- end
- meta[:location]
- end
- ensure
- ::RSpec.reset
- end
-
- def cucumber_scenarios
- if feature_files.any?
- scenarios
- else
- []
- end
- end
-
- def scenarios
- Cucumber.runtime.send(:features).map do |feature|
- feature.feature_elements.map do |scenario|
- "#{feature.file}:#{scenario.instance_variable_get(:@line)}"
- end
- end.flatten
- end
-
- def kill_worker_processes
- signal = Specjour.interrupted? ? 'INT' : 'TERM'
- Process.kill(signal, *worker_pids) rescue Errno::ESRCH
- end
-
- def connection
- @connection ||= begin
- at_exit { connection.disconnect }
- Connection.new URI.parse(printer_uri)
- end
- end
-
end
end