daemonizer 0.4.18 → 0.5.0.beta.1

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.
@@ -0,0 +1,103 @@
1
+ require "spec_helper"
2
+
3
+ class CallbacksSpecHandler < SpecHandler
4
+ class <<self
5
+ attr_accessor :call_on_prepare
6
+ attr_accessor :call_on_start
7
+ end
8
+
9
+ def start
10
+ self.class.call_on_start && self.class.call_on_start.call
11
+ super
12
+ end
13
+
14
+ def prepare(starter, &block)
15
+ self.class.call_on_prepare && self.class.call_on_prepare.call
16
+ super
17
+ end
18
+ end
19
+
20
+
21
+ describe "callbacks in Daemonfile" do
22
+ before :each do
23
+ stubs_logger
24
+ end
25
+
26
+ %w(after_prepare before_prepare before_start).each do |callback|
27
+ context "initializing #{callback} callbacks" do
28
+ before :each do
29
+ @eval = Daemonizer::Dsl.evaluate(<<-G)
30
+ #{callback} do
31
+ 1
32
+ end
33
+
34
+ pool :test do
35
+ #{callback} do
36
+ 2
37
+ end
38
+
39
+ #{callback} do
40
+ 3
41
+ end
42
+ end
43
+ G
44
+ end
45
+
46
+ it { @eval.configs[:test][:callbacks].should be_kind_of(Hash) }
47
+ it { @eval.configs[:test][:callbacks][callback.to_sym].should be_kind_of(Array) }
48
+ it { @eval.configs[:test][:callbacks][callback.to_sym].size.should == 3 }
49
+ it "should keep valid callbacks order" do
50
+ @eval.configs[:test][:callbacks][callback.to_sym][0].call.should == 1
51
+ @eval.configs[:test][:callbacks][callback.to_sym][1].call.should == 2
52
+ @eval.configs[:test][:callbacks][callback.to_sym][2].call.should == 3
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "callbacks in Daemonizer::Config" do
59
+ before :each do
60
+ stubs_logger
61
+ end
62
+
63
+ before :each do
64
+ CallbacksSpecHandler.call_on_prepare = lambda { @engine_state.become('prepare_invoked') }
65
+ CallbacksSpecHandler.call_on_start = lambda { @engine_state.become('start_invoked') }
66
+
67
+ @engine_state = states('engine_state').starts_as('pending')
68
+ end
69
+
70
+ it "should work in correct order with many callbacks" do
71
+ @before_prepare = mock('before_prepare')
72
+ @before_prepare.expects('touch').when(@engine_state.is('pending')).twice
73
+
74
+ @after_prepare = mock('after_prepare')
75
+ @after_prepare.expects('touch').when(@engine_state.is('prepare_invoked')).twice
76
+
77
+ @before_start = mock('before_start')
78
+ @before_start.expects('touch').when(@engine_state.is('after_prepare_invoked')).twice
79
+
80
+ @callbacks = {
81
+ :before_prepare => [ Proc.new { @before_prepare.touch }, Proc.new { @before_prepare.touch; @engine_state.become('before_prepare_invoked') } ],
82
+ :after_prepare => [ Proc.new { @after_prepare.touch }, Proc.new { @after_prepare.touch; @engine_state.become('after_prepare_invoked') } ],
83
+ :before_start => [ Proc.new { @before_start.touch }, Proc.new { @before_start.touch; @engine_state.become('before_start_invoked') } ]
84
+ }
85
+
86
+ @engine = Daemonizer::Engine.new(Daemonizer::Config.new(:pool, {
87
+ :workers => 1,
88
+ :pid_file =>"#{tmp_dir}/test1.pid",
89
+ :log_file =>"#{tmp_dir}/test1.log",
90
+ :callbacks => @callbacks,
91
+ :handler => CallbacksSpecHandler
92
+ }))
93
+ @engine.run_prepare_with_callbacks do
94
+ @engine.run_start_with_callbacks
95
+ end
96
+ end
97
+
98
+ after :each do
99
+ CallbacksSpecHandler.call_on_prepare = nil
100
+ CallbacksSpecHandler.call_on_start = nil
101
+ end
102
+
103
+ end
@@ -0,0 +1,146 @@
1
+ require "spec_helper"
2
+
3
+ class OptionsSpecHandler < SpecHandler; end
4
+
5
+ describe "set_option in Daemonfile" do
6
+ it "should initialize simple setting correctly" do
7
+ Daemonizer::Option.expects(:new).with(:simple, "simple_value").once
8
+ Daemonizer::Dsl.evaluate(<<-G)
9
+ pool :test do
10
+ set_option :simple, "simple_value"
11
+ end
12
+ G
13
+ end
14
+
15
+ it "should initialize block setting correctly" do
16
+ Daemonizer::Option.expects(:new).with(:lambda, kind_of(Proc), any_of(true, nil)).once
17
+ Daemonizer::Dsl.evaluate(<<-G)
18
+ pool :test do
19
+ set_option :lambda do
20
+ "lambda_value"
21
+ end
22
+ end
23
+ G
24
+ end
25
+
26
+ it "should correctly set option_handlers" do
27
+ @eval = Daemonizer::Dsl.evaluate(<<-G)
28
+ pool :test do
29
+ set_option :option1, "option1_value"
30
+ set_option :option2, "option1_value"
31
+ set_option :option3, "option1_value"
32
+ end
33
+ G
34
+ @eval.configs[:test][:handler_options].should be_kind_of(Hash)
35
+ @eval.configs[:test][:handler_options].size.should == 3
36
+ end
37
+
38
+ it "should raise DslError if nothing provided to set_option" do
39
+ lambda {
40
+ Daemonizer::Dsl.evaluate(<<-G)
41
+ pool :test do
42
+ set_option :option1, nil
43
+ end
44
+ G
45
+ }.should raise_error Daemonizer::Dsl::DslError
46
+ end
47
+ end
48
+
49
+ describe "pool options in Daemonizer::Config" do
50
+ context "with name and value" do
51
+ before :each do
52
+ @handler = Daemonizer::Engine.new(Daemonizer::Config.new(:pool, {
53
+ :workers => 1,
54
+ :pid_file =>"#{tmp_dir}/test1.pid",
55
+ :log_file =>"#{tmp_dir}/test1.log",
56
+ :handler_options => {
57
+ :simple => Daemonizer::Option.new(:simple, "simple_value"),
58
+ :lambda => Daemonizer::Option.new(:lambda, lambda { "lambda_value" }),
59
+ :block => Daemonizer::Option.new(:block, lambda { "block_value" }, true)
60
+ },
61
+ :handler => OptionsSpecHandler
62
+ })).run_start_with_callbacks
63
+ end
64
+
65
+ it "should return simple option" do
66
+ @handler.option(:simple).should == "simple_value"
67
+ end
68
+
69
+ it "should return lambda value" do
70
+ @handler.option(:lambda).should be_kind_of(Proc)
71
+ end
72
+
73
+ it "should return simple option" do
74
+ @handler.option(:block).should == "block_value"
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ describe Daemonizer::Option do
82
+ context "with auto_eval set to true" do
83
+ context "and not lambda value" do
84
+ it do
85
+ lambda {
86
+ Daemonizer::Option.new(:option, "not_lambda", true)
87
+ }.should raise_error(Daemonizer::Option::OptionError)
88
+ end
89
+ end
90
+
91
+ context "and lambda value" do
92
+ context "and handler is not defined" do
93
+ it do
94
+ lambda {
95
+ Daemonizer::Option.new(:option, lambda { "lambda" }, true).value
96
+ }.should raise_error(Daemonizer::Option::OptionError)
97
+ end
98
+ end
99
+ context "and handler defined" do
100
+ context "with arity == 0" do
101
+ it do
102
+ Daemonizer::Option.new(:option, lambda { "lambda" }, true).
103
+ value(OptionsSpecHandler.new).
104
+ should == "lambda"
105
+ end
106
+ end
107
+
108
+ context "with arity == 2" do
109
+ it do
110
+ Daemonizer::Option.new(:option, lambda { |worker_id, workers_count| "#{worker_id}/#{workers_count}" }, true).
111
+ value(OptionsSpecHandler.new).
112
+ should == "1/1"
113
+ end
114
+ end
115
+
116
+ context "with arity == 1" do
117
+
118
+ it do
119
+ lambda {
120
+ Daemonizer::Option.new(:option, lambda { |worker_id| "lambda" }, true).
121
+ value(OptionsSpecHandler.new)
122
+ }.should raise_error(Daemonizer::Option::OptionError)
123
+ end
124
+
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+
131
+ context "with auto_eval set to false" do
132
+ context "and not lambda value" do
133
+ it do
134
+ Daemonizer::Option.new(:option, "simple").value.should == "simple"
135
+ end
136
+ end
137
+
138
+ context "and lambda value" do
139
+ it do
140
+ Daemonizer::Option.new(:option, lambda { "lambda" }).value.
141
+ should be_kind_of(Proc)
142
+ end
143
+ end
144
+ end
145
+
146
+ end
@@ -0,0 +1,43 @@
1
+ require "spec_helper"
2
+
3
+ describe "Evaluating pool settings through dsl" do
4
+ before :each do
5
+ @dsl = Daemonizer::Dsl.evaluate(<<-EOF)
6
+ poll_period 10
7
+
8
+ pool "pool1" do
9
+ workers 1
10
+
11
+ not_cow_friendly
12
+ end
13
+ pool "pool2" do
14
+ workers 2
15
+ poll_period 2
16
+ end
17
+ EOF
18
+
19
+ @configuration = @dsl.configs
20
+ end
21
+
22
+ it "should create 2 pool record" do
23
+ @configuration.size.should == 2
24
+ end
25
+
26
+ it "should set parameters on pools isolated" do
27
+ @configuration[:pool1].keys.should include(:workers, :poll_period, :cow_friendly)
28
+ @configuration[:pool2].keys.should include(:workers, :poll_period)
29
+ @configuration[:pool2].keys.should_not include(:cow_friendly)
30
+ end
31
+
32
+ it "should correctly inherit parameters from top level" do
33
+ @configuration[:pool1][:poll_period].should == 10
34
+ @configuration[:pool2][:poll_period].should == 2
35
+ end
36
+
37
+ it "should process pool definition on call Daemonizer::Dsl#process" do
38
+ pool_config = Daemonizer::Config
39
+ pool_config.expects(:new).with(:pool2, equals(@configuration[:pool2])).once
40
+ pool_config.expects(:new).with(:pool1, equals(@configuration[:pool1])).once
41
+ @processed_config = @dsl.process
42
+ end
43
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,57 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
- require 'test'
4
- require 'spec'
5
- require 'spec/autorun'
6
-
7
- Spec::Runner.configure do |config|
8
-
1
+ #$:.unshift File.expand_path('..', __FILE__)
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'daemonizer'
5
+ require 'fileutils'
6
+ require 'rubygems'
7
+ require 'rspec'
8
+ require 'open3'
9
+
10
+ Dir["#{File.expand_path('support', File.dirname(__FILE__))}/*.rb"].each do |file|
11
+ require file
12
+ end
13
+
14
+ $debug = false
15
+ $show_err = true
16
+
17
+ FileUtils.rm_rf(Spec::Path.app_root)
18
+
19
+ RSpec.configure do |config|
20
+ config.include Spec::Helpers
21
+ config.include Spec::Path
22
+ config.include Spec::DaemonfileFactory
23
+ config.include Spec::Processes
24
+
25
+ config.filter_run :focused => true
26
+ config.run_all_when_everything_filtered = true
27
+ config.alias_example_to :fit, :focused => true
28
+
29
+ config.mock_with :mocha
30
+
31
+ original_wd = Dir.pwd
32
+
33
+ config.before :each do
34
+ reset!
35
+ in_app_root
36
+ end
37
+
38
+ config.after :each do
39
+ Dir.chdir(original_wd)
40
+ end
41
+ end
42
+
43
+ class SpecHandler < Daemonizer::Handler
44
+ def initialize(*args)
45
+ @worker_id = 1
46
+ @workers_count = 1
47
+ super
48
+ end
49
+
50
+ def prepare(starter, &block)
51
+ super
52
+ end
53
+
54
+ def start
55
+ self
56
+ end
9
57
  end
