meepo 1.5.2

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 (108) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +29 -0
  6. data/.travis.yml +10 -0
  7. data/Dockerfile +7 -0
  8. data/Gemfile +13 -0
  9. data/MIT-LICENSE +20 -0
  10. data/Rakefile +15 -0
  11. data/TODO +5 -0
  12. data/bin/invoker +7 -0
  13. data/contrib/completion/invoker-completion.bash +70 -0
  14. data/contrib/completion/invoker-completion.zsh +62 -0
  15. data/examples/hello_sinatra.rb +26 -0
  16. data/examples/sample.ini +3 -0
  17. data/invoker.gemspec +43 -0
  18. data/lib/invoker.rb +152 -0
  19. data/lib/invoker/cli.rb +159 -0
  20. data/lib/invoker/cli/pinger.rb +23 -0
  21. data/lib/invoker/cli/question.rb +15 -0
  22. data/lib/invoker/cli/tail.rb +34 -0
  23. data/lib/invoker/cli/tail_watcher.rb +34 -0
  24. data/lib/invoker/command_worker.rb +60 -0
  25. data/lib/invoker/commander.rb +95 -0
  26. data/lib/invoker/daemon.rb +126 -0
  27. data/lib/invoker/dns_cache.rb +23 -0
  28. data/lib/invoker/errors.rb +17 -0
  29. data/lib/invoker/event/manager.rb +79 -0
  30. data/lib/invoker/ipc.rb +45 -0
  31. data/lib/invoker/ipc/add_command.rb +12 -0
  32. data/lib/invoker/ipc/add_http_command.rb +10 -0
  33. data/lib/invoker/ipc/base_command.rb +24 -0
  34. data/lib/invoker/ipc/client_handler.rb +26 -0
  35. data/lib/invoker/ipc/dns_check_command.rb +17 -0
  36. data/lib/invoker/ipc/list_command.rb +11 -0
  37. data/lib/invoker/ipc/message.rb +170 -0
  38. data/lib/invoker/ipc/message/list_response.rb +35 -0
  39. data/lib/invoker/ipc/message/tail_response.rb +10 -0
  40. data/lib/invoker/ipc/ping_command.rb +10 -0
  41. data/lib/invoker/ipc/reload_command.rb +12 -0
  42. data/lib/invoker/ipc/remove_command.rb +12 -0
  43. data/lib/invoker/ipc/server.rb +26 -0
  44. data/lib/invoker/ipc/tail_command.rb +11 -0
  45. data/lib/invoker/ipc/unix_client.rb +60 -0
  46. data/lib/invoker/logger.rb +13 -0
  47. data/lib/invoker/parsers/config.rb +184 -0
  48. data/lib/invoker/parsers/procfile.rb +86 -0
  49. data/lib/invoker/power/balancer.rb +131 -0
  50. data/lib/invoker/power/config.rb +77 -0
  51. data/lib/invoker/power/dns.rb +38 -0
  52. data/lib/invoker/power/http_parser.rb +68 -0
  53. data/lib/invoker/power/http_response.rb +81 -0
  54. data/lib/invoker/power/pf_migrate.rb +64 -0
  55. data/lib/invoker/power/port_finder.rb +49 -0
  56. data/lib/invoker/power/power.rb +3 -0
  57. data/lib/invoker/power/powerup.rb +29 -0
  58. data/lib/invoker/power/setup.rb +90 -0
  59. data/lib/invoker/power/setup/distro/arch.rb +15 -0
  60. data/lib/invoker/power/setup/distro/base.rb +57 -0
  61. data/lib/invoker/power/setup/distro/debian.rb +11 -0
  62. data/lib/invoker/power/setup/distro/mint.rb +10 -0
  63. data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
  64. data/lib/invoker/power/setup/distro/redhat.rb +11 -0
  65. data/lib/invoker/power/setup/distro/ubuntu.rb +10 -0
  66. data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
  67. data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
  68. data/lib/invoker/power/setup/linux_setup.rb +105 -0
  69. data/lib/invoker/power/setup/osx_setup.rb +137 -0
  70. data/lib/invoker/power/templates/400.html +40 -0
  71. data/lib/invoker/power/templates/404.html +40 -0
  72. data/lib/invoker/power/templates/503.html +40 -0
  73. data/lib/invoker/power/url_rewriter.rb +40 -0
  74. data/lib/invoker/process_manager.rb +198 -0
  75. data/lib/invoker/process_printer.rb +43 -0
  76. data/lib/invoker/reactor.rb +37 -0
  77. data/lib/invoker/reactor/reader.rb +54 -0
  78. data/lib/invoker/version.rb +47 -0
  79. data/readme.md +25 -0
  80. data/spec/invoker/cli/pinger_spec.rb +22 -0
  81. data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
  82. data/spec/invoker/cli_spec.rb +27 -0
  83. data/spec/invoker/command_worker_spec.rb +45 -0
  84. data/spec/invoker/commander_spec.rb +152 -0
  85. data/spec/invoker/config_spec.rb +361 -0
  86. data/spec/invoker/daemon_spec.rb +34 -0
  87. data/spec/invoker/event/manager_spec.rb +67 -0
  88. data/spec/invoker/invoker_spec.rb +71 -0
  89. data/spec/invoker/ipc/client_handler_spec.rb +54 -0
  90. data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
  91. data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
  92. data/spec/invoker/ipc/message_spec.rb +49 -0
  93. data/spec/invoker/ipc/unix_client_spec.rb +29 -0
  94. data/spec/invoker/power/balancer_spec.rb +22 -0
  95. data/spec/invoker/power/config_spec.rb +18 -0
  96. data/spec/invoker/power/http_parser_spec.rb +32 -0
  97. data/spec/invoker/power/http_response_spec.rb +34 -0
  98. data/spec/invoker/power/pf_migrate_spec.rb +87 -0
  99. data/spec/invoker/power/port_finder_spec.rb +16 -0
  100. data/spec/invoker/power/setup/linux_setup_spec.rb +103 -0
  101. data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
  102. data/spec/invoker/power/setup_spec.rb +4 -0
  103. data/spec/invoker/power/url_rewriter_spec.rb +70 -0
  104. data/spec/invoker/power/web_sockets_spec.rb +61 -0
  105. data/spec/invoker/process_manager_spec.rb +130 -0
  106. data/spec/invoker/reactor_spec.rb +6 -0
  107. data/spec/spec_helper.rb +43 -0
  108. metadata +389 -0
