simpleworker 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.travis.yml +6 -0
  4. data/LICENSE +1 -1
  5. data/README.md +52 -15
  6. data/examples/basic.rb +26 -0
  7. data/examples/cucumber_worker.rb +20 -0
  8. data/examples/local_worker.rb +8 -0
  9. data/examples/ssh_worker.rb +13 -0
  10. data/examples/worker.rb +12 -0
  11. data/lib/simpleworker/abstract_listener.rb +41 -0
  12. data/lib/simpleworker/event_monitor.rb +50 -0
  13. data/lib/simpleworker/event_server.rb +48 -0
  14. data/lib/simpleworker/local_worker.rb +17 -10
  15. data/lib/simpleworker/logging_listener.rb +65 -0
  16. data/lib/simpleworker/redis_support.rb +33 -0
  17. data/lib/simpleworker/retry_listener.rb +32 -0
  18. data/lib/simpleworker/runner.rb +85 -26
  19. data/lib/simpleworker/scripts/expired_tasks.lua +13 -0
  20. data/lib/simpleworker/scripts/lpopall.lua +9 -0
  21. data/lib/simpleworker/scripts/reliable_queue.lua +12 -0
  22. data/lib/simpleworker/ssh_worker.rb +40 -19
  23. data/lib/simpleworker/task_queue.rb +78 -0
  24. data/lib/simpleworker/version.rb +1 -1
  25. data/lib/simpleworker.rb +12 -1
  26. data/simpleworker.gemspec +1 -1
  27. data/spec/simpleworker/event_monitor_spec.rb +92 -0
  28. data/spec/simpleworker/event_server_spec.rb +24 -0
  29. data/spec/simpleworker/local_worker_spec.rb +11 -18
  30. data/spec/simpleworker/logging_listener_spec.rb +44 -0
  31. data/spec/simpleworker/retry_listener_spec.rb +25 -0
  32. data/spec/simpleworker/runner_spec.rb +74 -12
  33. data/spec/simpleworker/ssh_worker_spec.rb +20 -31
  34. data/spec/simpleworker/task_queue_spec.rb +76 -0
  35. metadata +42 -5
  36. data/lib/simpleworker/abstract_worker.rb +0 -42
  37. data/lib/simpleworker/bash/simple-localworker +0 -8
  38. data/lib/simpleworker/bash/ssh-remoteworker +0 -21
@@ -0,0 +1,12 @@
1
+ local task = redis.call('LPOP', KEYS[1])
2
+ if not task then
3
+ return nil
4
+ end
5
+
6
+ local task_key = string.format("%s:active:%s:%s:%s", ARGV[1], ARGV[2], ARGV[3], task)
7
+ redis.pcall('SADD', KEYS[2], task_key)
8
+ redis.pcall('SET',
9
+ task_key,
10
+ task,
11
+ "EX", ARGV[4])
12
+ return task
@@ -1,33 +1,54 @@
1
1
 
2
2
  module SimpleWorker
3
- class SshWorker
4
- include AbstractWorker
5
3
 
6
- attr_accessor :directory, :user, :host
4
+ #
5
+ # SshWorker.new(opts)
6
+ #
7
+ # where 'opts' is a Hash of options:
8
+ #
9
+ # :user => String name of user on remote host (default: `whoami`)
10
+ # :host => String name of remote host (default: `hostname`)
11
+ # :port => String port to connect on the remote host (default: 22)
12
+ # :cmd => String bash string to execute on the remote host in the users login shell, in the remote 'dirname', and with the JOBID environment variable set to the current jobid, (default: `bundle install; rake;`)
13
+ # :dirname => String remote directory in the users home directory (default: dynamic jobid)
14
+ class SshWorker < AbstractListener
7
15
 
