redis 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.order CHANGED
@@ -22,7 +22,8 @@
22
22
  "slaveof",
23
23
  "slowlog",
24
24
  "sync",
25
- "time"
25
+ "time",
26
+ "client"
26
27
  ],
27
28
  "generic": [
28
29
  "persist",
@@ -70,7 +71,8 @@
70
71
  "append",
71
72
  "bitcount",
72
73
  "getset",
73
- "strlen"
74
+ "strlen",
75
+ "bitop"
74
76
  ],
75
77
  "list": [
76
78
  "llen",
@@ -90,8 +92,7 @@
90
92
  "lrange",
91
93
  "lrem",
92
94
  "lset",
93
- "ltrim",
94
- "bitop"
95
+ "ltrim"
95
96
  ],
96
97
  "set": [
97
98
  "scard",
@@ -166,4 +167,4 @@
166
167
  "eval",
167
168
  "evalsha"
168
169
  ]
169
- }
170
+ }
@@ -3,12 +3,12 @@ language: ruby
3
3
  branches:
4
4
  only:
5
5
  - master
6
- - test-unit
7
6
 
8
7
  rvm:
9
8
  - 1.8.7
10
9
  - 1.9.2
11
10
  - 1.9.3
11
+ - 2.0.0
12
12
  - jruby-18mode
13
13
  - jruby-19mode
14
14
 
@@ -1,4 +1,23 @@
1
- # 3.0.2 (unreleased)
1
+ # 3.0.4 (unreleased)
2
+
3
+ * ...
4
+
5
+ # 3.0.3
6
+
7
+ * Blocking list commands (`BLPOP`, `BRPOP`, `BRPOPLPUSH`) use a socket
8
+ timeout equal to the sum of the command's timeout and the Redis
9
+ client's timeout, instead of disabling socket timeout altogether.
10
+
11
+ * Ruby 2.0 compatibility.
12
+
13
+ * Added support for `DUMP` and `RESTORE` (Redis 2.6).
14
+
15
+ * Added support for `BITCOUNT` and `BITOP` (Redis 2.6).
16
+
17
+ * Call `#to_s` on value argument for `SET`, `SETEX`, `PSETEX`, `GETSET`,
18
+ `SETNX`, and `SETRANGE`.
19
+
20
+ # 3.0.2
2
21
 
3
22
  * Unescape CGI escaped password in URL.
4
23
 
@@ -54,7 +54,16 @@ benchmark "Default options (no logger)" do
54
54
  end
55
55
 
56
56
  logging_redises.each do |redis|
57
- benchmark "#{redis.client.logger.class} on #{Logger::SEV_LABEL[redis.client.logger.level]}" do
57
+ logger = redis.client.logger
58
+
59
+ case logger
60
+ when Logger
61
+ level = Logger::SEV_LABEL[logger.level]
62
+ when Log4r::Logger
63
+ level = logger.levels[logger.level]
64
+ end
65
+
66
+ benchmark "#{logger.class} on #{level}" do
58
67
  stress(redis)
59
68
  end
60
69
  end
@@ -181,7 +181,7 @@ class Redis
181
181
  if reply.kind_of?(String)
182
182
  reply = Hash[reply.split("\r\n").map do |line|
183
183
  line.split(":", 2) unless line =~ /^(#|$)/
184
- end]
184
+ end.compact]
185
185
 
186
186
  if cmd && cmd.to_s == "commandstats"
187
187
  # Extract nested hashes for INFO COMMANDSTATS
@@ -359,6 +359,28 @@ class Redis
359
359
  end
360
360
  end
361
361
 
362
+ # Return a serialized version of the value stored at a key.
363
+ #
364
+ # @param [String] key
365
+ # @return [String] serialized_value
366
+ def dump(key)
367
+ synchronize do |client|
368
+ client.call([:dump, key])
369
+ end
370
+ end
371
+
372
+ # Create a key using the serialized value, previously obtained using DUMP.
373
+ #
374
+ # @param [String] key
375
+ # @param [String] ttl
376
+ # @param [String] serialized_value
377
+ # @return `"OK"`
378
+ def restore(key, ttl, serialized_value)
379
+ synchronize do |client|
380
+ client.call([:restore, key, ttl, serialized_value])
381
+ end
382
+ end
383
+
362
384
  # Delete one or more keys.