@@ -0,0 +1,43 @@
1
+ module Invoker
2
+ class ProcessPrinter
3
+ MAX_COLUMN_WIDTH = 40
4
+ attr_accessor :list_response
5
+
6
+ def initialize(list_response)
7
+ self.list_response = list_response
8
+ end
9
+
10
+ def print_table
11
+ hash_with_colors = []
12
+ list_response.processes.each do |process|
13
+ if process.pid
14
+ hash_with_colors << colorize_hash(process, "green")
15
+ else
16
+ hash_with_colors << colorize_hash(process, "light_black")
17
+ end
18
+ end
19
+ Formatador.display_compact_table(hash_with_colors)
20
+ end
21
+
22
+ private
23
+
24
+ def colorize_hash(process, color)
25
+ hash_with_colors = {}
26
+
27
+ hash_with_colors['dir'] = colored_string(process.dir, color)
28
+ hash_with_colors['pid'] = colored_string(process.pid || 'Not Running', color)
29
+ hash_with_colors['port'] = colored_string(process.port, color)
30
+ hash_with_colors['shell_command'] = colored_string(process.shell_command, color)
31
+ hash_with_colors['process_name'] = colored_string(process.process_name, color)
32
+ hash_with_colors
33
+ end
34
+
35
+ def colored_string(string, color)
36
+ string = string.to_s
37
+ if string.length > MAX_COLUMN_WIDTH
38
+ string = "#{string[0..MAX_COLUMN_WIDTH]}.."
39
+ end
40
+ "[#{color}]#{string}[/]"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ module Invoker
2
+ class Reactor
3
+ attr_accessor :reader
4
+
5
+ def initialize
6
+ @reader = Invoker::Reactor::Reader.new
7
+ end
8
+
9
+ def watch_for_read(fd)
10
+ reader.watch_for_read(fd)
11
+ end
12
+
13
+ # Writes data to client socket and raises error if errors
14
+ # while writing
15
+ def send_data(socket, data)
16
+ socket.write(data)
17
+ rescue
18
+ raise Invoker::Errors::ClientDisconnected
19
+ end
20
+
21
+ def monitor_for_fd_events
22
+ ready_read_fds, _ , _ = select(*options_for_select)
23
+
24
+ if ready_read_fds && !ready_read_fds.empty?
25
+ reader.handle_read_event(ready_read_fds)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def options_for_select
32
+ [reader.read_array, [], [], 0.05]
33
+ end
34
+ end
35
+ end
36
+
37
+ require "invoker/reactor/reader"
@@ -0,0 +1,54 @@
1
+ module Invoker
2
+ class Reactor::Reader
3
+ attr_accessor :read_array
4
+
5
+ def initialize
6
+ @read_array = []
7
+ end
8
+
9
+ def watch_for_read(socket)
10
+ @read_array << socket
11
+ end
12
+
13
+ def handle_read_event(read_ready_fds)
14
+ ready_fds = read_ready_fds.flatten.compact
15
+ ready_fds.each { |ready_fd| process_read(ready_fd) }
16
+ end
17
+
18
+ private
19
+
20
+ def process_read(ready_fd)
21
+ command_worker = Invoker.commander.get_worker_from_fd(ready_fd)
22
+ return unless command_worker
23
+ begin
24
+ data = read_data(ready_fd)
25
+ command_worker.receive_data(data)
26
+ rescue Invoker::Errors::ProcessTerminated
27
+ remove_from_read_monitoring(command_worker.pipe_end, command_worker)
28
+ end
29
+ end
30
+
31
+ def remove_from_read_monitoring(fd, command_worker)
32
+ read_array.delete(fd)
33
+ command_worker.unbind
34
+ rescue StandardError => error
35
+ Invoker::Logger.puts(error.message)
36
+ Invoker::Logger.puts(error.backtrace)
37
+ end
38
+
39
+ def read_data(ready_fd)
40
+ sock_data = []
41
+ begin
42
+ while(t_data = ready_fd.read_nonblock(64))
43
+ sock_data << t_data
44
+ end
45
+ rescue Errno::EAGAIN
46
+ return sock_data.join
47
+ rescue Errno::EWOULDBLOCK
48
+ return sock_data.join
49
+ rescue
50
+ raise Invoker::Errors::ProcessTerminated.new(ready_fd,sock_data.join)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,47 @@
1
+ module Invoker
2
+ class Version
3
+ include Comparable
4
+ attr_reader :major, :minor, :patch
5
+
6
+ def initialize(number)
7
+ t_major, t_minor, t_patch = number.split('.')
8
+ @major = t_major.to_i
9
+ @minor = t_minor.to_i
10
+ @patch = t_patch.to_i
11
+ end
12
+
13
+ def to_a
14
+ [major, minor, patch].compact
15
+ end
16
+
17
+ def <=>(version)
18
+ (major.to_i <=> version.major.to_i).nonzero? ||
19
+ (minor.to_i <=> version.minor.to_i).nonzero? ||
20
+ patch.to_i <=> version.patch.to_i
21
+ end
22
+
23
+ def matches?(operator, number)
24
+ version = Version.new(number)
25
+ self == version
26
+
27
+ return self == version if operator == '='
28
+ return self > version if operator == '>'
29
+ return self < version if operator == '<'
30
+ return version <= self && version.next > self if operator == '~>'
31
+ end
32
+
33
+ def next
34
+ next_splits = to_a
35
+
36
+ if next_splits.length == 1
37
+ next_splits[0] += 1
38
+ else
39
+ next_splits[-2] += 1
40
+ next_splits[-1] = 0
41
+ end
42
+
43
+ Version.new(next_splits.join('.'))
44
+ end
45
+ end
46
+ VERSION = "1.5.2"
47
+ end
@@ -0,0 +1,25 @@
1
+ Invoker is a gem for managing processes in development environment.
2
+
3
+ [![Build Status](https://travis-ci.org/code-mancers/invoker.svg)](https://travis-ci.org/code-mancers/invoker)
4
+ [![Code Climate](https://codeclimate.com/github/code-mancers/invoker.svg)](https://codeclimate.com/github/code-mancers/invoker)
5
+ [![Coverage Status](https://coveralls.io/repos/code-mancers/invoker/badge.svg)](https://coveralls.io/r/code-mancers/invoker)
6
+ [![Dependency Status](https://gemnasium.com/code-mancers/invoker.svg)](https://gemnasium.com/code-mancers/invoker)
7
+
8
+ ## Usage ##
9
+
10
+ First we need to install `invoker` gem to get command line utility called `invoker`, we can do that via:
11
+
12
+ gem install invoker
13
+
14
+ Currently it only works with Ruby 1.9.3, 2.0 and 2.1.
15
+
16
+ ## Manual ##
17
+
18
+ Information about configuring and using Invoker can be found on - [Invoker Website](http://invoker.codemancers.com)
19
+
20
+ Invoker documentation is maintained via `Jekyll` and hosted on `github`. If you would like to fix an error
21
+ or update something - please submit a pull request against `gh-pages` branch of `Invoker`.
22
+
23
+ ## Bug reports and Feature requests
24
+
25
+ Please use [Github Issue Tracker](https://github.com/code-mancers/invoker/issues) for feature requests or bug reports.
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::CLI::Pinger do
4
+ let(:unix_client) { Invoker::IPC::UnixClient.new }
5
+ let(:pinger) { Invoker::CLI::Pinger.new(unix_client) }
6
+ let(:pong) { MM::Pong.new(status: 'pong') }
7
+
8
+ context "If Invoker is running" do
9
+ it "should return true" do
10
+ unix_client.expects(:send_and_receive).returns(pong)
11
+ expect(pinger.invoker_running?).to be_truthy
12
+ end
13
+ end
14
+
15
+ context "if Invoker is not running" do
16
+ it "should return false" do
17
+ unix_client.expects(:send_and_receive).returns(nil)
18
+ unix_client.expects(:abort).never
19
+ expect(pinger.invoker_running?).to be_falsey
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::CLI::TailWatcher do
4
+ let(:tail_watcher) { Invoker::CLI::TailWatcher.new }
5
+
6
+ describe "Adding processes to watch list" do
7
+ it "should allow add" do
8
+ tail_watcher.add(["rails"], "socket")
9
+ expect(tail_watcher.tail_watchers).to_not be_empty
10
+ expect(tail_watcher["rails"]).to eql ["socket"]
11
+ end
12
+ end
13
+
14
+ describe "removing processes from watch list" do
15
+ context "when process has only one watcher" do
16
+ before do
17
+ tail_watcher.add(["rails"], "socket")
18
+ end
19
+ it "should remove and purge process watch list" do
20
+ expect(tail_watcher.tail_watchers).to_not be_empty
21
+ tail_watcher.remove("rails", "socket")
22
+ expect(tail_watcher.tail_watchers).to be_empty
23
+ end
24
+ end
25
+ context "when process multiple watchers" do
26
+ before do
27
+ tail_watcher.add(["rails"], "socket")
28
+ tail_watcher.add(["rails"], "socket2")
29
+ end
30
+
31
+ it "should remove only related socket" do
32
+ expect(tail_watcher.tail_watchers).to_not be_empty
33
+ tail_watcher.remove("rails", "socket")
34
+ expect(tail_watcher.tail_watchers).to_not be_empty
35
+ expect(tail_watcher["rails"]).to eql ["socket2"]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::CLI do
4
+ describe "default start command" do
5
+ it "should use default if no other command specified" do
6
+ Invoker::CLI.any_instance.expects(:start).with("dummy")
7
+ Invoker::CLI.start(["dummy"])
8
+ end
9
+
10
+ it "should use proper command if it exists" do
11
+ Invoker::CLI.any_instance.expects(:list)
12
+ Invoker::CLI.start(["list"])
13
+ end
14
+
15
+ it "should list version" do
16
+ Invoker::CLI.any_instance.expects(:version)
17
+ Invoker::CLI.start(["-v"])
18
+ end
19
+ end
20
+
21
+ describe "stop command" do
22
+ it "should stop the daemon" do
23
+ Invoker.daemon.expects(:stop).once
24
+ Invoker::CLI.start(["stop"])
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe "Command Worker" do
4
+ let(:pipe_end) { StringIO.new }
5
+ let(:command_worker) { Invoker::CommandWorker.new('rails', pipe_end, 100, :red) }
6
+
7
+ describe "converting workers hash to json" do
8
+ before do
9
+ @workers = {}
10
+ @workers["foo"] = Invoker::CommandWorker.new("foo", 89, 1023, "red")
11
+ @workers["bar"] = Invoker::CommandWorker.new("bar", 99, 1024, "blue")
12
+ end
13
+
14
+ it "should print json" do
15
+ expect(@workers.values.map {|worker| worker.to_h }.to_json).not_to be_empty
16
+ end
17
+ end
18
+
19
+ describe "sending json responses" do
20
+ before do
21
+ @socket = StringIO.new
22
+ Invoker.tail_watchers = Invoker::CLI::TailWatcher.new
23
+ Invoker.tail_watchers.add(['rails'], @socket)
24
+ end
25
+
26
+ after do
27
+ Invoker.tail_watchers = nil
28
+ end
29
+
30
+ context "when there is a error encoding the message" do
31
+ it "should send nothing to the socket" do
32
+ MM::TailResponse.any_instance.expects(:encoded_message).raises(StandardError, "encoding error")
33
+ command_worker.receive_line('hello_world')
34
+ expect(@socket.string).to be_empty
35
+ end
36
+ end
37
+
38
+ context "when there is successful delivery" do
39
+ it "should return json data to client if tail watchers" do
40
+ command_worker.receive_line('hello_world')
41
+ expect(@socket.string).to match(/hello_world/)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,152 @@
1
+ require "spec_helper"
2
+
3
+ describe "Invoker::Commander" do
4
+ before(:each) do
5
+ @original_invoker_config = Invoker.config
6
+ Invoker.config = mock
7
+ end
8
+
9
+ after(:each) do
10
+ Invoker.config = @original_invoker_config
11
+ end
12
+
13
+ describe "With no processes configured" do
14
+ before(:each) do
15
+ @commander = Invoker::Commander.new
16
+ end
17
+
18
+ it "should throw error" do
19
+ Invoker.config.stubs(:processes).returns([])
20
+
21
+ expect {
22
+ @commander.start_manager
23
+ }.to raise_error(Invoker::Errors::InvalidConfig)
24
+ end
25
+ end
26
+
27
+ describe "#start_process" do
28
+ describe "when not daemonized" do
29
+ before do
30
+ processes = [OpenStruct.new(:label => "foobar", :cmd => "foobar_command", :dir => ENV['HOME'], :sleep_duration => 2)]
31
+ Invoker.config.stubs(:processes).returns(processes)
32
+ Invoker.config.stubs(:autorunnable_processes).returns(processes)
33
+ Invoker.stubs(:can_run_balancer?).returns(false)
34
+ @commander = Invoker::Commander.new
35
+ Invoker.commander = @commander
36
+ end
37
+
38
+ after do
39
+ Invoker.commander = nil
40
+ end
41
+
42
+ it "should populate workers and open_pipes" do
43
+ @commander.expects(:start_event_loop)
44
+ @commander.process_manager.expects(:load_env).returns({})
45
+ @commander.process_manager.expects(:spawn).returns(100)
46
+ @commander.process_manager.expects(:wait_on_pid)
47
+ @commander.expects(:at_exit)
48
+ @commander.start_manager
49
+ expect(@commander.process_manager.open_pipes).not_to be_empty
50
+ expect(@commander.process_manager.workers).not_to be_empty
51
+
52
+ worker = @commander.process_manager.workers['foobar']
53
+
54
+ expect(worker).not_to be_nil
55
+ expect(worker.command_label).to eq('foobar')
56
+
57
+ pipe_end_worker = @commander.process_manager.open_pipes[worker.pipe_end.fileno]
58
+ expect(pipe_end_worker).not_to be_nil
59
+ end
60
+ end
61
+
62
+ describe "when daemonized" do
63
+ before do
64
+ processes = [OpenStruct.new(:label => "foobar", :cmd => "foobar_command", :dir => ENV['HOME'], :sleep_duration => 2)]
65
+ Invoker.config.stubs(:processes).returns(processes)
66
+ Invoker.config.stubs(:autorunnable_processes).returns(processes)
67
+ Invoker.stubs(:can_run_balancer?).returns(false)
68
+ @commander = Invoker::Commander.new
69
+ Invoker.commander = @commander
70
+ Invoker.daemonize = true
71
+ end
72
+
73
+ after do
74
+ Invoker.commander = nil
75
+ Invoker.daemonize = false
76
+ end
77
+
78
+ it "should daemonize the process and populate workers and open_pipes" do
79
+ @commander.expects(:start_event_loop)
80
+ @commander.process_manager.expects(:load_env).returns({})
81
+ Invoker.daemon.expects(:start).once
82
+ @commander.process_manager.expects(:spawn).returns(100)
83
+ @commander.process_manager.expects(:wait_on_pid)
84
+ @commander.expects(:at_exit)
85
+ @commander.start_manager
86
+
87
+ expect(@commander.process_manager.open_pipes).not_to be_empty
88
+ expect(@commander.process_manager.workers).not_to be_empty
89
+
90
+ worker = @commander.process_manager.workers['foobar']
91
+
92
+ expect(worker).not_to be_nil
93
+ expect(worker.command_label).to eq('foobar')
94
+
95
+ pipe_end_worker = @commander.process_manager.open_pipes[worker.pipe_end.fileno]
96
+ expect(pipe_end_worker).not_to be_nil
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'disable_autorun option' do
102
+ context 'autorun is disabled for a process' do
103
+ before do
104
+ @processes = [
105
+ OpenStruct.new(:label => "foobar", :cmd => "foobar_command", :dir => ENV['HOME'], :sleep_duration => 2),
106
+ OpenStruct.new(:label => "panda", :cmd => "panda_command", :dir => ENV['HOME'], :disable_autorun => true, :sleep_duration => 2)
107
+ ]
108
+ Invoker.config.stubs(:processes).returns(@processes)
109
+ Invoker.config.stubs(:autorunnable_processes).returns([@processes.first])
110
+
111
+ @commander = Invoker::Commander.new
112
+ end
113
+
114
+ it "doesn't run process" do
115
+ @commander.expects(:install_interrupt_handler)
116
+ @commander.process_manager.expects(:run_power_server)
117
+ @commander.expects(:at_exit)
118
+ @commander.expects(:start_event_loop)
119
+
120
+ @commander.process_manager.expects(:start_process).with(@processes[0])
121
+ @commander.process_manager.expects(:start_process).with(@processes[1]).never
122
+ @commander.start_manager
123
+ end
124
+ end
125
+ end
126
+
127
+ describe "#runnables" do
128
+ before do
129
+ @commander = Invoker::Commander.new
130
+ end
131
+
132
+ it "should run runnables in reactor tick with one argument" do
133
+ @commander.on_next_tick("foo") { |cmd| start_process_by_name(cmd) }
134
+ @commander.expects(:start_process_by_name).returns(true)
135
+ @commander.run_runnables()
136
+ end
137
+
138
+ it "should run runnables with multiple args" do
139
+ @commander.on_next_tick("foo", "bar", "baz") { |t1,*rest|
140
+ stop_process(t1, rest)
141
+ }
142
+ @commander.expects(:stop_process).with("foo", ["bar", "baz"]).returns(true)
143
+ @commander.run_runnables()
144
+ end
145
+
146
+ it "should run runnable with no args" do
147
+ @commander.on_next_tick() { hello() }
148
+ @commander.expects(:hello).returns(true)
149
+ @commander.run_runnables()
150
+ end
151
+ end
152
+ end