zeusd 0.0.1 → 0.1.0

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.
data/.gitignore CHANGED
@@ -15,3 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+
19
+ *.log
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in zeusd.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'simplecov', :require => false
7
+
6
8
  group :tool do
7
9
  gem "guard-rspec"
8
10
  gem "pry"
data/Guardfile CHANGED
@@ -1,7 +1,6 @@
1
1
  guard :rspec, :failed_mode => :none do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
- watch(%r{^lib/zeusd/(.+)\.rb$}) { |m| "spec/lib/zeusd/#{m[1]}_spec.rb" }
3
+ watch(%r{^lib/zeusd/(.+)\.rb$}) { |m| "spec/zeusd/#{m[1]}_spec.rb" }
5
4
  watch('spec/spec_helper.rb') { "spec" }
6
5
  end
7
6
 
data/README.md CHANGED
@@ -1,48 +1,52 @@
1
- # Zeusd
1
+ # Zeusd [![Gem Version](https://badge.fury.io/rb/zeusd.png)](http://badge.fury.io/rb/zeusd) [![Build Status](https://travis-ci.org/veloper/zeusd.png?branch=master)](https://travis-ci.org/veloper/zeusd) [![Code Climate](https://codeclimate.com/github/veloper/zeusd.png)](https://codeclimate.com/github/veloper/zeusd)
2
2
 
3
- Run the Zeud Gem as a daemon
3
+ *Run Zeus as a daemon.*
4
4
 