363
385
  #
364
386
  # @param [String, Array<String>] keys
@@ -605,7 +627,7 @@ class Redis
605
627
  # @return `"OK"`
606
628
  def set(key, value)
607
629
  synchronize do |client|
608
- client.call([:set, key, value])
630
+ client.call([:set, key, value.to_s])
609
631
  end
610
632
  end
611
633
 
@@ -619,7 +641,7 @@ class Redis
619
641
  # @return `"OK"`
620
642
  def setex(key, ttl, value)
621
643
  synchronize do |client|
622
- client.call([:setex, key, ttl, value])
644
+ client.call([:setex, key, ttl, value.to_s])
623
645
  end
624
646
  end
625
647
 
@@ -631,7 +653,7 @@ class Redis
631
653
  # @return `"OK"`
632
654
  def psetex(key, ttl, value)
633
655
  synchronize do |client|
634
- client.call([:psetex, key, ttl, value])
656
+ client.call([:psetex, key, ttl, value.to_s])
635
657
  end
636
658
  end
637
659
 
@@ -642,7 +664,7 @@ class Redis
642
664
  # @return [Boolean] whether the key was set or not
643
665
  def setnx(key, value)
644
666
  synchronize do |client|
645
- client.call([:setnx, key, value], &_boolify)
667
+ client.call([:setnx, key, value.to_s], &_boolify)
646
668
  end
647
669
  end
648
670
 
@@ -762,7 +784,7 @@ class Redis
762
784
  # @return [Fixnum] length of the string after it was modified
763
785
  def setrange(key, offset, value)
764
786
  synchronize do |client|
765
- client.call([:setrange, key, offset, value])
787
+ client.call([:setrange, key, offset, value.to_s])
766
788
  end
767
789
  end
768
790
 
@@ -813,6 +835,30 @@ class Redis
813
835
  end
814
836
  end
815
837
 
838
+ # Count the number of set bits in a range of the string value stored at key.
839
+ #
840
+ # @param [String] key
841
+ # @param [Fixnum] start start index
842
+ # @param [Fixnum] stop stop index
843
+ # @return [Fixnum] the number of bits set to 1
844
+ def bitcount(key, start = 0, stop = -1)
845
+ synchronize do |client|
846
+ client.call([:bitcount, key, start, stop])
847
+ end
848
+ end
849
+
850
+ # Perform a bitwise operation between strings and store the resulting string in a key.
851
+ #
852
+ # @param [String] operation e.g. `and`, `or`, `xor`, `not`
853
+ # @param [String] destkey destination key
854
+ # @param [String, Array<String>] keys one or more source keys to perform `operation`
855
+ # @return [Fixnum] the length of the string stored in `destkey`
856
+ def bitop(operation, destkey, *keys)
857
+ synchronize do |client|
858
+ client.call([:bitop, operation, destkey] + keys)
859
+ end
860
+ end
861
+
816
862
  # Set the string value of a key and return its old value.
817
863
  #
818
864
  # @param [String] key
@@ -821,7 +867,7 @@ class Redis
821
867
  # did not exist
822
868
  def getset(key, value)
823
869
  synchronize do |client|
824
- client.call([:getset, key, value])
870
+ client.call([:getset, key, value.to_s])
825
871
  end
826
872
  end
827
873
 
@@ -849,7 +895,7 @@ class Redis
849
895
  # Prepend one or more values to a list, creating the list if it doesn't exist
850
896
  #
851
897
  # @param [String] key
852
- # @param [String] value
898
+ # @param [String, Array] string value, or array of string values to push
853
899
  # @return [Fixnum] the length of the list after the push operation
854
900
  def lpush(key, value)
855
901
  synchronize do |client|
@@ -940,7 +986,9 @@ class Redis
940
986
  timeout = options[:timeout] || 0
941
987
 
942
988
  synchronize do |client|
943
- client.call_without_timeout([cmd, keys, timeout])
989
+ command = [cmd, keys, timeout]
990
+ timeout += client.timeout if timeout > 0
991
+ client.call_with_timeout(command, timeout)
944
992
  end
