right_agent 0.13.5 → 0.14.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.
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2009-2011 RightScale Inc
2
+ # Copyright (c) 2009-2012 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -75,311 +75,249 @@ class Doomed
75
75
  on_exception :doh
76
76
  end
77
77
 
78
- # Mock the EventMachine deferrer.
79
- class EMMock
80
- def self.defer(op = nil, callback = nil)
81
- callback.call(op.call)
82
- end
83
- end
84
-
85
- # Mock the EventMachine deferrer but do not do callback.
86
- class EMMockNoCallback
87
- def self.defer(op = nil, callback = nil)
88
- op.call
89
- end
90
- end
91
-
92
78
  describe "RightScale::Dispatcher" do
93
79
 
94
80
  include FlexMock::ArgumentTypes
95
81
 
96
82
  before(:each) do
97
- flexmock(RightScale::Log).should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
98
- flexmock(RightScale::Log).should_receive(:info).by_default
83
+ @log = flexmock(RightScale::Log)
84
+ @log.should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
85
+ @log.should_receive(:info).by_default
99
86
  @now = Time.at(1000000)
100
87
  flexmock(Time).should_receive(:now).and_return(@now).by_default
101
- @broker = flexmock("Broker", :subscribe => true, :publish => true).by_default
102
88
  @actor = Foo.new
103
89
  @registry = RightScale::ActorRegistry.new
104
90
  @registry.register(@actor, nil)
105
91
  @agent_id = "rs-agent-1-1"
106
- @agent = flexmock("Agent", :identity => @agent_id, :broker => @broker, :registry => @registry, :options => {}).by_default
92
+ @agent = flexmock("Agent", :identity => @agent_id, :registry => @registry).by_default
107
93
  @cache = RightScale::DispatchedCache.new(@agent_id)
108
94
  @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
109
- @dispatcher.em = EMMock
110
- @response_queue = RightScale::Dispatcher::RESPONSE_QUEUE
111
- @header = flexmock("amqp header")
112
- @header.should_receive(:ack).once.by_default
113
95
  end
114
96
 
115
- it "should dispatch a request" do
116
- req = RightScale::Request.new('/foo/bar', 'you', :token => 'token')
117
- res = @dispatcher.dispatch(req, @header)
118
- res.should(be_kind_of(RightScale::Result))
119
- res.token.should == 'token'
120
- res.results.should == ['hello', 'you']
121
- end
97
+ context "routable?" do
122
98
 
123
- it "should dispatch a request with required arity" do
124
- req = RightScale::Request.new('/foo/bar2', 'you', :token => 'token')
125
- res = @dispatcher.dispatch(req, @header)
126
- res.should(be_kind_of(RightScale::Result))
127
- res.token.should == 'token'
128
- res.results.should == ['hello', 'you', req]
129
- end
99
+ it "should return false if actor is not available for routing" do
100
+ @dispatcher.routable?("foo").should be_true
101
+ end
130
102
 
131
- it "should dispatch a request to the default action" do
132
- req = RightScale::Request.new('/foo', 'you', :token => 'token')
133
- res = @dispatcher.dispatch(req, @header)
134
- res.should(be_kind_of(RightScale::Result))
135
- res.token.should == req.token
136
- res.results.should == ['hello', 'you']
137
- end
103
+ it "should return true if actor is available for routing" do
104
+ @dispatcher.routable?("bar").should be_false
105
+ end
138
106
 
139
- it "should publish result of request to response queue" do
140
- req = RightScale::Request.new('/foo', 'you', :token => 'token')
141
- req.reply_to = "rs-mapper-1-1"
142
- @broker.should_receive(:publish).with(hsh(:name => @response_queue),
143
- on {|arg| arg.class == RightScale::Result &&
144
- arg.to == "rs-mapper-1-1" &&
145
- arg.results == ['hello', 'you']},
146
- hsh(:persistent => true, :mandatory => true)).once
147
- @dispatcher.dispatch(req, @header)
148
107
  end
