beetle 0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.rdoc +18 -8
  2. data/beetle.gemspec +37 -121
  3. data/bin/beetle +9 -0
  4. data/examples/README.rdoc +0 -2
  5. data/examples/rpc.rb +3 -2
  6. data/ext/mkrf_conf.rb +19 -0
  7. data/lib/beetle/base.rb +1 -8
  8. data/lib/beetle/client.rb +16 -14
  9. data/lib/beetle/commands/configuration_client.rb +73 -0
  10. data/lib/beetle/commands/configuration_server.rb +85 -0
  11. data/lib/beetle/commands.rb +30 -0
  12. data/lib/beetle/configuration.rb +70 -7
  13. data/lib/beetle/deduplication_store.rb +50 -38
  14. data/lib/beetle/handler.rb +2 -5
  15. data/lib/beetle/logging.rb +7 -0
  16. data/lib/beetle/message.rb +11 -13
  17. data/lib/beetle/publisher.rb +2 -2
  18. data/lib/beetle/r_c.rb +2 -1
  19. data/lib/beetle/redis_configuration_client.rb +136 -0
  20. data/lib/beetle/redis_configuration_server.rb +301 -0
  21. data/lib/beetle/redis_ext.rb +79 -0
  22. data/lib/beetle/redis_master_file.rb +35 -0
  23. data/lib/beetle/redis_server_info.rb +65 -0
  24. data/lib/beetle/subscriber.rb +4 -1
  25. data/lib/beetle.rb +2 -2
  26. data/test/beetle/configuration_test.rb +14 -2
  27. data/test/beetle/deduplication_store_test.rb +61 -43
  28. data/test/beetle/message_test.rb +28 -4
  29. data/test/beetle/redis_configuration_client_test.rb +97 -0
  30. data/test/beetle/redis_configuration_server_test.rb +278 -0
  31. data/test/beetle/redis_ext_test.rb +71 -0
  32. data/test/beetle/redis_master_file_test.rb +39 -0
  33. data/test/test_helper.rb +13 -1
  34. metadata +59 -50
  35. data/.gitignore +0 -5
  36. data/MIT-LICENSE +0 -20
  37. data/Rakefile +0 -114
  38. data/TODO +0 -7
  39. data/doc/redundant_queues.graffle +0 -7744
  40. data/etc/redis-master.conf +0 -189
  41. data/etc/redis-slave.conf +0 -189
  42. data/examples/redis_failover.rb +0 -65
  43. data/script/start_rabbit +0 -29
  44. data/snafu.rb +0 -55
  45. data/test/beetle/bla.rb +0 -0
  46. data/test/beetle.yml +0 -81
  47. data/tmp/master/.gitignore +0 -2
  48. data/tmp/slave/.gitignore +0 -3
@@ -4,6 +4,11 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
4
  module Beetle
5
5
 
6
6
  class EncodingTest < Test::Unit::TestCase
7
+ test "an exception during decoding should be stored in the exception attribute" do
8
+ header = stub_everything("raising header")
9
+ m = Message.new("queue", header, 'foo')
10
+ assert_instance_of NoMethodError, m.exception
11
+ end
7
12
 
8
13
  test "a message should encode/decode the message format version correctly" do
9
14
  header = header_with_params({})
@@ -371,6 +376,17 @@ module Beetle
371
376
  @store.flushdb
372
377
  end
373
378
 
379
+ test "a message with an exception set should not be processed at all, but it should be acked" do
380
+ header = {}
381
+ message = Message.new("somequeue", header, 'foo')
382
+ assert message.exception
383
+
384
+ proc = mock("proc")
385
+ proc.expects(:call).never
386
+ message.expects(:ack!)
387
+ assert_equal RC::DecodingError, message.__send__(:process_internal, proc)
388
+ end
389
+
374
390
  test "a completed existing message should be just acked and not run the handler" do
375
391
  header = header_with_params({})
376
392
  message = Message.new("somequeue", header, 'foo', :attempts => 2, :store => @store)
@@ -379,7 +395,6 @@ module Beetle
379
395
  assert message.completed?
380
396
 