945
993
  end
946
994
 
@@ -1006,7 +1054,9 @@ class Redis
1006
1054
  timeout = options[:timeout] || 0
1007
1055
 
1008
1056
  synchronize do |client|
1009
- client.call_without_timeout([:brpoplpush, source, destination, timeout])
1057
+ command = [:brpoplpush, source, destination, timeout]
1058
+ timeout += client.timeout if timeout > 0
1059
+ client.call_with_timeout(command, timeout)
1010
1060
  end
1011
1061
  end
1012
1062
 
@@ -1150,13 +1200,18 @@ class Redis
1150
1200
  end
1151
1201
  end
1152
1202
 
1153
- # Get a random member from a set.
1203
+ # Get one or more random members from a set.
1154
1204
  #
1155
1205
  # @param [String] key
1206
+ # @param [Fixnum] count
1156
1207
  # @return [String]
1157
- def srandmember(key)
1208
+ def srandmember(key, count = nil)
1158
1209
  synchronize do |client|
1159
- client.call([:srandmember, key])
1210
+ if count.nil?
1211
+ client.call([:srandmember, key])
1212
+ else
1213
+ client.call([:srandmember, key, count])
1214
+ end
1160
1215
  end
1161
1216
  end
1162
1217
 
@@ -160,14 +160,18 @@ class Redis
160
160
  result
161
161
  end
162
162
 
163
- def call_without_timeout(command, &blk)
164
- without_socket_timeout do
163
+ def call_with_timeout(command, timeout, &blk)
164
+ with_socket_timeout(timeout) do
165
165
  call(command, &blk)
166
166
  end
167
167
  rescue ConnectionError
168
168
  retry
169
169
  end
170
170
 
171
+ def call_without_timeout(command, &blk)
172
+ call_with_timeout(command, 0, &blk)
173
+ end
174
+
171
175
  def process(commands)
172
176
  logging(commands) do
173
177
  ensure_connected do
@@ -218,17 +222,21 @@ class Redis
218
222
  end
219
223
  end
220
224
 
221
- def without_socket_timeout
225
+ def with_socket_timeout(timeout)
222
226
  connect unless connected?
223
227
 
224
228
  begin
225
- connection.timeout = 0
229
+ connection.timeout = timeout
226
230
  yield
227
231
  ensure
228
- connection.timeout = timeout if connected?
232
+ connection.timeout = self.timeout if connected?
229
233
  end
230
234
  end
231
235
 
236
+ def without_socket_timeout(&blk)
237
+ with_socket_timeout(0, &blk)
238
+ end
239
+
232
240
  def with_reconnect(val=true)
233
241
  begin
234
242
  original, @reconnect = @reconnect, val
@@ -83,11 +83,7 @@ class Redis
83
83
 
84
84
  class UNIXSocket < ::UNIXSocket
85
85
 
86
- # This class doesn't include the mixin, because JRuby raises
87
- # Errno::EAGAIN on #read_nonblock even when IO.select says it is
88
- # readable. This behavior shows in 1.6.6 in both 1.8 and 1.9 mode.
89
- # Therefore, fall back on the default Unix socket implementation,
90
- # without timeouts.
86
+ include SocketMixin
91
87
 
92
88
  def self.connect(path, timeout)
93
89
  Timeout.timeout(timeout) do
@@ -97,6 +93,17 @@ class Redis
97
93
  rescue Timeout::Error
98
94
  raise TimeoutError
99
95
  end
96
+
97
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
98
+ # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
99
+ # Use the blocking #readpartial method instead.
100
+
101
+ def _read_from_socket(nbytes)
102
+ readpartial(nbytes)
103
+
104
+ rescue EOFError
105
+ raise Errno::ECONNRESET
106
+ end
100
107
  end
101
108
 
102
109
  end
@@ -132,8 +139,7 @@ class Redis
132
139
 
133
140
  class UNIXSocket < ::Socket
134
141
 
135
- # This class doesn't include the mixin to keep its behavior in sync
136
- # with the JRuby implementation.
142
+ include SocketMixin
137
143
 