149
108
 
150
- it "should handle custom prefixes" do
151
- @registry.register(Foo.new, 'umbongo')
152
- req = RightScale::Request.new('/umbongo/bar', 'you')
153
- res = @dispatcher.dispatch(req, @header)
154
- res.should(be_kind_of(RightScale::Result))
155
- res.token.should == req.token
156
- res.results.should == ['hello', 'you']
157
- end
109
+ context "dispatch" do
158
110
 
159
- it "should call the on_exception callback if something goes wrong" do
160
- flexmock(RightScale::Log).should_receive(:error).once
161
- req = RightScale::Request.new('/foo/i_kill_you', nil)
162
- flexmock(@actor).should_receive(:handle_exception).with(:i_kill_you, req, Exception).once
163
- res = @dispatcher.dispatch(req, @header)
164
- res.results.error?.should be_true
165
- (res.results.content =~ /Could not handle \/foo\/i_kill_you request/).should be_true
166
- end
111
+ it "should dispatch a request" do
112
+ req = RightScale::Request.new('/foo/bar', 'you', :token => 'token')
113
+ res = @dispatcher.dispatch(req)
114
+ res.should(be_kind_of(RightScale::Result))
115
+ res.token.should == 'token'
116
+ res.results.should == ['hello', 'you']
117
+ end
167
118
 
168
- it "should call on_exception Procs defined in a subclass with the correct arguments" do
169
- flexmock(RightScale::Log).should_receive(:error).once
170
- actor = Bar.new
171
- @registry.register(actor, nil)
172
- req = RightScale::Request.new('/bar/i_kill_you', nil)
173
- @dispatcher.dispatch(req, @header)
174
- called_with = actor.instance_variable_get("@called_with")
175
- called_with[0].should == :i_kill_you
176
- called_with[1].should == req
177
- called_with[2].should be_kind_of(RuntimeError)
178
- called_with[2].message.should == 'I kill you!'
179
- end
119
+ it "should dispatch a request with required arity" do
120
+ req = RightScale::Request.new('/foo/bar2', 'you', :token => 'token')
121
+ res = @dispatcher.dispatch(req)
122
+ res.should(be_kind_of(RightScale::Result))
123
+ res.token.should == 'token'
124
+ res.results.should == ['hello', 'you', req]
125
+ end
180
126
 
181
- it "should call on_exception Procs defined in a subclass in the scope of the actor" do
182
- flexmock(RightScale::Log).should_receive(:error).once
183
- actor = Bar.new
184
- @registry.register(actor, nil)
185
- req = RightScale::Request.new('/bar/i_kill_you', nil)
186
- @dispatcher.dispatch(req, @header)
187
- actor.instance_variable_get("@scope").should == actor
188
- end
127
+ it "should dispatch a request to the default action" do
128
+ req = RightScale::Request.new('/foo', 'you', :token => 'token')
129
+ res = @dispatcher.dispatch(req)
130
+ res.should(be_kind_of(RightScale::Result))
131
+ res.token.should == req.token
132
+ res.results.should == ['hello', 'you']
133
+ end
189
134
 
190
- it "should log error if something goes wrong" do
191
- RightScale::Log.should_receive(:error).once
192
- req = RightScale::Request.new('/foo/i_kill_you', nil)
193
- @dispatcher.dispatch(req, @header)
194
- end
135
+ it "should return nil for successful push" do
136
+ req = RightScale::Push.new('/foo', 'you', :token => 'token')
137
+ res = @dispatcher.dispatch(req)
138
+ res.should be_nil
139
+ end
195
140
 
