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 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