138
144
  def self.connect(path, timeout)
139
145
  sock = new(::Socket::AF_UNIX, Socket::SOCK_STREAM, 0)
@@ -137,6 +137,16 @@ class Redis
137
137
  node_for(key).pttl(key)
138
138
  end
139
139
 
140
+ # Return a serialized version of the value stored at a key.
141
+ def dump(key)
142
+ node_for(key).dump(key)
143
+ end
144
+
145
+ # Create a key using the serialized value, previously obtained using DUMP.
146
+ def restore(key, ttl, serialized_value)
147
+ node_for(key).restore(key, ttl, serialized_value)
148
+ end
149
+
140
150
  # Delete a key.
141
151
  def del(*args)
142
152
  keys_per_node = args.group_by { |key| node_for(key) }
@@ -295,6 +305,18 @@ class Redis
295
305
  node_for(key).append(key, value)
296
306
  end
297
307
 
308
+ # Count the number of set bits in a range of the string value stored at key.
309
+ def bitcount(key, start = 0, stop = -1)
310
+ node_for(key).bitcount(key, start, stop)
311
+ end
312
+
313
+ # Perform a bitwise operation between strings and store the resulting string in a key.
314
+ def bitop(operation, destkey, *keys)
315
+ ensure_same_node(:bitop, [destkey] + keys) do |node|
316
+ node.bitop(operation, destkey, *keys)
317
+ end
318
+ end
319
+
298
320
  # Set the string value of a key and return its old value.
299
321
  def getset(key, value)
300
322
  node_for(key).getset(key, value)
@@ -455,8 +477,8 @@ class Redis
455
477
  end
456
478
 
457
479
  # Get a random member from a set.
458
- def srandmember(key)
459
- node_for(key).srandmember(key)
480
+ def srandmember(key, count = nil)
481
+ node_for(key).srandmember(key, count)
460
482
  end
461
483
 
462
484
  # Move a member from one set to another.
@@ -55,8 +55,8 @@ class Redis
55
55
  def iter_nodes(key)
56
56
  return [nil,nil] if @ring.size == 0
57
57
  _, pos = get_node_pos(key)
58
- @sorted_keys[pos..-1].each do |k|
59
- yield @ring[k]
58
+ @ring.size.times do |n|
59
+ yield @ring[@sorted_keys[(pos+n) % @ring.size]]
60
60
  end
61
61
  end
62
62
 
@@ -29,14 +29,17 @@ class Redis
29
29
  def subscription(start, stop, channels, block)
30
30
  sub = Subscription.new(&block)
31
31
 
32
+ unsubscribed = false
33
+
32
34
  begin
33
35
  @client.call_loop([start, *channels]) do |line|
34
36
  type, *rest = line
35
37
  sub.callbacks[type].call(*rest)
36
- break if type == stop && rest.last == 0
38
+ unsubscribed = type == stop && rest.last == 0
39
+ break if unsubscribed
37
40
  end
38
41
  ensure
39
- send(stop)
42
+ send(stop) if !unsubscribed
40
43
  end
41
44
  end
42
45
  end
@@ -1,3 +1,3 @@
1
1
  class Redis
2
- VERSION = "3.0.2"
2
+ VERSION = "3.0.3"
3
3
  end
@@ -80,4 +80,20 @@ class TestCommandsOnStrings < Test::Unit::TestCase
80
80
  assert_equal "s2", r.get("foo")
81
81
  assert_equal "s3", r.get("bar")
82
82
  end
83
+
84
+ def test_bitop
85
+ return if version < "2.5.10"
86
+
87
+ r.set("foo", "a")
88
+ r.set("bar", "b")
89
+
90
+ r.bitop(:and, "foo&bar", "foo", "bar")
91
+ assert_equal "\x60", r.get("foo&bar")
92
+ r.bitop(:or, "foo|bar", "foo", "bar")
93
+ assert_equal "\x63", r.get("foo|bar")
94
+ r.bitop(:xor, "foo^bar", "foo", "bar")
95
+ assert_equal "\x03", r.get("foo^bar")
96
+ r.bitop(:not, "~foo", "foo")
97
+ assert_equal "\x9E", r.get("~foo")
98
+ end
83
99
  end
