rightscale-nanite 0.4.1 → 0.4.1.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.
- data/lib/nanite.rb +71 -0
- data/lib/nanite/actor.rb +60 -0
- data/lib/nanite/actor_registry.rb +24 -0
- data/lib/nanite/admin.rb +153 -0
- data/lib/nanite/agent.rb +250 -0
- data/lib/nanite/amqp.rb +47 -0
- data/lib/nanite/cluster.rb +203 -0
- data/lib/nanite/config.rb +102 -0
- data/lib/nanite/console.rb +39 -0
- data/lib/nanite/daemonize.rb +13 -0
- data/lib/nanite/dispatcher.rb +90 -0
- data/lib/nanite/identity.rb +16 -0
- data/lib/nanite/job.rb +104 -0
- data/lib/nanite/local_state.rb +34 -0
- data/lib/nanite/log.rb +64 -0
- data/lib/nanite/log/formatter.rb +39 -0
- data/lib/nanite/mapper.rb +277 -0
- data/lib/nanite/mapper_proxy.rb +56 -0
- data/lib/nanite/packets.rb +231 -0
- data/lib/nanite/pid_file.rb +52 -0
- data/lib/nanite/reaper.rb +38 -0
- data/lib/nanite/security/cached_certificate_store_proxy.rb +24 -0
- data/lib/nanite/security/certificate.rb +55 -0
- data/lib/nanite/security/certificate_cache.rb +66 -0
- data/lib/nanite/security/distinguished_name.rb +34 -0
- data/lib/nanite/security/encrypted_document.rb +46 -0
- data/lib/nanite/security/rsa_key_pair.rb +53 -0
- data/lib/nanite/security/secure_serializer.rb +67 -0
- data/lib/nanite/security/signature.rb +40 -0
- data/lib/nanite/security/static_certificate_store.rb +35 -0
- data/lib/nanite/security_provider.rb +47 -0
- data/lib/nanite/serializer.rb +52 -0
- data/lib/nanite/state.rb +164 -0
- data/lib/nanite/streaming.rb +125 -0
- data/lib/nanite/util.rb +51 -0
- data/spec/actor_registry_spec.rb +62 -0
- data/spec/actor_spec.rb +59 -0
- data/spec/agent_spec.rb +235 -0
- data/spec/cached_certificate_store_proxy_spec.rb +34 -0
- data/spec/certificate_cache_spec.rb +49 -0
- data/spec/certificate_spec.rb +27 -0
- data/spec/cluster_spec.rb +300 -0
- data/spec/dispatcher_spec.rb +136 -0
- data/spec/distinguished_name_spec.rb +24 -0
- data/spec/encrypted_document_spec.rb +21 -0
- data/spec/job_spec.rb +219 -0
- data/spec/local_state_spec.rb +112 -0
- data/spec/packet_spec.rb +218 -0
- data/spec/rsa_key_pair_spec.rb +33 -0
- data/spec/secure_serializer_spec.rb +41 -0
- data/spec/serializer_spec.rb +107 -0
- data/spec/signature_spec.rb +30 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/static_certificate_store_spec.rb +30 -0
- data/spec/util_spec.rb +63 -0
- metadata +62 -1
data/spec/agent_spec.rb
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Agent:" do
|
4
|
+
|
5
|
+
describe "Default Option" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
EM.stub!(:add_periodic_timer)
|
9
|
+
AMQP.stub!(:connect)
|
10
|
+
@amq = mock("AMQueue", :queue => mock("queue", :subscribe => {}), :fanout => mock("fanout", :publish => nil))
|
11
|
+
MQ.stub!(:new).and_return(@amq)
|
12
|
+
@agent = Nanite::Agent.start
|
13
|
+
end
|
14
|
+
|
15
|
+
it "for daemonize is false" do
|
16
|
+
@agent.options.should include(:daemonize)
|
17
|
+
@agent.options[:daemonize].should == false
|
18
|
+
end
|
19
|
+
|
20
|
+
it "for format is marshal" do
|
21
|
+
@agent.options.should include(:format)
|
22
|
+
@agent.options[:format].should == :marshal
|
23
|
+
end
|
24
|
+
|
25
|
+
it "for console is false" do
|
26
|
+
@agent.options.should include(:console)
|
27
|
+
@agent.options[:console].should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
it "for user is nanite" do
|
31
|
+
@agent.options.should include(:user)
|
32
|
+
@agent.options[:user].should == "nanite"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "for pass(word) is testing" do
|
36
|
+
@agent.options.should include(:pass)
|
37
|
+
@agent.options[:pass].should == "testing"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "for secure is false" do
|
41
|
+
@agent.options.should include(:secure)
|
42
|
+
@agent.options[:secure].should == false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "for host is 0.0.0.0" do
|
46
|
+
@agent.options.should include(:host)
|
47
|
+
@agent.options[:host].should == "0.0.0.0"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "for log_level is info" do
|
51
|
+
@agent.options.should include(:log_level)
|
52
|
+
@agent.options[:log_level].should == :info
|
53
|
+
end
|
54
|
+
|
55
|
+
it "for vhost is /nanite" do
|
56
|
+
@agent.options.should include(:vhost)
|
57
|
+
@agent.options[:vhost].should == "/nanite"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "for ping_time is 15" do
|
61
|
+
@agent.options.should include(:ping_time)
|
62
|
+
@agent.options[:ping_time].should == 15
|
63
|
+
end
|
64
|
+
|
65
|
+
it "for default_services is []" do
|
66
|
+
@agent.options.should include(:default_services)
|
67
|
+
@agent.options[:default_services].should == []
|
68
|
+
end
|
69
|
+
|
70
|
+
it "for root is #{File.expand_path(File.join(File.dirname(__FILE__), '..'))}" do
|
71
|
+
@agent.options.should include(:root)
|
72
|
+
@agent.options[:root].should == File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
73
|
+
end
|
74
|
+
|
75
|
+
it "for file_root is #{File.expand_path(File.join(File.dirname(__FILE__), '..', 'files'))}" do
|
76
|
+
@agent.options.should include(:file_root)
|
77
|
+
@agent.options[:file_root].should == File.expand_path(File.join(File.dirname(__FILE__), '..', 'files'))
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "Options from config.yml" do
|
83
|
+
|
84
|
+
before(:all) do
|
85
|
+
@agent = Nanite::Agent.start
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "Passed in Options" do
|
91
|
+
|
92
|
+
before(:each) do
|
93
|
+
EM.stub!(:add_periodic_timer)
|
94
|
+
AMQP.stub!(:connect)
|
95
|
+
@amq = mock("AMQueue", :queue => mock("queue", :subscribe => {}), :fanout => mock("fanout", :publish => nil))
|
96
|
+
MQ.stub!(:new).and_return(@amq)
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO figure out how to stub call to daemonize
|
100
|
+
# it "for daemonize should override default (false)" do
|
101
|
+
# agent = Nanite::Agent.start(:daemonize => true)
|
102
|
+
# agent.options.should include(:daemonize)
|
103
|
+
# agent.options[:daemonize].should == true
|
104
|
+
# end
|
105
|
+
|
106
|
+
it "for format should override default (marshal)" do
|
107
|
+
agent = Nanite::Agent.start(:format => :json)
|
108
|
+
agent.options.should include(:format)
|
109
|
+
agent.options[:format].should == :json
|
110
|
+
end
|
111
|
+
|
112
|
+
# TODO figure out how to avoid console output
|
113
|
+
# it "for console should override default (false)" do
|
114
|
+
# agent = Nanite::Agent.start(:console => true)
|
115
|
+
# agent.options.should include(:console)
|
116
|
+
# agent.options[:console].should == true
|
117
|
+
# end
|
118
|
+
|
119
|
+
it "for user should override default (nanite)" do
|
120
|
+
agent = Nanite::Agent.start(:user => "me")
|
121
|
+
agent.options.should include(:user)
|
122
|
+
agent.options[:user].should == "me"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "for pass(word) should override default (testing)" do
|
126
|
+
agent = Nanite::Agent.start(:pass => "secret")
|
127
|
+
agent.options.should include(:pass)
|
128
|
+
agent.options[:pass].should == "secret"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "for secure should override default (false)" do
|
132
|
+
agent = Nanite::Agent.start(:secure => true)
|
133
|
+
agent.options.should include(:secure)
|
134
|
+
agent.options[:secure].should == true
|
135
|
+
end
|
136
|
+
|
137
|
+
it "for host should override default (0.0.0.0)" do
|
138
|
+
agent = Nanite::Agent.start(:host => "127.0.0.1")
|
139
|
+
agent.options.should include(:host)
|
140
|
+
agent.options[:host].should == "127.0.0.1"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "for log_level should override default (info)" do
|
144
|
+
agent = Nanite::Agent.start(:log_level => :debug)
|
145
|
+
agent.options.should include(:log_level)
|
146
|
+
agent.options[:log_level].should == :debug
|
147
|
+
end
|
148
|
+
|
149
|
+
it "for vhost should override default (/nanite)" do
|
150
|
+
agent = Nanite::Agent.start(:vhost => "/virtual_host")
|
151
|
+
agent.options.should include(:vhost)
|
152
|
+
agent.options[:vhost].should == "/virtual_host"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "for ping_time should override default (15)" do
|
156
|
+
agent = Nanite::Agent.start(:ping_time => 5)
|
157
|
+
agent.options.should include(:ping_time)
|
158
|
+
agent.options[:ping_time].should == 5
|
159
|
+
end
|
160
|
+
|
161
|
+
it "for default_services should override default ([])" do
|
162
|
+
agent = Nanite::Agent.start(:default_services => [:test])
|
163
|
+
agent.options.should include(:default_services)
|
164
|
+
agent.options[:default_services].should == [:test]
|
165
|
+
end
|
166
|
+
|
167
|
+
it "for root should override default (#{File.expand_path(File.join(File.dirname(__FILE__), '..'))})" do
|
168
|
+
agent = Nanite::Agent.start(:root => File.expand_path(File.dirname(__FILE__)))
|
169
|
+
agent.options.should include(:root)
|
170
|
+
agent.options[:root].should == File.expand_path(File.dirname(__FILE__))
|
171
|
+
end
|
172
|
+
|
173
|
+
it "for file_root should override default (#{File.expand_path(File.join(File.dirname(__FILE__), '..', 'files'))})" do
|
174
|
+
agent = Nanite::Agent.start(:file_root => File.expand_path(File.dirname(__FILE__)))
|
175
|
+
agent.options.should include(:file_root)
|
176
|
+
agent.options[:file_root].should == File.expand_path(File.dirname(__FILE__))
|
177
|
+
end
|
178
|
+
|
179
|
+
it "for a single tag should result in the agent's tags being set" do
|
180
|
+
agent = Nanite::Agent.start(:tag => "sample_tag")
|
181
|
+
agent.tags.should include("sample_tag")
|
182
|
+
end
|
183
|
+
|
184
|
+
it "for multiple tags should result in the agent's tags being set" do
|
185
|
+
agent = Nanite::Agent.start(:tag => ["sample_tag_1", "sample_tag_2"])
|
186
|
+
agent.tags.should include("sample_tag_1")
|
187
|
+
agent.tags.should include("sample_tag_2")
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "Security" do
|
193
|
+
|
194
|
+
before(:each) do
|
195
|
+
EM.stub!(:add_periodic_timer)
|
196
|
+
AMQP.stub!(:connect)
|
197
|
+
@amq = mock("AMQueue", :queue => mock("queue", :subscribe => {}, :publish => {}), :fanout => mock("fanout", :publish => nil))
|
198
|
+
MQ.stub!(:new).and_return(@amq)
|
199
|
+
serializer = Nanite::Serializer.new
|
200
|
+
@request = Nanite::Request.new('/foo/bar', '')
|
201
|
+
@push = Nanite::Push.new('/foo/bar', '')
|
202
|
+
@agent = Nanite::Agent.start
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should correctly deny requests' do
|
206
|
+
security = mock("Security")
|
207
|
+
@agent.register_security(security)
|
208
|
+
|
209
|
+
security.should_receive(:authorize).twice.and_return(false)
|
210
|
+
@agent.dispatcher.should_not_receive(:dispatch)
|
211
|
+
@agent.__send__(:receive, @request)
|
212
|
+
@agent.__send__(:receive, @push)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should correctly authorize requests' do
|
216
|
+
security = mock("Security")
|
217
|
+
@agent.register_security(security)
|
218
|
+
|
219
|
+
security.should_receive(:authorize).twice.and_return(true)
|
220
|
+
@agent.dispatcher.stub!(:dispatch)
|
221
|
+
@agent.dispatcher.should_receive(:dispatch).twice
|
222
|
+
@agent.__send__(:receive, @request)
|
223
|
+
@agent.__send__(:receive, @push)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should be ignored when not specified' do
|
227
|
+
@agent.dispatcher.stub!(:dispatch)
|
228
|
+
@agent.dispatcher.should_receive(:dispatch).twice
|
229
|
+
@agent.__send__(:receive, @request)
|
230
|
+
@agent.__send__(:receive, @push)
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::CachedCertificateStoreProxy do
|
4
|
+
|
5
|
+
include SpecHelpers
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@signer, key = issue_cert
|
9
|
+
@recipient, key = issue_cert
|
10
|
+
@store = mock("Store")
|
11
|
+
@proxy = Nanite::CachedCertificateStoreProxy.new(@store)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should not raise and return nil for non existent certificates' do
|
15
|
+
res = nil
|
16
|
+
@store.should_receive(:get_recipients).with(nil).and_return(nil)
|
17
|
+
lambda { res = @proxy.get_recipients(nil) }.should_not raise_error
|
18
|
+
res.should == nil
|
19
|
+
@store.should_receive(:get_signer).with(nil).and_return(nil)
|
20
|
+
lambda { res = @proxy.get_signer(nil) }.should_not raise_error
|
21
|
+
res.should == nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should return recipient certificates' do
|
25
|
+
@store.should_receive(:get_recipients).with('anything').and_return(@recipient)
|
26
|
+
@proxy.get_recipients('anything').should == @recipient
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return signer certificates' do
|
30
|
+
@store.should_receive(:get_signer).with('anything').and_return(@signer)
|
31
|
+
@proxy.get_signer('anything').should == @signer
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::CertificateCache do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@cache = Nanite::CertificateCache.new(2)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should allow storing and retrieving objects' do
|
10
|
+
@cache['some_id'].should be_nil
|
11
|
+
@cache['some_id'] = 'some_value'
|
12
|
+
@cache['some_id'].should == 'some_value'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should not store more than required' do
|
16
|
+
@cache[1] = 'oldest'
|
17
|
+
@cache[2] = 'older'
|
18
|
+
@cache[1].should == 'oldest'
|
19
|
+
@cache[2].should == 'older'
|
20
|
+
|
21
|
+
@cache[3] = 'new'
|
22
|
+
@cache[3].should == 'new'
|
23
|
+
|
24
|
+
@cache[1].should be_nil
|
25
|
+
@cache[2].should == 'older'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should use LRU to remove entries' do
|
29
|
+
@cache[1] = 'oldest'
|
30
|
+
@cache[2] = 'older'
|
31
|
+
@cache[1].should == 'oldest'
|
32
|
+
@cache[2].should == 'older'
|
33
|
+
|
34
|
+
@cache[1] = 'new'
|
35
|
+
@cache[3] = 'newer'
|
36
|
+
@cache[1].should == 'new'
|
37
|
+
@cache[3].should == 'newer'
|
38
|
+
|
39
|
+
@cache[2].should be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should store items returned by block' do
|
43
|
+
@cache[1].should be_nil
|
44
|
+
item = @cache.get(1) { 'item' }
|
45
|
+
item.should == 'item'
|
46
|
+
@cache[1].should == 'item'
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::Certificate do
|
4
|
+
|
5
|
+
include SpecHelpers
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@certificate, key = issue_cert
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should save' do
|
12
|
+
filename = File.join(File.dirname(__FILE__), "cert.pem")
|
13
|
+
@certificate.save(filename)
|
14
|
+
File.size(filename).should be > 0
|
15
|
+
File.delete(filename)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should load' do
|
19
|
+
filename = File.join(File.dirname(__FILE__), "cert.pem")
|
20
|
+
@certificate.save(filename)
|
21
|
+
cert = Nanite::Certificate.load(filename)
|
22
|
+
File.delete(filename)
|
23
|
+
cert.should_not be_nil
|
24
|
+
cert.data.should == @certificate.data
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,300 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::Cluster do
|
4
|
+
|
5
|
+
describe "Intialization" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@fanout = mock("fanout")
|
9
|
+
@binding = mock("binding", :subscribe => true)
|
10
|
+
@queue = mock("queue", :bind => @binding)
|
11
|
+
@amq = mock("AMQueue", :queue => @queue, :fanout => @fanout)
|
12
|
+
@serializer = mock("Serializer")
|
13
|
+
@reaper = mock("Reaper")
|
14
|
+
@mapper = mock("Mapper")
|
15
|
+
Nanite::Reaper.stub!(:new).and_return(@reaper)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "of Heartbeat (Queue)" do
|
19
|
+
|
20
|
+
it "should setup the heartbeat (queue) for id" do
|
21
|
+
@amq.should_receive(:queue).with("heartbeat-the_identity", anything()).and_return(@queue)
|
22
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should make the heartbeat (queue) exclusive" do
|
26
|
+
@amq.should_receive(:queue).with("heartbeat-the_identity", { :exclusive => true }).and_return(@queue)
|
27
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should bind the heartbeat (queue) to 'heartbeat' fanout" do
|
31
|
+
@amq.should_receive(:fanout).with("heartbeat", { :durable => true }).and_return(@fanout)
|
32
|
+
@queue.should_receive(:bind).with(@fanout).and_return(@binding)
|
33
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
34
|
+
end
|
35
|
+
|
36
|
+
end # of Heartbeat (Queue)
|
37
|
+
|
38
|
+
|
39
|
+
describe "of Registration (Queue)" do
|
40
|
+
|
41
|
+
it "should setup the registration (queue) for id" do
|
42
|
+
@amq.should_receive(:queue).with("registration-the_identity", anything()).and_return(@queue)
|
43
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should make the registration (queue) exclusive" do
|
47
|
+
@amq.should_receive(:queue).with("registration-the_identity", { :exclusive => true }).and_return(@queue)
|
48
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should bind the registration (queue) to 'registration' fanout" do
|
52
|
+
@amq.should_receive(:fanout).with("registration", { :durable => true }).and_return(@fanout)
|
53
|
+
@queue.should_receive(:bind).with(@fanout).and_return(@binding)
|
54
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
55
|
+
end
|
56
|
+
|
57
|
+
end # of Registration (Queue)
|
58
|
+
|
59
|
+
describe "of Request (Queue)" do
|
60
|
+
|
61
|
+
it "should setup the request (queue) for id" do
|
62
|
+
@amq.should_receive(:queue).with("request-the_identity", anything()).and_return(@queue)
|
63
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should make the request (queue) exclusive" do
|
67
|
+
@amq.should_receive(:queue).with("request-the_identity", { :exclusive => true }).and_return(@queue)
|
68
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should bind the request (queue) to 'request' fanout" do
|
72
|
+
@amq.should_receive(:fanout).with("request", { :durable => true }).and_return(@fanout)
|
73
|
+
@queue.should_receive(:bind).with(@fanout).and_return(@binding)
|
74
|
+
cluster = Nanite::Cluster.new(@amq, 10, "the_identity", @serializer, @mapper)
|
75
|
+
end
|
76
|
+
|
77
|
+
end # of Request (Queue)
|
78
|
+
|
79
|
+
|
80
|
+
describe "Reaper" do
|
81
|
+
|
82
|
+
it "should be created" do
|
83
|
+
Nanite::Reaper.should_receive(:new).with(anything()).and_return(@reaper)
|
84
|
+
cluster = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should use the agent timeout" do
|
88
|
+
Nanite::Reaper.should_receive(:new).with(443).and_return(@reaper)
|
89
|
+
cluster = Nanite::Cluster.new(@amq, 443, "the_identity", @serializer, @mapper)
|
90
|
+
end
|
91
|
+
|
92
|
+
end # Reaper
|
93
|
+
|
94
|
+
end # Intialization
|
95
|
+
|
96
|
+
|
97
|
+
describe "Target Selection" do
|
98
|
+
|
99
|
+
before(:each) do
|
100
|
+
@fanout = mock("fanout")
|
101
|
+
@binding = mock("binding", :subscribe => true)
|
102
|
+
@queue = mock("queue", :bind => @binding)
|
103
|
+
@amq = mock("AMQueue", :queue => @queue, :fanout => @fanout)
|
104
|
+
@serializer = mock("Serializer")
|
105
|
+
@reaper = mock("Reaper")
|
106
|
+
Nanite::Reaper.stub!(:new).and_return(@reaper)
|
107
|
+
@cluster = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return array containing targets for request" do
|
111
|
+
target = mock("Supplied Target")
|
112
|
+
request = mock("Request", :target => target)
|
113
|
+
@cluster.targets_for(request).should be_instance_of(Array)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should use target from request" do
|
117
|
+
target = mock("Supplied Target")
|
118
|
+
request = mock("Request", :target => target)
|
119
|
+
@cluster.targets_for(request).should == [target]
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should use targets choosen by least loaded selector (:least_loaded)" do
|
123
|
+
targets = { "target 3" => 3 }
|
124
|
+
request = mock("Request", :target => nil, :selector => :least_loaded, :type => "service", :tags => [])
|
125
|
+
@cluster.should_receive(:least_loaded).with("service", []).and_return(targets)
|
126
|
+
@cluster.targets_for(request).should == ["target 3"]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should use targets choosen by all selector (:all)" do
|
130
|
+
targets = { "target 1" => 1, "target 2" => 2, "target 3" => 3 }
|
131
|
+
request = mock("Request", :target => nil, :selector => :all, :type => "service", :tags => [])
|
132
|
+
@cluster.should_receive(:all).with("service", []).and_return(targets)
|
133
|
+
@cluster.targets_for(request).should == ["target 1", "target 2", "target 3"]
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should use targets choosen by random selector (:random)" do
|
137
|
+
targets = { "target 3" => 3 }
|
138
|
+
request = mock("Request", :target => nil, :selector => :random, :type => "service", :tags => [])
|
139
|
+
@cluster.should_receive(:random).with("service", []).and_return(targets)
|
140
|
+
@cluster.targets_for(request).should == ["target 3"]
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should use targets choosen by round-robin selector (:rr)" do
|
144
|
+
targets = { "target 2" => 2 }
|
145
|
+
request = mock("Request", :target => nil, :selector => :rr, :type => "service", :tags => [])
|
146
|
+
@cluster.should_receive(:rr).with("service", []).and_return(targets)
|
147
|
+
@cluster.targets_for(request).should == ["target 2"]
|
148
|
+
end
|
149
|
+
|
150
|
+
end # Target Selection
|
151
|
+
|
152
|
+
|
153
|
+
describe "Nanite Registration" do
|
154
|
+
|
155
|
+
before(:each) do
|
156
|
+
@fanout = mock("fanout")
|
157
|
+
@binding = mock("binding", :subscribe => true)
|
158
|
+
@queue = mock("queue", :bind => @binding)
|
159
|
+
@amq = mock("AMQueue", :queue => @queue, :fanout => @fanout)
|
160
|
+
@serializer = mock("Serializer")
|
161
|
+
@reaper = mock("Reaper", :timeout => true)
|
162
|
+
Nanite::Log.stub!(:info)
|
163
|
+
Nanite::Reaper.stub!(:new).and_return(@reaper)
|
164
|
+
@cluster = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper)
|
165
|
+
@register_packet = Nanite::Register.new("nanite_id", ["the_nanite_services"], "nanite_status",[])
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should add the Nanite to the nanites map" do
|
169
|
+
@cluster.register(@register_packet)
|
170
|
+
@cluster.nanites['nanite_id'].should_not be_nil
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should use hash of the Nanite's services and status as value" do
|
174
|
+
@cluster.register(@register_packet)
|
175
|
+
@cluster.nanites['nanite_id'].keys.size == 2
|
176
|
+
@cluster.nanites['nanite_id'].keys.should include(:services)
|
177
|
+
@cluster.nanites['nanite_id'].keys.should include(:status)
|
178
|
+
@cluster.nanites['nanite_id'][:services].should == ["the_nanite_services"]
|
179
|
+
@cluster.nanites['nanite_id'][:status].should == "nanite_status"
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should add nanite to reaper" do
|
183
|
+
@reaper.should_receive(:timeout).with('nanite_id', 33)
|
184
|
+
@cluster.register(@register_packet)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should log info message that nanite was registered" do
|
188
|
+
Nanite::Log.should_receive(:info)
|
189
|
+
@cluster.register(@register_packet)
|
190
|
+
end
|
191
|
+
|
192
|
+
end # Nanite Registration
|
193
|
+
|
194
|
+
|
195
|
+
describe "Route" do
|
196
|
+
|
197
|
+
before(:each) do
|
198
|
+
@fanout = mock("fanout")
|
199
|
+
@binding = mock("binding", :subscribe => true)
|
200
|
+
@queue = mock("queue", :bind => @binding)
|
201
|
+
@amq = mock("AMQueue", :queue => @queue, :fanout => @fanout)
|
202
|
+
@serializer = mock("Serializer")
|
203
|
+
@reaper = mock("Reaper")
|
204
|
+
Nanite::Reaper.stub!(:new).and_return(@reaper)
|
205
|
+
@cluster = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper)
|
206
|
+
@request = mock("Request")
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should publish request to all targets" do
|
210
|
+
target1 = mock("Target 1")
|
211
|
+
target2 = mock("Target 2")
|
212
|
+
@cluster.should_receive(:publish).with(@request, target1)
|
213
|
+
@cluster.should_receive(:publish).with(@request, target2)
|
214
|
+
EM.run {
|
215
|
+
@cluster.route(@request, [target1, target2])
|
216
|
+
EM.stop
|
217
|
+
}
|
218
|
+
end
|
219
|
+
|
220
|
+
end # Route
|
221
|
+
|
222
|
+
|
223
|
+
describe "Publish" do
|
224
|
+
|
225
|
+
before(:each) do
|
226
|
+
@fanout = mock("fanout")
|
227
|
+
@binding = mock("binding", :subscribe => true)
|
228
|
+
@queue = mock("queue", :bind => @binding, :publish => true)
|
229
|
+
@amq = mock("AMQueue", :queue => @queue, :fanout => @fanout)
|
230
|
+
@serializer = mock("Serializer", :dump => "dumped_value")
|
231
|
+
@reaper = mock("Reaper")
|
232
|
+
Nanite::Reaper.stub!(:new).and_return(@reaper)
|
233
|
+
@cluster = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper)
|
234
|
+
@request = mock("Request", :persistent => true)
|
235
|
+
@target = mock("Target of Request")
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should serialize request before publishing it" do
|
239
|
+
@request.should_receive(:target=).with(@target)
|
240
|
+
@request.should_receive(:target=)
|
241
|
+
@request.should_receive(:target)
|
242
|
+
@serializer.should_receive(:dump).with(@request).and_return("serialized_request")
|
243
|
+
@cluster.publish(@request, @target)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should publish request to target queue" do
|
247
|
+
@request.should_receive(:target=).with(@target)
|
248
|
+
@request.should_receive(:target=)
|
249
|
+
@request.should_receive(:target)
|
250
|
+
@queue.should_receive(:publish).with("dumped_value", anything())
|
251
|
+
@cluster.publish(@request, @target)
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should persist request based on request setting" do
|
255
|
+
@request.should_receive(:target=).with(@target)
|
256
|
+
@request.should_receive(:target=)
|
257
|
+
@request.should_receive(:target)
|
258
|
+
@request.should_receive(:persistent).and_return(false)
|
259
|
+
@queue.should_receive(:publish).with(anything(), { :persistent => false })
|
260
|
+
@cluster.publish(@request, @target)
|
261
|
+
end
|
262
|
+
|
263
|
+
end # Publish
|
264
|
+
|
265
|
+
describe "Agent Request Handling" do
|
266
|
+
|
267
|
+
before(:each) do
|
268
|
+
@fanout = mock("fanout")
|
269
|
+
@binding = mock("binding", :subscribe => true)
|
270
|
+
@queue = mock("queue", :bind => @binding, :publish => true)
|
271
|
+
@amq = mock("AMPQueue", :queue => @queue, :fanout => @fanout)
|
272
|
+
@serializer = mock("Serializer", :dump => "dumped_value")
|
273
|
+
@target = mock("Target of Request")
|
274
|
+
@reaper = mock("Reaper")
|
275
|
+
Nanite::Reaper.stub!(:new).and_return(@reaper)
|
276
|
+
@request_without_target = mock("Request", :target => nil, :token => "Token",
|
277
|
+
:reply_to => "Reply To", :from => "From", :persistent => true, :identity => "Identity")
|
278
|
+
@request_with_target = mock("Request", :target => "Target", :token => "Token",
|
279
|
+
:reply_to => "Reply To", :from => "From", :persistent => true)
|
280
|
+
@mapper_with_target = mock("Mapper", :identity => "id")
|
281
|
+
@mapper_without_target = mock("Mapper", :request => false, :identity => @request_without_target.identity)
|
282
|
+
@cluster_with_target = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper_with_target)
|
283
|
+
@cluster_without_target = Nanite::Cluster.new(@amq, 32, "the_identity", @serializer, @mapper_without_target)
|
284
|
+
Nanite::Cluster.stub!(:mapper).and_return(@mapper)
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should forward requests with targets" do
|
288
|
+
@mapper_with_target.should_receive(:send_request).with(@request_with_target, anything())
|
289
|
+
@cluster_with_target.__send__(:handle_request, @request_with_target)
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should reply back with nil results for requests with no target when offline queue is disabled" do
|
293
|
+
@mapper_without_target.should_receive(:send_request).with(@request_without_target, anything())
|
294
|
+
Nanite::Result.should_receive(:new).with(@request_without_target.token, @request_without_target.from, nil, @request_without_target.identity)
|
295
|
+
@cluster_without_target.__send__(:handle_request, @request_without_target)
|
296
|
+
end
|
297
|
+
|
298
|
+
end # Agent Request Handling
|
299
|
+
|
300
|
+
end # Nanite::Cluster
|