cumuli 0.3.2 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/features/graceful_exits.feature +27 -0
- data/features/step_definitions/app_steps.rb +18 -7
- data/lib/cumuli/app/app.rb +26 -31
- data/lib/cumuli/app/procs.rb +0 -18
- data/lib/cumuli/app/{foreman_process.rb → spawner.rb} +19 -13
- data/lib/cumuli/app/sub_app.rb +50 -0
- data/lib/cumuli/app.rb +2 -1
- data/lib/cumuli/ps.rb +63 -29
- data/lib/cumuli/tasks/cumuli.rake +34 -5
- data/lib/cumuli/version.rb +1 -1
- data/spec/app/app_spec.rb +24 -13
- data/spec/app/sub_app_spec.rb +25 -0
- data/spec/cli/terminal_spec.rb +1 -0
- data/spec/fixtures/ps.txt +118 -0
- data/spec/ps_spec.rb +38 -0
- data/spec/support/report.rb +3 -0
- metadata +14 -7
- data/features/graceful_exit.feature +0 -14
- data/features/support/io_capture.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e61d96a9203fd5fed28980e2d3817ab7afcdfd5a
|
4
|
+
data.tar.gz: 0721f35292c999e27c9e7ad25904c93b2d59f353
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 557916c9a94781c074aad2eb6646a7d7cf99755f17a4c9800d0a89ae45061a0bc58ba4725700fe018a88b81ab653a21caaa53c0990701ed9583ea30278b203bf
|
7
|
+
data.tar.gz: c83034cfc14815ca7d13d9b3aed3a109993ddaeb5be4d3ff6ed4f3777514038477a9f6155f2a097c8d9ee2843c4edc97a62e47fac1a1dcb57c833c4cd2306aa4
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Feature: Cumuli exits the app gracefully
|
2
|
+
In order to use Cumuli to test in an integration way, a suite of apps and services
|
3
|
+
As a developer with a SOA stack
|
4
|
+
I want cucumber to exit with a good success code
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given the app suite is loaded
|
8
|
+
|
9
|
+
Scenario: App is stopped in a cucumber step
|
10
|
+
When I shutdown the app suite
|
11
|
+
Then the processes should not be running
|
12
|
+
And I should see that the rake was not aborted
|
13
|
+
|
14
|
+
#Scenario: App's forked pid receives an INT signal
|
15
|
+
#When the forked pid receives an INT signal
|
16
|
+
#Then the processes should not be running
|
17
|
+
#And I should see that the rake was not aborted
|
18
|
+
|
19
|
+
Scenario: App's forked pid receives a KILL signal
|
20
|
+
When the forked pid receives an KILL signal
|
21
|
+
Then the processes should not be running
|
22
|
+
And I should see that the rake was not aborted
|
23
|
+
|
24
|
+
Scenario: App's forked pid receives a TERM signal
|
25
|
+
When the forked pid receives an TERM signal
|
26
|
+
Then the processes should not be running
|
27
|
+
And I should see that the rake was not aborted
|
@@ -6,27 +6,38 @@ Given(/^the app suite is loaded$/) do
|
|
6
6
|
app_dir: File.dirname(__FILE__) + "/../../spec/fixtures/app_set"
|
7
7
|
})
|
8
8
|
@app.start
|
9
|
+
@app.wait_for_apps
|
9
10
|
@pid = @app.pid
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
@
|
13
|
+
Given(/^the current thread is listening for signals$/) do
|
14
|
+
@signals = []
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
['KILL', 'INT', 'TERM', 'HUP'].each do |signal|
|
17
|
+
trap signal do
|
18
|
+
@signals << signal
|
19
|
+
end
|
17
20
|
end
|
21
|
+
end
|
18
22
|
|
23
|
+
When(/^I shutdown the app suite$/) do
|
24
|
+
step "the current thread is listening for signals"
|
19
25
|
@app.stop
|
20
26
|
end
|
21
27
|
|
28
|
+
When(/^the forked pid receives an (.*) signal$/) do |signal|
|
29
|
+
step "the current thread is listening for signals"
|
30
|
+
Process.kill(signal, @pid)
|
31
|
+
end
|
32
|
+
|
22
33
|
Then(/^I should see that the rake was not aborted$/) do
|
23
|
-
@
|
34
|
+
@signals.should be_empty
|
24
35
|
end
|
25
36
|
|
26
37
|
Then(/^the processes should not be running$/) do
|
27
38
|
Cumuli::Waiter.new.wait_until(3) do
|
28
|
-
|
29
|
-
|
39
|
+
report = Cumuli::PS.new.report(@pid)
|
40
|
+
report.empty?
|
30
41
|
end
|
31
42
|
end
|
32
43
|
|
data/lib/cumuli/app/app.rb
CHANGED
@@ -15,7 +15,7 @@ module Cumuli
|
|
15
15
|
def start
|
16
16
|
return if foreman_process.started?
|
17
17
|
|
18
|
-
Dir.chdir(app_dir) do
|
18
|
+
Dir.chdir(app_dir) do
|
19
19
|
listen_for_signals
|
20
20
|
logger.print "Starting ..."
|
21
21
|
foreman_process.start
|
@@ -23,20 +23,32 @@ module Cumuli
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def stop
|
27
|
+
if foreman_process.started?
|
28
|
+
foreman_process.stop
|
29
|
+
wait_for_apps('stop') if wait?
|
30
|
+
@foreman_process = nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
26
34
|
def logger
|
27
35
|
@logger = StdoutLogger.new
|
28
36
|
end
|
29
37
|
|
30
38
|
def foreman_process
|
31
|
-
@
|
39
|
+
@foreman_process ||= Spawner.new(env, log_dir)
|
32
40
|
end
|
33
41
|
|
34
42
|
def apps
|
35
|
-
@apps ||= Procs.new(app_dir)
|
43
|
+
@apps ||= Procs.new(app_dir).apps
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_pids
|
47
|
+
PS.new.family
|
36
48
|
end
|
37
49
|
|
38
50
|
def pid
|
39
|
-
foreman_process.
|
51
|
+
foreman_process.group_id
|
40
52
|
end
|
41
53
|
|
42
54
|
def wait?
|
@@ -46,46 +58,29 @@ module Cumuli
|
|
46
58
|
def listen_for_signals
|
47
59
|
SIGNALS.each do |signal|
|
48
60
|
trap(signal) do
|
61
|
+
puts "#{self.class}: trapped signal #{signal} in #{Process.pid} ... stopping"
|
49
62
|
stop
|
50
63
|
end
|
51
64
|
end
|
52
65
|
end
|
53
66
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def wait_for_apps
|
59
|
-
app_ports.each do |port|
|
60
|
-
wait_for_app(port)
|
67
|
+
def wait_for_apps(direction = 'start')
|
68
|
+
logger.add_space
|
69
|
+
apps.each do |app|
|
70
|
+
log_and_wait(app, direction)
|
61
71
|
end
|
62
|
-
|
63
72
|
logger.add_space
|
64
73
|
end
|
65
74
|
|
66
|
-
def
|
67
|
-
logger.print "waiting for apps on port: #{port}"
|
75
|
+
def log_and_wait(app, direction)
|
68
76
|
timeout = wait_time || DEFAULT_WAIT_TIME
|
69
|
-
|
70
|
-
|
71
|
-
logger.print "
|
77
|
+
logger.print "#{direction}: waiting for app named '#{app.name}' at #{app.url}"
|
78
|
+
app.send("wait_for_#{direction}", timeout)
|
79
|
+
logger.print "#{direction}: application '#{app.name}' on #{app.url} complete"
|
80
|
+
logger.add_space
|
72
81
|
rescue Exception => e
|
73
82
|
stop
|
74
83
|
raise e
|
75
84
|
end
|
76
|
-
|
77
|
-
def open_socket(port)
|
78
|
-
TCPSocket.new('localhost', port)
|
79
|
-
true
|
80
|
-
rescue Errno::ECONNREFUSED
|
81
|
-
false
|
82
|
-
end
|
83
|
-
|
84
|
-
def stop
|
85
|
-
if foreman_process.started?
|
86
|
-
foreman_process.stop
|
87
|
-
@foreman_process = nil
|
88
|
-
end
|
89
|
-
end
|
90
85
|
end
|
91
86
|
end
|
data/lib/cumuli/app/procs.rb
CHANGED
@@ -28,24 +28,6 @@ module Cumuli
|
|
28
28
|
def names
|
29
29
|
map.keys
|
30
30
|
end
|
31
|
-
|
32
|
-
class SubApp
|
33
|
-
attr_reader :parts
|
34
|
-
|
35
|
-
def initialize(line)
|
36
|
-
@parts = line.split
|
37
|
-
end
|
38
|
-
|
39
|
-
def name
|
40
|
-
parts.first.gsub(':', '')
|
41
|
-
end
|
42
|
-
|
43
|
-
def port
|
44
|
-
if index = parts.find_index('-p')
|
45
|
-
parts[index + 1] && parts[index + 1].to_i
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
31
|
end
|
50
32
|
end
|
51
33
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Cumuli
|
2
2
|
class App
|
3
|
-
class
|
3
|
+
class Spawner
|
4
4
|
attr_reader :pid, :env, :log_dir
|
5
5
|
|
6
6
|
def initialize(env, log_dir)
|
@@ -15,7 +15,7 @@ module Cumuli
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def command
|
18
|
-
"
|
18
|
+
"foreman start"
|
19
19
|
end
|
20
20
|
|
21
21
|
def log_file
|
@@ -24,9 +24,17 @@ module Cumuli
|
|
24
24
|
|
25
25
|
def start
|
26
26
|
@pid = fork do
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
spawn(
|
28
|
+
{
|
29
|
+
'HEROKU_ENV' => env,
|
30
|
+
'RAILS_ENV' => env
|
31
|
+
},
|
32
|
+
command,
|
33
|
+
{
|
34
|
+
out: $stdout.reopen(log_file),
|
35
|
+
pgroup: true, # start a new process group
|
36
|
+
}
|
37
|
+
)
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
@@ -50,16 +58,14 @@ module Cumuli
|
|
50
58
|
@pid = nil
|
51
59
|
end
|
52
60
|
|
61
|
+
def group_id
|
62
|
+
PS.new.root_pid
|
63
|
+
end
|
64
|
+
|
53
65
|
def kill_children
|
54
|
-
|
55
|
-
pids.reverse.each do |p|
|
56
|
-
begin
|
57
|
-
Process.kill("KILL", p)
|
58
|
-
rescue Errno::ESRCH => e
|
59
|
-
puts "Small issue killing your child: #{p}; it looks to be dead"
|
60
|
-
end
|
61
|
-
end
|
66
|
+
Process.kill('INT', -group_id) # kills the forked group
|
62
67
|
end
|
63
68
|
end
|
64
69
|
end
|
65
70
|
end
|
71
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Cumuli
|
2
|
+
class App
|
3
|
+
class SubApp
|
4
|
+
attr_reader :parts
|
5
|
+
attr_accessor :host
|
6
|
+
|
7
|
+
def initialize(line)
|
8
|
+
@parts = line.split
|
9
|
+
@host = 'localhost'
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
parts.first.gsub(':', '')
|
14
|
+
end
|
15
|
+
|
16
|
+
def port
|
17
|
+
if index = parts.find_index('-p')
|
18
|
+
parts[index + 1] && parts[index + 1].to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def waitable?
|
23
|
+
host != 'localhost' || port
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait_for_start(timeout)
|
27
|
+
return unless waitable?
|
28
|
+
Waiter.new("Application #{name} on port #{port} unavailable after #{timeout} seconds")
|
29
|
+
.wait_until(timeout) { socket_available? }
|
30
|
+
end
|
31
|
+
|
32
|
+
def wait_for_stop(timeout)
|
33
|
+
return unless waitable?
|
34
|
+
Waiter.new("Application #{name} on port #{port} still connected after #{timeout} seconds")
|
35
|
+
.wait_until(timeout) { !socket_available? }
|
36
|
+
end
|
37
|
+
|
38
|
+
def url
|
39
|
+
"http://#{host}#{port ? ':' + port.to_s : ''}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def socket_available?
|
43
|
+
TCPSocket.new(host, port)
|
44
|
+
true
|
45
|
+
rescue Errno::ECONNREFUSED
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/cumuli/app.rb
CHANGED
data/lib/cumuli/ps.rb
CHANGED
@@ -5,64 +5,98 @@ module Cumuli
|
|
5
5
|
attr_reader :lines
|
6
6
|
|
7
7
|
def initialize(list=self.class.list)
|
8
|
-
|
9
|
-
|
8
|
+
lines = list.lines
|
9
|
+
lines.shift # to remove the header
|
10
|
+
@lines = lines.map{|l| Line.new(l) }
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
class Line
|
14
|
+
attr_reader :pid, :ppid, :command
|
15
|
+
|
16
|
+
def initialize(line)
|
17
|
+
elements = line.split
|
18
|
+
@pid = elements.shift.to_i
|
19
|
+
@ppid = elements.shift.to_i
|
20
|
+
@command = elements.join(' ')
|
21
|
+
end
|
22
|
+
|
23
|
+
def <=>(other)
|
24
|
+
self.pid <=> other.pid
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{pid} #{ppid} #{command}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def root_pid
|
33
|
+
root && root.pid
|
16
34
|
end
|
17
35
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
36
|
+
def root
|
37
|
+
foremans.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def foremans
|
41
|
+
lines.select{|l| l.command.match(/foreman: master/) }.sort
|
42
|
+
end
|
43
|
+
|
44
|
+
def int(pids=[root_pids])
|
45
|
+
pids.compact.each do |pid|
|
46
|
+
Process.kill('INT', pid)
|
21
47
|
end
|
22
48
|
end
|
23
49
|
|
24
|
-
def pids
|
25
|
-
|
26
|
-
.
|
27
|
-
|
28
|
-
.map(&:to_i)
|
50
|
+
def kill(pids=[root_pid])
|
51
|
+
pids.compact.each do |pid|
|
52
|
+
Process.kill(9, pid)
|
53
|
+
end
|
29
54
|
end
|
30
55
|
|
31
56
|
def ppid_hash
|
32
57
|
lines
|
33
|
-
.
|
34
|
-
|
35
|
-
|
36
|
-
ppid = line_values[1].to_i
|
37
|
-
hash[ppid] ||= []
|
38
|
-
hash[ppid] << pid
|
58
|
+
.inject({}) do |hash, line|
|
59
|
+
hash[line.ppid] ||= []
|
60
|
+
hash[line.ppid] << line.pid
|
39
61
|
hash
|
40
62
|
end
|
41
63
|
end
|
42
64
|
|
43
|
-
def line(pid)
|
44
|
-
lines.detect{|l| l.
|
65
|
+
def line(pid=root_pid)
|
66
|
+
line = lines.detect{|l| l.pid == pid }
|
67
|
+
line && line.to_s
|
45
68
|
end
|
46
69
|
|
47
|
-
def
|
70
|
+
def family(pid=root_pid)
|
48
71
|
collection = []
|
49
72
|
if kids = children(pid)
|
50
73
|
collection += kids
|
51
74
|
kids.each do |k|
|
52
|
-
collection +=
|
75
|
+
collection += family(k)
|
53
76
|
end
|
54
77
|
end
|
55
78
|
collection
|
56
79
|
end
|
57
80
|
|
58
|
-
def children(pid)
|
81
|
+
def children(pid=root_pid)
|
59
82
|
ppid_hash[pid]
|
60
83
|
end
|
61
84
|
|
62
|
-
def report(pid)
|
63
|
-
|
64
|
-
|
65
|
-
|
85
|
+
def report(pid=root_pid)
|
86
|
+
r = [line(pid).to_s]
|
87
|
+
family(pid).each do |p|
|
88
|
+
l = line(p)
|
89
|
+
r << l.to_s
|
90
|
+
end
|
91
|
+
r.join("\n")
|
92
|
+
end
|
93
|
+
|
94
|
+
def report_all
|
95
|
+
r = []
|
96
|
+
foremans.each do |line|
|
97
|
+
r << report(line.pid)
|
98
|
+
end
|
99
|
+
r.join("\n")
|
66
100
|
end
|
67
101
|
|
68
102
|
def self.list
|
@@ -4,14 +4,43 @@ require_relative "../cli/commander"
|
|
4
4
|
require_relative "../cli/terminal"
|
5
5
|
|
6
6
|
namespace :cumuli do
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
namespace :kill do
|
8
|
+
desc "kill all foreman related processes"
|
9
|
+
task :all do
|
10
|
+
ps = Cumuli::PS.new
|
11
|
+
ps.kill(ps.foremans.map(&:pid))
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "kill the first spawned foreman process"
|
15
|
+
task :root do
|
16
|
+
ps = Cumuli::PS.new
|
17
|
+
ps.kill
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "kill the root process"
|
22
|
+
task :kill => ['cumuli:kill:root']
|
23
|
+
|
24
|
+
namespace :int do
|
25
|
+
desc "interrupt all foreman related processes"
|
26
|
+
task :all do
|
27
|
+
ps = Cumuli::PS.new
|
28
|
+
ps.int(ps.foremans.map(&:pid))
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "kill the first spawned foreman process"
|
32
|
+
task :root do
|
33
|
+
ps = Cumuli::PS.new
|
34
|
+
ps.int
|
35
|
+
end
|
10
36
|
end
|
11
37
|
|
12
|
-
desc "
|
38
|
+
desc "interrupt the root process"
|
39
|
+
task :int => ['cumuli:int:root']
|
40
|
+
|
41
|
+
desc "look at the list of foreman related processes"
|
13
42
|
task :ps do
|
14
|
-
puts Cumuli::PS.new.
|
43
|
+
puts Cumuli::PS.new.report_all
|
15
44
|
end
|
16
45
|
|
17
46
|
desc "run a remote command with the right ruby: rake cumuli:remote ../my_app rake db:migrate"
|
data/lib/cumuli/version.rb
CHANGED
data/spec/app/app_spec.rb
CHANGED
@@ -1,35 +1,46 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Cumuli::App do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
app_dir: app_set_dir
|
11
|
-
}
|
4
|
+
let(:opts) {
|
5
|
+
{
|
6
|
+
env: 'test',
|
7
|
+
wait: false,
|
8
|
+
log_dir: log_dir,
|
9
|
+
app_dir: app_set_dir
|
12
10
|
}
|
13
|
-
|
14
|
-
|
11
|
+
}
|
12
|
+
let(:app) { Cumuli::App.new(opts) }
|
13
|
+
let(:logs) { File.readlines("#{log_dir}/test.log") }
|
15
14
|
|
15
|
+
describe '#start' do
|
16
16
|
before do
|
17
17
|
clear_logs
|
18
18
|
app.start
|
19
|
-
app.
|
19
|
+
app.wait_for_apps
|
20
20
|
end
|
21
21
|
|
22
22
|
after do
|
23
23
|
app.stop
|
24
24
|
end
|
25
25
|
|
26
|
+
it "stores a list of subprocesses" do
|
27
|
+
app.process_pids.size.should == 9
|
28
|
+
end
|
29
|
+
|
26
30
|
it "launches subprocesses with the foreman command" do
|
27
|
-
ps_line = Cumuli::PS.new.
|
28
|
-
ps_line.
|
31
|
+
ps_line = Cumuli::PS.new.foremans
|
32
|
+
ps_line.size.should == 3
|
29
33
|
end
|
30
34
|
|
31
35
|
it "redirects subprocess output to the logs" do
|
32
36
|
logs.detect {|line| line.match(/started with pid/) }
|
33
37
|
end
|
34
38
|
end
|
39
|
+
|
40
|
+
describe '#stop' do
|
41
|
+
before do
|
42
|
+
app.start
|
43
|
+
app.wait_for_apps
|
44
|
+
end
|
45
|
+
end
|
35
46
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cumuli::App::SubApp do
|
4
|
+
let(:sub_app) {
|
5
|
+
Cumuli::App::SubApp.new(
|
6
|
+
"nodified: ../../../bin/cumuli ./noded -p 2323"
|
7
|
+
)
|
8
|
+
}
|
9
|
+
|
10
|
+
describe '#wait_for_start' do
|
11
|
+
it "raises an error if the app in unavailable via TCP socket after timeout" do
|
12
|
+
TCPSocket.should_receive(:new).with('localhost', 2323).and_raise(Exception)
|
13
|
+
expect {
|
14
|
+
sub_app.wait_for_start(0.002)
|
15
|
+
}.to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it "does not raise an error if the TCP socket is available" do
|
19
|
+
TCPSocket.should_receive(:new).with('localhost', 2323)
|
20
|
+
expect {
|
21
|
+
sub_app.wait_for_start(10)
|
22
|
+
}.not_to raise_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/cli/terminal_spec.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
PID PPID COMM ARGS USER
|
2
|
+
1 0 /sbin/launchd /sbin/launchd root
|
3
|
+
12 1 /usr/libexec/kex /usr/libexec/kextd root
|
4
|
+
13 1 /usr/libexec/Use /usr/libexec/UserEventAgent -l System root
|
5
|
+
14 1 /usr/sbin/notify /usr/sbin/notifyd root
|
6
|
+
15 1 /usr/sbin/diskar /usr/sbin/diskarbitrationd root
|
7
|
+
16 1 /usr/libexec/con /usr/libexec/configd root
|
8
|
+
17 1 /usr/sbin/syslog /usr/sbin/syslogd root
|
9
|
+
18 1 /usr/libexec/ope /usr/libexec/opendirectoryd root
|
10
|
+
19 1 /usr/sbin/distno /usr/sbin/distnoted daemon root
|
11
|
+
20 1 /System/Library/ /System/Library/CoreServices/powerd.bundle/powerd root
|
12
|
+
21 1 /System/Library/ /System/Library/Frameworks/CoreServices.framework/Versions/A/Fra root
|
13
|
+
22 1 /usr/sbin/blued /usr/sbin/blued root
|
14
|
+
24 1 /System/Library/ /System/Library/CoreServices/coreservicesd root
|
15
|
+
26 1 /usr/sbin/securi /usr/sbin/securityd -i root
|
16
|
+
34 1 /usr/sbin/ntpd /usr/sbin/ntpd -c /private/etc/ntp-restrict.conf -n -g -p /var/r root
|
17
|
+
38 1 /System/Library/ /System/Library/PrivateFrameworks/MobileDevice.framework/Version _usbmuxd
|
18
|
+
41 1 /usr/libexec/sta /usr/libexec/stackshot -t root
|
19
|
+
44 1 /System/Library/ /System/Library/PrivateFrameworks/GenerationalStorage.framework/ root
|
20
|
+
48 1 /System/Library/ /System/Library/CoreServices/backupd.bundle/Contents/Resources/m root
|
21
|
+
50 1 /System/Library/ /System/Library/Frameworks/CoreServices.framework/Frameworks/Met root
|
22
|
+
51 1 /usr/sbin/mDNSRe /usr/sbin/mDNSResponder -launchd _mdnsresponder
|
23
|
+
53 1 /System/Library/ /System/Library/CoreServices/loginwindow.app/Contents/MacOS/logi socialchorus
|
24
|
+
55 1 /usr/sbin/Kernel /usr/sbin/KernelEventAgent root
|
25
|
+
57 1 /usr/libexec/hid /usr/libexec/hidd root
|
26
|
+
59 1 /sbin/dynamic_pa /sbin/dynamic_pager -F /private/var/vm/swapfile root
|
27
|
+
64 1 autofsd autofsd root
|
28
|
+
86 1 /System/Library/ /System/Library/Frameworks/ApplicationServices.framework/Framewo _windowserver
|
29
|
+
87 1 /usr/sbin/netbio /usr/sbin/netbiosd _netbios
|
30
|
+
95 1 /System/Library/ /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries root
|
31
|
+
107 1 /System/Library/ /System/Library/CoreServices/logind root
|
32
|
+
111 1 /usr/sbin/coreau /usr/sbin/coreaudiod _coreaudiod
|
33
|
+
132 1 /sbin/launchd /sbin/launchd socialchorus
|
34
|
+
135 132 /usr/libexec/Use /usr/libexec/UserEventAgent -l Aqua socialchorus
|
35
|
+
137 132 /usr/sbin/distno /usr/sbin/distnoted agent socialchorus
|
36
|
+
142 132 /Applications/Go /Applications/Google Chrome.app/Contents/MacOS/Google Chrome -ps socialchorus
|
37
|
+
143 132 /usr/sbin/pboard /usr/sbin/pboard socialchorus
|
38
|
+
145 132 /Applications/Ut /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -ps socialchorus
|
39
|
+
151 132 /System/Library/ /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock socialchorus
|
40
|
+
152 132 /System/Library/ /System/Library/CoreServices/talagent socialchorus
|
41
|
+
153 132 /System/Library/ /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/S socialchorus
|
42
|
+
154 132 /System/Library/ /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder socialchorus
|
43
|
+
161 132 /System/Library/ /System/Library/Frameworks/ApplicationServices.framework/Framewo socialchorus
|
44
|
+
167 1 com.apple.dock.e com.apple.dock.extra socialchorus
|
45
|
+
170 132 /System/Library/ /System/Library/Image Capture/Support/Image Capture Extension.ap socialchorus
|
46
|
+
197 1 /usr/sbin/fileco /usr/sbin/filecoordinationd root
|
47
|
+
201 132 /System/Library/ /System/Library/Services/AppleSpell.service/Contents/MacOS/Apple socialchorus
|
48
|
+
206 132 /Users/socialcho /Users/socialchorus/Library/Application Support/1Password/Agent/ socialchorus
|
49
|
+
244 132 /usr/libexec/war /usr/libexec/warmd_agent socialchorus
|
50
|
+
251 132 /System/Library/ /System/Library/PrivateFrameworks/IMCore.framework/imagent.app/C socialchorus
|
51
|
+
257 132 /usr/local/opt/r /usr/local/opt/redis/bin/redis-server /usr/local/etc/redis.conf socialchorus
|
52
|
+
258 132 /usr/local/Cella /usr/local/Cellar/erlang/R15B03-1/lib/erlang/erts-5.9.3.1/bin/be socialchorus
|
53
|
+
259 132 /usr/local/opt/p /usr/local/opt/postgresql/bin/postgres -D /usr/local/var/postgre socialchorus
|
54
|
+
279 132 /System/Library/ /System/Library/CoreServices/Menu Extras/TextInput.menu/Contents socialchorus
|
55
|
+
280 132 /Applications/iT /Applications/iTunes.app/Contents/MacOS/iTunesHelper.app/Content socialchorus
|
56
|
+
287 1 /usr/local/Cella /usr/local/Cellar/erlang/R15B03-1/lib/erlang/erts-5.9.3.1/bin/ep socialchorus
|
57
|
+
294 259 postgres: checkp postgres: checkpointer process socialchorus
|
58
|
+
295 259 postgres: writer postgres: writer process socialchorus
|
59
|
+
296 259 postgres: wal wr postgres: wal writer process socialchorus
|
60
|
+
297 259 postgres: autova postgres: autovacuum launcher process socialchorus
|
61
|
+
298 259 postgres: stats postgres: stats collector process socialchorus
|
62
|
+
314 258 inet_gethost inet_gethost 4 socialchorus
|
63
|
+
315 314 inet_gethost inet_gethost 4 socialchorus
|
64
|
+
476 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
65
|
+
480 1 /System/Library/ /System/Library/Frameworks/CoreMediaIO.framework/Resources/VDC.p root
|
66
|
+
635 132 /Applications/Si /Applications/SizeUp.app/Contents/MacOS/SizeUp -psn_0_196656 socialchorus
|
67
|
+
636 132 /System/Library/ /System/Library/CoreServices/System Events.app/Contents/MacOS/Sy socialchorus
|
68
|
+
1181 132 /usr/bin/ssh-age /usr/bin/ssh-agent -l socialchorus
|
69
|
+
3407 132 /System/Library/ /System/Library/Frameworks/CoreServices.framework/Frameworks/Met socialchorus
|
70
|
+
9711 1 /System/Library/ /System/Library/CoreServices/backupd.bundle/Contents/Resources/m root
|
71
|
+
12532 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
72
|
+
13700 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
73
|
+
18651 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
74
|
+
21361 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
75
|
+
24124 1 /sbin/launchd /sbin/launchd _spotlight
|
76
|
+
24126 24124 /System/Library/ /System/Library/Frameworks/CoreServices.framework/Frameworks/Met _spotlight
|
77
|
+
24127 24124 /usr/sbin/distno /usr/sbin/distnoted agent _spotlight
|
78
|
+
31310 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
79
|
+
33165 132 /System/Library/ /System/Library/Frameworks/InputMethodKit.framework/Resources/im socialchorus
|
80
|
+
39847 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
81
|
+
42063 132 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
82
|
+
43458 132 /usr/libexec/lsb /usr/libexec/lsboxd socialchorus
|
83
|
+
44874 132 /Applications/1P /Applications/1Password.app/Contents/MacOS/1Password -psn_0_5612 socialchorus
|
84
|
+
55087 142 /Applications/Go /Applications/Google Chrome.app/Contents/Versions/27.0.1453.116/ socialchorus
|
85
|
+
62807 132 /Applications/Te /Applications/TextMate.app/Contents/MacOS/TextMate -psn_0_268763 socialchorus
|
86
|
+
68282 132 /Applications/CC /Applications/CCMenu.app/Contents/MacOS/CCMenu -psn_0_2941646 socialchorus
|
87
|
+
71315 1 /usr/local/Cella /usr/local/Cellar/macvim/7.3-66/MacVim.app/Contents/MacOS/MacVim socialchorus
|
88
|
+
73066 151 /System/Library/ /System/Library/CoreServices/Dock.app/Contents/Resources/Dashboa socialchorus
|
89
|
+
86518 1 /usr/local/Cella /usr/local/Cellar/macvim/7.3-66/MacVim.app/Contents/MacOS/Vim -f socialchorus
|
90
|
+
87838 1 /usr/libexec/tas /usr/libexec/taskgated -p -s root
|
91
|
+
45925 145 login login -pf socialchorus root
|
92
|
+
45926 45925 -bash -bash socialchorus
|
93
|
+
57983 145 login login -pf socialchorus root
|
94
|
+
57984 57983 -bash -bash socialchorus
|
95
|
+
28280 1 foreman: master foreman: master socialchorus
|
96
|
+
28282 28280 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus
|
97
|
+
28283 28280 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@nimbus exec for socialchorus
|
98
|
+
28320 28282 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus
|
99
|
+
28321 28283 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@nimbus exec for socialchorus
|
100
|
+
28322 28320 foreman: master foreman: master socialchorus
|
101
|
+
28323 28321 foreman: master foreman: master socialchorus
|
102
|
+
28550 28322 ruby ruby loop.rb socialchorus
|
103
|
+
28551 28322 ruby ruby half_loop.rb socialchorus
|
104
|
+
28552 28323 node node nodified.js socialchorus
|
105
|
+
28562 1 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus
|
106
|
+
28564 1 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus
|
107
|
+
28638 28562 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus
|
108
|
+
28639 28638 foreman: master foreman: master socialchorus
|
109
|
+
28657 28564 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus
|
110
|
+
28659 28657 foreman: master foreman: master socialchorus
|
111
|
+
29102 28639 ruby ruby loop.rb socialchorus
|
112
|
+
29103 28639 ruby ruby half_loop.rb socialchorus
|
113
|
+
29106 28659 ruby ruby loop.rb socialchorus
|
114
|
+
29107 28659 ruby ruby half_loop.rb socialchorus
|
115
|
+
29142 69064 ps ps axo pid,ppid,comm,args,user root
|
116
|
+
29143 69064 mate mate socialchorus
|
117
|
+
69063 145 login login -pf socialchorus root
|
118
|
+
69064 69063 -bash -bash socialchorus
|
data/spec/ps_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cumuli::PS do
|
4
|
+
let(:ps_data) { File.read(File.dirname(__FILE__) + "/fixtures/ps.txt") }
|
5
|
+
let(:ps) { Cumuli::PS.new(ps_data) }
|
6
|
+
let(:pid) { 28280 }
|
7
|
+
|
8
|
+
describe '#root' do
|
9
|
+
it "should find the lead foreman process" do
|
10
|
+
ps.root_pid.should == pid
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#family' do
|
15
|
+
let(:family) { ps.family(pid) }
|
16
|
+
let(:children) { ps.children(pid) }
|
17
|
+
|
18
|
+
it "should not include the passed in pid" do
|
19
|
+
family.should_not include(pid)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "includes direct children" do
|
23
|
+
family.should include(*children)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "includes grandchildren" do
|
27
|
+
children.each do |child|
|
28
|
+
family.should include(*ps.children(child))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#report' do
|
34
|
+
it "prints all the lines descended from the root process" do
|
35
|
+
ps.report.should == report_text
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,3 @@
|
|
1
|
+
def report_text
|
2
|
+
"28280 1 foreman: master foreman: master socialchorus\n28282 28280 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus\n28283 28280 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@nimbus exec for socialchorus\n28320 28282 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@cumuli exec for socialchorus\n28322 28320 foreman: master foreman: master socialchorus\n28550 28322 ruby ruby loop.rb socialchorus\n28551 28322 ruby ruby half_loop.rb socialchorus\n28321 28283 bash bash /Users/socialchorus/.rvm/bin/rvm ruby-2.0.0@nimbus exec for socialchorus\n28323 28321 foreman: master foreman: master socialchorus\n28552 28323 node node nodified.js socialchorus"
|
3
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cumuli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SocialChorus
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2013-07-
|
15
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: foreman
|
@@ -102,16 +102,16 @@ files:
|
|
102
102
|
- bin/cumuli
|
103
103
|
- cumuli.gemspec
|
104
104
|
- features/fixtures/test.log
|
105
|
-
- features/
|
105
|
+
- features/graceful_exits.feature
|
106
106
|
- features/step_definitions/app_steps.rb
|
107
107
|
- features/support/env.rb
|
108
|
-
- features/support/io_capture.rb
|
109
108
|
- lib/cumuli.rb
|
110
109
|
- lib/cumuli/app.rb
|
111
110
|
- lib/cumuli/app/app.rb
|
112
|
-
- lib/cumuli/app/foreman_process.rb
|
113
111
|
- lib/cumuli/app/procs.rb
|
112
|
+
- lib/cumuli/app/spawner.rb
|
114
113
|
- lib/cumuli/app/stdout_logger.rb
|
114
|
+
- lib/cumuli/app/sub_app.rb
|
115
115
|
- lib/cumuli/cli.rb
|
116
116
|
- lib/cumuli/cli/args.rb
|
117
117
|
- lib/cumuli/cli/cli.rb
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- lib/cumuli/waiter.rb
|
127
127
|
- spec/app/app_spec.rb
|
128
128
|
- spec/app/procs_spec.rb
|
129
|
+
- spec/app/sub_app_spec.rb
|
129
130
|
- spec/cli/args_spec.rb
|
130
131
|
- spec/cli/commander_spec.rb
|
131
132
|
- spec/cli/remote_command_spec.rb
|
@@ -137,10 +138,13 @@ files:
|
|
137
138
|
- spec/fixtures/app_set/loopy/loop.rb
|
138
139
|
- spec/fixtures/app_set/noded/.rvmrc
|
139
140
|
- spec/fixtures/app_set/noded/nodified.js
|
141
|
+
- spec/fixtures/ps.txt
|
142
|
+
- spec/ps_spec.rb
|
140
143
|
- spec/spec_helper.rb
|
141
144
|
- spec/support/functional_helpers.rb
|
142
145
|
- spec/support/log_helpers.rb
|
143
146
|
- spec/support/mock_apps.rb
|
147
|
+
- spec/support/report.rb
|
144
148
|
- spec/waiter_spec.rb
|
145
149
|
homepage: http://github.com/socialchorus/cumuli
|
146
150
|
licenses:
|
@@ -168,12 +172,12 @@ specification_version: 4
|
|
168
172
|
summary: Cumuli makes SOA on Heroku easier by delegating to Foreman in a Procfile
|
169
173
|
test_files:
|
170
174
|
- features/fixtures/test.log
|
171
|
-
- features/
|
175
|
+
- features/graceful_exits.feature
|
172
176
|
- features/step_definitions/app_steps.rb
|
173
177
|
- features/support/env.rb
|
174
|
-
- features/support/io_capture.rb
|
175
178
|
- spec/app/app_spec.rb
|
176
179
|
- spec/app/procs_spec.rb
|
180
|
+
- spec/app/sub_app_spec.rb
|
177
181
|
- spec/cli/args_spec.rb
|
178
182
|
- spec/cli/commander_spec.rb
|
179
183
|
- spec/cli/remote_command_spec.rb
|
@@ -185,8 +189,11 @@ test_files:
|
|
185
189
|
- spec/fixtures/app_set/loopy/loop.rb
|
186
190
|
- spec/fixtures/app_set/noded/.rvmrc
|
187
191
|
- spec/fixtures/app_set/noded/nodified.js
|
192
|
+
- spec/fixtures/ps.txt
|
193
|
+
- spec/ps_spec.rb
|
188
194
|
- spec/spec_helper.rb
|
189
195
|
- spec/support/functional_helpers.rb
|
190
196
|
- spec/support/log_helpers.rb
|
191
197
|
- spec/support/mock_apps.rb
|
198
|
+
- spec/support/report.rb
|
192
199
|
- spec/waiter_spec.rb
|
@@ -1,14 +0,0 @@
|
|
1
|
-
Feature: Cumuli exits the app gracefully
|
2
|
-
In order to use Cumuli to test in an integration way, a suite of apps and services
|
3
|
-
As a developer with a SOA stack
|
4
|
-
I want cucumber to exit with a good success code
|
5
|
-
|
6
|
-
Background:
|
7
|
-
Given the app suite is loaded
|
8
|
-
|
9
|
-
Scenario: App is stopped in a cucumber step
|
10
|
-
When I shutdown the app suite
|
11
|
-
Then the processes should not be running
|
12
|
-
And I should see that the rake was not aborted
|
13
|
-
|
14
|
-
|