@@ -45,4 +45,15 @@ class TestDistributedCommandsOnStrings < Test::Unit::TestCase
45
45
  r.mapped_msetnx(:foo => "s2", :bar => "s3")
46
46
  end
47
47
  end
48
+
49
+ def test_bitop
50
+ return if version < "2.5.10"
51
+
52
+ assert_raise Redis::Distributed::CannotDistribute do
53
+ r.set("foo", "a")
54
+ r.set("bar", "b")
55
+
56
+ r.bitop(:and, "foo&bar", "foo", "bar")
57
+ end
58
+ end
48
59
  end
@@ -145,4 +145,20 @@ class TestDistributedCommandsRequiringClustering < Test::Unit::TestCase
145
145
  r.sort("{qux}bar", :get => "{qux}foo:*", :store => "{qux}baz")
146
146
  assert_equal ["s1", "s2"], r.lrange("{qux}baz", 0, -1)
147
147
  end
148
+
149
+ def test_bitop
150
+ return if version < "2.5.10"
151
+
152
+ r.set("{qux}foo", "a")
153
+ r.set("{qux}bar", "b")
154
+
155
+ r.bitop(:and, "{qux}foo&bar", "{qux}foo", "{qux}bar")
156
+ assert_equal "\x60", r.get("{qux}foo&bar")
157
+ r.bitop(:or, "{qux}foo|bar", "{qux}foo", "{qux}bar")
158
+ assert_equal "\x63", r.get("{qux}foo|bar")
159
+ r.bitop(:xor, "{qux}foo^bar", "{qux}foo", "{qux}bar")
160
+ assert_equal "\x03", r.get("{qux}foo^bar")
161
+ r.bitop(:not, "{qux}~foo", "{qux}foo")
162
+ assert_equal "\x9E", r.get("{qux}~foo")
163
+ end
148
164
  end
@@ -17,9 +17,9 @@ class TestDistributedRemoteServerControlCommands < Test::Unit::TestCase
17
17
  "total_commands_processed",
18
18
  ]
19
19
 
20
- info = r.info
20
+ infos = r.info
21
21
 
22
- info.each do |info|
22
+ infos.each do |info|
23
23
  keys.each do |k|
24
24
  msg = "expected #info to include #{k}"
25
25
  assert info.keys.include?(k), msg
@@ -113,7 +113,7 @@ module Helper
113
113
 
114
114
  return -1 if a.nil?
115
115
  return +1 if b.nil?
116
- return a <=> b if a != b
116
+ return a.to_i <=> b.to_i if a != b
117
117
  end
118
118
 
119
119
  0
@@ -7,16 +7,18 @@ class TestHelper < Test::Unit::TestCase
7
7
  include Helper
8
8
 
9
9
  def test_version_comparison
10
- v = Version.new("2.0.0")
10
+ v = Version.new("2.0.1")
11
11
 
12
- assert v < "3"
13
12
  assert v > "1"
14
13
  assert v > "2"
14
+ assert v < "3"
15
+ assert v < "10"
15
16
 
16
17
  assert v < "2.1"
17
- assert v < "2.0.1"
18
- assert v < "2.0.0.1"
18
+ assert v < "2.0.2"
19
+ assert v < "2.0.1.1"
20
+ assert v < "2.0.10"
19
21
 
20
- assert v == "2.0.0"
22
+ assert v == "2.0.1"
21
23
  end
22
24
  end
@@ -280,7 +280,7 @@ class TestInternals < Test::Unit::TestCase
280
280
 
281
281
  def test_connecting_to_unix_domain_socket
282
282
  assert_nothing_raised do
283
- Redis.new(OPTIONS.merge(:path => "/tmp/redis.sock")).ping
283
+ Redis.new(OPTIONS.merge(:path => "./test/db/redis.sock")).ping
284
284
  end
285
285
  end
286
286
 
@@ -120,5 +120,31 @@ module Lint
120
120
  assert_equal "1", r.brpoplpush("{zap}foo", "{zap}bar", 1)
121
121
  end
122
122
  end