381
397
  proc = mock("proc")
382
- s = sequence("s")
383
398
  header.expects(:ack)
384
399
  proc.expects(:call).never
385
400
  assert_equal RC::OK, message.__send__(:process_internal, proc)
@@ -394,7 +409,6 @@ module Beetle
394
409
  assert message.delayed?
395
410
 
396
411
  proc = mock("proc")
397
- s = sequence("s")
398
412
  header.expects(:ack).never
399
413
  proc.expects(:call).never
400
414
  assert_equal RC::Delayed, message.__send__(:process_internal, proc)
@@ -412,7 +426,6 @@ module Beetle
412
426
  assert !message.timed_out?
413
427
 
414
428
  proc = mock("proc")
415
- s = sequence("s")
416
429
  header.expects(:ack).never
417
430
  proc.expects(:call).never
418
431
  assert_equal RC::HandlerNotYetTimedOut, message.__send__(:process_internal, proc)
@@ -577,7 +590,7 @@ module Beetle
577
590
  @store.flushdb
578
591
  end
579
592
 
580
- test "a handler running longer than the specified timeout should be aborted" do
593
+ test "a handler running longer than the specified timeout should be aborted (when given a float timeout number)" do
581
594
  header = header_with_params({})
582
595
  header.expects(:ack)
583
596
  message = Message.new("somequeue", header, 'foo', :timeout => 0.1, :attempts => 2, :store => @store)
@@ -586,6 +599,17 @@ module Beetle
586
599
  result = message.process(handler)
587
600
  assert_equal RC::ExceptionsLimitReached, result
588
601
  end
602
+
603
+ test "a handler running longer than the specified timeout should be aborted (when using active_support seconds)" do
604
+ header = header_with_params({})
605
+ header.expects(:ack)
606
+ message = Message.new("somequeue", header, 'foo', :timeout => 1.seconds, :attempts => 2, :store => @store)
607
+ action = lambda{|*args| while true; end}
608
+ handler = Handler.create(action)
609
+ result = message.process(handler)
610
+ assert_equal RC::ExceptionsLimitReached, result
611
+ end
612
+
589
613
  end
590
614
 
591
615
  class SettingsTest < Test::Unit::TestCase