196
- it "should reject requests whose time-to-live has expired" do
197
- flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
198
- flexmock(RightScale::Log).should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED.*TTL 2 sec ago/})
199
- @broker.should_receive(:publish).never
200
- @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
201
- @dispatcher.em = EMMock
202
- req = RightScale::Push.new('/foo/bar', 'you', :expires_at => @now.to_i + 8)
203
- flexmock(Time).should_receive(:now).and_return(@now += 10)
204
- @dispatcher.dispatch(req, @header).should be_nil
205
- end
141
+ it "should handle custom prefixes" do
142
+ @registry.register(Foo.new, 'umbongo')
143
+ req = RightScale::Request.new('/umbongo/bar', 'you')
144
+ res = @dispatcher.dispatch(req)
145
+ res.should(be_kind_of(RightScale::Result))
146
+ res.token.should == req.token
147
+ res.results.should == ['hello', 'you']
148
+ end
206
149
 
207
- it "should send non-delivery result if Request is rejected because its time-to-live has expired" do
208
- flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
209
- flexmock(RightScale::Log).should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED/})
210
- @broker.should_receive(:publish).with(hsh(:name => @response_queue),
211
- on {|arg| arg.class == RightScale::Result &&
212
- arg.to == @response_queue &&
213
- arg.results.non_delivery? &&
214
- arg.results.content == RightScale::OperationResult::TTL_EXPIRATION},
215
- hsh(:persistent => true, :mandatory => true)).once
216
- @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
217
- @dispatcher.em = EMMock
218
- req = RightScale::Request.new('/foo/bar', 'you', {:reply_to => @response_queue, :expires_at => @now.to_i + 8})
219
- flexmock(Time).should_receive(:now).and_return(@now += 10)
220
- @dispatcher.dispatch(req, @header).should be_nil
221
- end
150
+ it "should raise exception if actor is unknown" do
151
+ req = RightScale::Request.new('/bad', 'you', :token => 'token')
152
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::InvalidRequestType)
153
+ end
222
154
 
223
- it "should send error result instead of non-delivery if agent does not know about non-delivery" do
224
- flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
225
- flexmock(RightScale::Log).should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED/})
226
- @broker.should_receive(:publish).with(hsh(:name => @response_queue),
227
- on {|arg| arg.class == RightScale::Result &&
228
- arg.to == "rs-mapper-1-1" &&
229
- arg.results.error? &&
230
- arg.results.content =~ /Could not deliver/},
231
- hsh(:persistent => true, :mandatory => true)).once
232
- @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
233
- @dispatcher.em = EMMock
234
- req = RightScale::Request.new('/foo/bar', 'you', {:reply_to => "rs-mapper-1-1", :expires_at => @now.to_i + 8}, [12, 13])
235
- flexmock(Time).should_receive(:now).and_return(@now += 10)
236
- @dispatcher.dispatch(req, @header).should be_nil
237
- end
155
+ it "should raise exception if actor method is unknown" do
156
+ req = RightScale::Request.new('/foo/bar-none', 'you', :token => 'token')
157
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::InvalidRequestType)
158
+ end
238
159
 
239
- it "should not reject requests whose time-to-live has not expired" do
240
- flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
241
- @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
242
- @dispatcher.em = EMMock
243
- req = RightScale::Request.new('/foo/bar', 'you', :expires_at => @now.to_i + 11)
244
- flexmock(Time).should_receive(:now).and_return(@now += 10)
245
- res = @dispatcher.dispatch(req, @header)
246
- res.should(be_kind_of(RightScale::Result))
247
- res.token.should == req.token
248
- res.results.should == ['hello', 'you']
249
- end
160
+ it "should call the on_exception callback if something goes wrong" do
161
+ @log.should_receive(:error).once
162
+ req = RightScale::Request.new('/foo/i_kill_you', nil)
163
+ flexmock(@actor).should_receive(:handle_exception).with(:i_kill_you, req, Exception).once
164
+ res = @dispatcher.dispatch(req)
165
+ res.results.error?.should be_true
166
+ (res.results.content =~ /Could not handle \/foo\/i_kill_you request/).should be_true
167
+ end
250
168
 
