cumuli 0.3.2 → 0.3.4
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.
- 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
|
-
|