@@ -0,0 +1,97 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Beetle
4
+ class RedisConfigurationClientTest < Test::Unit::TestCase
5
+ def setup
6
+ Beetle.config.redis_servers = "redis:0,redis:1"
7
+ @client = RedisConfigurationClient.new
8
+ Client.any_instance.stubs(:listen)
9
+ @client.stubs(:touch_master_file)
10
+ @client.stubs(:verify_redis_master_file_string)
11
+ end
12
+
13
+ test "config should return the beetle config" do
14
+ assert_equal Beetle.config, @client.config
15
+ end
16
+
17
+ test "ping message should answer with pong" do
18
+ @client.expects(:pong!)
19
+ @client.ping("token" => 1)
20
+ end
21
+
22
+ test "pong should publish a pong message" do
23
+ @client.beetle.expects(:publish)
24
+ @client.send(:pong!)
25
+ end
26
+
27
+ test "invalidation should send an invalidation message and clear the redis master file" do
28
+ @client.expects(:clear_redis_master_file)
29
+ @client.beetle.expects(:publish).with(:client_invalidated, anything)
30
+ @client.send(:invalidate!)
31
+ end
32
+
33
+ test "should ignore outdated invalidate messages" do
34
+ new_payload = {"token" => 2}
35
+ old_payload = {"token" => 1}
36
+
37
+ @client.expects(:invalidate!).once
38
+
39
+ @client.invalidate(new_payload)
40
+ @client.invalidate(old_payload)
41
+ end
42
+
43
+ test "should ignore invalidate messages when current master is still a master" do
44
+ @client.instance_variable_set :@current_master, stub(:master? => true)
45
+ @client.expects(:invalidate!).never
46
+ @client.invalidate("token" => 1)
47
+ end
48
+
49
+ test "should ignore outdated reconfigure messages" do
50
+ new_payload = {"token" => 2, "server" => "master:2"}
51
+ old_payload = {"token" => 1, "server" => "master:1"}
52
+ @client.stubs(:read_redis_master_file).returns("")
53
+
54
+ @client.expects(:write_redis_master_file).once
55
+
56
+ @client.reconfigure(new_payload)
57
+ @client.reconfigure(old_payload)
58
+ end
59
+
60
+ test "should clear redis master file if redis from master file is slave" do
61
+ @client.stubs(:redis_master_from_master_file).returns(stub(:master? => false))
62
+ @client.expects(:clear_redis_master_file)
63
+ @client.start
64
+ end
65
+
66
+ test "should clear redis master file if redis from master file is not available" do
67
+ @client.stubs(:redis_master_from_master_file).returns(nil)
68
+ @client.expects(:clear_redis_master_file)
69
+ @client.start
70
+ end
71
+
72
+ test "the dispatcher should just forward messages to the client" do
73
+ dispatcher_class = RedisConfigurationClient.class_eval "MessageDispatcher"
74
+ dispatcher_class.configuration_client = @client
75
+ dispatcher = dispatcher_class.new
76
+ payload = {"token" => 1}
77
+ dispatcher.stubs(:message).returns(stub(:data => payload.to_json, :header => stub(:routing_key=> "ping")))
78
+ @client.expects(:ping).with(payload)
79
+ dispatcher.send(:process)
80
+ end
81
+
82
+ test "determine_initial_master should return nil if there is no file" do
83
+ @client.expects(:master_file_exists?).returns(false)
84
+ assert_nil @client.send(:determine_initial_master)
85
+ assert_nil @client.current_master
86
+ end
87
+
88
+ test "determine_initial_master should instantiate a new redis if there is a file with content" do
89
+ @client.expects(:master_file_exists?).returns(true)
90
+ @client.expects(:read_redis_master_file).returns("localhost:6379")
91
+ master = @client.send(:determine_initial_master)
92
+ assert_equal "master", master.role
93
+ assert_equal master, @client.current_master
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,278 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Beetle
4
+ class RedisConfigurationServerTest < Test::Unit::TestCase
5
+ def setup
6
+ Beetle.config.redis_configuration_client_ids = "rc-client-1,rc-client-2"
7
+ @server = RedisConfigurationServer.new
8
+ EventMachine.stubs(:add_timer).yields
9
+ end
10
+
11
+ test "should exit when started with less than two redis configured" do
12
+ Beetle.config.redis_servers = ""
13
+ assert_raise Beetle::ConfigurationError do
14
+ @server.start
15
+ end
16
+ end
17
+
18
+ test "should initialize the current token for messages to not reuse old tokens" do
19
+ sleep 0.1
20
+ later_server = RedisConfigurationServer.new
21
+ assert later_server.current_token > @server.current_token
22
+ end
23
+
24
+ test "should ignore outdated client_invalidated messages" do
25
+ @server.instance_variable_set(:@current_token, 2)
26
+ @server.client_invalidated("id" => "rc-client-1", "token" => 2)
27
+ old_token = 1.minute.ago.to_f
28
+ @server.client_invalidated("id" => "rc-client-2", "token" => 1)
29
+
30
+ assert_equal(["rc-client-1"].to_set, @server.instance_variable_get(:@client_invalidated_ids_received))
31
+ end
32
+
33
+ test "should ignore outdated pong messages" do
34
+ @server.instance_variable_set(:@current_token, 2)
35
+ @server.pong("id" => "rc-client-1", "token" => 2)
36
+ old_token = 1.minute.ago.to_f
37
+ @server.pong("id" => "rc-client-2", "token" => 1)
38
+
39
+ assert_equal(["rc-client-1"].to_set, @server.instance_variable_get(:@client_pong_ids_received))
40
+ end
41
+
42
+ test "the dispatcher should just forward messages to the server" do
43
+ dispatcher_class = RedisConfigurationServer.class_eval "MessageDispatcher"
44
+ dispatcher_class.configuration_server = @server
45
+ dispatcher = dispatcher_class.new
46
+ payload = {"token" => 1}
47
+ dispatcher.stubs(:message).returns(stub(:data => payload.to_json, :header => stub(:routing_key=> "pong")))
48
+ @server.expects(:pong).with(payload)
49
+ dispatcher.send(:process)
50
+ end
51
+
52
+ test "if a new master is available, it should be published and the available slaves should be configured" do
53
+ redis = Redis.new
54
+ other_master = Redis.new(:port => 6380)
55
+ other_master.expects(:slave_of!).with(redis.host, redis.port)
56
+ @server.stubs(:current_master).returns(redis)
57
+ @server.redis.instance_variable_set(:@server_info, {"master" => [redis, other_master], "slave" => [], "unknown" => []})
58
+ payload = @server.send(:payload_with_current_token, {"server" => redis.server})
59
+ @server.beetle.expects(:publish).with(:reconfigure, payload)
60
+ @server.master_available!
61
+ end
62
+ end
63
+
64
+ class RedisConfigurationServerInvalidationTest < Test::Unit::TestCase
65
+ def setup
66
+ Beetle.config.redis_configuration_client_ids = "rc-client-1,rc-client-2"
67
+ Beetle.config.redis_servers = "redis:0,redis:1"
68
+ @server = RedisConfigurationServer.new
69
+ @server.instance_variable_set(:@current_master, stub('redis stub', :server => 'stubbed_server', :available? => false))
70
+ @server.stubs(:verify_redis_master_file_string)
71
+ @server.beetle.stubs(:listen).yields
72
+ @server.beetle.stubs(:publish)
73
+ EM::Timer.stubs(:new).returns(true)
74
+ EventMachine.stubs(:add_periodic_timer).yields
75
+ end
76
+
77
+ test "should pause watching of the redis master when it becomes unavailable" do
78
+ @server.expects(:determine_initial_master)
79
+ EM.stubs(:add_periodic_timer).returns(stub("timer", :cancel => true))
80
+ @server.start
81
+ assert !@server.paused?
82
+ @server.master_unavailable!
83
+ assert @server.paused?
84
+ end
85
+
86
+ test "should setup an invalidation timeout" do
87
+ EM::Timer.expects(:new).yields
88
+ @server.expects(:cancel_invalidation)
89
+ @server.master_unavailable!
90
+ end
91
+
92
+ test "should continue watching after the invalidation timeout has expired" do
93
+ EM::Timer.expects(:new).yields
94
+ @server.master_unavailable!
95
+ assert !@server.paused?
96
+ end
97
+
98
+ test "should invalidate the current master after receiving all pong messages" do
99
+ EM::Timer.expects(:new).yields.returns(:timer)
100
+ @server.beetle.expects(:publish).with(:invalidate, anything)
101
+ @server.expects(:cancel_invalidation)
102
+ @server.expects(:redeem_token).with(1).twice.returns(true)
103
+ @server.pong("token" => 1, "id" => "rc-client-1")
104
+ @server.pong("token" => 1, "id" => "rc-client-2")
105
+ end
106
+
107
+ test "should switch the current master after receiving all client_invalidated messages" do
108
+ @server.expects(:redeem_token).with(1).twice.returns(true)
109
+ @server.expects(:switch_master)
110
+ @server.client_invalidated("token" => 1, "id" => "rc-client-1")
111
+ @server.client_invalidated("token" => 1, "id" => "rc-client-2")
112
+ end
113
+
114
+ test "should switch the current master immediately if there are no clients" do
115
+ @server.instance_variable_set :@client_ids, Set.new
116
+ @server.expects(:switch_master)
117
+ @server.master_unavailable!
118
+ end
119
+
120
+ test "switching the master should turn the new master candidate into a master" do
121
+ new_master = stub(:master! => nil, :server => "jo:6379")
122
+ @server.beetle.expects(:publish).with(:system_notification, anything)
123
+ @server.expects(:determine_new_master).returns(new_master)
124
+ @server.send :switch_master
125
+ assert_equal new_master, @server.current_master
126
+ end
127
+
128
+ test "switching the master should resort to the old master if no candidate can be found" do
129
+ old_master = @server.current_master
130
+ @server.beetle.expects(:publish).with(:system_notification, anything)
131
+ @server.expects(:determine_new_master).returns(nil)
132
+ @server.send :switch_master
133
+ assert_equal old_master, @server.current_master
134
+ end
135
+
136
+ test "checking the availability of redis servers should publish the available servers as long as the master is available" do
137
+ @server.expects(:master_available?).returns(true)
138
+ @server.expects(:master_available!)
139
+ @server.send(:master_watcher).send(:check_availability)
140
+ end
141
+
142
+ test "checking the availability of redis servers should call master_unavailable after trying the specified number of times" do
143
+ @server.stubs(:master_available?).returns(false)
144
+ @server.expects(:master_unavailable!)
145
+ watcher = @server.send(:master_watcher)
146
+ watcher.instance_variable_set :@master_retries, 0
147
+ watcher.send(:check_availability)
148
+ end
149
+ end
150
+
151
+ class RedisConfigurationServerInitialRedisMasterDeterminationTest < Test::Unit::TestCase
152
+ def setup
153
+ EM::Timer.stubs(:new).returns(true)
154
+ EventMachine.stubs(:add_periodic_timer).yields
155
+ @client = Client.new(Configuration.new)
156
+ @client.stubs(:listen).yields
157
+ @client.stubs(:publish)
158
+ @client.config.redis_configuration_client_ids = "rc-client-1,rc-client-2"
159
+ @server = RedisConfigurationServer.new
160
+ @server.stubs(:beetle).returns(@client)
161
+ @server.stubs(:write_redis_master_file)
162
+ @redis_master = build_master_redis_stub
163
+ @redis_slave = build_slave_redis_stub
164
+ @server.instance_variable_set(:@redis, build_redis_server_info(@redis_master, @redis_slave))
165
+ end
166
+
167
+ test "should not try to auto-detect if the master file contains a server string" do
168
+ @server.expects(:master_file_exists?).returns(true)
169
+ @server.stubs(:read_redis_master_file).returns("foobar:0000")
170
+
171
+ @server.redis.expects(:auto_detect_master).never
172
+ @server.expects(:redis_master_from_master_file).returns(@redis_master)
173
+ @server.send(:determine_initial_master)
174
+ end
175
+
176
+ test "should try to auto-detect if the master file is empty" do
177
+ @server.expects(:master_file_exists?).returns(true)
178
+ @server.stubs(:read_redis_master_file).returns("")
179
+
180
+ @server.redis.expects(:auto_detect_master).returns(@redis_master)
181
+ @server.send(:determine_initial_master)
182
+ end
183
+
184
+ test "should try to auto-detect if the master file is not present" do
185
+ @server.expects(:master_file_exists?).returns(false)
186
+
187
+ @server.redis.expects(:auto_detect_master).returns(@redis_master)
188
+ @server.send(:determine_initial_master)
189
+ end
190
+
191
+ test "should use redis master from successful auto-detection" do
192
+ @server.expects(:master_file_exists?).returns(false)
193
+
194
+ @server.expects(:write_redis_master_file).with(@redis_master.server)
195
+ @server.send(:determine_initial_master)
196
+ assert_equal @redis_master, @server.current_master
197
+ end
198
+
199
+ test "should use redis master if master in file is the only master" do
200
+ @server.expects(:master_file_exists?).returns(true)
201
+ @server.stubs(:redis_master_from_master_file).returns(@redis_master)
202
+
203
+ @server.send(:determine_initial_master)
204
+ assert_equal @redis_master, @server.current_master
205
+ end
206
+
207
+ test "should start master switch if master in file is slave" do
208
+ @server.instance_variable_set(:@redis, build_redis_server_info(@redis_slave))
209
+ @server.expects(:master_file_exists?).returns(true)
210
+ @server.stubs(:redis_master_from_master_file).returns(@redis_slave)
211
+
212
+ @server.expects(:master_unavailable!)
213
+ @server.send(:determine_initial_master)
214
+ end
215
+
216
+ test "should use master from master file if multiple masters are available" do
217
+ redis_master2 = build_master_redis_stub
218
+ @server.instance_variable_set(:@redis, build_redis_server_info(@redis_master, redis_master2))
219
+ @server.expects(:master_file_exists?).returns(true)
220
+ @server.stubs(:redis_master_from_master_file).returns(@redis_master)
221
+
222
+ @server.send(:determine_initial_master)
223
+ assert_equal @redis_master, @server.current_master
224
+ end
225
+
226
+ test "should start master switch if master in file is not available" do
227
+ not_available_redis_master = build_unknown_redis_stub
228
+ @server.instance_variable_set(:@redis, build_redis_server_info(not_available_redis_master, @redis_slave))
229
+ @server.expects(:master_file_exists?).returns(true)
230
+ @server.stubs(:redis_master_from_master_file).returns(not_available_redis_master)
231
+
232
+ @server.expects(:master_unavailable!)
233
+ @server.send(:determine_initial_master)
234
+ end
235
+
236
+ test "should raise an exception if both master file and auto-detection fails" do
237
+ not_available_redis_master = build_unknown_redis_stub
238
+ not_available_redis_slave = build_unknown_redis_stub
239
+ @server.instance_variable_set(:@redis, build_redis_server_info(not_available_redis_master, not_available_redis_slave))
240
+ @server.expects(:master_file_exists?).returns(true)
241
+ @server.expects(:read_redis_master_file).returns("")
242
+ @server.redis.expects(:auto_detect_master).returns(nil)
243
+
244
+ assert_raises Beetle::NoRedisMaster do
245
+ @server.send(:determine_initial_master)
246
+ end
247
+ end
248
+
249
+ test "should detect a new redis_master" do
250
+ not_available_redis_master = build_unknown_redis_stub
251
+ @redis_slave.expects(:slave_of?).returns(true)
252
+ @server.instance_variable_set(:@current_master, not_available_redis_master)
253
+ @server.instance_variable_set(:@redis, build_redis_server_info(@redis_slave, not_available_redis_master))
254
+ assert_equal @redis_slave, @server.send(:determine_new_master)
255
+ end
256
+
257
+ private
258
+
259
+ def build_master_redis_stub
260
+ stub("redis master", :host => "stubbed_master", :port => 0, :server => "stubbed_master:0", :available? => true, :master? => true, :slave? => false, :role => "master")
261
+ end
262
+
263
+ def build_slave_redis_stub
264
+ stub("redis slave", :host => "stubbed_slave", :port => 0, :server => "stubbed_slave:0", :available? => true, :master? => false, :slave? => true, :role => "slave")
265
+ end
266
+
267
+ def build_unknown_redis_stub
268
+ stub("redis unknown", :host => "stubbed_unknown", :port => 0, :server => "stubbed_unknown:0", :available? => false, :master? => false, :slave? => false, :role => "unknown")
269
+ end
270
+
271
+ def build_redis_server_info(*redis_instances)
272
+ info = RedisServerInfo.new(Beetle.config, :timeout => 1)
273
+ info.instance_variable_set :@instances, redis_instances
274
+ redis_instances.each{|redis| info.send("#{redis.role}s") << redis }
275
+ info
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Beetle
4
+
5
+ class NonExistentRedisTest < Test::Unit::TestCase
6
+ def setup
7
+ @r = Redis.new(:host => "localhost", :port => 6390)
8
+ end
9
+
10
+ test "should return an empty hash for the info_with_rescue call" do
11
+ assert_equal({}, @r.info_with_rescue)
12
+ end
13
+
14
+ test "should have a role of unknown" do
15
+ assert_equal "unknown", @r.role
16
+ end
17
+
18
+ test "should not be available" do
19
+ assert !@r.available?
20
+ end
21
+
22
+ test "should not be a master" do
23
+ assert !@r.master?
24
+ end
25
+
26
+ test "should not be a slave" do
27
+ assert !@r.slave?
28
+ assert !@r.slave_of?("localhost", 6379)
29
+ end
30
+
31
+ test "should not try toconnect to the redis server on inspect" do
32
+ assert_nothing_raised { @r.inspect }
33
+ end
34
+ end
35
+
36
+ class AddedRedisMethodsTest < Test::Unit::TestCase
37
+ def setup
38
+ @r = Redis.new(:host => "localhost", :port => 6390)
39
+ end
40
+
41
+ test "should return the host, port and server string" do
42
+ assert_equal "localhost", @r.host
43
+ assert_equal 6390, @r.port
44
+ assert_equal "localhost:6390", @r.server
45
+ end
46
+
47
+ test "should stop slavery" do
48
+ @r.expects(:slaveof).with("no", "one")
49
+ @r.master!
50
+ end
51
+
52
+ test "should support slavery" do
53
+ @r.expects(:slaveof).with("localhost", 6379)
54
+ @r.slave_of!("localhost", 6379)
55
+ end
56
+ end
57
+
58
+ class RedisTimeoutTest < Test::Unit::TestCase
59
+ test "should use Redis::Timer if timeout is greater 0" do
60
+ r = Redis.new(:host => "localhost", :port => 6390, :timeout => 1)
61
+ Redis::Timer.expects(:timeout).with(1).raises(Timeout::Error)
62
+ assert_equal({}, r.info_with_rescue)
63
+ end
64
+
65
+ test "should not use Redis::Timer if timeout 0" do
66
+ r = Redis.new(:host => "localhost", :port => 6390, :timeout => 0)
67
+ Redis::Timer.expects(:timeout).never
68
+ assert_equal({}, r.info_with_rescue)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ module Beetle
4
+
5
+ class RedisMasterFileTest < Test::Unit::TestCase
6
+ include Logging
7
+ include RedisMasterFile
8
+
9
+ def setup
10
+ File.open(master_file, "w"){|f| f.puts "localhost:6379"}
11
+ end
12
+
13
+ def teardown
14
+ File.unlink(master_file) if File.exist?(master_file)
15
+ end
16
+
17
+ test "should be able to check existence" do
18
+ assert master_file_exists?
19
+ File.unlink(master_file)
20
+ assert !master_file_exists?
21
+ end
22
+
23
+ test "should be able to read and write the master file"do
24
+ write_redis_master_file("localhost:6380")
25
+ assert_equal "localhost:6380", read_redis_master_file
26
+ end
27
+
28
+ test "should be able to clear the master file" do
29
+ logger.expects(:warn)
30
+ clear_redis_master_file
31
+ assert_equal "", read_redis_master_file
32
+ end
33
+
34
+ private
35
+ def master_file
36
+ "/tmp/mumu.txt"
37
+ end
38
+ end
39
+ end
data/test/test_helper.rb CHANGED
@@ -2,7 +2,10 @@ require 'rubygems'
2
2
  require 'active_support'