123
+
124
+ driver(:ruby, :hiredis) do
125
+ def test_blpop_socket_timeout
126
+ mock(:delay => 1 + OPTIONS[:timeout] * 2) do |r|
127
+ assert_raises(Redis::TimeoutError) do
128
+ r.blpop("{zap}foo", :timeout => 1)
129
+ end
130
+ end
131
+ end
132
+
133
+ def test_brpop_socket_timeout
134
+ mock(:delay => 1 + OPTIONS[:timeout] * 2) do |r|
135
+ assert_raises(Redis::TimeoutError) do
136
+ r.brpop("{zap}foo", :timeout => 1)
137
+ end
138
+ end
139
+ end
140
+
141
+ def test_brpoplpush_socket_timeout
142
+ mock(:delay => 1 + OPTIONS[:timeout] * 2) do |r|
143
+ assert_raises(Redis::TimeoutError) do
144
+ r.brpoplpush("{zap}foo", "{zap}bar", :timeout => 1)
145
+ end
146
+ end
147
+ end
148
+ end
123
149
  end
124
150
  end
@@ -92,5 +92,34 @@ module Lint
92
92
 
93
93
  assert_equal 2, r.scard("foo")
94
94
  end
95
+
96
+ def test_srandmember_with_positive_count
97
+ r.sadd "foo", "s1"
98
+ r.sadd "foo", "s2"
99
+ r.sadd "foo", "s3"
100
+ r.sadd "foo", "s4"
101
+
102
+ 4.times do
103
+ assert !(["s1", "s2", "s3", "s4"] & r.srandmember("foo", 3)).empty?
104
+
105
+ assert_equal 3, r.srandmember("foo", 3).size
106
+ end
107
+
108
+ assert_equal 4, r.scard("foo")
109
+ end
110
+
111
+ def test_srandmember_with_negative_count
112
+ r.sadd "foo", "s1"
113
+ r.sadd "foo", "s2"
114
+ r.sadd "foo", "s3"
115
+ r.sadd "foo", "s4"
116
+
117
+ 4.times do
118
+ assert !(["s1", "s2", "s3", "s4"] & r.srandmember("foo", -6)).empty?
119
+ assert_equal 6, r.srandmember("foo", -6).size
120
+ end
121
+
122
+ assert_equal 4, r.scard("foo")
123
+ end
95
124
  end
96
125
  end
@@ -26,6 +26,14 @@ module Lint
26
26
  assert_equal "1\n", r.get("foo")
27
27
  end
28
28
 
29
+ def test_set_and_get_with_non_string_value
30
+ value = ["a", "b"]
31
+
32
+ r.set("foo", value)
33
+
34
+ assert_equal value.to_s, r.get("foo")
35
+ end
36
+
29
37
  def test_set_and_get_with_ascii_characters
30
38
  if defined?(Encoding)
31
39
  with_external_encoding("ASCII-8BIT") do
@@ -45,6 +53,14 @@ module Lint
45
53
  assert [0, 1].include? r.ttl("foo")
46
54
  end
47
55
 
56
+ def test_setex_with_non_string_value
57
+ value = ["b", "a", "r"]
58
+
59
+ assert r.setex("foo", 1, value)
60
+ assert_equal value.to_s, r.get("foo")
61
+ assert [0, 1].include? r.ttl("foo")
62
+ end
63
+
48
64
  def test_psetex
49
65
  return if version < "2.5.4"
50
66
 
@@ -53,6 +69,16 @@ module Lint
53
69
  assert [0, 1].include? r.ttl("foo")
54
70
  end
55
71
 
72
+ def test_psetex_with_non_string_value
73
+ return if version < "2.5.4"
74
+
75
+ value = ["b", "a", "r"]
76
+
77
+ assert r.psetex("foo", 1000, value)
78
+ assert_equal value.to_s, r.get("foo")
79
+ assert [0, 1].include? r.ttl("foo")
80
+ end
81
+
56
82
  def test_getset
57
83
  r.set("foo", "bar")
58
84
 
@@ -60,14 +86,35 @@ module Lint
60
86
  assert_equal "baz", r.get("foo")
61
87
  end
62
88
 
