Permalink
Browse files

A new approach to multiple remote slaves on a single machine. Specify…

… ?workers=N on the end of the testjour:// URI and the run:remote command will first rsync and then start up N slaves, avoiding duplicate rsyncs from a single machine. If your suite may do contentious file IO against the local dir, you wouldn't want to use this technique.
  • Loading branch information...
1 parent d397aec commit d935de0e36eb62edb68d0835f3b2d0643186e780 @lukemelia lukemelia committed Jan 8, 2010
@@ -22,9 +22,8 @@ Feature: Distributed runs
And the output should contain "1 steps failed"
And it should run on 2 remote slaves
- Scenario: Distribute runs (using named host, queue host and rsync uri)
- Given Testjour is configured to run on this machine in a temp1 directory
- And Testjour is configured to run on this machine in a temp2 directory
+ Scenario: Distribute runs (using > 1 remote slave, queue host and rsync uri)
+ Given Testjour is configured to run on this machine in a temp1 directory with 2 slaves
And Testjour is configured to use this machine as the queue host
And Testjour is configured to use this machine as the rsync host
When I run `testjour sleep1.feature sleep2.feature`
@@ -19,6 +19,15 @@
FileUtils.mkdir_p full_path
end
+Given /^Testjour is configured to run on this machine in a (\w+) directory with (\d+) slaves$/ do |dir_name, slave_count|
+ @args ||= []
+ full_path = File.expand_path("./tmp/#{dir_name}")
+ @args << "--on=testjour://#{Socket.gethostname}#{full_path}?workers=#{slave_count}"
+
+ FileUtils.rm_rf full_path
+ FileUtils.mkdir_p full_path
+end
+
Given /^Testjour is configured to use this machine as the queue host$/ do
@args ||= []
@args << "--queue-host=#{Socket.gethostname}"
View
@@ -8,11 +8,19 @@ def be_like(expected)
end
end
-Before do
+def testjour_cleanup
@full_dir = File.expand_path(File.dirname(__FILE__) + "/../../spec/fixtures")
Dir.chdir(@full_dir) do
File.unlink("testjour.log") if File.exists?("testjour.log")
File.unlink("testjour_preload.rb") if File.exists?("testjour_preload.rb")
end
+end
+
+Before do
+ testjour_cleanup
+end
+
+After do
+ testjour_cleanup
end
@@ -21,11 +21,17 @@ def execute
configuration.setup
if configuration.feature_files.any?
- RedisQueue.new(configuration.queue_host,
+ redis_queue = RedisQueue.new(configuration.queue_host,
configuration.queue_prefix,
- configuration.queue_timeout).reset_all
-
+ configuration.queue_timeout)
+ redis_queue.reset_all
queue_features
+
+ at_exit do
+ Testjour.logger.info caller.join("\n")
+ redis_queue.reset_all
+ end
+
@started_slaves = 0
start_slaves
@@ -76,14 +82,19 @@ def start_remote_slaves
end
def start_remote_slave(remote_slave)
+ num_workers = 1
+ if remote_slave.match(/\?workers=(\d+)/)
+ num_workers = $1.to_i
+ remote_slave.gsub(/\?workers=(\d+)/, '')
+ end
uri = URI.parse(remote_slave)
- cmd = remote_slave_run_command(uri.user, uri.host, uri.path)
+ cmd = remote_slave_run_command(uri.user, uri.host, uri.path, num_workers)
Testjour.logger.info "Starting remote slave: #{cmd}"
detached_exec(cmd)
end
- def remote_slave_run_command(user, host, path)
- "ssh -o StrictHostKeyChecking=no #{user}#{'@' if user}#{host} testjour run:remote --in=#{path} #{configuration.run_slave_args.join(' ')} #{testjour_uri}".squeeze(" ")
+ def remote_slave_run_command(user, host, path, max_remote_slaves)
+ "ssh -o StrictHostKeyChecking=no #{user}#{'@' if user}#{host} testjour run:remote --in=#{path} --max-remote-slaves=#{max_remote_slaves} #{configuration.run_slave_args.join(' ')} #{testjour_uri}".squeeze(" ")
end
def start_slave
@@ -8,24 +8,52 @@
require "stringio"
module Testjour
-module Commands
+ module Commands
- class RunRemote < RunSlave
+ class RunRemote < Command
- def dir
- configuration.in
- end
+ def dir
+ configuration.in
+ end
- def before_require
- rsync
- super
- end
-
- def rsync
- Rsync.copy_to_current_directory_from(configuration.rsync_uri)
+ def execute
+ configuration.parse!
+ configuration.parse_uri!
+
+ Dir.chdir(dir) do
+ Testjour.setup_logger(dir)
+ Testjour.logger.info "Starting #{self.class.name}"
+ rsync
+ start_additional_slaves
+ end
+ end
+
+ def start_additional_slaves
+ 1.upto(configuration.max_remote_slaves) do |i|
+ start_slave
+ end
+ end
+
+ def start_slave
+ Testjour.logger.info "Starting slave: #{local_run_command}"
+ detached_exec(local_run_command)
+ end
+
+ def local_run_command
+ "testjour run:slave #{configuration.run_slave_args.join(' ')} #{testjour_uri}".squeeze(" ")
+ end
+
+ def testjour_uri
+ user = Etc.getpwuid.name
+ host = Testjour.socket_hostname
+ "rsync://#{user}@#{host}" + File.expand_path(".")
+ end
+
+
+ def rsync
+ Rsync.copy_to_current_directory_from(configuration.rsync_uri)
+ end
end
-
- end
-end
+ end
end
@@ -24,6 +24,10 @@ def max_local_slaves
@options[:max_local_slaves] || 2
end
+ def max_remote_slaves
+ @options[:max_remote_slaves] || 1
+ end
+
def in
@options[:in]
end
@@ -39,6 +43,10 @@ def external_rsync_uri
def queue_host
@queue_host || @options[:queue_host] || Testjour.socket_hostname
end
+
+ def external_queue_host?
+ queue_host != Testjour.socket_hostname
+ end
def queue_prefix
@options[:queue_prefix] || 'default'
@@ -166,7 +174,7 @@ def parse_uri!
full_uri = URI.parse(@args.shift)
@path = full_uri.path
@full_uri = full_uri.dup
- @queue_host = full_uri.host
+ @queue_host = full_uri.host unless options[:queue_host]
end
def run_slave_args
@@ -178,8 +186,8 @@ def testjour_args
if @options[:create_mysql_db]
args_from_options << "--create-mysql-db"
end
- if @options[:queue_host]
- args_from_options << "--queue-host=#{@options[:queue_host]}"
+ if @options[:queue_host] || external_queue_host?
+ args_from_options << "--queue-host=#{queue_host}"
end
if @options[:queue_prefix]
args_from_options << "--queue-prefix=#{@options[:queue_prefix]}"
@@ -199,7 +207,7 @@ def option_parser
@options[:args_file] = args_file
end
- opts.on("--on=SLAVE", "Specify a slave URI") do |slave|
+ opts.on("--on=SLAVE", "Specify a slave URI (testjour://user@host:/path/to/working/dir?workers=3)") do |slave|
@options[:slaves] ||= []
@options[:slaves] << slave
end
@@ -208,6 +216,10 @@ def option_parser
@options[:in] = directory
end
+ opts.on("--max-remote-slaves=MAX", "Number of workers to run (for run:remote only)") do |max|
+ @options[:max_remote_slaves] = max.to_i
+ end
+
opts.on("--strict", "Fail if there are any undefined steps") do
@options[:strict] = true
end
View
@@ -22,7 +22,7 @@ def load_schema
end
def runner_database_name
- @runner_database_name ||= "testjour_runner_#{rand(1_000)}"
+ @runner_database_name ||= "testjour_runner_#{rand(1_000)}_#{Testjour.effective_pid}"
end
protected

0 comments on commit d935de0

Please sign in to comment.