3
3
  require 'active_support/testing/declarative'
4
4
  require 'test/unit'
5
- require 'redgreen' unless ENV['TM_FILENAME'] rescue nil
5
+ begin
6
+ require 'redgreen' unless ENV['TM_FILENAME']
7
+ rescue MissingSourceFile
8
+ end
6
9
  require 'mocha'
7
10
  require File.expand_path(File.dirname(__FILE__) + '/../lib/beetle')
8
11
 
@@ -10,7 +13,9 @@ class Test::Unit::TestCase
10
13
  extend ActiveSupport::Testing::Declarative
11
14
  end
12
15
 
16
+
13
17
  Beetle.config.logger = Logger.new(File.dirname(__FILE__) + '/../test.log')
18
+ Beetle.config.redis_server = "localhost:6379"
14
19
 
15
20
  def header_with_params(opts = {})
16
21
  beetle_headers = Beetle::Message.publishing_options(opts)
@@ -18,3 +23,10 @@ def header_with_params(opts = {})
18
23
  header.stubs(:properties).returns(beetle_headers)
19
24
  header
20
25
  end
26
+
27
+ def redis_stub(name, opts = {})
28
+ default_port = opts['port'] || "1234"
29
+ default_host = opts['host'] || "foo"
30
+ opts = {'host' => default_host, 'port' => default_port, 'server' => "#{default_host}:#{default_port}"}.update(opts)
31
+ stub(name, opts)
32
+ end