rightscale-nanite 0.4.1 → 0.4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
include Nanite::Actor
|
5
|
+
expose :bar, :index, :i_kill_you
|
6
|
+
on_exception :handle_exception
|
7
|
+
|
8
|
+
def index(payload)
|
9
|
+
bar(payload)
|
10
|
+
end
|
11
|
+
|
12
|
+
def bar(payload)
|
13
|
+
['hello', payload]
|
14
|
+
end
|
15
|
+
|
16
|
+
def bar2(payload, deliverable)
|
17
|
+
deliverable
|
18
|
+
end
|
19
|
+
|
20
|
+
def i_kill_you(payload)
|
21
|
+
raise RuntimeError.new('I kill you!')
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_exception(method, deliverable, error)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Bar
|
29
|
+
include Nanite::Actor
|
30
|
+
expose :i_kill_you
|
31
|
+
on_exception do |method, deliverable, error|
|
32
|
+
@scope = self
|
33
|
+
@called_with = [method, deliverable, error]
|
34
|
+
end
|
35
|
+
|
36
|
+
def i_kill_you(payload)
|
37
|
+
raise RuntimeError.new('I kill you!')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# No specs, simply ensures multiple methods for assigning on_exception callback,
|
42
|
+
# on_exception raises exception when called with an invalid argument.
|
43
|
+
class Doomed
|
44
|
+
include Nanite::Actor
|
45
|
+
on_exception do
|
46
|
+
end
|
47
|
+
on_exception lambda {}
|
48
|
+
on_exception :doh
|
49
|
+
end
|
50
|
+
|
51
|
+
# Mock the EventMachine deferrer.
|
52
|
+
class EMMock
|
53
|
+
def self.defer(op = nil, callback = nil)
|
54
|
+
callback.call(op.call)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "Nanite::Dispatcher" do
|
59
|
+
|
60
|
+
before(:each) do
|
61
|
+
Nanite::Log.stub!(:info)
|
62
|
+
Nanite::Log.stub!(:error)
|
63
|
+
amq = mock('amq', :queue => mock('queue', :publish => nil))
|
64
|
+
@actor = Foo.new
|
65
|
+
@registry = Nanite::ActorRegistry.new
|
66
|
+
@registry.register(@actor, nil)
|
67
|
+
@dispatcher = Nanite::Dispatcher.new(amq, @registry, Nanite::Serializer.new(:marshal), '0xfunkymonkey', {})
|
68
|
+
@dispatcher.evmclass = EMMock
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should dispatch a request" do
|
72
|
+
req = Nanite::Request.new('/foo/bar', 'you')
|
73
|
+
res = @dispatcher.dispatch(req)
|
74
|
+
res.should(be_kind_of(Nanite::Result))
|
75
|
+
res.token.should == req.token
|
76
|
+
res.results.should == ['hello', 'you']
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should dispatch the deliverable to actions that accept it" do
|
80
|
+
req = Nanite::Request.new('/foo/bar2', 'you')
|
81
|
+
res = @dispatcher.dispatch(req)
|
82
|
+
res.should(be_kind_of(Nanite::Result))
|
83
|
+
res.token.should == req.token
|
84
|
+
res.results.should == req
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should dispatch a request to the default action" do
|
88
|
+
req = Nanite::Request.new('/foo', 'you')
|
89
|
+
res = @dispatcher.dispatch(req)
|
90
|
+
res.should(be_kind_of(Nanite::Result))
|
91
|
+
res.token.should == req.token
|
92
|
+
res.results.should == ['hello', 'you']
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should handle custom prefixes" do
|
96
|
+
@registry.register(Foo.new, 'umbongo')
|
97
|
+
req = Nanite::Request.new('/umbongo/bar', 'you')
|
98
|
+
res = @dispatcher.dispatch(req)
|
99
|
+
res.should(be_kind_of(Nanite::Result))
|
100
|
+
res.token.should == req.token
|
101
|
+
res.results.should == ['hello', 'you']
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should call the on_exception callback if something goes wrong" do
|
105
|
+
req = Nanite::Request.new('/foo/i_kill_you', nil)
|
106
|
+
@actor.should_receive(:handle_exception).with(:i_kill_you, req, duck_type(:exception, :backtrace))
|
107
|
+
@dispatcher.dispatch(req)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should call on_exception Procs defined in a subclass with the correct arguments" do
|
111
|
+
actor = Bar.new
|
112
|
+
@registry.register(actor, nil)
|
113
|
+
req = Nanite::Request.new('/bar/i_kill_you', nil)
|
114
|
+
@dispatcher.dispatch(req)
|
115
|
+
called_with = actor.instance_variable_get("@called_with")
|
116
|
+
called_with[0].should == :i_kill_you
|
117
|
+
called_with[1].should == req
|
118
|
+
called_with[2].should be_kind_of(RuntimeError)
|
119
|
+
called_with[2].message.should == 'I kill you!'
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should call on_exception Procs defined in a subclass in the scope of the actor" do
|
123
|
+
actor = Bar.new
|
124
|
+
@registry.register(actor, nil)
|
125
|
+
req = Nanite::Request.new('/bar/i_kill_you', nil)
|
126
|
+
@dispatcher.dispatch(req)
|
127
|
+
actor.instance_variable_get("@scope").should == actor
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should log error if something goes wrong" do
|
131
|
+
Nanite::Log.should_receive(:error)
|
132
|
+
req = Nanite::Request.new('/foo/i_kill_you', nil)
|
133
|
+
@dispatcher.dispatch(req)
|
134
|
+
end
|
135
|
+
|
136
|
+
end # Nanite::Dispatcher
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::DistinguishedName do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
test_dn = { 'C' => 'US',
|
7
|
+
'ST' => 'California',
|
8
|
+
'L' => 'Santa Barbara',
|
9
|
+
'O' => 'RightScale',
|
10
|
+
'OU' => 'Certification Services',
|
11
|
+
'CN' => 'rightscale.com/emailAddress=cert@rightscale.com' }
|
12
|
+
@dn = Nanite::DistinguishedName.new(test_dn)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should convert to string and X509 DN' do
|
16
|
+
@dn.to_s.should_not be_nil
|
17
|
+
@dn.to_x509.should_not be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should correctly encode' do
|
21
|
+
@dn.to_s.should == @dn.to_x509.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::EncryptedDocument do
|
4
|
+
|
5
|
+
include SpecHelpers
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@test_data = "Test Data to Sign"
|
9
|
+
@cert, @key = issue_cert
|
10
|
+
@doc = Nanite::EncryptedDocument.new(@test_data, @cert)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should create encrypted data' do
|
14
|
+
@doc.encrypted_data.should_not be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should decrypt correctly' do
|
18
|
+
@doc.decrypted_data(@key, @cert).should == @test_data
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/spec/job_spec.rb
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Nanite::JobWarden do
|
4
|
+
|
5
|
+
describe "Creating a new Job" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@serializer = mock("Serializer")
|
9
|
+
@warden = Nanite::JobWarden.new(@serializer)
|
10
|
+
|
11
|
+
@request = mock("Request")
|
12
|
+
@targets = mock("Targets")
|
13
|
+
@job = mock("Job", :token => "3faba24fcc")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should instantiate a new Job" do
|
17
|
+
Nanite::Job.should_receive(:new).with(@request, @targets, nil, nil).and_return(@job)
|
18
|
+
@warden.new_job(@request, @targets)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should add the job to the job list" do
|
22
|
+
Nanite::Job.should_receive(:new).with(@request, @targets, nil, nil).and_return(@job)
|
23
|
+
@warden.jobs.size.should == 0
|
24
|
+
@warden.new_job(@request, @targets)
|
25
|
+
@warden.jobs.size.should == 1
|
26
|
+
@warden.jobs["3faba24fcc"].should == @job
|
27
|
+
end
|
28
|
+
|
29
|
+
it "return the newly crated job" do
|
30
|
+
Nanite::Job.should_receive(:new).with(@request, @targets, nil, nil).and_return(@job)
|
31
|
+
@warden.new_job(@request, @targets).should == @job
|
32
|
+
end
|
33
|
+
|
34
|
+
end # Creating a new Job
|
35
|
+
|
36
|
+
|
37
|
+
describe "Processing a Message" do
|
38
|
+
|
39
|
+
before(:each) do
|
40
|
+
@message = mock("Message", :token => "3faba24fcc")
|
41
|
+
@warden = Nanite::JobWarden.new(@serializer)
|
42
|
+
@job = mock("Job", :token => "3faba24fcc", :process => true, :completed? => false, :results => 42, :pending_keys => [], :intermediate_handler => true)
|
43
|
+
|
44
|
+
Nanite::Log.stub!(:debug)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should log debug message about message to be processed" do
|
48
|
+
Nanite::Log.should_receive(:debug)
|
49
|
+
@warden.process(@message)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should hand over processing to job" do
|
53
|
+
Nanite::Job.stub!(:new).and_return(@job)
|
54
|
+
@job.should_receive(:process).with(@message)
|
55
|
+
|
56
|
+
@warden.new_job("request", "targets")
|
57
|
+
@warden.process(@message)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should delete job from jobs after completion" do
|
61
|
+
Nanite::Job.stub!(:new).and_return(@job)
|
62
|
+
@job.should_receive(:process).with(@message)
|
63
|
+
@job.should_receive(:completed?).and_return(true)
|
64
|
+
@job.should_receive(:completed).and_return(nil)
|
65
|
+
|
66
|
+
@warden.jobs["3faba24fcc"].should be_nil
|
67
|
+
@warden.new_job("request", "targets")
|
68
|
+
@warden.jobs["3faba24fcc"].should == @job
|
69
|
+
@warden.process(@message)
|
70
|
+
@warden.jobs["3faba24fcc"].should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should call completed block after completion" do
|
74
|
+
completed_block = mock("Completed", :arity => 1, :call => true)
|
75
|
+
|
76
|
+
Nanite::Job.stub!(:new).and_return(@job)
|
77
|
+
@job.should_receive(:process).with(@message)
|
78
|
+
@job.should_receive(:completed?).and_return(true)
|
79
|
+
@job.should_receive(:completed).exactly(3).times.and_return(completed_block)
|
80
|
+
|
81
|
+
@warden.new_job("request", "targets")
|
82
|
+
@warden.process(@message)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should pass in job result if arity of completed block is one" do
|
86
|
+
completed_block = mock("Completed")
|
87
|
+
|
88
|
+
Nanite::Job.stub!(:new).and_return(@job)
|
89
|
+
@job.should_receive(:process).with(@message)
|
90
|
+
@job.should_receive(:completed?).and_return(true)
|
91
|
+
@job.should_receive(:completed).exactly(3).times.and_return(completed_block)
|
92
|
+
@job.should_receive(:results).and_return("the job result")
|
93
|
+
completed_block.should_receive(:arity).and_return(1)
|
94
|
+
completed_block.should_receive(:call).with("the job result")
|
95
|
+
|
96
|
+
@warden.new_job("request", "targets")
|
97
|
+
@warden.process(@message)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should pass in job result and job if arity of completed block is two" do
|
101
|
+
completed_block = mock("Completed")
|
102
|
+
|
103
|
+
Nanite::Job.stub!(:new).and_return(@job)
|
104
|
+
@job.should_receive(:process).with(@message)
|
105
|
+
@job.should_receive(:completed?).and_return(true)
|
106
|
+
@job.should_receive(:completed).exactly(3).times.and_return(completed_block)
|
107
|
+
@job.should_receive(:results).and_return("the job result")
|
108
|
+
completed_block.should_receive(:arity).and_return(2)
|
109
|
+
completed_block.should_receive(:call).with("the job result", @job)
|
110
|
+
|
111
|
+
@warden.new_job("request", "targets")
|
112
|
+
@warden.process(@message)
|
113
|
+
end
|
114
|
+
|
115
|
+
end # Processing a Message
|
116
|
+
|
117
|
+
end # Nanite::JobWarden
|
118
|
+
|
119
|
+
|
120
|
+
describe Nanite::Job do
|
121
|
+
|
122
|
+
describe "Creating a Job" do
|
123
|
+
|
124
|
+
before(:each) do
|
125
|
+
@request = mock("Request", :token => "af534ceaaacdcd")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should initialize the request" do
|
129
|
+
job = Nanite::Job.new(@request, nil, nil)
|
130
|
+
job.request.should == @request
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should initialize the targets" do
|
134
|
+
job = Nanite::Job.new(@request, "targets", nil)
|
135
|
+
job.targets.should == "targets"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should initialize the job token to the request token" do
|
139
|
+
job = Nanite::Job.new(@request, nil, nil)
|
140
|
+
job.token.should == "af534ceaaacdcd"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should initialize the results to an empty hash" do
|
144
|
+
job = Nanite::Job.new(@request, nil, nil)
|
145
|
+
job.results.should == {}
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should initialize the intermediate state to an empty hash" do
|
149
|
+
job = Nanite::Job.new(@request, nil, nil)
|
150
|
+
job.intermediate_state.should == {}
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should initialize the job block" do
|
154
|
+
job = Nanite::Job.new(@request, nil, nil, "my block")
|
155
|
+
job.completed.should == "my block"
|
156
|
+
end
|
157
|
+
|
158
|
+
end # Creating a new Job
|
159
|
+
|
160
|
+
|
161
|
+
describe "Processing a Message" do
|
162
|
+
|
163
|
+
before(:each) do
|
164
|
+
@request = mock("Request", :token => "feeefe132")
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should set the job result (for sender) to the message result for 'final' status messages" do
|
168
|
+
job = Nanite::Job.new(@request, [], nil)
|
169
|
+
message = Nanite::Result.new('token', 'to', 'results', 'from')
|
170
|
+
job.results.should == {}
|
171
|
+
job.process(message)
|
172
|
+
job.results.should == { 'from' => 'results' }
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should delete the message sender from the targets for 'final' status messages" do
|
176
|
+
job = Nanite::Job.new(@request, ['from'], nil)
|
177
|
+
message = Nanite::Result.new('token', 'to', 'results', 'from')
|
178
|
+
job.targets.should == ['from']
|
179
|
+
job.process(message)
|
180
|
+
job.targets.should == []
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should set the job result (for sender) to the message result for 'intermediate' status messages" do
|
184
|
+
job = Nanite::Job.new(@request, ['from'], nil)
|
185
|
+
message = Nanite::IntermediateMessage.new('token', 'to', 'from', 'messagekey', 'message')
|
186
|
+
job.process(message)
|
187
|
+
job.intermediate_state.should == { 'from' => { 'messagekey' => ['message'] } }
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should not delete the message sender from the targets for 'intermediate' status messages" do
|
191
|
+
job = Nanite::Job.new(@request, ['from'], nil)
|
192
|
+
message = Nanite::IntermediateMessage.new('token', 'to', 'from', 'messagekey', 'message')
|
193
|
+
job.targets.should == ['from']
|
194
|
+
job.process(message)
|
195
|
+
job.targets.should == ['from']
|
196
|
+
end
|
197
|
+
|
198
|
+
end # Processing a Message
|
199
|
+
|
200
|
+
|
201
|
+
describe "Completion" do
|
202
|
+
|
203
|
+
before(:each) do
|
204
|
+
@request = mock("Request", :token => "af534ceaaacdcd")
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should be true is targets are empty" do
|
208
|
+
job = Nanite::Job.new(@request, {}, nil)
|
209
|
+
job.completed?.should == true
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should be false is targets are not empty" do
|
213
|
+
job = Nanite::Job.new(@request, { :a => 1 }, nil)
|
214
|
+
job.completed?.should == false
|
215
|
+
end
|
216
|
+
|
217
|
+
end # Completion
|
218
|
+
|
219
|
+
end # Nanite::Job
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
require 'nanite/local_state'
|
3
|
+
|
4
|
+
describe "Nanite::LocalState: " do
|
5
|
+
|
6
|
+
describe "Class" do
|
7
|
+
|
8
|
+
it "should a Hash" do
|
9
|
+
Nanite::LocalState.new({}).should be_kind_of(Hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should create empty hash if no hash passed in" do
|
13
|
+
Nanite::LocalState.new.should == {}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should initialize hash with value passed in" do
|
17
|
+
state = Nanite::LocalState.new({:a => 1, :b => 2, :c => 3})
|
18
|
+
state.should == {:a => 1, :b => 2, :c => 3}
|
19
|
+
end
|
20
|
+
|
21
|
+
end # Class
|
22
|
+
|
23
|
+
|
24
|
+
describe "All services" do
|
25
|
+
|
26
|
+
it "should return empty array if no services are defined" do
|
27
|
+
state = Nanite::LocalState.new({:f => { :foo => 1 }, :b => { :bar => 2 }})
|
28
|
+
state.all_services.should == []
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return all :services values" do
|
32
|
+
state = Nanite::LocalState.new({:f => { :foo => 1 }, :b => { :services => "b's services" }, :c => { :services => "c's services" }})
|
33
|
+
state.all_services.should include("b's services")
|
34
|
+
state.all_services.should include("c's services")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should only return one entry for each service" do
|
38
|
+
state = Nanite::LocalState.new({:f => { :services => "services" }, :b => { :services => "services" }})
|
39
|
+
state.all_services.size == 1
|
40
|
+
state.all_services.should == ["services"]
|
41
|
+
end
|
42
|
+
|
43
|
+
end # All services
|
44
|
+
|
45
|
+
|
46
|
+
describe "All tags" do
|
47
|
+
|
48
|
+
it "should return empty array if no tags are defined" do
|
49
|
+
state = Nanite::LocalState.new({:f => { :foo => 1 }, :b => { :bar => 2 }})
|
50
|
+
state.all_tags.should == []
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return all :tags values" do
|
54
|
+
state = Nanite::LocalState.new({:f => { :foo => 1 }, :b => { :tags => ["a", "b"] }, :c => { :tags => ["c", "d"] }})
|
55
|
+
state.all_tags.should include("a")
|
56
|
+
state.all_tags.should include("b")
|
57
|
+
state.all_tags.should include("c")
|
58
|
+
state.all_tags.should include("d")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should only return one entry for each tag" do
|
62
|
+
state = Nanite::LocalState.new({:f => { :foo => 1 }, :b => { :tags => ["a", "b"] }, :c => { :tags => ["a", "c"] }})
|
63
|
+
state.all_tags.size == 3
|
64
|
+
state.all_tags.should include("a")
|
65
|
+
state.all_tags.should include("b")
|
66
|
+
state.all_tags.should include("c")
|
67
|
+
end
|
68
|
+
|
69
|
+
end # All tags
|
70
|
+
|
71
|
+
|
72
|
+
describe "Nanites lookup" do
|
73
|
+
|
74
|
+
it "should find services matching the service criteria if no tags criteria is specified" do
|
75
|
+
state = Nanite::LocalState.new({:a => { :services => "a's services" }, :b => { :services => "b's services" }})
|
76
|
+
state.nanites_for("b's services").should == [[:b, {:services => "b's services"}]]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should find all services matching the service criteria if no tags criteria is specified" do
|
80
|
+
state = Nanite::LocalState.new({:a => { :services => "services" }, :b => { :services => "services" }, :c => { :services => "other services" }})
|
81
|
+
state.nanites_for("services").should include([:a, {:services => "services"}])
|
82
|
+
state.nanites_for("services").should include([:b, {:services => "services"}])
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should only services matching the service criteria that also match the tags criteria" do
|
86
|
+
state = Nanite::LocalState.new({:a => { :services => "a's services", :tags => ["a_1", "a_2"] }, :b => { :services => "b's services", :tags => ["b_1", "b_2"] }})
|
87
|
+
state.nanites_for("b's services").should == [[:b, {:tags=>["b_1", "b_2"], :services=>"b's services"}]]
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should also return all tags for services matching the service criteria that also match a single tags criterium" do
|
91
|
+
state = Nanite::LocalState.new({:a => { :services => "services", :tags => ["t_1", "t_2"] }})
|
92
|
+
state.nanites_for("services", ["t_1"]).should == [[:a, {:tags=>["t_1", "t_2"], :services=>"services"}]]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return services matching the service criteria and also match the tags criterium" do
|
96
|
+
state = Nanite::LocalState.new({:a => { :services => "a's services", :tags => ["a_1", "a_2"] }, :b => { :services => "b's services", :tags => ["b_1", "b_2"] }})
|
97
|
+
state.nanites_for("b's services", ["b_1"]).should == [[:b, {:tags=>["b_1", "b_2"], :services=>"b's services"}]]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should ignore services matching the service criteria and but not the tags criteria" do
|
101
|
+
state = Nanite::LocalState.new({:a => { :services => "services", :tags => ["t_1", "t_2"] }, :b => { :services => "services", :tags => ["t_3", "t_4"] }})
|
102
|
+
state.nanites_for("services", ["t_1"]).should == [[:a, {:services => "services", :tags => ["t_1", "t_2"]}]]
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should lookup services matching the service criteria and and any of the tags criteria" do
|
106
|
+
state = Nanite::LocalState.new({'a' => { :services => "services", :tags => ["t_1", "t_2"] }, 'b' => { :services => "services", :tags => ["t_2", "t_3"] }})
|
107
|
+
state.nanites_for("services", ["t_1", "t_3"]).sort.should == [['a', {:services => "services", :tags => ["t_1", "t_2"]}], ['b', {:services => "services", :tags => ["t_2", "t_3"]}]]
|
108
|
+
end
|
109
|
+
|
110
|
+
end # Nanites lookup
|
111
|
+
|
112
|
+
end # Nanite::LocalState
|