@@ -0,0 +1,33 @@
1
+ module Spec
2
+ module DaemonfileFactory
3
+ def simple_daemonfile(*pools)
4
+ code = ""
5
+ pid_files = pools.map do |pool|
6
+ if pool[:exit_on_start]
7
+ end
8
+ code << <<EOF
9
+ pool :#{pool[:name]} do
10
+ workers #{pool[:workers] || 1}
11
+ poll_period #{pool[:poll_period] || 1}
12
+ log_file "test.log"
13
+ pid_file "#{pool[:pid_file]}"
14
+
15
+ prepare do |block|
16
+ #{pool[:on_prepare]}
17
+ block.call
18
+ end
19
+
20
+ start do |worker_id, workers_count|
21
+ trap("TERM") { exit 0; }
22
+ #{pool[:on_start]}
23
+ end
24
+ end
25
+
26
+ EOF
27
+ pool[:pid_file]
28
+ end
29
+ daemonfile code
30
+ pid_files
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,70 @@
1
+ module Spec
2
+ module Helpers
3
+ def reset!
4
+ kill_if_running!
5
+ FileUtils.rm_rf(app_root)
6
+ FileUtils.mkdir_p(app_root)
7
+ end
8
+
9
+ def in_app_root(&blk)
10
+ Dir.chdir(app_root, &blk)
11
+ end
12
+
13
+ def daemonizer(cmd)
14
+ sys_exec File.join(gem_root, 'bin/daemonizer') + " " + cmd.to_s
15
+ end
16
+
17
+ def daemonfile(code)
18
+ File.open(File.join(app_root, "Daemonfile"), 'w') do |f|
19
+ f.puts code
20
+ end
21
+ end
22
+
23
+ attr_reader :out, :err, :exitstatus
24
+
25
+ def sys_exec(cmd, expect_err = false)
26
+ Open3.popen3(cmd.to_s) do |stdin, stdout, stderr|
27
+ @in_p, @out_p, @err_p = stdin, stdout, stderr
28
+
29
+ yield @in_p if block_given?
30
+ @in_p.close
31
+
32
+ @out = @out_p.read_available_bytes.strip
33
+ @err = @err_p.read_available_bytes.strip
34
+ end
35
+
36
+ puts @err unless expect_err || @err.empty? || !$show_err
37
+ @out
38
+ end
39
+
40
+ def kill_if_running!
41
+ Dir["#{tmp_dir}/**/*.pid"].each do |pid_file|
42
+ pid = File.read(pid_file).chomp
43
+ if pid.to_i > 0
44
+ puts "Warning: Daemonizer was not properly stopped. Stop it in after block. Killing #{pid.to_i}"
45
+ Process.kill("TERM", pid.to_i) rescue true
46
+ sleep 5
47
+ end
48
+ end
49
+ end
50
+
51
+ def daemonizer_runned?(pid_file)
52
+ pid = File.read(pid_file).chomp.to_i
53
+ if pid.to_i > 0
54
+ return !!Process.kill(0, pid.to_i)
55
+ else
56
+ return false
57
+ end
58
+ rescue Errno::ESRCH, Errno::ECHILD, Errno::EPERM
59
+ false
60
+ end
61
+
62
+ def stubs_logger
63
+ logger = stubs(:logger)
64
+ logger.stubs(:info).returns(true)
65
+ Daemonizer.stubs(:logger).returns(logger)
66
+ end
67
+
68
+ extend self
69
+ end
70
+ end