ant_hill 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ module AntHill
2
+ # Version of gem
3
+ VERSION = "0.3.1"
4
+ end
@@ -0,0 +1,48 @@
1
+ require 'ant_hill'
2
+
3
+ namespace :ant_hill do
4
+ task :add_colony do
5
+ host = ENV['drb_host'] || 'localhost'
6
+ AntHill::Queen.create_colony ARGV[1..-1], host
7
+ end
8
+
9
+ task :kill_colony do
10
+ host = ENV['drb_host'] || 'localhost'
11
+ AntHill::Queen.kill_colony ARGV[1..-1], host
12
+ end
13
+
14
+ task :monitor do
15
+ queen = AntHill::Queen.drb_queen(host)
16
+ while true
17
+ sleep 2
18
+ print "\e[2J\e[f"
19
+ puts "Creep size: #{queen.creeps.size}"
20
+ puts "Ants left: #{queen.size}"
21
+ queen.creeps.each{|creep|
22
+ puts creep.to_s
23
+ }
24
+ end
25
+ end
26
+
27
+ task :execute_each do
28
+ threads = []
29
+ AntHill::Queen.creeps(host).each{|creep|
30
+ threads << Thread.new do
31
+ creep.exec!(ENV['command'])
32
+ end
33
+ }
34
+ threads.each{ |t| t.join}
35
+ end
36
+
37
+ task :suspend_queen do
38
+ AntHill::Queen.drb_queen(host).suspend
39
+ end
40
+
41
+ task :release_queen do
42
+ AntHill::Queen.drb_queen(host).release
43
+ end
44
+
45
+ def host
46
+ ENV['drb_host'] || 'localhost'
47
+ end
48
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ module AntHill
4
+ describe AntColony do
5
+ let(:params){ {"type" => "type", "a" => 1, "b" => 2 } }
6
+ let(:colony){ AntColony.new(params) }
7
+
8
+ before :each do
9
+ config = double("config")
10
+ config.stub(:creep_modifier_class){|type| "Creep modifier for #{type}" }
11
+ config.stub(:log_level){ :log_level }
12
+ config.stub(:log_dir){ log_dir }
13
+ config.stub(:init_time){ Time.now}
14
+ Configuration.stub(:config){config}
15
+
16
+ logger = double("logger")
17
+ Log.stub(:logger_for){logger}
18
+ end
19
+
20
+ context "#initialize" do
21
+ it "should store params" do
22
+ colony.params.should eql(params)
23
+ end
24
+ end
25
+
26
+ context "#type" do
27
+ it "should return type from params" do
28
+ colony.type.should eql("type")
29
+ end
30
+ end
31
+
32
+ context "#creep_modifier_class" do
33
+ it "should return creep modifier class for type" do
34
+ Configuration.config.should_receive(:creep_modifier_class).with("type").and_return("Creep modifier for type")
35
+ colony.creep_modifier_class.should eql("Creep modifier for type")
36
+ end
37
+
38
+ it "should log error if no such type defined" do
39
+ test_params = params
40
+ test_params['type']="wrong_type"
41
+
42
+ colony = AntColony.new(params)
43
+ Configuration.config.should_receive(:creep_modifier_class).with("wrong_type").and_return(nil)
44
+ Log.logger_for.should_receive(:error).with("Colony will die without creep modifier ;(")
45
+ colony.creep_modifier_class.should be_nil
46
+ end
47
+ end
48
+
49
+ context "#spoiled?" do
50
+ it "should be spoiled if no creep modifier class was set" do
51
+ test_params = params
52
+ test_params['type']="wrong_type"
53
+ colony = AntColony.new(params)
54
+ colony.spoiled?.should be_true
55
+ end
56
+ end
57
+
58
+ context "#get_ants" do
59
+ it "should add self params to all ants " do
60
+ colony.stub(:search_ants){ [{:param1 => 1, :param2 => 2},{ :param1 => 3, :param2 => 2}] }
61
+ ants = colony.get_ants
62
+ ants.should_not be_empty
63
+ ants.each{|ant|
64
+ ant.params['type'].should eql('type')
65
+ ant.params['a'].should eql(1)
66
+ ant.params['b'].should eql(2)
67
+ ant.params[:param2].should eql(2)
68
+ }
69
+ ants[0].params[:param1].should eql(1)
70
+ ants[1].params[:param1].should eql(3)
71
+ end
72
+
73
+ it "should call after_search" do
74
+ colony.stub(:search_ants){ [{:param1 => 1, :param2 => 2},{ :param1 => 3, :param2 => 2}] }
75
+ colony.should_receive(:after_search)
76
+ colony.get_ants
77
+ end
78
+
79
+ it "should log error if something's happened" do
80
+ colony.stub(:search_ants){ raise }
81
+ Log.logger_for.should_receive(:error).with(/Error while processing search ants for colony/)
82
+ ants = colony.get_ants
83
+ end
84
+ end
85
+
86
+ context "#is_it_me?" do
87
+ it "should return true if all params matches" do
88
+ colony.is_it_me?({"type"=> "type", "a" => 1}).should be_true
89
+ end
90
+ it "should return false if at least one param doesn't match" do
91
+ colony.is_it_me?({"type"=> "type", "a" => 2}).should be_false
92
+ end
93
+ end
94
+
95
+ context "#not_finished" do
96
+ it "should return not finished ants" do
97
+ ant1 = double("ant1")
98
+ ant2 = double("ant2")
99
+ ant3 = double("ant3")
100
+ ant4 = double("ant4")
101
+ ant1.stub(:finished?){true}
102
+ ant2.stub(:finished?){false}
103
+ ant3.stub(:finished?){true}
104
+ ant4.stub(:finished?){true}
105
+ colony.stub(:ants){ [ant1, ant2, ant3, ant4] }
106
+ colony.not_finished.should eql([ant1, ant3, ant4])
107
+ end
108
+
109
+ end
110
+ context "#type" do
111
+ it "should return type from params" do
112
+ colony.params['type'].should eql("type")
113
+ end
114
+ end
115
+
116
+
117
+ end
118
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ module AntHill
4
+ describe Ant do
5
+ before :each do
6
+ config = double("config")
7
+ config.stub(:creep_modifier_class){|type| "Creep modifier for #{type}" }
8
+ config.stub(:log_level){ :log_level }
9
+ config.stub(:log_dir){ log_dir }
10
+ config.stub(:init_time){ Time.at(0)}
11
+ Configuration.stub(:config){config}
12
+
13
+ logger = double("logger")
14
+ Log.stub(:logger_for){logger}
15
+ end
16
+
17
+ let(:ant_colony){
18
+ ac = double("ant_colony")
19
+ ac.stub(:type){ "type" }
20
+ ac.stub(:params){ {"type" => "type", "a" => 1, "b" => 2} }
21
+ cmc = double(:creep_modifier_class)
22
+ cm = double(:creep_modifier)
23
+ cmc.stub(:change_time_for_param){|param|
24
+ case param
25
+ when 'a' then 1
26
+ when 'b' then 2
27
+ else
28
+ 0
29
+ end
30
+
31
+ }
32
+ cmc.stub(:new){ cm}
33
+ ac.stub(:creep_modifier_class){cmc}
34
+ ac.stub(:change_time_for_param){|param|
35
+ case param
36
+ when 'a' then 1
37
+ when 'b' then 2
38
+ else
39
+ 0
40
+ end
41
+
42
+ }
43
+ ac
44
+ }
45
+
46
+ let(:ant){Ant.new( { "param1" => "params", "param2" => "param2"}, ant_colony )}
47
+
48
+ context "#initialize" do
49
+ it "should have colony" do
50
+ ant.colony.should eql(ant_colony)
51
+ end
52
+ it "should merge colony and self params" do
53
+ ant.params.should eql({ "type" => "type", "a" => 1, "b" => 2, "param1" => "params", "param2" => "param2" })
54
+ end
55
+ it "should have status not_started" do
56
+ ant.status.should eql(:not_started)
57
+ end
58
+ end
59
+
60
+ context "#to_s" do
61
+ it "should return string of params" do
62
+ ant.to_s.should eql(ant.params.inspect.to_s)
63
+ end
64
+ end
65
+
66
+ context "#change_status" do
67
+ it "should set status" do
68
+ ant.change_status(:started)
69
+ ant.status.should eql(:started)
70
+ end
71
+ end
72
+
73
+ context "#priority" do
74
+ it "should have higher priority for matches params" do
75
+ ant.priority({}).should < ant.priority({"a" => 1})
76
+ ant.priority({"a" => 1}).should < ant.priority({"a" => 1, "b" => 2})
77
+ end
78
+
79
+ it "should increase priority on sum values defined for param in change_time_for_param method" do
80
+ ant.priority({ "a" => 1 }).should be_within(0.0001).of( ant.priority({"a" => 0}) + 1 )
81
+ ant.priority({ "b" => 2 }).should be_within(0.0001).of( ant.priority({"b" => 0}) + 2 )
82
+
83
+ end
84
+ it "should return same value for same params " do
85
+ ant.priority({ "b" => 2 }).should be_within(0.0001).of( ant.priority({"b" => 2}) )
86
+ end
87
+
88
+ end
89
+
90
+ context "#finished?" do
91
+ it "should return false if ant status is finished" do
92
+ ant.stub(:status){:in_progress}
93
+ ant.finished?.should be_false
94
+ end
95
+ it "should return true if ant status is finished" do
96
+ ant.stub(:status){:finished}
97
+ ant.finished?.should be_true
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,201 @@
1
+ require 'spec_helper'
2
+ module AntHill
3
+ describe Configuration do
4
+
5
+ let(:hash){
6
+ {
7
+ 'basedir' => "a",
8
+ 'lib_path' => 'b',
9
+ 'sleep_interval' => 1,
10
+ 'log_dir' => 'some_dir',
11
+ 'log_level' => ':error',
12
+ 'types' => {
13
+ 'a' => {
14
+ 'ant_colony_class' => 'String',
15
+ 'creep_modifier_class' => 'Object'
16
+ },
17
+ 'b' => {
18
+ 'ant_colony_class' => 'Hash',
19
+ 'creep_modifier_class' => 'String'
20
+ },
21
+ 'c' => {
22
+ 'ant_colony_class' => 'SomeClass',
23
+ 'creep_modifier_class' => 'SomeOtherClass'
24
+ }
25
+ },
26
+ 'default_type' => 'a',
27
+ 'log_path' => 'log_path',
28
+ 'creeps' => [
29
+ { 'name' => 1, 'host' => 'host', 'login' => 'login', 'password' => 'password'},
30
+ { 'name' => 2, 'host' => 'host2', 'login' => 'login2', 'password' => 'password2'}
31
+ ]
32
+
33
+ }
34
+ }
35
+ before(:each) do
36
+ YAML.stub(:load_file) {|filename| hash }
37
+ Time.stub(:now) { Time.at(0) }
38
+ File.stub(:join) { 'rubygems'}
39
+ logger = double("logger")
40
+ Log.stub(:logger_for){logger}
41
+ end
42
+
43
+ let(:config) { Configuration.new }
44
+
45
+ let(:config_parsed){
46
+ c = Configuration.new
47
+ c.parse_yaml("config.yml")
48
+ c
49
+ }
50
+
51
+ context "#initialize" do
52
+ it "should set init_time" do
53
+ config.init_time == Time.at(0)
54
+ end
55
+ end
56
+
57
+ context "#parse_yaml" do
58
+ it "should fail if file not exists" do
59
+ STDERR.stub(:puts)
60
+ STDERR.should_receive(:puts).with(/Couldn't find config file/)
61
+ YAML.stub(:load_file){raise}
62
+ lambda{ config.parse_yaml("config.yml") }.should raise_error(SystemExit)
63
+ end
64
+
65
+ it "should load configuration" do
66
+ config.parse_yaml("config.yml")
67
+ config.instance_variable_get("@configuration").should_not eql({})
68
+ end
69
+ end
70
+
71
+ context "#require_libs" do
72
+ it "should require file base_dir+libpath" do
73
+ config_parsed.stub(:require){nil}
74
+ config_parsed.should_receive(:require).with("rubygems")
75
+ config_parsed.require_libs
76
+ end
77
+ it "should require file base_dir+libpath" do
78
+ config_parsed.stub(:require){ raise LoadError }
79
+ config_parsed.should_receive(:require).with("rubygems")
80
+ STDERR.should_receive(:puts).with(/Configuration file is invalid! No such file exists rubygems/)
81
+ config_parsed.require_libs
82
+ end
83
+ end
84
+
85
+ context "#validate" do
86
+
87
+ context "with valid config" do
88
+ it "should not exit if config is valid" do
89
+ lambda{config_parsed.validate}.should_not raise_error(SystemExit)
90
+ end
91
+ end
92
+ context "with invalid config" do
93
+ before(:each) do
94
+ STDERR.stub(:puts)
95
+ end
96
+ %w{ basedir lib_path types creeps log_dir log_level }.each do |key|
97
+ it "should log error and exit if #{key} unset" do
98
+ new_hash = hash.clone
99
+ new_hash.delete(key)
100
+ YAML.stub(:load_file){|filename| new_hash }
101
+ c = Configuration.new
102
+ c.parse_yaml("config.yml")
103
+ STDERR.should_receive(:puts).with(/Configuration file is invalid! Pls. define .* keys in it/)
104
+ lambda{c.validate}.should raise_error(SystemExit)
105
+ end
106
+ end
107
+
108
+ %w{ types creeps }.each do |key|
109
+ it "should log error and exit #{key} has no children" do
110
+ new_hash = hash.clone
111
+ new_hash[key] = []
112
+ YAML.stub(:load_file){|filename| new_hash }
113
+ c = Configuration.new
114
+ c.parse_yaml("config.yml")
115
+ STDERR.should_receive(:puts).with(/Configuration file is invalid! Pls. define at least one .* in #{key} section/)
116
+ lambda{c.validate}.should raise_error(SystemExit)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ context "#creep_modifier_class" do
123
+ it "should return creep_modifier_class from config if type specified" do
124
+ config_parsed.creep_modifier_class('b').should eql(String)
125
+ end
126
+ it "should return creep_modifier_class from config for default type if not type specified" do
127
+ config_parsed.creep_modifier_class.should eql(Object)
128
+ end
129
+ end
130
+
131
+ context "#ant_colony_class" do
132
+ it "should return creep_modifier_class from config if type specified" do
133
+ config_parsed.ant_colony_class('b').should eql(Hash)
134
+ end
135
+ it "should return creep_modifier_class from config for default type if not type specified" do
136
+ config_parsed.ant_colony_class.should eql(String)
137
+ end
138
+ end
139
+
140
+ context "#get_class_by_type_and_object" do
141
+ it "should log error if no class name defiend for given type and object" do
142
+ Log.logger_for.should_receive(:error).with(/No class configuration defined for object and type a/)
143
+ Log.logger_for.should_receive(:error).with(/No class configuration defined for String and type d/)
144
+ config_parsed.get_class_by_type_and_object('a', 'object')
145
+ config_parsed.get_class_by_type_and_object('d', 'String')
146
+ end
147
+ it "should log error if no specified class defiend" do
148
+ Log.logger_for.should_receive(:error).with("No such class defined: SomeClass")
149
+ config_parsed.get_class_by_type_and_object('c', 'ant_colony_class')
150
+ end
151
+ end
152
+
153
+ context "#[]" do
154
+ it "should access to configuration with [] method" do
155
+ config_parsed['default_type'].should eql('a')
156
+ config_parsed['default_type'].should eql('a')
157
+ end
158
+ end
159
+
160
+ context "#method_missing" do
161
+ it "should return default_type from config" do
162
+ config_parsed.default_type.should eql("a")
163
+ end
164
+ end
165
+
166
+ context "Configuration#config" do
167
+ let(:config_double){
168
+ config_double = double("config")
169
+ config_double.stub(:parse_yaml){|file| }
170
+ config_double.stub(:validate)
171
+ config_double.stub(:require_libs)
172
+ config_double
173
+ }
174
+ before :each do
175
+ Configuration.method(:remove_class_variable).call(:@@config) if Configuration.class_variable_defined?(:@@config)
176
+ end
177
+ it "should return same object every time" do
178
+ Configuration.stub(:new){config_double}
179
+ config_double.should_receive(:parse_yaml)
180
+ config_double.should_receive(:validate)
181
+ config_double.should_receive(:require_libs)
182
+ Configuration.config.should be_equal(Configuration.config)
183
+ end
184
+ it "should use passed filename for parsing" do
185
+ Configuration.stub(:new){ config_double }
186
+ config_double.should_receive(:parse_yaml).with("filename.yml")
187
+ config_double.should_receive(:require_libs)
188
+ config_double.should_receive(:validate)
189
+ Configuration.config("filename.yml")
190
+ end
191
+ it "should use ARGV[0] as filename for parsing" do
192
+ Configuration.stub(:new){ config_double }
193
+ ARGV[0]='filename.yml'
194
+ config_double.should_receive(:parse_yaml).with("filename.yml")
195
+ config_double.should_receive(:require_libs)
196
+ config_double.should_receive(:validate)
197
+ Configuration.config
198
+ end
199
+ end
200
+ end
201
+ end