89
+ def test_getset_with_non_string_value
90
+ r.set("foo", "zap")
91
+
92
+ value = ["b", "a", "r"]
93
+
94
+ assert_equal "zap", r.getset("foo", value)
95
+ assert_equal value.to_s, r.get("foo")
96
+ end
97
+
63
98
  def test_setnx
64
- r.set("foo", "s1")
99
+ r.set("foo", "qux")
100
+ assert !r.setnx("foo", "bar")
101
+ assert_equal "qux", r.get("foo")
65
102
 
66
- assert_equal "s1", r.get("foo")
103
+ r.del("foo")
104
+ assert r.setnx("foo", "bar")
105
+ assert_equal "bar", r.get("foo")
106
+ end
67
107
 
68
- r.setnx("foo", "s2")
108
+ def test_setnx_with_non_string_value
109
+ value = ["b", "a", "r"]
69
110
 
70
- assert_equal "s1", r.get("foo")
111
+ r.set("foo", "qux")
112
+ assert !r.setnx("foo", value)
113
+ assert_equal "qux", r.get("foo")
114
+
115
+ r.del("foo")
116
+ assert r.setnx("foo", value)
117
+ assert_equal value.to_s, r.get("foo")
71
118
  end
72
119
 
73
120
  def test_incr
@@ -133,6 +180,15 @@ module Lint
133
180
  assert_equal "c", r.get("foo")
134
181
  end
135
182
 
183
+ def test_bitcount
184
+ return if version < "2.5.10"
185
+
186
+ r.set("foo", "abcde")
187
+
188
+ assert_equal 10, r.bitcount("foo", 1, 3)
189
+ assert_equal 17, r.bitcount("foo", 0, -1)
190
+ end
191
+
136
192
  def test_getrange
137
193
  r.set("foo", "abcde")
138
194
 
@@ -148,6 +204,16 @@ module Lint
148
204
  assert_equal "abare", r.get("foo")
149
205
  end
150
206
 
207
+ def test_setrange_with_non_string_value
208
+ r.set("foo", "abcde")
209
+
210
+ value = ["b", "a", "r"]
211
+
212
+ r.setrange("foo", 2, value)
213
+
214
+ assert_equal "ab#{value.to_s}", r.get("foo")
215
+ end
216
+
151
217
  def test_strlen
152
218
  r.set "foo", "lorem"
153
219
 
@@ -80,6 +80,26 @@ module Lint
80
80
  assert_in_range 1..2000, r.pttl("foo")
81
81
  end
82
82
 
83
+ def test_dump_and_restore
84
+ return if version < "2.5.7"
85
+
86
+ r.set("foo", "a")
87
+ v = r.dump("foo")
88
+ r.del("foo")
89
+
90
+ assert r.restore("foo", 1000, v)
91
+ assert_equal "a", r.get("foo")
92
+ assert [0, 1].include? r.ttl("foo")
93
+
94
+ r.rpush("bar", ["b", "c", "d"])
95
+ w = r.dump("bar")
96
+ r.del("bar")
97
+
98
+ assert r.restore("bar", 1000, w)
99
+ assert_equal ["b", "c", "d"], r.lrange("bar", 0, -1)
100
+ assert [0, 1].include? r.ttl("bar")
101
+ end
102
+
83
103
  def test_move
84
104
  r.select 14
85
105
  r.flushdb
@@ -67,8 +67,6 @@ class TestPublishSubscribe < Test::Unit::TestCase
67
67
  @unsubscribed = true
68
68
  @t2 = total
69
69
  end
70
-
71
- listening = true
72
70
  end
73
71
  end
74
72
 
@@ -1,7 +1,7 @@
1
1
  dir ./test/db
2
2
  pidfile ./redis.pid
3
3
  port 6381
4
- unixsocket /tmp/redis.sock
4
+ unixsocket ./redis.sock
5
5
  timeout 300
6
6
  loglevel debug
7
7
  logfile stdout
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -17,7 +17,7 @@ authors:
17
17
  autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
- date: 2012-10-05 00:00:00.000000000 Z
20
+ date: 2013-03-01 00:00:00.000000000 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: rake