5
- [![Build Status](https://travis-ci.org/veloper/zeusd.png?branch=master)](https://travis-ci.org/veloper/zeusd) [![Code Climate](https://codeclimate.com/github/veloper/zeusd.png)](https://codeclimate.com/github/veloper/zeusd)
5
+ ## Introduction
6
6
 
7
+ Zeus**d** lets you work with the [Zeus Gem](https://github.com/burke/zeus) like it's a daemon -- allowing greater control and easier scripting
7
8
 
8
- ## Installation
9
-
10
- Add this line to your application's Gemfile:
11
-
12
- gem 'zeusd'
9
+ ### Primary Commands
13
10
 
14
- And then execute:
15
-
16
- $ bundle
17
-
18
- Or install it yourself as:
11
+ ```
12
+ $ zeusd start [--cwd=/path/to/rails/root]
13
+ [--block | -b]
14
+ [--verbose | -v]
19
15
 
20
- $ gem install zeusd
16
+ $ zeusd restart [--cwd=/path/to/rails/root]
17
+ [--block | -b]
18
+ [--verbose | -v]
21
19
 
22
- ## Usage
20
+ $ zeusd stop [--cwd=/path/to/rails/root]
21
+ [--verbose | -v]
22
+ ```
23
23
 
24
- ### Commands
24
+ ### Utility Commands
25
25
 
26
26
  ```
27
- zeusd start [--block]
28
- zeusd stop
29
- zeusd restart
27
+ $ zeusd tail [--cwd=/path/to/rails/root]
28
+ [--follow | -f]
30
29
  ```
31
30
 
32
- ### Global Flags
33
- * `--cwd=current/work/directory/of/rails/app` or alias `-d`
34
- * `--verbose` or `-v`
31
+ ## Installation
35
32
 
33
+ ```
34
+ $ gem install zeusd
35
+ ```
36
36
 
37
37
  ## Contributing
38
38
 
39
39
  1. Fork it
40
40
  2. Create your feature branch (`git checkout -b my-new-feature`)
41
- 3. Write and test your changes
41
+ 3. Write passing specs that test your changes
42
42
  3. Commit your changes and specs (`git commit -am 'Add some feature'`)
43
43
  4. Push to the branch (`git push origin my-new-feature`)
44
44
  5. Create new Pull Request
45
45
 
46
+ ## Author
47
+
48
+ [Daniel Doezema](http://dan.doezema.com)
49
+
46
50
  ## License
47
51
 
48
52
  * Zeusd is released under the New BSD license. http://dan.doezema.com/licenses/new-bsd/
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rspec/core/rake_task'
3
3
 
4
- RSpec::Core::RakeTask.new('spec')
4
+ RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- # If you want to make this the default task
7
6
  task :default => :spec
data/bin/zeusd CHANGED
@@ -4,37 +4,35 @@ require "zeusd"
4
4
  class ZeusdCLI < Thor
5
5
  class_option :verbose, :type => :boolean, :aliases => :v
6
6
  class_option :block, :type => :boolean, :aliases => :b
7
- class_option :cwd, :type => :string, :aliases => :d
8
- class_option :log, :type => :string, :aliases => :l
7
+ class_option :cwd, :type => :string
9
8
 
10
- desc "start", "."
9
+ desc "start", "Start the daemon."
11
10
  def start
12
- daemon.start! :block => options[:block]
11
+ daemon.start!(:block => options[:block])
13
12
  end
14
13
 
15
- desc "restart", "."
14
+ desc "restart", "Restart the daemon."
16
15
  def restart
17
- stop
18
- start
16
+ daemon.restart!(:block => options[:block])
19
17
  end
20
18
 
21
- desc "stop", "."
19
+ desc "stop", "Stop the daemon."
22
20
  def stop
23
21
  daemon.stop!
24
22
  end
25
23
 
26
- desc "status", "."
27
- def status
28
- # Zeusd::Daemon.new(options).stop!
24
+ desc "tail", "Tail the daemon's log."
25
+ method_option :follow, :type => :boolean, :aliases => :f
26
+ def tail
27
+ cmd = "tail#{options[:follow] ? ' -f' : ''} -n 25 #{daemon.log_file.to_path}"
28
+ puts "\n\n[Zeusd] exec(#{cmd})\n\n"
29
+ exec(cmd)
29
30
  end
30
31
 
31
32
  protected
32
33
 
33
34
  def daemon
34
- Zeusd::Daemon.new(
35
- :verbose => options[:verbose],
36
- :cwd => options[:cwd]
37
- )
35
+ Zeusd::Daemon.new(:verbose => options[:verbose], :cwd => options[:cwd])
38
36
  end
39
37
 
40
38
  end
data/lib/zeusd.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'zeusd/version'
2
2
  require 'zeusd/process'
3
- require 'zeusd/state_interpreter'
3
+ require 'zeusd/interpreter'
4
4
  require 'zeusd/daemon'
5
5
 
6
6
  module Zeusd
data/lib/zeusd/daemon.rb CHANGED
@@ -1,78 +1,113 @@
1
1
  require 'thread'
2
2
  require 'childprocess'
3
3
  require 'pathname'
4
+ require 'hooks'
4
5
 
5
6
  module Zeusd
6
7
  class DaemonException < StandardError; end
7
8
 
8
9
  class Daemon
9
- attr_reader :cwd, :verbose
10
- attr_reader :queue
11
- attr_reader :state
12
- attr_reader :child_process, :reader, :writer
10
+ include Hooks
11
+ define_hooks :after_output, :after_start!, :after_stop!, :after_start_process!
13
12
 
14
- def initialize(options = {})
15
- @cwd = Pathname.new(options.fetch(:cwd, Dir.pwd)).realpath
16
- @verbose = options.fetch(:verbose, false)
17
- @queue = Queue.new
18
- @state = StateInterpreter.new
19
- on_update(&method(:puts)) if verbose
20
- end
13
+ after_start! { log(:start) }
14
+ after_stop! { log(:stop) }
15
+ after_output {|x| log(x, :zeus) }
21
16
 
22
- def stop!
23
- processes = process ? Array([process.descendants, process]).flatten : []
24
- if processes.any?
25
- Zeusd::Process.kill!(processes.map(&:pid))
26
- end
17
+ after_start_process! :ensure_log_worker
18
+
19
+ after_stop! do
27
20
  (socket_file.delete rescue nil) if socket_file.exist?
28
- if (alive_processes = processes).all?(&:alive?)
29
- raise DaemonException, "Unable to KILL processes: " + alive_processes.join(', ')
30
- else
31
- @process = nil
32
- true
33
- end
21
+ @process = nil
22
+ end
23
+
24
+ after_output do |output|
25
+ interpreter.translate(output)
26
+ puts(output) if verbose?
27
+ end
28
+
29
+ attr_reader :cwd, :verbose, :log_file, :log_queue, :interpreter, :child_process
30
+
31
+ def initialize(options = {})
32
+ @cwd = Pathname.new(options.fetch(:cwd, Dir.pwd)).realpath
33
+ @verbose = options.fetch(:verbose, false)
34
+ @interpreter = Interpreter.new
34
35
  end
35
36
 
36
37
  def start!(options = {})
37
- @process = Zeusd::Process.find(start_child_process!.pid)
38
+ @process = Zeusd::Process.find(start_process!.pid)
38
39
 
39
40
  if options.fetch(:block, false)
40
- loop do
41
- if loaded?
42
- puts state.last_status
43
- break
44
- end
45
- sleep(0.1)
46
- end
41
+ sleep(0.1) until loaded?
47
42
  end
48
43
 
49
- process
44
+ self
45
+ ensure
46
+ run_hook :after_start!
50
47
  end
51
48
 
52
- def process
53
- @process ||= Process.all.find do |p|
54
- !!p.command[/zeus.*start$/] && p.cwd == cwd
49
+ def restart!(options = {})
50
+ stop!.start!(options)
51
+ end
52
+
53
+ def stop!
54
+ return self unless process
55
+
56
+ # Kill Pids and Wait
57
+ process.kill!(:recursive => true, :wait => true)
58
+
59
+ # Check for remaining processes
60
+ if[process, process.descendants].flatten.select(&:alive?).any?
61
+ raise DaemonException, "Unable to KILL processes: " + alive_processes.join(', ')
55
62
  end
63
+
64
+ self
65
+ ensure
66
+ run_hook :after_stop!
67
+ end
68
+
69
+ def process
70
+ @process ||= Process.all.find {|p| !!p.command[/zeus.*start$/] && p.cwd == cwd }
56
71
  end
57
72
 
58
73
  def loaded?
59
- process.descendants.all?(&:asleep?)
74
+ interpreter.complete?
60
75
  end
61
76
 
62
- def on_update(&block)
63
- @on_update = block if block_given?
64
- @on_update
77
+
78
+ def log_file
79
+ cwd.join('log/zeusd.log')
65
80
  end
66
81
 
67
82
  def socket_file
68
83
  cwd.join('.zeus.sock')
69
84
  end
70
85
 
86
+ def verbose?
87
+ !!verbose
88
+ end
89
+
71
90
  protected
72
91
 
73
- def start_child_process!
92
+ def log(entry, type = :zeusd)
93
+ log_queue << "<#{type.to_s} utc='#{Time.now.utc}'>#{entry}</#{type.to_s}>\n"
94
+ end
95
+
96
+ def log_queue
97
+ @log_queue ||= Queue.new
98
+ end
99
+
100
+ def ensure_log_worker
101
+ @log_worker ||= Thread.new do
102
+ while value = log_queue.shift
103
+ log_file.open("a+") {|f| f.write(value) }
104
+ end
105
+ end
106
+ end
107
+
108
+ def start_process!
74
109
  @reader, @writer = IO.pipe
75
- @child_process = ChildProcess.build("zeus", "start")
110
+ @child_process = ChildProcess.build("zeus", "start")
76
111
  @child_process.environment["BUNDLE_GEMFILE"] = cwd.join("Gemfile").to_path
77
112
  @child_process.io.stdout = @child_process.io.stderr = @writer
78
113
  @child_process.cwd = cwd.to_path
@@ -80,22 +115,15 @@ module Zeusd
80
115
  @child_process.start
81
116
  @writer.close
82
117
 
83
- Thread.new do
84
- while (buffer = (reader.readpartial(10000) rescue nil)) do
85
- state << buffer
86
- queue << buffer
87
- end
88
- end
118
+ run_hook :after_start_process!
89
119
 
90
- if on_update.is_a?(Proc)
91
- Thread.new do
92
- while output = queue.pop
93
- on_update.call(output)
94
- end
120
+ Thread.new do
121
+ while (buffer = (@reader.readpartial(10000) rescue nil)) do
122
+ run_hook :after_output, buffer
95
123
  end
96
124
  end
97
125
 
98
- sleep(0.1) until state.commands.any?
126
+ sleep 0.1 until interpreter.commands.any?
99
127
 
100
128
  @child_process
101
129
  end
@@ -1,23 +1,22 @@
1
- require 'stringio'
2
1
  module Zeusd
3
- class StateInterpreter
2
+ class Interpreter
4
3
  STATES = %w[ready crashed running connecting waiting]
5
4
 
6
5
  attr_reader :lines
7
6
  attr_reader :state_colors, :commands, :errors
7
+ attr_reader :last_status
8
8
 
9
9
  def initialize(*args)
10
10
  @state_colors = Hash[STATES.zip([nil]*STATES.length)]
11
11
  @commands = {}
12
12
  @errors = []
13
13
  @lines = []
14
- super(*args)
15
14
  end
16
15
 
17
- def <<(input)
18
- input.split("\n").map{|x| Line.new(x) }.each do |line|
16
+ def translate(zeus_output)
17
+ zeus_output.split("\n").map{|x| Line.new(x) }.each do |line|
19
18
  # State Colors
20
- if @state_colors.values.any?(&:nil?) && line.legend?
19
+ if @state_colors.values.any?(&:nil?) && line.state_legend?
21
20
  STATES.each do |state|
22
21
  state_colors[state] = line.color_of(state)
23
22
  end
@@ -32,15 +31,22 @@ module Zeusd
32
31
  # Add Line
33
32
  @lines << line
34
33
  end
34
+
35
+ # Garbage Collection
36
+ if @lines.length > 100
37
+ @lines = @lines.last(100)
38
+ end
35
39
  end
36
40
 
37
- def is_complete?
41
+ def complete?
38
42
  return false if errors.any?
39
- return true if commands.all? {|command, status| %[crashed running].include?(status)}
43
+ return true if commands.all? {|command, status| %[crashed ready].include?(status)}
40
44
  false
41
45
  end
42
46
 
43
- def last_status
47
+
48
+
49
+ def last_update
44
50
  @lines[@lines.rindex(&:update?)..-1].join("\n").to_s
45
51
  end
46
52
 
@@ -55,12 +61,12 @@ module Zeusd
55
61
  end
56
62
 
57
63
  def command
58
- if match = self.match(/^(\e.*?)zeus\s(.*?)(\s|\e)/)
59
- { :name => match[2], :color => match[1] }
64
+ if @match ||= self.match(/^(\e.*?)zeus\s(.*?)(\s|\e)/)
65
+ { :name => @match[2], :color => @match[1] }
60
66
  end
61
67
  end
62
68
 
63
- def legend?
69
+ def state_legend?
64
70
  STATES.all?{|state| !!self[state]}
65
71
  end
66
72
 
data/lib/zeusd/process.rb CHANGED
@@ -7,11 +7,15 @@ module Zeusd
7
7
  "stat" => ->(x){x.to_s},
8
8
  "command" => ->(x){x.to_s}
9
9
  }
10
- attr_accessor :attributes
11
- attr_accessor :children
10
+ attr_accessor :attributes, :children
12
11
 
13
- def initialize(attributes = {})
14
- self.attributes = attributes
12
+ def initialize(attributes_or_pid)
13
+ if attributes_or_pid.is_a? Hash
14
+ self.attributes = attributes_or_pid
15
+ else
16
+ self.attributes = {"pid" => attributes_or_pid.to_i}
17
+ reload!
18
+ end
15
19
  end
16
20
 
17
21
  def self.ps(options = {})
@@ -35,17 +39,10 @@ module Zeusd
35
39
  end
36
40
  end
37
41
 
38
- # Note: Non-chinable, AND joined, Proc allowed for value
39
- # {"attr" => value}
40
42
  def self.where(criteria, options = {})
41
43
  all(options).select do |process|
42
44
  criteria.all? do |key, value|
43
- case value
44
- when Array then value.include?(process.send(key))
45
- when Proc then !!value.call(process)
46
- else
47
- process.send(key) == value
48
- end
45
+ process.send(key) == value
49
46
  end
50
47
  end
51
48
  end
@@ -56,12 +53,24 @@ module Zeusd
56
53
  end
57
54
  end
58
55
 
56
+ def self.wait(pids = [])
57
+ pids = Array(pids).map(&:to_s)
58
+ loop do
59
+ break if (self.ps.map{|x| x["pid"]} & pids).length.zero?
60
+ sleep(0.1)
61
+ end
62
+ end
63
+
59
64
  def self.kill!(pids, options = {})
60
- signal = options.fetch(:signal, "INT")
61
- pids = Array(pids).map(&:to_i).select{|x| x > 0}
62
- if pids.any?
63
- system("kill -#{signal} #{pids.join(' ')}")
64
- $?.success?
65
+ pids = Array(pids).map(&:to_i).select{|x| x > 0}
66
+ processes = pids.map{|pid| self.new(pid)}
67
+ signal = options.fetch(:signal, "TERM")
68
+ wait = options.fetch(:wait, false)
69
+ return false if processes.any?(&:dead?)
70
+
71
+ if system("kill -#{signal} #{processes.map(&:pid).join(' ')}")
72
+ self.wait(pids) if wait
73
+ true
65
74
  else
66
75
  false
67
76
  end
@@ -69,7 +78,7 @@ module Zeusd
69
78
 
70
79
  def reload!
71
80
  self.attributes = self.class.ps(:pid => pid).first || {}
72
- @children = nil
81
+ @children = nil
73
82
  !attributes.empty?
74
83
  end
75
84
 
@@ -112,8 +121,14 @@ module Zeusd
112
121
  end
113
122
 
114
123
  def kill!(options = {})
115
- self.class.kill!(pid, options)
116
- reload!
124
+ return false if dead?
125
+ opts = options.dup
126
+
127
+ pids = [pid].tap do |x|
128
+ x.concat(descendants.map(&:pid)) if !!opts.delete(:recursive)
129
+ end
130
+
131
+ self.class.kill!(pids, opts)
117
132
  end
118
133
 
119
134
  def descendants(options = {})
@@ -123,11 +138,7 @@ module Zeusd
123
138
  end
124
139
 
125
140
  def children(options = {})
126
- @children = self.class.where("ppid" => pid).tap do |processes|
127
- if options.fetch(:recursive, false)
128
- processes.each{|p| p.children(options)}
129
- end
130
- end
141
+ @children = self.class.where("ppid" => pid)
131
142
  end
132
143
 
133
144
  def attributes=(hash)
data/lib/zeusd/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Zeusd
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
- require 'bundler/setup'
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
2
4
  require 'zeusd'
3
5
 
4
6
  DUMMY_APP_PATH = File.expand_path('../dummy', __FILE__)
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Signal.trap('USR1') do
4
+ sleep (ARGV[1] || 1).to_f
5
+ exit 0
6
+ end
7
+
8
+ stop_time = Time.now.to_f + (ARGV[0] || 2).to_f
9
+
10
+ sleep 0.01 until Time.now.to_i.to_f >= stop_time
@@ -3,23 +3,51 @@ require 'spec_helper'
3
3
  describe Zeusd::Daemon do
4
4
  let(:daemon) { Zeusd::Daemon.new(:cwd => DUMMY_APP_PATH) }
5
5
  after(:each) { daemon.stop! }
6
+
6
7
  describe ".start!" do
8
+ subject { daemon.start!(:verbose => true) }
9
+ it { should be daemon }
10
+ it { should_not be_loaded }
7
11
 
8
- context "blocking" do
12
+ describe ":block option" do
9
13
  subject { daemon.start!(:block => true) }
10
- it { should be_a Zeusd::Process }
14
+ it { should be_loaded }
15
+ end
16
+ end
11
17
 
12
- it "should be a zeus start process" do
13
- process = daemon.start!(:block => true)
14
- process.command[/zeus.*?start$/].should_not be_nil, "Process Command: " + process.command
15
- end
18
+ describe ".stop!" do
19
+ subject { daemon.start!.stop! }
20
+ it { should be daemon }
21
+ it { should_not be_loaded }
22
+ end
23
+
24
+ describe ".restart!" do
25
+ subject { daemon }
26
+ context "when daemon is already running" do
27
+ before { subject.start!.restart!(:block => true) }
28
+ it { should be_loaded }
16
29
  end
30
+ end
17
31
 
18
- context "non-blocking" do
19
- subject { daemon.start! }
20
- it { should be_a Zeusd::Process }
32
+ describe ".process" do
33
+ context "before start" do
34
+ subject { daemon.process }
35
+ it { should be_nil }
21
36
  end
22
37
 
38
+ context "after start" do
39
+ subject { daemon.start!.process }
40
+ it { should be_a Zeusd::Process}
41
+ it { should be_alive }
42
+ its "a zeus start process" do
43
+ subject.command.should match(/zeus.*?start$/)
44
+ end
45
+ end
46
+
47
+ context "after start and stop" do
48
+ subject { daemon.start!.stop!.process }
49
+ it { should be_nil }
50
+ end
23
51
  end
24
52
 
25
53
  end
@@ -1,16 +1,83 @@
1
1
  require 'spec_helper'
2
+ require 'benchmark'
2
3
  require 'zeusd'
3
4
 
4
5
  describe Zeusd::Process do
5
6
 
6
- def spawn_dummy_process(ttl_seconds = 1)
7
- spawn("while [ $(date +\"%s\") -le #{Time.now.to_i + ttl_seconds} ]; do continue; done")
7
+ def spawn_dummy_process(ttl = 1, usr1delay = 0.5, options = {})
8
+ ttl = ttl.to_f.to_s
9
+ usr1delay = usr1delay.to_f.to_s
10
+ script = File.expand_path("../../support/dummy_process.rb", __FILE__)
11
+ p = ChildProcess.build(script, ttl, usr1delay)
12
+ p.cwd = options[:cwd] if options[:cwd]
13
+ p.detach = true
14
+ p.start
15
+ p
8
16
  end
9
17
 
18
+ before(:each) do
19
+ @dummy_ttl = 1
20
+ @dummy_usr1delay = 0.5
21
+ @dummy_process = spawn_dummy_process(@dummy_ttl, @dummy_usr1delay)
22
+ end
10
23
  subject(:model) { Zeusd::Process }
11
24
 
12
- describe "process management class methods" do
13
- before(:each) { @dummy_pid = spawn_dummy_process }
25
+
26
+ describe "process instance" do
27
+ subject { model.find(@dummy_process.pid) }
28
+ it { should be_a Zeusd::Process }
29
+ it { should be_alive }
30
+ it { should_not be_dead }
31
+ end
32
+
33
+ describe "instance methods" do
34
+ subject { model.find(@dummy_process.pid) }
35
+
36
+ describe ".cwd" do
37
+ it "return the current working directory" do
38
+ subject.cwd.to_path == Dir.pwd
39
+ end
40
+ end
41
+
42
+ describe ".kill!" do
43
+ context "when process exists" do
44
+ it "kills the process and returns true" do
45
+ subject.kill!(:wait => true).should be_true
46
+ subject.should be_dead
47
+ end
48
+ end
49
+
50
+ context "when processes does not exists" do
51
+ it "returns false" do
52
+ subject.kill!(:wait => true).should be_true
53
+ subject.kill!.should be_false
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+ describe "class methods" do
61
+
62
+ describe "::kill!" do
63
+ it "kills a process in under 0.1 seconds" do
64
+ model.kill!(@dummy_process.pid)
65
+ sleep 0.1
66
+ model.find(@dummy_process.pid).should be_nil
67
+ end
68
+
69
+ it "blocks until the process exits" do
70
+ Benchmark.realtime do
71
+ model.kill!(@dummy_process.pid, :signal => "USR1", :wait => true).should be_true
72
+ end.should be < 1.0
73
+ end
74
+ end
75
+
76
+ describe "::wait" do
77
+ it "blocks until the process exits" do
78
+ Benchmark.realtime { model.wait(@dummy_process.pid) }.should be > 1
79
+ end
80
+ end
14
81
 
15
82
  describe "::ps" do
16
83
  subject { model.ps }
@@ -19,7 +86,7 @@ describe Zeusd::Process do
19
86
  subject.all?{|x| x.is_a?(Hash)}.should be_true
20
87
  end
21
88
  it "includes the dummy process" do
22
- subject.map{|x|x["pid"]}.should include(@dummy_pid.to_s)
89
+ subject.map{|x|x["pid"]}.should include(@dummy_process.pid.to_s)
23
90
  end
24
91
  it "allows additional -o keywords" do
25
92
  model.ps(:keywords => "user").first.should include("user")
@@ -60,7 +127,7 @@ describe Zeusd::Process do
60
127
  it { should have_at_least(2).items }
61
128
  end
62
129
  context "criteria not met" do
63
- subject {model.where(:pid => @dummy_pid, :pgid => 9999999999999)}
130
+ subject {model.where(:pid => @dummy_process.pid, :pgid => 9999999999999)}
64
131
  it { should be_an Array }
65
132
  it { should be_empty }
66
133
  end
@@ -68,14 +135,14 @@ describe Zeusd::Process do
68
135
  end
69
136
 
70
137
  describe "::find" do
71
- subject { model.find(@dummy_pid) }
138
+ subject { model.find(@dummy_process.pid) }
72
139
  context "existing process" do
73
140
  it { should be_a Zeusd::Process }
74
141
  it { should be_alive }
75
- it { subject.pid.should eq(@dummy_pid) }
142
+ it { subject.pid.should eq(@dummy_process.pid) }
76
143
  end
77
144
  context "non-existant process" do
78
- before(:each) { ::Process.kill("KILL", @dummy_pid); ::Process.waitpid(@dummy_pid) }
145
+ before(:each) { @dummy_process.stop }
79
146
  it { should be_nil }
80
147
  end
81
148
  end
data/zeusd.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency "thor"
22
22
  spec.add_runtime_dependency "childprocess"
23
+ spec.add_runtime_dependency "hooks"
23
24
  spec.add_runtime_dependency "zeus"
24
25
 
25
26
  spec.add_development_dependency "bundler", "~> 1.3"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeusd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-07 00:00:00.000000000 Z
12
+ date: 2014-02-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: hooks
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: zeus
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -126,8 +142,8 @@ files:
126
142
  - bin/zeusd
127
143
  - lib/zeusd.rb
128
144
  - lib/zeusd/daemon.rb
145
+ - lib/zeusd/interpreter.rb
129
146
  - lib/zeusd/process.rb
130
- - lib/zeusd/state_interpreter.rb
131
147
  - lib/zeusd/version.rb
132
148
  - spec/dummy/.gitignore
133
149
  - spec/dummy/Gemfile
@@ -180,6 +196,7 @@ files:
180
196
  - spec/dummy/vendor/plugins/.gitkeep
181
197
  - spec/dummy/zeus.json
182
198
  - spec/spec_helper.rb
199
+ - spec/support/dummy_process.rb
183
200
  - spec/zeusd/daemon_spec.rb
184
201
  - spec/zeusd/process_spec.rb
185
202
  - zeusd.gemspec
@@ -198,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
198
215
  version: '0'
199
216
  segments:
200
217
  - 0
201
- hash: -2296072518175803333
218
+ hash: -3204481942119935445
202
219
  required_rubygems_version: !ruby/object:Gem::Requirement
203
220
  none: false
204
221
  requirements:
@@ -207,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
224
  version: '0'
208
225
  segments:
209
226
  - 0
210
- hash: -2296072518175803333
227
+ hash: -3204481942119935445
211
228
  requirements: []
212
229
  rubyforge_project:
213
230
  rubygems_version: 1.8.25
@@ -266,5 +283,6 @@ test_files:
266
283
  - spec/dummy/vendor/plugins/.gitkeep
267
284
  - spec/dummy/zeus.json
268
285
  - spec/spec_helper.rb
286
+ - spec/support/dummy_process.rb
269
287
  - spec/zeusd/daemon_spec.rb
270
288
  - spec/zeusd/process_spec.rb