redis 3.0.2 → 3.0.3

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.
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