251
- it "should not check age of requests with time-to-live check disabled" do
252
- @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
253
- @dispatcher.em = EMMock
254
- req = RightScale::Request.new('/foo/bar', 'you', :expires_at => 0)
255
- res = @dispatcher.dispatch(req, @header)
256
- res.should(be_kind_of(RightScale::Result))
257
- res.token.should == req.token
258
- res.results.should == ['hello', 'you']
259
- end
169
+ it "should call on_exception Procs defined in a subclass with the correct arguments" do
170
+ @log.should_receive(:error).once
171
+ actor = Bar.new
172
+ @registry.register(actor, nil)
173
+ req = RightScale::Request.new('/bar/i_kill_you', nil)
174
+ @dispatcher.dispatch(req)
175
+ called_with = actor.instance_variable_get("@called_with")
176
+ called_with[0].should == :i_kill_you
177
+ called_with[1].should == req
178
+ called_with[2].should be_kind_of(RuntimeError)
179
+ called_with[2].message.should == 'I kill you!'
180
+ end
181
+
182
+ it "should call on_exception Procs defined in a subclass in the scope of the actor" do
183
+ @log.should_receive(:error).once
184
+ actor = Bar.new
185
+ @registry.register(actor, nil)
186
+ req = RightScale::Request.new('/bar/i_kill_you', nil)
187
+ @dispatcher.dispatch(req)
188
+ actor.instance_variable_get("@scope").should == actor
189
+ end
260
190
 
261
- it "should reject duplicate requests" do
262
- flexmock(RightScale::Log).should_receive(:info).once.with(on {|arg| arg =~ /REJECT DUP/})
263
- EM.run do
191
+ it "should log error if dispatch fails" do
192
+ RightScale::Log.should_receive(:error).once
193
+ req = RightScale::Request.new('/foo/i_kill_you', nil)
194
+ @dispatcher.dispatch(req)
195
+ end
196
+
197
+ it "should reject requests whose time-to-live has expired" do
198
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
199
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED.*TTL 2 sec ago/})
264
200
  @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
265
- @dispatcher.em = EMMock
266
- req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
267
- @cache.store(req.token, nil)
268
- @dispatcher.dispatch(req, @header).should be_nil
269
- EM.stop
201
+ req = RightScale::Push.new('/foo/bar', 'you', :expires_at => @now.to_i + 8)
202
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
203
+ @dispatcher.dispatch(req).should be_nil
270
204
  end
271
- end
272
205
 
273
- it "should reject duplicate retry requests" do
274
- flexmock(RightScale::Log).should_receive(:info).once.with(on {|arg| arg =~ /REJECT RETRY DUP/})
275
- EM.run do
206
+ it "should return non-delivery result if Request is rejected because its time-to-live has expired" do
207
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
208
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED/})
276
209
  @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
277
- @dispatcher.em = EMMock
278
- req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
279
- req.tries.concat(["try1", "try2"])
280
- @cache.store("try2", nil)
281
- @dispatcher.dispatch(req, @header).should be_nil
282
- EM.stop
210
+ req = RightScale::Request.new('/foo/bar', 'you', {:reply_to => @response_queue, :expires_at => @now.to_i + 8})
211
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
212
+ res = @dispatcher.dispatch(req)
213
+ res.results.non_delivery?.should be_true
214
+ res.results.content.should == RightScale::OperationResult::TTL_EXPIRATION
283
215
  end
284
- end
285
216
 
286
- it "should not reject non-duplicate requests" do
287
- EM.run do
217
+ it "should return error result instead of non-delivery if agent does not know about non-delivery" do
218
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
219
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED/})
288
220
  @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
289
- @dispatcher.em = EMMock
290
- req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
291
- req.tries.concat(["try1", "try2"])
292
- @cache.store("try3", nil)
293
- @dispatcher.dispatch(req, @header).should_not be_nil
294
- EM.stop
221
+ req = RightScale::Request.new('/foo/bar', 'you', {:reply_to => "rs-mapper-1-1", :expires_at => @now.to_i + 8}, [12, 13])
222
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
223
+ res = @dispatcher.dispatch(req)
224
+ res.results.error?.should be_true
225
+ res.results.content.should =~ /Could not deliver/
295
226
  end
