infopark-politics 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ Gemfile.lock
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.8.7-p374
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Manifest ADDED
@@ -0,0 +1,17 @@
1
+ examples/queue_worker_example.rb
2
+ examples/token_worker_example.rb
3
+ History.rdoc
4
+ lib/init.rb
5
+ lib/politics/discoverable_node.rb
6
+ lib/politics/static_queue_worker.rb
7
+ lib/politics/token_worker.rb
8
+ lib/politics/version.rb
9
+ lib/politics.rb
10
+ LICENSE
11
+ Manifest
12
+ politics.gemspec
13
+ Rakefile
14
+ README.rdoc
15
+ test/static_queue_worker_test.rb
16
+ test/test_helper.rb
17
+ test/token_worker_test.rb
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ require 'rdoc/task'
3
+ require 'rake/testtask'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubygems/tasks'
6
+
7
+ Gem::Tasks.new
8
+
9
+ desc "Run tests"
10
+ Rake::TestTask.new do |t|
11
+ t.libs << 'test' << 'lib'
12
+ t.test_files = FileList['test/*_test.rb']
13
+ end
14
+
15
+ desc "Run specs"
16
+ RSpec::Core::RakeTask.new
17
+
18
+ desc "Create rdoc"
19
+ Rake::RDocTask.new do |rd|
20
+ rd.main = "README.rdoc"
21
+ rd.rdoc_files.include("README.rdoc", "History.rdoc", "lib/**/*.rb")
22
+ end
23
+
24
+
25
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.2
data/dcc_config.rb ADDED
@@ -0,0 +1,5 @@
1
+ send_notifications_to "tilo@infopark.de"
2
+
3
+ buckets "test" do
4
+ bucket(:specs).performs_rake_tasks("spec")
5
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ requirement = Gem::Requirement.new(">= 1.6.2")
3
+ unless requirement.satisfied_by?(Gem::Version.new(Gem::VERSION))
4
+ raise "You need at RubyGems in Version #{requirement} to build this gem."
5
+ end
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = "infopark-politics"
9
+ gem.version = "0.3.3"
10
+ gem.summary = "Algorithms and Tools for Distributed Computing in Ruby."
11
+ gem.description = ""
12
+ gem.authors = ["Mike Perham", "Tilo Prütz"]
13
+ gem.email = "tilo@infopark.de"
14
+ gem.homepage = "http://github.com/infopark/politics"
15
+
16
+ gem.required_rubygems_version = Gem::Requirement.new(">= 1.8")
17
+ gem.extra_rdoc_files = [
18
+ "History.rdoc",
19
+ "LICENSE",
20
+ "README.rdoc"
21
+ ]
22
+ gem.files = `git ls-files`.split("\n")
23
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ gem.require_paths = ["lib"]
26
+
27
+ gem.add_development_dependency "rspec", ">= 2.14"
28
+ gem.add_development_dependency "rake", ">= 10"
29
+ gem.add_development_dependency "rdoc", ">= 3.9"
30
+ gem.add_development_dependency "rubygems-tasks", ">=0.2"
31
+
32
+ gem.add_runtime_dependency "memcache-client", ">= 1.5.0"
33
+ gem.add_runtime_dependency "starling-starling", ">= 0.9.8"
34
+ gem.add_runtime_dependency "net-mdns", ">= 0.4"
35
+ end
36
+
@@ -223,6 +223,10 @@ module Politics
223
223
  workers
224
224
  end
225
225
 
226
+ def hostname
227
+ nil
228
+ end
229
+
226
230
  private
227
231
 
228
232
  def restart_wanted?
@@ -329,7 +333,7 @@ module Politics
329
333
  end
330
334
 
331
335
  def register_with_bonjour
332
- server = DRb.start_service(nil, self)
336
+ server = DRb.start_service("druby://#{hostname || ""}:0", self)
333
337
  @uri = DRb.uri
334
338
  @port = URI.parse(DRb.uri).port
