redis 3.0.0 → 4.2.2

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.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +269 -0
  3. data/README.md +295 -58
  4. data/lib/redis.rb +1760 -451
  5. data/lib/redis/client.rb +355 -88
  6. data/lib/redis/cluster.rb +295 -0
  7. data/lib/redis/cluster/command.rb +81 -0
  8. data/lib/redis/cluster/command_loader.rb +34 -0
  9. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  10. data/lib/redis/cluster/node.rb +107 -0
  11. data/lib/redis/cluster/node_key.rb +31 -0
  12. data/lib/redis/cluster/node_loader.rb +37 -0
  13. data/lib/redis/cluster/option.rb +90 -0
  14. data/lib/redis/cluster/slot.rb +86 -0
  15. data/lib/redis/cluster/slot_loader.rb +49 -0
  16. data/lib/redis/connection.rb +4 -2
  17. data/lib/redis/connection/command_helper.rb +5 -10
  18. data/lib/redis/connection/hiredis.rb +12 -8
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +232 -63
  21. data/lib/redis/connection/synchrony.rb +41 -14
  22. data/lib/redis/distributed.rb +205 -70
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +31 -73
  25. data/lib/redis/pipeline.rb +74 -18
  26. data/lib/redis/subscribe.rb +24 -13
  27. data/lib/redis/version.rb +3 -1
  28. metadata +63 -160
  29. data/.gitignore +0 -10
  30. data/.order +0 -169
  31. data/.travis.yml +0 -50
  32. data/.travis/Gemfile +0 -11
  33. data/.yardopts +0 -3
  34. data/Rakefile +0 -392
  35. data/benchmarking/logging.rb +0 -62
  36. data/benchmarking/pipeline.rb +0 -51
  37. data/benchmarking/speed.rb +0 -21
  38. data/benchmarking/suite.rb +0 -24
  39. data/benchmarking/worker.rb +0 -71
  40. data/examples/basic.rb +0 -15
  41. data/examples/dist_redis.rb +0 -43
  42. data/examples/incr-decr.rb +0 -17
  43. data/examples/list.rb +0 -26
  44. data/examples/pubsub.rb +0 -31
  45. data/examples/sets.rb +0 -36
  46. data/examples/unicorn/config.ru +0 -3
  47. data/examples/unicorn/unicorn.rb +0 -20
  48. data/redis.gemspec +0 -41
  49. data/test/blocking_commands_test.rb +0 -42
  50. data/test/command_map_test.rb +0 -30
  51. data/test/commands_on_hashes_test.rb +0 -21
  52. data/test/commands_on_lists_test.rb +0 -20
  53. data/test/commands_on_sets_test.rb +0 -77
  54. data/test/commands_on_sorted_sets_test.rb +0 -109
  55. data/test/commands_on_strings_test.rb +0 -83
  56. data/test/commands_on_value_types_test.rb +0 -99
  57. data/test/connection_handling_test.rb +0 -189
  58. data/test/db/.gitignore +0 -1
  59. data/test/distributed_blocking_commands_test.rb +0 -46
  60. data/test/distributed_commands_on_hashes_test.rb +0 -10
  61. data/test/distributed_commands_on_lists_test.rb +0 -22
  62. data/test/distributed_commands_on_sets_test.rb +0 -83
  63. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  64. data/test/distributed_commands_on_strings_test.rb +0 -48
  65. data/test/distributed_commands_on_value_types_test.rb +0 -87
  66. data/test/distributed_commands_requiring_clustering_test.rb +0 -148
  67. data/test/distributed_connection_handling_test.rb +0 -23
  68. data/test/distributed_internals_test.rb +0 -15
  69. data/test/distributed_key_tags_test.rb +0 -52
  70. data/test/distributed_persistence_control_commands_test.rb +0 -26
  71. data/test/distributed_publish_subscribe_test.rb +0 -92
  72. data/test/distributed_remote_server_control_commands_test.rb +0 -53
  73. data/test/distributed_scripting_test.rb +0 -102
  74. data/test/distributed_sorting_test.rb +0 -20
  75. data/test/distributed_test.rb +0 -58
  76. data/test/distributed_transactions_test.rb +0 -32
  77. data/test/encoding_test.rb +0 -18
  78. data/test/error_replies_test.rb +0 -59
  79. data/test/helper.rb +0 -188
  80. data/test/helper_test.rb +0 -22
  81. data/test/internals_test.rb +0 -214
  82. data/test/lint/blocking_commands.rb +0 -124
  83. data/test/lint/hashes.rb +0 -162
  84. data/test/lint/lists.rb +0 -143
  85. data/test/lint/sets.rb +0 -96
  86. data/test/lint/sorted_sets.rb +0 -201
  87. data/test/lint/strings.rb +0 -157
  88. data/test/lint/value_types.rb +0 -106
  89. data/test/persistence_control_commands_test.rb +0 -26
  90. data/test/pipelining_commands_test.rb +0 -195
  91. data/test/publish_subscribe_test.rb +0 -153
  92. data/test/remote_server_control_commands_test.rb +0 -104
  93. data/test/scripting_test.rb +0 -78
  94. data/test/sorting_test.rb +0 -45
  95. data/test/support/connection/hiredis.rb +0 -1
  96. data/test/support/connection/ruby.rb +0 -1
  97. data/test/support/connection/synchrony.rb +0 -17
  98. data/test/support/redis_mock.rb +0 -92
  99. data/test/support/wire/synchrony.rb +0 -24
  100. data/test/support/wire/thread.rb +0 -5
  101. data/test/synchrony_driver.rb +0 -57
  102. data/test/test.conf +0 -9
  103. data/test/thread_safety_test.rb +0 -32
  104. data/test/transactions_test.rb +0 -244
  105. data/test/unknown_commands_test.rb +0 -14
  106. data/test/url_param_test.rb +0 -64