8
- def initialize
9
- @script = %W[bash #{File.expand_path(File.dirname(__FILE__))}/bash/ssh-remoteworker]
10
- @env = {}
16
+ attr_reader :user, :host, :port, :dirname, :cmd
17
+
18
+ def initialize(opts = {})
19
+ @user = opts[:user] || `whoami`.strip
20
+ @host = opts[:host] || `hostname`.strip
21
+ @port = opts[:port] || '22'
22
+ @cmd = opts[:cmd] || 'bundle install; rake;'
23
+ @dirname = opts[:dirname]
24
+ end
25
+
26
+ # Destructive rsync to remote and start a process in the background on the remote server.
27
+ def on_start(jobid)
28
+ @dirname ||= jobid
29
+ @jobid = jobid
30
+
31
+ sync_to_remote
32
+ async_cmd
11
33
  end
12
34
 
13
- def self.create(config = {})
14
- worker = new
15
- worker.script = config['script'] if config.has_key? 'script'
16
- worker.cmd = config['cmd'] if config.has_key? 'cmd'
17
- worker.user = config['user'] if config.has_key? 'user'
18
- worker.host = config['host'] if config.has_key? 'host'
19
- worker.directory = config['directory'] if config.has_key? 'directory'
20
- worker
35
+ # Rsync from remote.
36
+ def on_stop
37
+ sync_from_remote
21
38
  end
22
39
 
23
40
  private
24
41
 
25
- def set_process_env
26
- env['user'] = user || `whoami`
27
- env['host'] = host || 'localhost'
28
- env['directory'] = directory || Dir.pwd
42
+ def sync_to_remote
43
+ `rsync -a --delete -e "ssh -p #{port}" "${PWD}/" "#{user}@#{host}:~/#{dirname}"`
44
+ end
45
+
46
+ def sync_from_remote
47
+ `rsync -a -e "ssh -p #{port}" "#{user}@#{host}:~/#{dirname}/" "${PWD}"`
48
+ end
29
49
 
30
- super
50
+ def async_cmd
51
+ `ssh -p #{port} "#{user}@#{host}" "/bin/bash -lc 'cd ~/#{dirname}; export JOBID=#{@jobid}; #{cmd}' </dev/null >/dev/null 2>&1 &"`
31
52
  end
32
53
  end
33
54
  end
@@ -0,0 +1,78 @@
1
+
2
+ module SimpleWorker
3
+
4
+ # TaskQueue.new(redis, hostname, jobid, opts)
5
+ #
6
+ # where hostname is the machines hostname or a unique identifier
7
+ # and 'opts' is a Hash of options:
8
+ #
9
+ # :namespace => String prefix to keys in redis used by SimpleWorker (default: simpleworker)
10
+ # :task_timeout => Fixnum time after which a task expires, this should be > timout set in Runner (default: 10 seconds)
11
+ class TaskQueue
12
+ include RedisSupport
13
+
14
+ DEFAULT_OPTIONS = {
15
+ :namespace => 'simpleworker'
16
+ }
17
+
18
+ def initialize(redis, hostname, jobid, opts = {})
19
+ opts = DEFAULT_OPTIONS.dup.merge(opts)
20
+ @redis = redis
21
+ @namespace = opts[:namespace]
22
+ @task_timeout = opts[:task_timeout]
23
+ @jobid = jobid
24
+ @hostname = hostname
25
+ @active_key_prefix = "#{active_tasks_key}:#{@hostname}"
26
+ @task_timeout = JSON.parse(@redis.get(config_key))['task_timeout']
27
+ load_lua_scripts
28
+ end
29
+
30
+ def fire_start
31
+ push_to_log('on_node_start', @hostname)
32
+ end
33
+
34
+ def fire_stop
35
+ push_to_log('on_node_stop', @hostname)
36
+ end
37
+
38
+ def fire_task_start(task)
39
+ push_to_log('on_task_start', @hostname, task)
40
+ end
41
+
42
+ def fire_task_stop(task)
43
+ push_to_log('on_task_stop', @hostname, task)
44
+ end
45
+
46
+ def expire_current_task
47
+ @redis.del "#{@active_key_prefix}:#{@current_task}" if @current_task
48
+ @current_task = nil
49
+ end
50
+
51
+ def fire_log_message(msg)
52
+ push_to_log('on_log', @hostname, msg)
53
+ end
54
+
55
+ def each_task
56
+ until pop.nil?
57
+ local_task = @current_task
58
+ fire_task_start local_task
59
+ yield local_task
60
+ fire_task_stop local_task
61
+ end
62
+ end
63
+
64
+ def pop
65
+ @redis.srem(active_tasks_key, "#{@active_key_prefix}:#{@current_task}") if @current_task
66
+ @current_task = @redis.evalsha(@reliable_queue_sha,
67
+ :keys => [tasks_key, active_tasks_key],
68
+ :argv => [namespace, jobid, @hostname, @task_timeout])
69
+ @current_task
70
+ end
71
+
72
+ private
73
+
74
+ def push_to_log(*args)
75
+ @redis.rpush(log_key, args.to_json)
76
+ end
77
+ end
78
+ end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module SimpleWorker
3
- VERSION = '0.0.1'
3
+ VERSION = '0.1.0'
4
4
  end
data/lib/simpleworker.rb CHANGED
@@ -1,11 +1,22 @@
1
1
 
2
2
  require 'childprocess'
3
3
  require 'yaml'
4
+ require 'redis'
5
+ require 'observer'
6
+ require 'json'
7
+ require 'securerandom'
8
+ require 'logger'
4
9
 
5
10
  module SimpleWorker
6
11
  end
7
12
 
13
+ require 'simpleworker/redis_support'
8
14
  require 'simpleworker/runner'
9
- require 'simpleworker/abstract_worker'
15
+ require 'simpleworker/abstract_listener'
16
+ require 'simpleworker/event_monitor'
17
+ require 'simpleworker/event_server'
18
+ require 'simpleworker/task_queue'
10
19
  require 'simpleworker/local_worker'
11
20
  require 'simpleworker/ssh_worker'
21
+ require 'simpleworker/logging_listener'
22
+ require 'simpleworker/retry_listener'
data/simpleworker.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  $:.push File.expand_path("../lib", __FILE__)
3
2
  require "simpleworker/version"
4
3
 
@@ -16,6 +15,7 @@ Gem::Specification.new do |s|
16
15
  s.rubyforge_project = "simpleworker"
17
16
 
18
17
  s.add_dependency 'childprocess', '>= 0.5.3'
18
+ s.add_dependency 'redis', '>= 0.0.1'
19
19
 
20
20
  s.add_development_dependency "rspec", "~> 2.5"
21
21
  s.add_development_dependency "rake", "~> 0.9.2"
@@ -0,0 +1,92 @@
1
+ require File.expand_path('../../spec_helper.rb', __FILE__)
2
+
3
+ module SimpleWorker
4
+ describe EventMonitor do
5
+ let(:start_time) { Time.now }
6
+ let(:event_monitor) { EventMonitor.new(start_time = start_time) }
7
+ let(:jobid) { 'my_jobid' }
8
+ let(:hostname) { 'my_hostname' }
9
+ let(:task) { 'my_task' }
10
+
11
+ it 'can initialize event monitor' do
12
+ event_monitor = EventMonitor.new(start_time = start_time)
13
+
14
+ expect(event_monitor.start_time).to eq(start_time)
15
+ expect(event_monitor.latest_time).to eq(start_time)
16
+ expect(event_monitor.expired_tasks).to be_empty
17
+ expect(event_monitor.done?(1)).to be false
18
+ expect(event_monitor.done?(0)).to be true
19
+ end
20
+
21
+ it 'can start node' do
22
+ event_monitor.on_start(jobid)
23
+ event_monitor.on_node_start(hostname)
24
+
25
+ expect(event_monitor.done?(0)).to be false
26
+ end
27
+
28
+ it 'can stop node' do
29
+ event_monitor.on_start(jobid)
30
+ event_monitor.on_node_start(hostname)
31
+ event_monitor.on_node_stop(hostname)
32
+
33
+ expect(event_monitor.done?(0)).to be true
34
+ end
35
+
36
+ it 'can start task' do
37
+ event_monitor.on_start(jobid)
38
+ event_monitor.on_node_start(hostname)
39
+ event_monitor.on_task_start(hostname, task)
40
+
41
+ expect(event_monitor.done?(0)).to be false
42
+ end
43
+
44
+ it 'can stop task' do
45
+ event_monitor.on_start(jobid)
46
+ event_monitor.on_node_start(hostname)
47
+ event_monitor.on_task_start(hostname, task)
48
+ event_monitor.on_task_stop(hostname, task)
49
+
50
+ expect(event_monitor.done?(0)).to be false
51
+ end
52
+
53
+ it 'can expire task' do
54
+ event_monitor.on_start(jobid)
55
+ event_monitor.on_node_start(hostname)
56
+ event_monitor.on_task_start(hostname, task)
57
+ event_monitor.on_task_expire(hostname, task)
58
+
59
+ expect(event_monitor.done?(0)).to be false
60
+ end
61
+
62
+ it 'can expire task and stop node' do
63
+ event_monitor.on_start(jobid)
64
+ event_monitor.on_node_start(hostname)
65
+ event_monitor.on_task_start(hostname, task)
66
+ event_monitor.on_task_expire(hostname, task)
67
+ event_monitor.on_node_stop(hostname)
68
+
69
+ expect(event_monitor.done?(0)).to be true
70
+ end
71
+
72
+ it 'can complete on happy path' do
73
+ event_monitor.on_start(jobid)
74
+ event_monitor.on_node_start(hostname)
75
+ event_monitor.on_task_start(hostname, task)
76
+ event_monitor.on_task_stop(hostname, task)
77
+ event_monitor.on_node_stop(hostname)
78
+
79
+ expect(event_monitor.done?(0)).to be true
80
+ end
81
+
82
+ it 'can complete with expired task' do
83
+ event_monitor.on_start(jobid)
84
+ event_monitor.on_node_start(hostname)
85
+ event_monitor.on_task_start(hostname, task)
86
+ event_monitor.on_task_expire(hostname, task)
87
+ event_monitor.on_node_stop(hostname)
88
+
89
+ expect(event_monitor.done?(0)).to be true
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../../spec_helper.rb', __FILE__)
2
+
3
+ module SimpleWorker
4
+ describe EventServer do
5
+ let(:redis) { double(Redis, :script => nil) }
6
+ let(:namespace) { 'my_namespace' }
7
+ let(:jobid) { 'my_jobid' }
8
+ let(:event_server) { EventServer.new(redis, namespace, jobid) }
9
+ let(:log_key) { "#{namespace}:log:#{jobid}" }
10
+ let(:active_tasks_key) { "#{namespace}:active:#{jobid}" }
11
+ let(:tasks_key) { "#{namespace}:tasks:#{jobid}" }
12
+
13
+ it 'can pull events' do
14
+ expect(redis).to receive(:multi).and_return([[["event"].to_json], [["#{namespace}:active:#{jobid}:my_hostname:my_task"],["#{namespace}:active:#{jobid}:my2_hostname:my2_task"]], 0])
15
+
16
+ expect(event_server).to receive(:fire).with("event")
17
+ expect(event_server).to receive(:fire).with('on_task_expire', 'my_hostname', 'my_task')
18
+ expect(event_server).to receive(:fire).with('on_task_active', 'my2_hostname', 'my2_task')
19
+
20
+ result = event_server.pull_events
21
+ expect(result).to eq(1)
22
+ end
23
+ end
24
+ end
@@ -2,32 +2,25 @@ require File.expand_path('../../spec_helper.rb', __FILE__)
2
2
 
3
3
  module SimpleWorker
4
4
  describe LocalWorker do
5
+ let(:mock_process) { double(ChildProcess, :io => double('io').as_null_object) }
5
6
  let(:mock_env) { double(Hash) }
6
- let(:mock_process) { double(ChildProcess, :start => nil, :stop => nil, :wait => nil, :io => double('io').as_null_object, :environment => mock_env) }
7
+ let(:local_worker) { LocalWorker.new }
8
+ let(:jobid) { 'my_jobid' }
7
9
 
8
- it 'can start local worker with defaults' do
9
- ChildProcess.should_receive(:build).with('bash', end_with('simple-localworker')).and_return(mock_process)
10
+ it 'can start local worker' do
11
+ ChildProcess.should_receive(:build).and_return(mock_process)
12
+ mock_process.should_receive(:environment).and_return(mock_env)
13
+ mock_env.should_receive(:[]=).with('JOBID', jobid)
10
14
  mock_process.should_receive(:start)
11
- mock_env.should_receive(:[]=).with('cmd', 'rake')
12
15
 
13
- worker = LocalWorker.new
14
- worker.cmd = 'rake'
15
- worker.start
16
+ local_worker.on_start(jobid)
16
17
  end
17
18
 
18
- it 'can start local worker with customization' do
19
- ChildProcess.should_receive(:build).with('bash', end_with('simple-localworker')).and_return(mock_process)
20
- mock_process.should_receive(:start)
21
- mock_env.should_receive(:[]=).with('cmd', 'cuke')
22
- mock_process.should_receive(:wait)
19
+ it 'can stop local worker' do
20
+ ChildProcess.should_receive(:build).and_return(mock_process)
23
21
  mock_process.should_receive(:stop)
24
22
 
25
- worker = LocalWorker.new
26
- worker.cmd = 'cuke'
27
- worker.start
28
- worker.wait
29
- worker.stop
23
+ local_worker.on_stop
30
24
  end
31
25
  end
32
26
  end
33
-
@@ -0,0 +1,44 @@
1
+ require File.expand_path('../../spec_helper.rb', __FILE__)
2
+
3
+ module SimpleWorker
4
+ describe LoggingListener do
5
+ let(:stdout) { StringIO.new }
6
+ let(:listener) { LoggingListener.new stdout }
7
+
8
+ it 'logs all events' do
9
+ Time.stub(:now => Time.now)
10
+
11
+ jobid = 'my_jobid'
12
+ host = 'my_host'
13
+ task = 'my_task'
14
+
15
+ listener.on_start jobid
16
+ listener.on_node_start host
17
+ listener.on_task_start host, task
18
+ listener.on_task_active host, task
19
+ listener.on_task_expire host, task
20
+ listener.on_task_stop host, task
21
+ listener.on_node_stop host
22
+ listener.on_timeout
23
+ listener.on_log host, 'message'
24
+ listener.on_interrupted
25
+ listener.on_stop
26
+
27
+ timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S##{Process.pid}")
28
+
29
+ stdout.string.should == <<-OUTPUT
30
+ I, [#{timestamp}] INFO -- : start: my_jobid
31
+ I, [#{timestamp}] INFO -- : start node: my_host
32
+ I, [#{timestamp}] INFO -- : start host: my_host task: my_task
33
+ I, [#{timestamp}] INFO -- : active host: my_host task: my_task
34
+ I, [#{timestamp}] INFO -- : expire host: my_host task: my_task
35
+ I, [#{timestamp}] INFO -- : stop host: my_host task: my_task
36
+ I, [#{timestamp}] INFO -- : stop node: my_host
37
+ I, [#{timestamp}] INFO -- : timeout
38
+ I, [#{timestamp}] INFO -- : host: my_host message
39
+ I, [#{timestamp}] INFO -- : interrupted
40
+ I, [#{timestamp}] INFO -- : stop
41
+ OUTPUT
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path('../../spec_helper.rb', __FILE__)
2
+
3
+ module SimpleWorker
4
+ describe RetryListener do
5
+ let(:redis) { double(Redis) }
6
+ let(:namespace) { 'my_namespace' }
7
+ let(:jobid) { 'my_jobid' }
8
+ let(:hostname) { 'my_hostname' }
9
+ let(:jobid) { 'my_jobid' }
10
+
11
+ it 'does not retry if max retries is 0' do
12
+ listener = RetryListener.new(redis, 0, namespace, jobid)
13
+ redis.should_not_receive(:rpush)
14
+
15
+ listener.on_task_expire(hostname, jobid)
16
+ end
17
+
18
+ it 'does retry once if max retries is 1' do
19
+ listener = RetryListener.new(redis, 1, namespace, jobid)
20
+ redis.should_receive(:rpush).once
21
+
22
+ 2.times { listener.on_task_expire(hostname, jobid) }
23
+ end
24
+ end
25
+ end
@@ -2,18 +2,80 @@ require File.expand_path('../../spec_helper.rb', __FILE__)
2
2
 
3
3
  module SimpleWorker
4
4
  describe Runner do
5
- let(:mock_worker) { double(AbstractWorker, :start => nil, :wait => nil, :stop => nil) }
6
-
7
- it 'can run workers' do
8
- mock_worker.should_receive(:start)
9
- mock_worker.should_receive(:cmd=).with('cuke')
10
- mock_worker.should_receive(:wait)
11
- mock_worker.should_receive(:stop)
12
- IO.should_receive(:read).with('simpleworker.yml').and_return('hi')
13
- YAML.should_receive(:load).with('hi').and_return({'workers' => [{'type' => 'ssh'}]})
14
- SshWorker.should_receive(:create).and_return(mock_worker)
15
-
16
- Runner.run 'cuke'
5
+ let(:redis) { double(Redis, :script => nil) }
6
+ let(:tasks) { ['ask1', 'task2'] }
7
+ let(:hostname) { 'my_hostname' }
8
+ let(:jobid) { 'my_jobid' }
9
+ let(:runner) { Runner.new(redis, tasks, :timeout => 120, :interval => 0) }
10
+ let(:mock_event_monitor) { double(EventMonitor, :update => nil) }
11
+ let(:mock_event_server) { double(EventServer, :add_observer => nil) }
12
+ let(:mock_retry_listener) { double(RetryListener, :update => nil, :tasks => [] ) }
13
+ let(:listener) { double(AbstractListener, :update => nil) }
14
+
15
+ before(:each) do
16
+ ::SecureRandom.should_receive(:hex).with(6).and_return(jobid)
17
+
18
+ EventServer.should_receive(:new).and_return(mock_event_server)
19
+ EventMonitor.should_receive(:new).and_return(mock_event_monitor)
20
+ RetryListener.should_receive(:new).and_return(mock_retry_listener)
21
+ redis.should_receive(:rpush).with("simpleworker:tasks:#{jobid}", tasks)
22
+ redis.should_receive(:set).with("simpleworker:config:my_jobid", {'task_timeout' => 10}.to_json)
23
+
24
+ redis.should_receive(:multi)
25
+ end
26
+
27
+ it 'can run' do
28
+ mock_event_monitor.should_receive(:done?).and_return(false, true)
29
+ mock_event_server.should_receive(:pull_events).and_return(2, 0)
30
+ mock_event_monitor.should_receive(:latest_time).and_return(Time.now)
31
+ runner.add_observer listener
32
+ listener.should_receive(:update).with("on_start", jobid)
33
+ listener.should_receive(:update).with("on_stop")
34
+
35
+ runner.run
36
+ end
37
+
38
+ it 'can timeout' do
39
+ mock_event_monitor.should_receive(:done?).and_return(false)
40
+ mock_event_server.should_receive(:pull_events).and_return(2, 2)
41
+ mock_event_monitor.should_receive(:latest_time).and_return(Time.now)
42
+
43
+ runner = Runner.new(redis, tasks, :timeout => 0, :interval => 0)
44
+ runner.add_observer listener
45
+ listener.should_receive(:update).with("on_timeout")
46
+
47
+ runner.run
48
+ end
49
+
50
+ it 'fires on_interrupted and shuts down if interrupted' do
51
+ runner.add_observer listener
52
+
53
+ mock_event_server.should_receive(:pull_events).and_raise(Interrupt)
54
+ listener.should_receive(:update).with("on_interrupted")
55
+
56
+ runner.run
57
+ end
58
+
59
+ it 'fires on_interrupted and shuts down if an error occurs' do
60
+ runner.add_observer listener
61
+
62
+ mock_event_server.should_receive(:pull_events).and_raise(StandardError)
63
+ listener.should_receive(:update).with("on_interrupted")
64
+
65
+ lambda { runner.run }.should raise_error(StandardError)
66
+ end
67
+
68
+ it 'continue to run if retries exist' do
69
+ mock_event_monitor.should_receive(:done?).twice.with(2).and_return(false)
70
+ mock_event_monitor.should_receive(:done?).with(0).and_return(true)
71
+ mock_event_server.should_receive(:pull_events).and_return(2, 2, 0)
72
+
73
+ mock_event_monitor.should_receive(:latest_time).twice.and_return(Time.now)
74
+ runner.add_observer listener
75
+ listener.should_receive(:update).with("on_start", jobid)
76
+ listener.should_receive(:update).with("on_stop")
77
+
78
+ runner.run
17
79
  end
18
80
  end
19
81
  end
@@ -2,42 +2,31 @@ require File.expand_path('../../spec_helper.rb', __FILE__)
2
2
 
3
3
  module SimpleWorker
4
4
  describe SshWorker do
5
- let(:mock_env) { double(Hash) }
6
- let(:mock_process) { double(ChildProcess, :start => nil, :stop => nil, :wait => nil, :io => double('io').as_null_object, :environment => mock_env) }
5
+ let(:mock_process) { double(ChildProcess, :io => double('io').as_null_object) }
6
+ let(:jobid) { 'my_jobid' }
7
+ let(:ssh_worker) { SshWorker.new(
8
+ :user => 'jesg',
9
+ :host => 'localhost',
10
+ :port => '22',
11
+ :cmd => 'my_cmd',
12
+ :dirname => 'work_dir')
13
+ }
7
14
 
8
- it 'can start ssh worker with defaults' do
9
- ChildProcess.should_receive(:build).with('bash', end_with('ssh-remoteworker')).and_return(mock_process)
10
- mock_process.should_receive(:start)
11
- mock_env.should_receive(:[]=).once.with('cmd', 'rake')
12
- mock_env.should_receive(:[]=).once.with('user', `whoami`)
13
- mock_env.should_receive(:[]=).once.with('host', 'localhost')
14
- mock_env.should_receive(:[]=).once.with('directory', Dir.pwd)
15
+ it 'can start ssh worker' do
16
+ expected_sync_cmd ='rsync -a --delete -e "ssh -p 22" "${PWD}/" "jesg@localhost:~/work_dir"'
17
+ expected_async_cmd = %q[ssh -p 22 "jesg@localhost" "/bin/bash -lc 'cd ~/work_dir; export JOBID=my_jobid; my_cmd' </dev/null >/dev/null 2>&1 &"]
18
+ Kernel.stub('`')
19
+ ssh_worker.should_receive(:sync_to_remote)
20
+ ssh_worker.should_receive(:async_cmd)
15
21
 
16
- worker = SshWorker.new
17
- worker.cmd = 'rake'
18
- worker.start
22
+ ssh_worker.on_start(jobid)
19
23
  end
20
24
 
21
- it 'can start ssh worker with customization' do
22
- ChildProcess.should_receive(:build).with('bash', end_with('ssh-remoteworker')).and_return(mock_process)
23
- mock_process.should_receive(:start)
24
- mock_env.should_receive(:[]=).once.with('cmd', 'cuke')
25
- mock_env.should_receive(:[]=).once.with('user', 'bob')
26
- mock_env.should_receive(:[]=).once.with('host', 'foo')
27
- mock_env.should_receive(:[]=).once.with('directory', 'bar')
25
+ it 'can stop ssh worker' do
26
+ Kernel.stub('`')
27
+ ssh_worker.should_receive(:sync_from_remote)
28
28
 
29
- mock_process.should_receive(:wait)
30
- mock_process.should_receive(:stop)
31
-
32
- worker = SshWorker.new
33
- worker.cmd = 'cuke'
34
- worker.user = 'bob'
35
- worker.host = 'foo'
36
- worker.directory = 'bar'
37
- worker.start
38
- worker.wait
39
- worker.stop
29
+ ssh_worker.on_stop
40
30
  end
41
31
  end
42
32
  end
43
-