296
- end
297
227
 
298
- it "should not reject duplicate idempotent requests" do
299
- EM.run do
228
+ it "should not reject requests whose time-to-live has not expired" do
229
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
300
230
  @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
301
- @dispatcher.em = EMMock
302
- req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
303
- @cache.store(req.token, nil)
304
- @dispatcher.dispatch(req, @header).should_not be_nil
305
- EM.stop
231
+ req = RightScale::Request.new('/foo/bar', 'you', :expires_at => @now.to_i + 11)
232
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
233
+ res = @dispatcher.dispatch(req)
234
+ res.should(be_kind_of(RightScale::Result))
235
+ res.token.should == req.token
236
+ res.results.should == ['hello', 'you']
306
237
  end
307
- end
308
238
 
309
- it "should not check for duplicates if duplicate checking is disabled" do
310
- EM.run do
311
- @dispatcher = RightScale::Dispatcher.new(@agent, dispatched_cache = nil)
312
- @dispatcher.em = EMMock
313
- req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
314
- req.tries.concat(["try1", "try2"])
315
- @dispatcher.instance_variable_get(:@dispatched_cache).should be_nil
316
- @dispatcher.dispatch(req, @header).should_not be_nil
317
- EM.stop
239
+ it "should not check age of requests with time-to-live check disabled" do
240
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
241
+ req = RightScale::Request.new('/foo/bar', 'you', :expires_at => 0)
242
+ res = @dispatcher.dispatch(req)
243
+ res.should(be_kind_of(RightScale::Result))
244
+ res.token.should == req.token
245
+ res.results.should == ['hello', 'you']
318
246
  end
319
- end
320
247
 
321
- it "should not check for duplicates if actor method is idempotent" do
322
- EM.run do
323
- @dispatcher = RightScale::Dispatcher.new(@agent, dispatched_cache = nil)
324
- @dispatcher.em = EMMock
325
- req = RightScale::Request.new('/foo/bar', 1, :token => "try")
326
- req.tries.concat(["try1", "try2"])
327
- @dispatcher.instance_variable_get(:@dispatched_cache).should be_nil
328
- @dispatcher.dispatch(req, @header).should_not be_nil
329
- EM.stop
248
+ it "should reject duplicate request by raising exception" do
249
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT DUP/})
250
+ EM.run do
251
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
252
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
253
+ @cache.store(req.token)
254
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::DuplicateRequest)
255
+ EM.stop
256
+ end
330
257
  end
331
- end
332
258
 
333
- it "should return dispatch age of youngest unfinished request" do
334
- @header.should_receive(:ack).never
335
- @dispatcher.em = EMMockNoCallback
336
- @dispatcher.dispatch_age.should be_nil
337
- @dispatcher.dispatch(RightScale::Push.new('/foo/bar', 'you'), @header)
338
- @dispatcher.dispatch_age.should == 0
339
- @dispatcher.dispatch(RightScale::Request.new('/foo/bar', 'you'), @header)
340
- flexmock(Time).should_receive(:now).and_return(@now += 100)
341
- @dispatcher.dispatch_age.should == 100
342
- end
259
+ it "should reject duplicate request from a retry by raising exception" do
260
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT RETRY DUP/})
261
+ EM.run do
262
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
263
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
264
+ req.tries.concat(["try1", "try2"])
265
+ @cache.store("try2")
266
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::DuplicateRequest)
267
+ EM.stop
268
+ end
269
+ end
343
270
 