@@ -1,78 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestScripting < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def to_sha(script)
10
- r.script(:load, script)
11
- end
12
-
13
- def test_script_exists
14
- return if version < "2.5.9" # 2.6-rc1
15
-
16
- a = to_sha("return 1")
17
- b = a.succ
18
-
19
- assert_equal true, r.script(:exists, a)
20
- assert_equal false, r.script(:exists, b)
21
- assert_equal [true], r.script(:exists, [a])
22
- assert_equal [false], r.script(:exists, [b])
23
- assert_equal [true, false], r.script(:exists, [a, b])
24
- end
25
-
26
- def test_script_flush
27
- return if version < "2.5.9" # 2.6-rc1
28
-
29
- sha = to_sha("return 1")
30
- assert r.script(:exists, sha)
31
- assert_equal "OK", r.script(:flush)
32
- assert !r.script(:exists, sha)
33
- end
34
-
35
- def test_script_kill
36
- return if version < "2.5.9" # 2.6-rc1
37
-
38
- redis_mock(:script => lambda { |arg| "+#{arg.upcase}" }) do |redis|
39
- assert_equal "KILL", redis.script(:kill)
40
- end
41
- end
42
-
43
- def test_eval
44
- return if version < "2.5.9" # 2.6-rc1
45
-
46
- assert_equal 0, r.eval("return #KEYS")
47
- assert_equal 0, r.eval("return #ARGV")
48
- assert_equal ["k1", "k2"], r.eval("return KEYS", ["k1", "k2"])
49
- assert_equal ["a1", "a2"], r.eval("return ARGV", [], ["a1", "a2"])
50
- end
51
-
52
- def test_eval_with_options_hash
53
- return if version < "2.5.9" # 2.6-rc1
54
-
55
- assert_equal 0, r.eval("return #KEYS", {})
56
- assert_equal 0, r.eval("return #ARGV", {})
57
- assert_equal ["k1", "k2"], r.eval("return KEYS", { :keys => ["k1", "k2"] })
58
- assert_equal ["a1", "a2"], r.eval("return ARGV", { :argv => ["a1", "a2"] })
59
- end
60
-
61
- def test_evalsha
62
- return if version < "2.5.9" # 2.6-rc1
63
-
64
- assert_equal 0, r.evalsha(to_sha("return #KEYS"))
65
- assert_equal 0, r.evalsha(to_sha("return #ARGV"))
66
- assert_equal ["k1", "k2"], r.evalsha(to_sha("return KEYS"), ["k1", "k2"])
67
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), [], ["a1", "a2"])
68
- end
69
-
70
- def test_evalsha_with_options_hash
71
- return if version < "2.5.9" # 2.6-rc1
72
-
73
- assert_equal 0, r.evalsha(to_sha("return #KEYS"), {})
74
- assert_equal 0, r.evalsha(to_sha("return #ARGV"), {})
75
- assert_equal ["k1", "k2"], r.evalsha(to_sha("return KEYS"), { :keys => ["k1", "k2"] })
76
- assert_equal ["a1", "a2"], r.evalsha(to_sha("return ARGV"), { :argv => ["a1", "a2"] })
77
- end
78
- end
@@ -1,45 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestSorting < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_sort
10
- r.set("foo:1", "s1")
11
- r.set("foo:2", "s2")
12
-
13
- r.rpush("bar", "1")
14
- r.rpush("bar", "2")
15
-
16
- assert_equal ["s1"], r.sort("bar", :get => "foo:*", :limit => [0, 1])
17
- assert_equal ["s2"], r.sort("bar", :get => "foo:*", :limit => [0, 1], :order => "desc alpha")
18
- end
19
-
20
- def test_sort_with_an_array_of_gets
21
- r.set("foo:1:a", "s1a")
22
- r.set("foo:1:b", "s1b")
23
-
24
- r.set("foo:2:a", "s2a")
25
- r.set("foo:2:b", "s2b")
26
-
27
- r.rpush("bar", "1")
28
- r.rpush("bar", "2")
29
-
30
- assert_equal [["s1a", "s1b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1])
31
- assert_equal [["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1], :order => "desc alpha")
32
- assert_equal [["s1a", "s1b"], ["s2a", "s2b"]], r.sort("bar", :get => ["foo:*:a", "foo:*:b"])
33
- end
34
-
35
- def test_sort_with_store
36
- r.set("foo:1", "s1")
37
- r.set("foo:2", "s2")
38
-
39
- r.rpush("bar", "1")
40
- r.rpush("bar", "2")
41
-
42
- r.sort("bar", :get => "foo:*", :store => "baz")
43
- assert_equal ["s1", "s2"], r.lrange("baz", 0, -1)
44
- end
45
- end
@@ -1 +0,0 @@
1
- require "support/wire/thread"
@@ -1 +0,0 @@
1
- require "support/wire/thread"
@@ -1,17 +0,0 @@
1
- require "support/wire/synchrony"
2
-
3
- module Helper
4
- def around
5
- rv = nil
6
-
7
- EM.synchrony do
8
- begin
9
- rv = yield
10
- ensure
11
- EM.stop
12
- end
13
- end
14
-
15
- rv
16
- end
17
- end
@@ -1,92 +0,0 @@
1
- require "socket"
2
-
3
- module RedisMock
4
- class Server
5
- VERBOSE = false
6
-
7
- def initialize(port, &block)
8
- @server = TCPServer.new("127.0.0.1", port)
9
- @server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
10
- end
11
-
12
- def start(&block)
13
- @thread = Thread.new { run(&block) }
14
- end
15
-
16
- # Bail out of @server.accept before closing the socket. This is required
17
- # to avoid EADDRINUSE after a couple of iterations.
18
- def shutdown
19
- @thread.terminate if @thread
20
- @server.close if @server
21
- rescue => ex
22
- $stderr.puts "Error closing mock server: #{ex.message}" if VERBOSE
23
- $stderr.puts ex.backtrace if VERBOSE
24
- end
25
-
26
- def run
27
- loop do
28
- session = @server.accept
29
-
30
- begin
31
- while line = session.gets
32
- parts = Array.new(line[1..-3].to_i) do
33
- bytes = session.gets[1..-3].to_i
34
- argument = session.read(bytes)
35
- session.read(2) # Discard \r\n
36
- argument
37
- end
38
-
39
- response = yield(*parts)
40
-
41
- # Convert a nil response to :close
42
- response ||= :close
43
-
44
- if response == :exit
45
- session.shutdown(Socket::SHUT_RDWR)
46
- return # exit server body
47
- elsif response == :close
48
- session.shutdown(Socket::SHUT_RDWR)
49
- break # exit connection body
50
- else
51
- session.write(response)
52
- session.write("\r\n") unless response.end_with?("\r\n")
53
- end
54
- end
55
- rescue Errno::ECONNRESET
56
- # Ignore client closing the connection
57
- end
58
- end
59
- rescue => ex
60
- $stderr.puts "Error running mock server: #{ex.message}" if VERBOSE
61
- $stderr.puts ex.backtrace if VERBOSE
62
- ensure
63
- @server.close
64
- end
65
- end
66
-
67
- MOCK_PORT = 6382
68
-
69
- # Starts a mock Redis server in a thread.
70
- #
71
- # The server will reply with a `+OK` to all commands, but you can
72
- # customize it by providing a hash. For example:
73
- #
74
- # RedisMock.start(:ping => lambda { "+PONG" }) do
75
- # assert_equal "PONG", Redis.new(:port => MOCK_PORT).ping
76
- # end
77
- #
78
- def self.start(commands = {})
79
- server = Server.new(MOCK_PORT)
80
-
81
- begin
82
- server.start do |command, *args|
83
- (commands[command.to_sym] || lambda { |*_| "+OK" }).call(*args)
84
- end
85
-
86
- yield(MOCK_PORT)
87
-
88
- ensure
89
- server.shutdown
90
- end
91
- end
92
- end
@@ -1,24 +0,0 @@
1
- class Wire < Fiber
2
- # We cannot run this fiber explicitly because EM schedules it. Resuming the
3
- # current fiber on the next tick to let the reactor do work.
4
- def self.pass
5
- f = Fiber.current
6
- EM.next_tick { f.resume }
7
- Fiber.yield
8
- end
9
-
10
- def self.sleep(sec)
11
- EM::Synchrony.sleep(sec)
12
- end
13
-
14
- def initialize(&blk)
15
- super
16
-
17
- # Schedule run in next tick
18
- EM.next_tick { resume }
19
- end
20
-
21
- def join
22
- self.class.pass while alive?
23
- end
24
- end
@@ -1,5 +0,0 @@
1
- class Wire < Thread
2
- def self.sleep(sec)
3
- Kernel.sleep(sec)
4
- end
5
- end
@@ -1,57 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'em-synchrony'
4
-
5
- require 'redis'
6
- require 'redis/connection/synchrony'
7
-
8
- require File.expand_path("./helper", File.dirname(__FILE__))
9
-
10
- #
11
- # if running under Eventmachine + Synchrony (Ruby 1.9+), then
12
- # we can simulate the blocking API while performing the network
13
- # IO via the EM reactor.
14
- #
15
-
16
- EM.synchrony do
17
- r = Redis.new
18
- r.flushdb
19
-
20
- r.rpush "foo", "s1"
21
- r.rpush "foo", "s2"
22
-
23
- assert_equal 2, r.llen("foo")
24
- assert_equal "s2", r.rpop("foo")
25
-
26
- r.set("foo", "bar")
27
-
28
- assert_equal "bar", r.getset("foo", "baz")
29
- assert_equal "baz", r.get("foo")
30
-
31
- r.set("foo", "a")
32
-
33
- assert_equal 1, r.getbit("foo", 1)
34
- assert_equal 1, r.getbit("foo", 2)
35
- assert_equal 0, r.getbit("foo", 3)
36
- assert_equal 0, r.getbit("foo", 4)
37
- assert_equal 0, r.getbit("foo", 5)
38
- assert_equal 0, r.getbit("foo", 6)
39
- assert_equal 1, r.getbit("foo", 7)
40
-
41
- r.flushdb
42
-
43
- # command pipelining
44
- r.pipelined do
45
- r.lpush "foo", "s1"
46
- r.lpush "foo", "s2"
47
- end
48
-
49
- assert_equal 2, r.llen("foo")
50
- assert_equal "s2", r.lpop("foo")
51
- assert_equal "s1", r.lpop("foo")
52
-
53
- assert_equal "OK", r.client.call(:quit)
54
- assert_equal "PONG", r.ping
55
-
56
- EM.stop
57
- end
@@ -1,9 +0,0 @@
1
- dir ./test/db
2
- pidfile ./redis.pid
3
- port 6381
4
- unixsocket /tmp/redis.sock
5
- timeout 300
6
- loglevel debug
7
- logfile stdout
8
- databases 16
9
- daemonize yes
@@ -1,32 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestThreadSafety < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- driver(:ruby, :hiredis) do
10
- def test_thread_safety
11
- redis = Redis.new(OPTIONS)
12
- redis.set "foo", 1
13
- redis.set "bar", 2
14
-
15
- sample = 100
16
-
17
- t1 = Thread.new do
18
- $foos = Array.new(sample) { redis.get "foo" }
19
- end
20
-
21
- t2 = Thread.new do
22
- $bars = Array.new(sample) { redis.get "bar" }
23
- end
24
-
25
- t1.join
26
- t2.join
27
-
28
- assert_equal ["1"], $foos.uniq
29
- assert_equal ["2"], $bars.uniq
30
- end
31
- end
32
- end
@@ -1,244 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require "helper"
4
-
5
- class TestTransactions < Test::Unit::TestCase
6
-
7
- include Helper::Client
8
-
9
- def test_multi_discard
10
- r.multi
11
-
12
- assert_equal "QUEUED", r.set("foo", "1")
13
- assert_equal "QUEUED", r.get("foo")
14
-
15
- r.discard
16
-
17
- assert_equal nil, r.get("foo")
18
- end
19
-
20
- def test_multi_exec_with_a_block
21
- r.multi do |multi|
22
- multi.set "foo", "s1"
23
- end
24
-
25
- assert_equal "s1", r.get("foo")
26
- end
27
-
28
- def test_multi_exec_with_a_block_doesn_t_return_replies_for_multi_and_exec
29
- r1, r2, nothing_else = r.multi do |multi|
30
- multi.set "foo", "s1"
31
- multi.get "foo"
32
- end
33
-
34
- assert_equal "OK", r1
35
- assert_equal "s1", r2
36
- assert_equal nil, nothing_else
37
- end
38
-
39
- def test_assignment_inside_multi_exec_block
40
- r.multi do |m|
41
- @first = m.sadd("foo", 1)
42
- @second = m.sadd("foo", 1)
43
- end
44
-
45
- assert_equal true, @first.value
46
- assert_equal false, @second.value
47
- end
48
-
49
- # Although we could support accessing the values in these futures,
50
- # it doesn't make a lot of sense.
51
- def test_assignment_inside_multi_exec_block_with_delayed_command_errors
52
- assert_raise(Redis::CommandError) do
53
- r.multi do |m|
54
- @first = m.set("foo", "s1")
55
- @second = m.incr("foo") # not an integer
56
- @third = m.lpush("foo", "value") # wrong kind of value
57
- end
58
- end
59
-
60
- assert_equal "OK", @first.value
61
- assert_raise(Redis::CommandError) { @second.value }
62
- assert_raise(Redis::FutureNotReady) { @third.value }
63
- end
64
-
65
- def test_assignment_inside_multi_exec_block_with_immediate_command_errors
66
- assert_raise(Redis::CommandError) do
67
- r.multi do |m|
68
- m.doesnt_exist
69
- @first = m.sadd("foo", 1)
70
- m.doesnt_exist
71
- @second = m.sadd("foo", 1)
72
- m.doesnt_exist
73
- end
74
- end
75
-
76
- assert_raise(Redis::FutureNotReady) { @first.value }
77
- assert_raise(Redis::FutureNotReady) { @second.value }
78
- end
79
-
80
- def test_raise_immediate_errors_in_multi_exec
81
- assert_raise(RuntimeError) do
82
- r.multi do |multi|
83
- multi.set "bar", "s2"
84
- raise "Some error"
85
- multi.set "baz", "s3"
86
- end
87
- end
88
-
89
- assert_equal nil, r.get("bar")
90
- assert_equal nil, r.get("baz")
91
- end
92
-
93
- def test_transformed_replies_as_return_values_for_multi_exec_block
94
- info, _ = r.multi do |m|
95
- r.info
96
- end
97
-
98
- assert info.kind_of?(Hash)
99
- end
100
-
101
- def test_transformed_replies_inside_multi_exec_block
102
- r.multi do |m|
103
- @info = r.info
104
- end
105
-
106
- assert @info.value.kind_of?(Hash)
107
- end
108
-
109
- def test_raise_command_errors_in_multi_exec
110
- assert_raise(Redis::CommandError) do
111
- r.multi do |m|
112
- m.set("foo", "s1")
113
- m.incr("foo") # not an integer
114
- m.lpush("foo", "value") # wrong kind of value
115
- end
116
- end
117
-
118
- assert_equal "s1", r.get("foo")
119
- end
120
-
121
- def test_raise_command_errors_when_accessing_futures_after_multi_exec
122
- begin
123
- r.multi do |m|
124
- m.set("foo", "s1")
125
- @counter = m.incr("foo") # not an integer
126
- end
127
- rescue Exception
128
- # Not gonna deal with it
129
- end
130
-
131
- # We should test for Redis::Error here, but hiredis doesn't yet do
132
- # custom error classes.
133
- err = nil
134
- begin
135
- @counter.value
136
- rescue => err
137
- end
138
-
139
- assert err.kind_of?(RuntimeError)
140
- end
141
-
142
- def test_multi_with_a_block_yielding_the_client
143
- r.multi do |multi|
144
- multi.set "foo", "s1"
145
- end
146
-
147
- assert_equal "s1", r.get("foo")
148
- end
149
-
150
- def test_watch_with_an_unmodified_key
151
- r.watch "foo"
152
- r.multi do |multi|
153
- multi.set "foo", "s1"
154
- end
155
-
156
- assert_equal "s1", r.get("foo")
157
- end
158
-
159
- def test_watch_with_an_unmodified_key_passed_as_array
160
- r.watch ["foo", "bar"]
161
- r.multi do |multi|
162
- multi.set "foo", "s1"
163
- end
164
-
165
- assert_equal "s1", r.get("foo")
166
- end
167
-
168
- def test_watch_with_a_modified_key
169
- r.watch "foo"
170
- r.set "foo", "s1"
171
- res = r.multi do |multi|
172
- multi.set "foo", "s2"
173
- end
174
-
175
- assert_equal nil, res
176
- assert_equal "s1", r.get("foo")
177
- end
178
-
179
- def test_watch_with_a_modified_key_passed_as_array
180
- r.watch ["foo", "bar"]
181
- r.set "foo", "s1"
182
- res = r.multi do |multi|
183
- multi.set "foo", "s2"
184
- end
185
-
186
- assert_equal nil, res
187
- assert_equal "s1", r.get("foo")
188
- end
189
-
190
- def test_watch_with_a_block_and_an_unmodified_key
191
- result = r.watch "foo" do
192
- r.multi do |multi|
193
- multi.set "foo", "s1"
194
- end
195
- end
196
-
197
- assert_equal ["OK"], result
198
- assert_equal "s1", r.get("foo")
199
- end
200
-
201
- def test_watch_with_a_block_and_a_modified_key
202
- result = r.watch "foo" do
203
- r.set "foo", "s1"
204
- r.multi do |multi|
205
- multi.set "foo", "s2"
206
- end
207
- end
208
-
209
- assert_equal nil, result
210
- assert_equal "s1", r.get("foo")
211
- end
212
-
213
- def test_watch_with_a_block_that_raises_an_exception
214
- r.set("foo", "s1")
215
-
216
- begin
217
- r.watch "foo" do
218
- raise "test"
219
- end
220
- rescue RuntimeError
221
- end
222
-
223
- r.set("foo", "s2")
224
-
225
- # If the watch was still set from within the block above, this multi/exec
226
- # would fail. This proves that raising an exception above unwatches.
227
- r.multi do |multi|
228
- multi.set "foo", "s3"
229
- end
230
-
231
- assert_equal "s3", r.get("foo")
232
- end
233
-
234
- def test_unwatch_with_a_modified_key
235
- r.watch "foo"
236
- r.set "foo", "s1"
237
- r.unwatch
238
- r.multi do |multi|
239
- multi.set "foo", "s2"
240
- end
241
-
242
- assert_equal "s2", r.get("foo")
243
- end
244
- end