335
339
 
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
@@ -0,0 +1,544 @@
1
+ # encoding: utf-8
2
+ # FIXME oberen Teil in spec_helper.rb auslagern
3
+ require 'rubygems'
4
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
5
+ require File.dirname(__FILE__) + '/../lib/init'
6
+ Politics::log.level = Logger::FATAL
7
+
8
+ class UninitializedWorker
9
+ include Politics::StaticQueueWorker
10
+ def initialize(memcache_client)
11
+ @memcache_client = memcache_client
12
+ log.level = Logger::FATAL
13
+ end
14
+
15
+ def start
16
+ process_bucket do |bucket|
17
+ sleep 0.1
18
+ end
19
+ end
20
+
21
+ def client_for(servers)
22
+ @memcache_client
23
+ end
24
+
25
+ def local_ip
26
+ IPAddr.new("127.0.0.1")
27
+ end
28
+
29
+ def at_exit
30
+ end
31
+ end
32
+
33
+ class Worker < UninitializedWorker
34
+ def initialize(memcache_client)
35
+ super
36
+ register_worker 'worker', 10, :iteration_length => 10
37
+ end
38
+ end
39
+
40
+ describe UninitializedWorker do
41
+ let(:memcache_client) { double('memcache', :set => nil, :get => nil) }
42
+ let(:worker) { UninitializedWorker.new memcache_client}
43
+
44
+ describe "when initializing" do
45
+ it "should register the removal of the leadership as exit handler" do
46
+ worker.should_receive(:at_exit).ordered.and_return {|&h| h}
47
+ handler = worker.register_worker('worker', 10, :iteration_length => 10)
48
+
49
+ worker.should_receive(:cleanup).ordered
50
+ handler.call
51
+ end
52
+
53
+ it "should have a druby url" do
54
+ worker.register_worker('worker', 10, :iteration_length => 10)
55
+ worker.uri.should =~ %r|druby://.*:[0-9]+|
56
+ end
57
+
58
+ it "should not have a hostname" do
59
+ worker.hostname.should be_nil
60
+ end
61
+
62
+ context "when it has a hostname" do
63
+ before do
64
+ worker.stub(:hostname).and_return '127.0.0.1'
65
+ end
66
+
67
+ it "should use it" do
68
+ worker.register_worker('worker', 10, :iteration_length => 10)
69
+ worker.uri.should =~ %r|druby://127.0.0.1:[0-9]+|
70
+ end
71
+ end
72
+
73
+ context "when it does not have a hostname" do
74
+ before do
75
+ worker.stub(:hostname).and_return nil
76
+ end
77
+
78
+ it "should use the systems hostname" do
79
+ worker.register_worker('worker', 10, :iteration_length => 10)
80
+ worker.uri.should =~ %r|druby://localhost:[0-9]+|
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ describe Worker do
87
+ let(:memcache_client) { double('memcache', :set => nil, :get => nil) }
88
+ let(:worker) { Worker.new memcache_client }
89
+
90
+ it "should provide 'until_next_iteration' even if nominate was not completed" do
91
+ worker.until_next_iteration
92
+ end
93
+
94
+ it "should return time to next iteration even if nominate was not completed" do
95
+ worker.until_next_iteration.should > 0
96
+ worker.until_next_iteration.should <= 10
97
+ end
98
+
99
+ it "should give access to the uri" do
100
+ worker.uri.should =~ %r(^druby://)
101
+ end
102
+
103
+ it "should be alive" do
104
+ worker.should be_alive
105
+ end
106
+
107
+ describe "when processing bucket" do
108
+ before do
109
+ DRbObject.stub(:new).with(nil, worker.uri).
110
+ and_return(@worker_drb = double('drb', :alive? => true))
111
+ end
112
+
113
+ it "should raise an error if it is not alive via Drb" do
114
+ @worker_drb.stub(:alive?).and_raise("drb error")
115
+ lambda {worker.start}.should raise_error(/cannot reach self/)
116
+ @worker_drb.stub(:alive?).and_return(false)
117
+ lambda {worker.start}.should raise_error(/not alive/)
118
+ end
119
+
120
+ describe "" do
121
+ before do
122
+ worker.stub(:until_next_iteration).and_return 666
123
+ worker.stub(:nominate)
124
+ worker.stub(:loop?).and_return true, true, true, false
125
+ end
126
+
127
+ it "should relax until next iteration on MemCache errors during nomination" do
128
+ worker.should_receive(:nominate).exactly(4).and_raise MemCache::MemCacheError.new("Buh!")
129
+ worker.should_receive(:relax).with(666).exactly(4).times
130
+
131
+ worker.start
132
+ end
133
+
134
+ it "should relax until next iteration on MemCache errors during request for leader" do
135
+ worker.should_receive(:leader_uri).exactly(4).and_raise(MemCache::MemCacheError.new("Buh"))
136
+ worker.should_receive(:relax).with(666).exactly(4).times
137
+
138
+ worker.start
139
+ end
140
+
141
+ describe "as leader" do
142
+ before do
143
+ worker.stub(:leader?).and_return true
144
+ end
145
+
146
+ it "should do leader duties" do
147
+ worker.should_receive(:perform_leader_duties).exactly(4).times
148
+ worker.start
149
+ end
150
+ end
151
+
152
+ describe "as follower" do
153
+ before do
154
+ worker.stub(:leader?).and_return false
155
+ worker.stub(:leader_uri).and_return "the leader"
156
+ worker.stub(:leader).and_return(@leader = double('leader'))
157
+ @leader.stub(:bucket_request).and_return([1, 0])
158
+ end
159
+
160
+ it "should get the bucket to process from the leader at every iteration" do
161
+ worker.should_receive(:leader).exactly(4).times.and_return @leader
162
+ @leader.should_receive(:bucket_request).with(worker.uri).exactly(4).times.
163
+ and_return([1, 2])
164
+ worker.start
165
+ end
166
+
167
+ it "should exit on :stop bucket" do
168
+ @leader.should_receive(:bucket_request).ordered.once.and_return([:stop, 0])
169
+ worker.should_receive(:exit).with(0).ordered.and_return do
170
+ worker.should_receive(:loop?).and_return false
171
+ end
172
+ worker.start
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ describe "when handling a bucket request" do
179
+ describe "as leader" do
180
+ before do
181
+ worker.stub(:leader?).and_return true
182
+ end
183
+
184
+ it "should deliver the bucket" do
185
+ worker.should_receive(:next_bucket).with("requestor").and_return "the bucket"
186
+ worker.bucket_request("requestor").should == "the bucket"
187
+ end
188
+
189
+ describe "when no buckets are left" do
190
+ before do
191
+ worker.stub(:find_workers).and_return(%w(1 2 3))
192
+ worker.populate_followers_to_stop
193
+ DRbObject.stub(:new).and_return(double('o', :alive? => true))
194
+ end
195
+
196
+ it "should deliver the :stop bucket if requestor is in followers_to_stop list" do
197
+ worker.bucket_request("1").should == [:stop, 0]
198
+ end
199
+
200
+ it "should not deliver the :stop bucket if requestor is not in followers_to_stop list" do
201
+ worker.bucket_request("requestor")[0].should be_nil
202
+ end
203
+
204
+ it "should remove the requestor from the followers_to_stop list" do
205
+ worker.bucket_request("2")
206
+ worker.followers_to_stop.should =~ %w(1 3)
207
+ end
208
+ end
209
+ end
210
+
211
+ describe "as follower" do
212
+ before do
213
+ worker.stub(:leader?).and_return false
214
+ end
215
+
216
+ it "should deliver the :not_leader bucket" do
217
+ worker.bucket_request("requestor")[0].should == :not_leader
218
+ end
219
+ end
220
+ end
221
+
222
+ describe "when determining if restart is wanted" do
223
+ it "should return true if the restart flag is set in memcache" do
224
+ memcache_client.should_receive(:get).with('worker_restart').and_return true
225
+ worker.should be_restart_wanted
226
+ end
227
+
228
+ it "should return false if the restart flag is not set in memcache" do
229
+ memcache_client.should_receive(:get).with('worker_restart').and_return false
230
+ worker.should_not be_restart_wanted
231
+ memcache_client.should_receive(:get).with('worker_restart').and_return nil
232
+ worker.should_not be_restart_wanted
233
+ end
234
+ end
235
+
236
+ describe "when performing leader duties" do
237
+ before do
238
+ worker.stub(:until_next_iteration).and_return 0
239
+ worker.stub(:leader?).and_return true
240
+ worker.stub(:dictatorship_length).and_return 666
241
+ worker.stub(:iteration_length).and_return 5
242
+ worker.stub(:find_workers).and_return []
243
+ end
244
+
245
+ it "should initialize buckets as dictator" do
246
+ worker.should_receive(:seize_leadership).with(666).ordered
247
+ worker.should_receive(:initialize_buckets).ordered
248
+ worker.should_receive(:seize_leadership).ordered
249
+ worker.perform_leader_duties
250
+ end
251
+
252
+ describe "as long as there are buckets" do
253
+ before do
254
+ worker.stub(:buckets).and_return([1], [2], [3], [4], [])
255
+ worker.stub(:relax)
256
+ end
257
+
258
+ it "should update buckets periodically" do
259
+ worker.should_receive(:update_buckets).exactly(4).times
260
+ worker.perform_leader_duties
261
+ end
262
+
263
+ it "should relax half of the time to the next iteration" do
264
+ worker.stub(:until_next_iteration).and_return(6)
265
+ worker.should_receive(:relax).with(3).exactly(4).times
266
+ worker.perform_leader_duties
267
+ end
268
+
269
+ it "should seize the leadership periodically" do
270
+ worker.should_receive(:seize_leadership).at_least(4).times
271
+ worker.perform_leader_duties
272
+ end
273
+
274
+ it "should seize the leadership periodically even if restart is wanted" do
275
+ worker.stub(:restart_wanted?).and_return true
276
+ worker.stub(:exit)
277
+ worker.should_receive(:seize_leadership).at_least(4).times
278
+ worker.perform_leader_duties
279
+ end
280
+
281
+ it "should not update buckets if restart is wanted" do
282
+ worker.stub(:restart_wanted?).and_return true
283
+ worker.stub(:exit)
284
+ worker.should_not_receive(:update_buckets)
285
+ worker.perform_leader_duties
286
+ end
287
+ end
288
+
289
+ describe "if there are no more buckets" do
290
+ before do
291
+ worker.stub(:buckets).and_return([])
292
+ end
293
+
294
+ it "should populate the followers_to_stop list before evaluating it if restart is wanted" do
295
+ worker.stub(:restart_wanted?).and_return true
296
+ worker.stub(:exit)
297
+ worker.should_receive(:populate_followers_to_stop).ordered.once
298
+ worker.should_receive(:followers_to_stop).ordered.and_return []
299
+ worker.perform_leader_duties
300
+ end
301
+
302
+ it "should not populate the followers_to_stop list if restart is not wanted" do
303
+ worker.stub(:restart_wanted?).and_return false
304
+ worker.should_not_receive(:populate_followers_to_stop)
305
+ worker.perform_leader_duties
306
+ end
307
+
308
+ describe "as long as there are followers to stop" do
309
+ before do
310
+ worker.stub(:followers_to_stop).and_return([1], [2], [3], [4], [])
311
+ worker.stub(:relax)
312
+ end
313
+
314
+ it "should relax half of the time to the next iteration" do
315
+ worker.stub(:until_next_iteration).and_return(6)
316
+ worker.should_receive(:relax).with(3).exactly(4).times
317
+ worker.perform_leader_duties
318
+ end
319
+
320
+ it "should seize the leadership periodically" do
321
+ worker.should_receive(:seize_leadership).at_least(4).times
322
+ worker.perform_leader_duties
323
+ end
324
+ end
325
+
326
+ describe "if there are no more followers to stop" do
327
+ before do
328
+ worker.stub(:followers_to_stop).and_return([])
329
+ end
330
+
331
+ it "should relax until next iteration" do
332
+ worker.stub(:until_next_iteration).and_return(6)
333
+ worker.should_receive(:relax).with(6).once
334
+ worker.perform_leader_duties
335
+ end
336
+
337
+ it "should exit if restart is wanted" do
338
+ worker.stub(:restart_wanted?).and_return true
339
+ worker.should_receive(:exit).with(0)
340
+ worker.perform_leader_duties
341
+ end
342
+ end
343
+ end
344
+ end
345
+
346
+ describe "when seizing leadership" do
347
+ before do
348
+ worker.stub(:uri).and_return('myself')
349
+ worker.stub(:iteration_length).and_return 123
350
+ worker.stub(:token).and_return('dcc-group')
351
+ end
352
+
353
+ it "should set itself to leader" do
354
+ memcache_client.should_receive(:set).with(anything(), 'myself', anything())
355
+ worker.seize_leadership
356
+ end
357
+
358
+ it "should seize the leadership for the amount of seconds given" do
359
+ memcache_client.should_receive(:set).with(anything(), anything(), 666)
360
+ worker.seize_leadership 666
361
+ end
362
+
363
+ it "should seize the leadership for iteration_length if no duration is given" do
364
+ memcache_client.should_receive(:set).with(anything(), anything(), 123)
365
+ worker.seize_leadership
366
+ end
367
+
368
+ it "should seize the leadership for the worker's group" do
369
+ memcache_client.should_receive(:set).with('dcc-group', anything(), anything())
370
+ worker.seize_leadership
371
+ end
372
+
373
+ it "should have the next iteration exactly when the seized leadership ends" do
374
+ now = Time.now
375
+ Time.stub(:now).and_return now
376
+ end_of_leadership = now + 666
377
+
378
+ worker.seize_leadership 666
379
+ worker.until_next_iteration.should == 666
380
+
381
+ worker.seize_leadership
382
+ worker.until_next_iteration.should == 123
383
+
384
+ worker.seize_leadership 6
385
+ worker.until_next_iteration.should == 6
386
+ end
387
+ end
388
+
389
+ describe "when creating next bucket" do
390
+ it "should set the sleep time to sleep_until_next_bucket_time" do
391
+ worker.should_receive(:sleep_until_next_bucket_time).and_return 'the sleep time'
392
+ worker.next_bucket('')[1].should == 'the sleep time'
393
+ end
394
+ end
395
+
396
+ describe "when computing the sleep_until_next_bucket_time" do
397
+ before do
398
+ worker.stub(:iteration_length).and_return 10
399
+ worker.stub(:until_next_iteration).and_return 6
400
+ end
401
+
402
+ it "should set the sleep time to half the time until_next_iteration" do
403
+ worker.sleep_until_next_bucket_time.should == 3
404
+ end
405
+
406
+ it "should set the sleep time to at least 1 second" do
407
+ worker.stub(:until_next_iteration).and_return 0.6
408
+ worker.sleep_until_next_bucket_time.should == 1
409
+ end
410
+
411
+ it "should set the sleep time to at most a half of the interation_length" do
412
+ worker.stub(:until_next_iteration).and_return 60
413
+ worker.sleep_until_next_bucket_time.should == 5
414
+ end
415
+ end
416
+
417
+ describe "when providing leader object" do
418
+ before do
419
+ worker.stub(:until_next_iteration).and_return 0
420
+ end
421
+
422
+ it "should return a drb object with the leader uri" do
423
+ worker.stub(:leader_uri).and_return("leader's uri")
424
+ DRbObject.should_receive(:new).with(nil, "leader's uri").and_return "leader"
425
+ worker.leader.should == "leader"
426
+ end
427
+
428
+ it "should try three times to get the leader on anarchy (no leader)" do
429
+ worker.should_receive(:leader_uri).at_least(3).times.and_return nil
430
+ worker.leader rescue nil
431
+ end
432
+
433
+ it "should raise an error when leader cannot be determined during anarchy" do
434
+ worker.stub(:leader_uri).and_return nil
435
+ lambda {worker.leader}.should raise_error(/cannot determine leader/)
436
+ end
437
+
438
+ it "should sleep until next iteration before retrying to get leader" do
439
+ worker.stub(:leader_uri).and_return nil
440
+ worker.stub(:until_next_iteration).and_return 666
441
+ worker.should_receive(:relax).with(666).exactly(2).times
442
+ worker.leader rescue nil
443
+ end
444
+ end
445
+
446
+ describe "when cleaning up" do
447
+ before do
448
+ worker.stub(:group_name).and_return('the group')
449
+ end
450
+
451
+ describe "as leader" do
452
+ before do
453
+ worker.stub(:leader?).and_return true
454
+ memcache_client.stub(:delete)
455
+ end
456
+
457
+ it "should remove the leadership token from memcache" do
458
+ memcache_client.should_receive(:delete).with('the group_token')
459
+ worker.send(:cleanup)
460
+ end
461
+
462
+ it "should remove the restart wanted flag from memcache" do
463
+ memcache_client.should_receive(:delete).with('the group_restart')
464
+ worker.send(:cleanup)
465
+ end
466
+ end
467
+
468
+ describe "as follower" do
469
+ before do
470
+ worker.stub(:leader?).and_return false
471
+ end
472
+
473
+ it "should not remove anything from memcache" do
474
+ memcache_client.should_not_receive(:delete)
475
+ worker.send(:cleanup)
476
+ end
477
+ end
478
+ end
479
+
480
+ describe "when finding workers" do
481
+ before do
482
+ Net::DNS::MDNSSD.stub(:browse).
483
+ and_yield(double('response1', :name => 'w1')).
484
+ and_yield(double('response2', :name => 'w2')).
485
+ and_yield(double('response3', :name => 'w3')).
486
+ and_yield(double('response4', :name => 'w4')).
487
+ and_return(@browser = double('browser', :stop => nil))
488
+ worker.stub(:sleep)
489
+ end
490
+
491
+ it "should browse mdns group and return workers found" do
492
+ worker.find_workers.should == %w(w1 w2 w3 w4)
493
+ end
494
+
495
+ it "should not add itself to the result list" do
496
+ worker.stub(:uri).and_return('w3')
497
+ worker.find_workers.should_not include('w3')
498
+ end
499
+
500
+ it "should stop browser thread after five seconds" do
501
+ worker.should_receive(:sleep).with(5).ordered
502
+ @browser.should_receive(:stop)
503
+ worker.find_workers
504
+ end
505
+ end
506
+
507
+ describe "when populating followers_to_stop" do
508
+ before do
509
+ worker.stub(:find_workers).and_return(%w(a b c))
510
+ DRbObject.stub(:new).and_return(double('o', :alive? => true))
511
+ end
512
+
513
+ it "should add all visible workers" do
514
+ worker.populate_followers_to_stop
515
+ worker.followers_to_stop.should =~ %w(a b c)
516
+ end
517
+ end
518
+
519
+ describe "when delivering followers_to_stop" do
520
+ before do
521
+ worker.stub(:find_workers).and_return(%w(a b c))
522
+ worker.populate_followers_to_stop
523
+ DRbObject.stub(:new).and_return(double('o', :alive? => true))
524
+ end
525
+
526
+ it "should return the actual followers_to_stop" do
527
+ worker.followers_to_stop.should =~ %w(a b c)
528
+ end
529
+
530
+ it "should not deliver entries that are not reachable at the moment" do
531
+ DRbObject.stub(:new).with(nil, 'a').and_return(double('o', :alive? => false))
532
+ DRbObject.stub(:new).with(nil, 'b').and_return(x = double('o'))
533
+ x.stub(:alive?).and_raise DRb::DRbConnError.new('nix da')
534
+ worker.followers_to_stop.should == %w(c)
535
+ end
536
+
537
+ it "should not remove unreachable entries from the list - maybe they reappear" do
538
+ DRbObject.stub(:new).with(nil, 'a').and_return(double('o', :alive? => false))
539
+ worker.followers_to_stop.should =~ %w(b c)
540
+ DRbObject.stub(:new).with(nil, 'a').and_return(double('o', :alive? => true))
541
+ worker.followers_to_stop.should =~ %w(a b c)
542
+ end
543
+ end
544
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+
4
+ Thread.abort_on_exception = true
5
+
6
+ class Worker
7
+ include Politics::StaticQueueWorker
8
+ def initialize
9
+ register_worker 'worker', 10, :iteration_length => 10
10
+ end
11
+
12
+ def start
13
+ process_bucket do |bucket|
14
+ sleep 1
15
+ end
16
+ end
17
+ end
18
+
19
+ class StaticQueueWorkerTest < Test::Unit::TestCase
20
+
21
+ context "nodes" do
22
+ setup do
23
+ @nodes = []
24
+ 5.times do
25
+ @nodes << nil
26
+ end
27
+ end
28
+
29
+ should "start up" do
30
+ processes = @nodes.map do
31
+ fork do
32
+ ['INT', 'TERM'].each { |signal|
33
+ trap(signal) { exit(0) }
34
+ }
35
+ Worker.new.start
36
+ end
37
+ end
38
+ sleep 10
39
+ puts "Terminating"
40
+ Process.kill('INT', *processes)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+
5
+ begin
6
+ gem 'thoughtbot-shoulda', '>=2.0.2'
7
+ require 'shoulda'
8
+ rescue LoadError => e
9
+ puts "Please install shoulda: `sudo gem install thoughtbot-shoulda -s http://gems.github.com`"
10
+ end
11
+
12
+ begin
13
+ require 'mocha'
14
+ rescue LoadError => e
15
+ puts "Please install mocha: `sudo gem install mocha`"
16
+ end
17
+
18
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
19
+ require File.dirname(__FILE__) + '/../lib/init'
20
+ Politics::log.level = Logger::WARN
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ class TokenWorkerTest < Test::Unit::TestCase
5
+
6
+ context "token workers" do
7
+ setup do
8
+ @harness = Class.new
9
+ @harness.send(:include, Politics::TokenWorker)
10
+ @harness.any_instance.stubs(:cleanup)
11
+ @harness.any_instance.stubs(:loop?).returns(false)
12
+ @harness.any_instance.stubs(:pause_until_expiry)
13
+ @harness.any_instance.stubs(:relax)
14
+
15
+ @worker = @harness.new
16
+ end
17
+
18
+ should "test_instance_property_accessors" do
19
+ assert @worker.iteration_length = 20
20
+ assert_equal 20, @worker.iteration_length
21
+ end
22
+
23
+ should 'test_tracks_a_registered_singleton' do
24
+ assert_nil @worker.class.worker_instance
25
+ @worker.register_worker('testing')
26
+ assert_equal @worker.class.worker_instance, @worker
27
+ end
28
+
29
+ should 'not process if they are not leader' do
30
+ @worker.expects(:nominate)
31
+ @worker.expects(:leader?).returns(false)
32
+ @worker.register_worker('testing')
33
+ @worker.process do
34
+ assert false
35
+ end
36
+ end
37
+
38
+ should 'handle unexpected MemCache errors' do
39
+ @worker.expects(:nominate)
40
+ @worker.expects(:leader?).raises(MemCache::MemCacheError)
41
+ Politics::log.expects(:error).times(3)
42
+
43
+ @worker.register_worker('testing')
44
+ @worker.process do
45
+ assert false
46
+ end
47
+ end
48
+
49
+ should 'process if they are leader' do
50
+ @worker.expects(:nominate)
51
+ @worker.expects(:leader?).returns(true)
52
+ @worker.register_worker('testing')
53
+
54
+ worked = 0
55
+ @worker.process do
56
+ worked += 1
57
+ end
58
+
59
+ assert_equal 1, worked
60
+ end
61
+
62
+ should 'not allow processing without registration' do
63
+ assert_raises ArgumentError do
64
+ @worker.process
65
+ end
66
+ end
67
+
68
+ should 'not allow processing by old instances' do
69
+ @worker.register_worker('testing')
70
+
71
+ foo = @worker.class.new
72
+ foo.register_worker('testing')
73
+
74
+ assert_raises SecurityError do
75
+ @worker.process
76
+ end
77
+ end
78
+ end
79
+ end
metadata CHANGED
@@ -1,107 +1,203 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: infopark-politics
3
- version: !ruby/object:Gem::Version
4
- version: 0.3.2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 3
10
+ version: 0.3.3
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Mike Perham
9
- - Tilo Prütz
14
+ - "Tilo Pr\xC3\xBCtz"
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2013-11-07 00:00:00.000000000 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: memcache-client
17
- requirement: !ruby/object:Gem::Requirement
18
+
19
+ date: 2013-11-09 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ requirement: &id001 !ruby/object:Gem::Requirement
18
24
  none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: 1.5.0
23
- type: :runtime
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 31
29
+ segments:
30
+ - 2
31
+ - 14
32
+ version: "2.14"
33
+ name: rspec
34
+ version_requirements: *id001
24
35
  prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
36
+ type: :development
37
+ - !ruby/object:Gem::Dependency
38
+ requirement: &id002 !ruby/object:Gem::Requirement
26
39
  none: false
27
- requirements:
28
- - - ! '>='
29
- - !ruby/object:Gem::Version
30
- version: 1.5.0
31
- - !ruby/object:Gem::Dependency
32
- name: starling-starling
33
- requirement: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 10
46
+ version: "10"
47
+ name: rake
48
+ version_requirements: *id002
49
+ prerelease: false
50
+ type: :development
51
+ - !ruby/object:Gem::Dependency
52
+ requirement: &id003 !ruby/object:Gem::Requirement
34
53
  none: false
35
- requirements:
36
- - - ! '>='
37
- - !ruby/object:Gem::Version
38
- version: 0.9.8
39
- type: :runtime
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 21
58
+ segments:
59
+ - 3
60
+ - 9
61
+ version: "3.9"
62
+ name: rdoc
63
+ version_requirements: *id003
40
64
  prerelease: false
41
- version_requirements: !ruby/object:Gem::Requirement
65
+ type: :development
66
+ - !ruby/object:Gem::Dependency
67
+ requirement: &id004 !ruby/object:Gem::Requirement
42
68
  none: false
43
- requirements:
44
- - - ! '>='
45
- - !ruby/object:Gem::Version
46
- version: 0.9.8
47
- - !ruby/object:Gem::Dependency
48
- name: net-mdns
49
- requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 15
73
+ segments:
74
+ - 0
75
+ - 2
76
+ version: "0.2"
77
+ name: rubygems-tasks
78
+ version_requirements: *id004
79
+ prerelease: false
80
+ type: :development
81
+ - !ruby/object:Gem::Dependency
82
+ requirement: &id005 !ruby/object:Gem::Requirement
50
83
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0.4'
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 1
90
+ - 5
91
+ - 0
92
+ version: 1.5.0
93
+ name: memcache-client
94
+ version_requirements: *id005
95
+ prerelease: false
55
96
  type: :runtime
97
+ - !ruby/object:Gem::Dependency
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 43
104
+ segments:
105
+ - 0
106
+ - 9
107
+ - 8
108
+ version: 0.9.8
109
+ name: starling-starling
110
+ version_requirements: *id006
56
111
  prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
112
+ type: :runtime
113
+ - !ruby/object:Gem::Dependency
114
+ requirement: &id007 !ruby/object:Gem::Requirement
58
115
  none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: '0.4'
63
- description: Algorithms and Tools for Distributed Computing in Ruby.
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ - 4
123
+ version: "0.4"
124
+ name: net-mdns
125
+ version_requirements: *id007
126
+ prerelease: false
127
+ type: :runtime
128
+ description: ""
64
129
  email: tilo@infopark.de
65
130
  executables: []
131
+
66
132
  extensions: []
67
- extra_rdoc_files:
133
+
134
+ extra_rdoc_files:
68
135
  - History.rdoc
69
136
  - LICENSE
70
137
  - README.rdoc
71
- files:
138
+ files:
139
+ - .gitignore
140
+ - .rbenv-version
141
+ - .rspec
142
+ - Gemfile
143
+ - History.rdoc
144
+ - LICENSE
145
+ - Manifest
146
+ - README.rdoc
147
+ - Rakefile
148
+ - VERSION
149
+ - dcc_config.rb
72
150
  - examples/queue_worker_example.rb
73
151
  - examples/token_worker_example.rb
152
+ - infopark-politics.gemspec
74
153
  - lib/init.rb
75
154
  - lib/politics.rb
76
155
  - lib/politics/discoverable_node.rb
77
156
  - lib/politics/static_queue_worker.rb
78
157
  - lib/politics/token_worker.rb
79
- - lib/politics/version.rb
80
- - History.rdoc
81
- - LICENSE
82
- - README.rdoc
158
+ - spec/spec_helper.rb
159
+ - spec/static_queue_worker_spec.rb
160
+ - test/static_queue_worker_test.rb
161
+ - test/test_helper.rb
162
+ - test/token_worker_test.rb
163
+ has_rdoc: true
83
164
  homepage: http://github.com/infopark/politics
84
165
  licenses: []
166
+
85
167
  post_install_message:
86
168
  rdoc_options: []
87
- require_paths:
169
+
170
+ require_paths:
88
171
  - lib
89
- required_ruby_version: !ruby/object:Gem::Requirement
172
+ required_ruby_version: !ruby/object:Gem::Requirement
90
173
  none: false
91
- requirements:
92
- - - ! '>='
93
- - !ruby/object:Gem::Version
94
- version: '0'
95
- required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ hash: 3
178
+ segments:
179
+ - 0
180
+ version: "0"
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
182
  none: false
97
- requirements:
98
- - - ! '>='
99
- - !ruby/object:Gem::Version
100
- version: '0'
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ hash: 31
187
+ segments:
188
+ - 1
189
+ - 8
190
+ version: "1.8"
101
191
  requirements: []
192
+
102
193
  rubyforge_project:
103
- rubygems_version: 1.8.23
194
+ rubygems_version: 1.6.2
104
195
  signing_key:
105
196
  specification_version: 3
106
197
  summary: Algorithms and Tools for Distributed Computing in Ruby.
107
- test_files: []
198
+ test_files:
199
+ - spec/spec_helper.rb
200
+ - spec/static_queue_worker_spec.rb
201
+ - test/static_queue_worker_test.rb
202
+ - test/test_helper.rb
203
+ - test/token_worker_test.rb
@@ -1,6 +0,0 @@
1
- # encoding: utf-8
2
- module Politics
3
- module Version
4
- STRING = "0.3.2"
5
- end
6
- end