344
- it "should return dispatch age of nil if all requests finished" do
345
- @dispatcher.dispatch_age.should be_nil
346
- @dispatcher.dispatch(RightScale::Request.new('/foo/bar', 'you'), @header)
347
- flexmock(Time).should_receive(:now).and_return(@now += 100)
348
- @dispatcher.dispatch_age.should be_nil
349
- end
271
+ it "should not reject non-duplicate requests" do
272
+ EM.run do
273
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
274
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
275
+ req.tries.concat(["try1", "try2"])
276
+ @cache.store("try3")
277
+ @dispatcher.dispatch(req).should_not be_nil
278
+ EM.stop
279
+ end
280
+ end
350
281
 
351
- it "should ack request even if fail while dispatching" do
352
- RightScale::Log.should_receive(:error).and_raise(Exception).once
353
- req = RightScale::Request.new('/foo/i_kill_you', nil)
354
- lambda { @dispatcher.dispatch(req, @header) }.should raise_error(Exception)
355
- end
282
+ it "should not reject duplicate idempotent requests" do
283
+ EM.run do
284
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
285
+ req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
286
+ @cache.store(req.token)
287
+ @dispatcher.dispatch(req).should_not be_nil
288
+ EM.stop
289
+ end
290
+ end
356
291
 
357
- it "should not attempt to ack request if fail while dispatching and there is no header" do
358
- @header.should_receive(:ack).never
359
- RightScale::Log.should_receive(:error).and_raise(Exception).once
360
- req = RightScale::Request.new('/foo/i_kill_you', nil)
361
- lambda { @dispatcher.dispatch(req, nil) }.should raise_error(Exception)
362
- end
292
+ it "should not check for duplicates if duplicate checking is disabled" do
293
+ EM.run do
294
+ @dispatcher = RightScale::Dispatcher.new(@agent, dispatched_cache = nil)
295
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
296
+ req.tries.concat(["try1", "try2"])
297
+ @dispatcher.instance_variable_get(:@dispatched_cache).should be_nil
298
+ @dispatcher.dispatch(req).should_not be_nil
299
+ EM.stop
300
+ end
301
+ end
363
302
 
364
- it "should ack request even if fail while doing final setup for processing request" do
365
- @dispatcher.em = EMMock
366
- flexmock(EMMock).should_receive(:defer).and_raise(Exception).once
367
- req = RightScale::Request.new('/foo/bar', 'you')
368
- lambda { @dispatcher.dispatch(req, @header) }.should raise_error(Exception)
369
- end
303
+ it "should not check for duplicates if actor method is idempotent" do
304
+ EM.run do
305
+ @dispatcher = RightScale::Dispatcher.new(@agent, dispatched_cache = nil)
306
+ req = RightScale::Request.new('/foo/bar', 1, :token => "try")
307
+ req.tries.concat(["try1", "try2"])
308
+ @dispatcher.instance_variable_get(:@dispatched_cache).should be_nil
309
+ @dispatcher.dispatch(req).should_not be_nil
310
+ EM.stop
311
+ end
312
+ end
370
313
 
371
- it "should not attempt to ack request if fail while doing final setup for processing request and there is no header" do
372
- @header.should_receive(:ack).never
373
- @dispatcher.em = EMMock
374
- flexmock(EMMock).should_receive(:defer).and_raise(Exception).once
375
- req = RightScale::Request.new('/foo/bar', 'you')
376
- lambda { @dispatcher.dispatch(req, nil) }.should raise_error(Exception)
377
- end
314
+ it "should return error result if dispatch fails" do
315
+ @log.should_receive(:error).with(/Could not handle/, Exception, :trace).once
316
+ req = RightScale::Request.new('/foo/i_kill_you', nil)
317
+ res = @dispatcher.dispatch(req)
318
+ res.results.error?.should be_true
319
+ end
378
320
 
379
- it "should not attempt to ack request if dispatch a request and there is no header" do
380
- @header.should_receive(:ack).never
381
- req = RightScale::Request.new('/foo/bar', 'you', :token => 'token')
382
- @dispatcher.dispatch(req, nil)
383
321
  end
384
322
 
385
323
  end # RightScale::Dispatcher