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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dfd75adb4172768fa85d3dc9201b7e25a8d478bb
4
- data.tar.gz: 6f5bf7cc32f829eca21c9811c7ec3c5ff6765ef4
3
+ metadata.gz: e61d96a9203fd5fed28980e2d3817ab7afcdfd5a
4
+ data.tar.gz: 0721f35292c999e27c9e7ad25904c93b2d59f353
5
5
  SHA512:
6
- metadata.gz: 9d867f58b1a5a5471b6c699bd9d7e899a9da273fe063c2140ae22c0872ae56f6fa11c5fb26ff4e84db828617595186096d6fc46cd1b5779bb432fb76309a155e
7
- data.tar.gz: 1bfb5e52e75fc552ad015803e5ce9b1472c351dcdbd292852281fc9e2f8ce02025bc799554d8074ac56a590d80460d571a5f2d3883e6ce2b0e9a56bf317fedd7
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
- When(/^I shutdown the app suite$/) do
13
- @trapped = false
13
+ Given(/^the current thread is listening for signals$/) do
14
+ @signals = []
14
15
 
15
- trap('INT') do
16
- @trapped = true
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
- @trapped.should == false
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
- pses = Cumuli::PS.new.children(@pid)
29
- pses.nil?
39
+ report = Cumuli::PS.new.report(@pid)
40
+ report.empty?
30
41
  end
31
42
  end
32
43
 
@@ -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
- @termial ||= ForemanProcess.new(env, log_dir)
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.pid
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 app_ports
55
- apps.map.values.compact
56
- end
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 wait_for_app(port)
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
- Waiter.new("Application on port #{port} unavailable after #{timeout} seconds")
70
- .wait_until(timeout) { open_socket(port) }
71
- logger.print "Application on #{port} available"
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
@@ -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 ForemanProcess
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
- "HEROKU_ENV=#{env} RAILS_ENV=#{env} foreman start"
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
- listen_for_signals
28
- $stdout.reopen(log_file)
29
- exec(command)
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
- pids = PS.new.tree(pid)
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
@@ -1,5 +1,6 @@
1
1
  require "cumuli/app/app"
2
- require "cumuli/app/foreman_process"
2
+ require "cumuli/app/spawner"
3
3
  require "cumuli/app/stdout_logger"
4
4
  require "cumuli/app/procs"
5
+ require "cumuli/app/sub_app"
5
6
 
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
- @lines = list.lines
9
- @lines.shift # to remove header line
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
- def matching(regex = REGEX)
13
- @matching ||= lines
14
- .select{|l| l.match(regex)}
15
- .select{|l| !l.match(/^#{Process.pid} /) }
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 kill
19
- pids.each do |pid|
20
- Process.kill("SIGINT", pid)
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(regex = REGEX)
25
- matching(regex)
26
- .map(&:split)
27
- .map(&:first)
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
- .map(&:split)
34
- .inject({}) do |hash, line_values|
35
- pid = line_values[0].to_i
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.match(/^#{pid} /)}
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 tree(pid)
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 += tree(k)
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
- tree(pid)
64
- puts "\n"
65
- puts matching
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
- desc "kill the processes showing up in the nimbus:ps task"
8
- task :kill do
9
- Cumuli::PS.new.kill
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 "look at processes likely related to cumuli"
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.matching
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"
@@ -1,3 +1,3 @@
1
1
  module Cumuli
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.4"
3
3
  end
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
- describe '#start' do
5
- let(:opts) {
6
- {
7
- env: 'test',
8
- wait: false,
9
- log_dir: log_dir,
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
- let(:app) { Cumuli::App.new(opts) }
14
- let(:logs) { File.readlines("#{log_dir}/test.log") }
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.wait_for_app(2323)
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.matching.detect{|line| line.match(/foreman: master/) }
28
- ps_line.should_not be_nil
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
@@ -12,6 +12,7 @@ describe Cumuli::CLI::Terminal do
12
12
  end
13
13
  end
14
14
 
15
+ # TODO: this generates lots of noise when it is killed
15
16
  it "spawns a new thread that runs the command" do
16
17
  preserving_env do
17
18
  pid = fork do
@@ -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.2
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-18 00:00:00.000000000 Z
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/graceful_exit.feature
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/graceful_exit.feature
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
-
@@ -1,11 +0,0 @@
1
- def capturing(stream=:stdout)
2
- stream = $stdout
3
- old_stream = stream.dup
4
- new_steam = StringIO.new
5
- stream = new_steam
6
- yield
7
- new_steam
8
- ensure
9
- stream = old_stream
10
- new_steam
11
- end