redis2-namespaced 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.order +170 -0
  4. data/.travis/Gemfile +11 -0
  5. data/.travis.yml +55 -0
  6. data/.yardopts +3 -0
  7. data/CHANGELOG.md +285 -0
  8. data/LICENSE +20 -0
  9. data/README.md +251 -0
  10. data/Rakefile +403 -0
  11. data/benchmarking/logging.rb +71 -0
  12. data/benchmarking/pipeline.rb +51 -0
  13. data/benchmarking/speed.rb +21 -0
  14. data/benchmarking/suite.rb +24 -0
  15. data/benchmarking/worker.rb +71 -0
  16. data/examples/basic.rb +15 -0
  17. data/examples/dist_redis.rb +43 -0
  18. data/examples/incr-decr.rb +17 -0
  19. data/examples/list.rb +26 -0
  20. data/examples/pubsub.rb +37 -0
  21. data/examples/sets.rb +36 -0
  22. data/examples/unicorn/config.ru +3 -0
  23. data/examples/unicorn/unicorn.rb +20 -0
  24. data/lib/redis2/client.rb +419 -0
  25. data/lib/redis2/connection/command_helper.rb +44 -0
  26. data/lib/redis2/connection/hiredis.rb +63 -0
  27. data/lib/redis2/connection/registry.rb +12 -0
  28. data/lib/redis2/connection/ruby.rb +322 -0
  29. data/lib/redis2/connection/synchrony.rb +124 -0
  30. data/lib/redis2/connection.rb +9 -0
  31. data/lib/redis2/distributed.rb +853 -0
  32. data/lib/redis2/errors.rb +40 -0
  33. data/lib/redis2/hash_ring.rb +131 -0
  34. data/lib/redis2/pipeline.rb +141 -0
  35. data/lib/redis2/subscribe.rb +83 -0
  36. data/lib/redis2/version.rb +3 -0
  37. data/lib/redis2.rb +2533 -0
  38. data/redis.gemspec +43 -0
  39. data/test/bitpos_test.rb +69 -0
  40. data/test/blocking_commands_test.rb +42 -0
  41. data/test/command_map_test.rb +30 -0
  42. data/test/commands_on_hashes_test.rb +21 -0
  43. data/test/commands_on_lists_test.rb +20 -0
  44. data/test/commands_on_sets_test.rb +77 -0
  45. data/test/commands_on_sorted_sets_test.rb +109 -0
  46. data/test/commands_on_strings_test.rb +101 -0
  47. data/test/commands_on_value_types_test.rb +131 -0
  48. data/test/connection_handling_test.rb +189 -0
  49. data/test/db/.gitkeep +0 -0
  50. data/test/distributed_blocking_commands_test.rb +46 -0
  51. data/test/distributed_commands_on_hashes_test.rb +10 -0
  52. data/test/distributed_commands_on_lists_test.rb +22 -0
  53. data/test/distributed_commands_on_sets_test.rb +83 -0
  54. data/test/distributed_commands_on_sorted_sets_test.rb +18 -0
  55. data/test/distributed_commands_on_strings_test.rb +59 -0
  56. data/test/distributed_commands_on_value_types_test.rb +95 -0
  57. data/test/distributed_commands_requiring_clustering_test.rb +164 -0
  58. data/test/distributed_connection_handling_test.rb +23 -0
  59. data/test/distributed_internals_test.rb +70 -0
  60. data/test/distributed_key_tags_test.rb +52 -0
  61. data/test/distributed_persistence_control_commands_test.rb +26 -0
  62. data/test/distributed_publish_subscribe_test.rb +92 -0
  63. data/test/distributed_remote_server_control_commands_test.rb +66 -0
  64. data/test/distributed_scripting_test.rb +102 -0
  65. data/test/distributed_sorting_test.rb +20 -0
  66. data/test/distributed_test.rb +58 -0
  67. data/test/distributed_transactions_test.rb +32 -0
  68. data/test/encoding_test.rb +18 -0
  69. data/test/error_replies_test.rb +59 -0
  70. data/test/helper.rb +218 -0
  71. data/test/helper_test.rb +24 -0
  72. data/test/internals_test.rb +410 -0
  73. data/test/lint/blocking_commands.rb +150 -0
  74. data/test/lint/hashes.rb +162 -0
  75. data/test/lint/lists.rb +143 -0
  76. data/test/lint/sets.rb +125 -0
  77. data/test/lint/sorted_sets.rb +238 -0
  78. data/test/lint/strings.rb +260 -0
  79. data/test/lint/value_types.rb +122 -0
  80. data/test/persistence_control_commands_test.rb +26 -0
  81. data/test/pipelining_commands_test.rb +242 -0
  82. data/test/publish_subscribe_test.rb +210 -0
  83. data/test/remote_server_control_commands_test.rb +117 -0
  84. data/test/scanning_test.rb +413 -0
  85. data/test/scripting_test.rb +78 -0
  86. data/test/sorting_test.rb +59 -0
  87. data/test/support/connection/hiredis.rb +1 -0
  88. data/test/support/connection/ruby.rb +1 -0
  89. data/test/support/connection/synchrony.rb +17 -0
  90. data/test/support/redis_mock.rb +115 -0
  91. data/test/support/wire/synchrony.rb +24 -0
  92. data/test/support/wire/thread.rb +5 -0
  93. data/test/synchrony_driver.rb +88 -0
  94. data/test/test.conf +9 -0
  95. data/test/thread_safety_test.rb +32 -0
  96. data/test/transactions_test.rb +264 -0
  97. data/test/unknown_commands_test.rb +14 -0
  98. data/test/url_param_test.rb +132 -0
  99. metadata +226 -0
@@ -0,0 +1,189 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+
5
+ class TestConnectionHandling < Test::Unit::TestCase
6
+
7
+ include Helper::Client
8
+
9
+ def test_auth
10
+ commands = {
11
+ :auth => lambda { |password| $auth = password; "+OK" },
12
+ :get => lambda { |key| $auth == "secret" ? "$3\r\nbar" : "$-1" },
13
+ }
14
+
15
+ redis_mock(commands, :password => "secret") do |redis|
16
+ assert_equal "bar", redis.get("foo")
17
+ end
18
+ end
19
+
20
+ def test_ping
21
+ assert_equal "PONG", r.ping
22
+ end
23
+
24
+ def test_select
25
+ r.set "foo", "bar"
26
+
27
+ r.select 14
28
+ assert_equal nil, r.get("foo")
29
+
30
+ r.client.disconnect
31
+
32
+ assert_equal nil, r.get("foo")
33
+ end
34
+
35
+ def test_quit
36
+ r.quit
37
+
38
+ assert !r.client.connected?
39
+ end
40
+
41
+ def test_shutdown
42
+ commands = {
43
+ :shutdown => lambda { :exit }
44
+ }
45
+
46
+ redis_mock(commands) do |redis|
47
+ # SHUTDOWN does not reply: test that it does not raise here.
48
+ assert_equal nil, redis.shutdown
49
+ end
50
+ end
51
+
52
+ def test_shutdown_with_error
53
+ connections = 0
54
+ commands = {
55
+ :select => lambda { |*_| connections += 1; "+OK\r\n" },
56
+ :connections => lambda { ":#{connections}\r\n" },
57
+ :shutdown => lambda { "-ERR could not shutdown\r\n" }
58
+ }
59
+
60
+ redis_mock(commands) do |redis|
61
+ connections = redis.connections
62
+
63
+ # SHUTDOWN replies with an error: test that it gets raised
64
+ assert_raise Redis2::CommandError do
65
+ redis.shutdown
66
+ end
67
+
68
+ # The connection should remain in tact
69
+ assert_equal connections, redis.connections
70
+ end
71
+ end
72
+
73
+ def test_shutdown_from_pipeline
74
+ commands = {
75
+ :shutdown => lambda { :exit }
76
+ }
77
+
78
+ redis_mock(commands) do |redis|
79
+ result = redis.pipelined do
80
+ redis.shutdown
81
+ end
82
+
83
+ assert_equal nil, result
84
+ assert !redis.client.connected?
85
+ end
86
+ end
87
+
88
+ def test_shutdown_with_error_from_pipeline
89
+ connections = 0
90
+ commands = {
91
+ :select => lambda { |*_| connections += 1; "+OK\r\n" },
92
+ :connections => lambda { ":#{connections}\r\n" },
93
+ :shutdown => lambda { "-ERR could not shutdown\r\n" }
94
+ }
95
+
96
+ redis_mock(commands) do |redis|
97
+ connections = redis.connections
98
+
99
+ # SHUTDOWN replies with an error: test that it gets raised
100
+ assert_raise Redis2::CommandError do
101
+ redis.pipelined do
102
+ redis.shutdown
103
+ end
104
+ end
105
+
106
+ # The connection should remain in tact
107
+ assert_equal connections, redis.connections
108
+ end
109
+ end
110
+
111
+ def test_shutdown_from_multi_exec
112
+ commands = {
113
+ :multi => lambda { "+OK\r\n" },
114
+ :shutdown => lambda { "+QUEUED\r\n" },
115
+ :exec => lambda { :exit }
116
+ }
117
+
118
+ redis_mock(commands) do |redis|
119
+ result = redis.multi do
120
+ redis.shutdown
121
+ end
122
+
123
+ assert_equal nil, result
124
+ assert !redis.client.connected?
125
+ end
126
+ end
127
+
128
+ def test_shutdown_with_error_from_multi_exec
129
+ connections = 0
130
+ commands = {
131
+ :select => lambda { |*_| connections += 1; "+OK\r\n" },
132
+ :connections => lambda { ":#{connections}\r\n" },
133
+ :multi => lambda { "+OK\r\n" },
134
+ :shutdown => lambda { "+QUEUED\r\n" },
135
+ :exec => lambda { "*1\r\n-ERR could not shutdown\r\n" }
136
+ }
137
+
138
+ redis_mock(commands) do |redis|
139
+ connections = redis.connections
140
+
141
+ # SHUTDOWN replies with an error: test that it gets returned
142
+ # We should test for Redis2::CommandError here, but hiredis doesn't yet do
143
+ # custom error classes.
144
+ err = nil
145
+
146
+ begin
147
+ redis.multi { redis.shutdown }
148
+ rescue => err
149
+ end
150
+
151
+ assert err.kind_of?(StandardError)
152
+
153
+ # The connection should remain intact
154
+ assert_equal connections, redis.connections
155
+ end
156
+ end
157
+
158
+ def test_slaveof
159
+ redis_mock(:slaveof => lambda { |host, port| "+SLAVEOF #{host} #{port}" }) do |redis|
160
+ assert_equal "SLAVEOF somehost 6381", redis.slaveof("somehost", 6381)
161
+ end
162
+ end
163
+
164
+ def test_bgrewriteaof
165
+ redis_mock(:bgrewriteaof => lambda { "+BGREWRITEAOF" }) do |redis|
166
+ assert_equal "BGREWRITEAOF", redis.bgrewriteaof
167
+ end
168
+ end
169
+
170
+ def test_config_get
171
+ assert r.config(:get, "*")["timeout"] != nil
172
+
173
+ config = r.config(:get, "timeout")
174
+ assert_equal ["timeout"], config.keys
175
+ assert config.values.compact.size > 0
176
+ end
177
+
178
+ def test_config_set
179
+ begin
180
+ assert_equal "OK", r.config(:set, "timeout", 200)
181
+ assert_equal "200", r.config(:get, "*")["timeout"]
182
+
183
+ assert_equal "OK", r.config(:set, "timeout", 100)
184
+ assert_equal "100", r.config(:get, "*")["timeout"]
185
+ ensure
186
+ r.config :set, "timeout", 300
187
+ end
188
+ end
189
+ end
data/test/db/.gitkeep ADDED
File without changes
@@ -0,0 +1,46 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/blocking_commands"
5
+
6
+ class TestDistributedBlockingCommands < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::BlockingCommands
10
+
11
+ def test_blpop_raises
12
+ assert_raises(Redis2::Distributed::CannotDistribute) do
13
+ r.blpop(["foo", "bar"])
14
+ end
15
+ end
16
+
17
+ def test_blpop_raises_with_old_prototype
18
+ assert_raises(Redis2::Distributed::CannotDistribute) do
19
+ r.blpop("foo", "bar", 0)
20
+ end
21
+ end
22
+
23
+ def test_brpop_raises
24
+ assert_raises(Redis2::Distributed::CannotDistribute) do
25
+ r.brpop(["foo", "bar"])
26
+ end
27
+ end
28
+
29
+ def test_brpop_raises_with_old_prototype
30
+ assert_raises(Redis2::Distributed::CannotDistribute) do
31
+ r.brpop("foo", "bar", 0)
32
+ end
33
+ end
34
+
35
+ def test_brpoplpush_raises
36
+ assert_raises(Redis2::Distributed::CannotDistribute) do
37
+ r.brpoplpush("foo", "bar")
38
+ end
39
+ end
40
+
41
+ def test_brpoplpush_raises_with_old_prototype
42
+ assert_raises(Redis2::Distributed::CannotDistribute) do
43
+ r.brpoplpush("foo", "bar", 0)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/hashes"
5
+
6
+ class TestDistributedCommandsOnHashes < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::Hashes
10
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/lists"
5
+
6
+ class TestDistributedCommandsOnLists < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::Lists
10
+
11
+ def test_rpoplpush
12
+ assert_raise Redis2::Distributed::CannotDistribute do
13
+ r.rpoplpush("foo", "bar")
14
+ end
15
+ end
16
+
17
+ def test_brpoplpush
18
+ assert_raise Redis2::Distributed::CannotDistribute do
19
+ r.brpoplpush("foo", "bar", :timeout => 1)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/sets"
5
+
6
+ class TestDistributedCommandsOnSets < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::Sets
10
+
11
+ def test_smove
12
+ assert_raise Redis2::Distributed::CannotDistribute do
13
+ r.sadd "foo", "s1"
14
+ r.sadd "bar", "s2"
15
+
16
+ r.smove("foo", "bar", "s1")
17
+ end
18
+ end
19
+
20
+ def test_sinter
21
+ assert_raise Redis2::Distributed::CannotDistribute do
22
+ r.sadd "foo", "s1"
23
+ r.sadd "foo", "s2"
24
+ r.sadd "bar", "s2"
25
+
26
+ r.sinter("foo", "bar")
27
+ end
28
+ end
29
+
30
+ def test_sinterstore
31
+ assert_raise Redis2::Distributed::CannotDistribute do
32
+ r.sadd "foo", "s1"
33
+ r.sadd "foo", "s2"
34
+ r.sadd "bar", "s2"
35
+
36
+ r.sinterstore("baz", "foo", "bar")
37
+ end
38
+ end
39
+
40
+ def test_sunion
41
+ assert_raise Redis2::Distributed::CannotDistribute do
42
+ r.sadd "foo", "s1"
43
+ r.sadd "foo", "s2"
44
+ r.sadd "bar", "s2"
45
+ r.sadd "bar", "s3"
46
+
47
+ r.sunion("foo", "bar")
48
+ end
49
+ end
50
+
51
+ def test_sunionstore
52
+ assert_raise Redis2::Distributed::CannotDistribute do
53
+ r.sadd "foo", "s1"
54
+ r.sadd "foo", "s2"
55
+ r.sadd "bar", "s2"
56
+ r.sadd "bar", "s3"
57
+
58
+ r.sunionstore("baz", "foo", "bar")
59
+ end
60
+ end
61
+
62
+ def test_sdiff
63
+ assert_raise Redis2::Distributed::CannotDistribute do
64
+ r.sadd "foo", "s1"
65
+ r.sadd "foo", "s2"
66
+ r.sadd "bar", "s2"
67
+ r.sadd "bar", "s3"
68
+
69
+ r.sdiff("foo", "bar")
70
+ end
71
+ end
72
+
73
+ def test_sdiffstore
74
+ assert_raise Redis2::Distributed::CannotDistribute do
75
+ r.sadd "foo", "s1"
76
+ r.sadd "foo", "s2"
77
+ r.sadd "bar", "s2"
78
+ r.sadd "bar", "s3"
79
+
80
+ r.sdiffstore("baz", "foo", "bar")
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/sorted_sets"
5
+
6
+ class TestDistributedCommandsOnSortedSets < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::SortedSets
10
+
11
+ def test_zcount
12
+ r.zadd "foo", 1, "s1"
13
+ r.zadd "foo", 2, "s2"
14
+ r.zadd "foo", 3, "s3"
15
+
16
+ assert_equal 2, r.zcount("foo", 2, 3)
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/strings"
5
+
6
+ class TestDistributedCommandsOnStrings < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::Strings
10
+
11
+ def test_mget
12
+ assert_raise Redis2::Distributed::CannotDistribute do
13
+ r.mget("foo", "bar")
14
+ end
15
+ end
16
+
17
+ def test_mget_mapped
18
+ assert_raise Redis2::Distributed::CannotDistribute do
19
+ r.mapped_mget("foo", "bar")
20
+ end
21
+ end
22
+
23
+ def test_mset
24
+ assert_raise Redis2::Distributed::CannotDistribute do
25
+ r.mset(:foo, "s1", :bar, "s2")
26
+ end
27
+ end
28
+
29
+ def test_mset_mapped
30
+ assert_raise Redis2::Distributed::CannotDistribute do
31
+ r.mapped_mset(:foo => "s1", :bar => "s2")
32
+ end
33
+ end
34
+
35
+ def test_msetnx
36
+ assert_raise Redis2::Distributed::CannotDistribute do
37
+ r.set("foo", "s1")
38
+ r.msetnx(:foo, "s2", :bar, "s3")
39
+ end
40
+ end
41
+
42
+ def test_msetnx_mapped
43
+ assert_raise Redis2::Distributed::CannotDistribute do
44
+ r.set("foo", "s1")
45
+ r.mapped_msetnx(:foo => "s2", :bar => "s3")
46
+ end
47
+ end
48
+
49
+ def test_bitop
50
+ target_version "2.5.10" do
51
+ assert_raise Redis2::Distributed::CannotDistribute do
52
+ r.set("foo", "a")
53
+ r.set("bar", "b")
54
+
55
+ r.bitop(:and, "foo&bar", "foo", "bar")
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+ require "lint/value_types"
5
+
6
+ class TestDistributedCommandsOnValueTypes < Test::Unit::TestCase
7
+
8
+ include Helper::Distributed
9
+ include Lint::ValueTypes
10
+
11
+ def test_del
12
+ r.set "foo", "s1"
13
+ r.set "bar", "s2"
14
+ r.set "baz", "s3"
15
+
16
+ assert_equal ["bar", "baz", "foo"], r.keys("*").sort
17
+
18
+ assert_equal 1, r.del("foo")
19
+
20
+ assert_equal ["bar", "baz"], r.keys("*").sort
21
+
22
+ assert_equal 2, r.del("bar", "baz")
23
+
24
+ assert_equal [], r.keys("*").sort
25
+ end
26
+
27
+ def test_del_with_array_argument
28
+ r.set "foo", "s1"
29
+ r.set "bar", "s2"
30
+ r.set "baz", "s3"
31
+
32
+ assert_equal ["bar", "baz", "foo"], r.keys("*").sort
33
+
34
+ assert_equal 1, r.del(["foo"])
35
+
36
+ assert_equal ["bar", "baz"], r.keys("*").sort
37
+
38
+ assert_equal 2, r.del(["bar", "baz"])
39
+
40
+ assert_equal [], r.keys("*").sort
41
+ end
42
+
43
+ def test_randomkey
44
+ assert_raise Redis2::Distributed::CannotDistribute do
45
+ r.randomkey
46
+ end
47
+ end
48
+
49
+ def test_rename
50
+ assert_raise Redis2::Distributed::CannotDistribute do
51
+ r.set("foo", "s1")
52
+ r.rename "foo", "bar"
53
+ end
54
+
55
+ assert_equal "s1", r.get("foo")
56
+ assert_equal nil, r.get("bar")
57
+ end
58
+
59
+ def test_renamenx
60
+ assert_raise Redis2::Distributed::CannotDistribute do
61
+ r.set("foo", "s1")
62
+ r.rename "foo", "bar"
63
+ end
64
+
65
+ assert_equal "s1", r.get("foo")
66
+ assert_equal nil , r.get("bar")
67
+ end
68
+
69
+ def test_dbsize
70
+ assert_equal [0], r.dbsize
71
+
72
+ r.set("foo", "s1")
73
+
74
+ assert_equal [1], r.dbsize
75
+ end
76
+
77
+ def test_flushdb
78
+ r.set("foo", "s1")
79
+ r.set("bar", "s2")
80
+
81
+ assert_equal [2], r.dbsize
82
+
83
+ r.flushdb
84
+
85
+ assert_equal [0], r.dbsize
86
+ end
87
+
88
+ def test_migrate
89
+ r.set("foo", "s1")
90
+
91
+ assert_raise Redis2::Distributed::CannotDistribute do
92
+ r.migrate("foo", {})
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,164 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path("helper", File.dirname(__FILE__))
4
+
5
+ class TestDistributedCommandsRequiringClustering < Test::Unit::TestCase
6
+
7
+ include Helper::Distributed
8
+
9
+ def test_rename
10
+ r.set("{qux}foo", "s1")
11
+ r.rename "{qux}foo", "{qux}bar"
12
+
13
+ assert_equal "s1", r.get("{qux}bar")
14
+ assert_equal nil, r.get("{qux}foo")
15
+ end
16
+
17
+ def test_renamenx
18
+ r.set("{qux}foo", "s1")
19
+ r.set("{qux}bar", "s2")
20
+
21
+ assert_equal false, r.renamenx("{qux}foo", "{qux}bar")
22
+
23
+ assert_equal "s1", r.get("{qux}foo")
24
+ assert_equal "s2", r.get("{qux}bar")
25
+ end
26
+
27
+ def test_brpoplpush
28
+ r.rpush "{qux}foo", "s1"
29
+ r.rpush "{qux}foo", "s2"
30
+
31
+ assert_equal "s2", r.brpoplpush("{qux}foo", "{qux}bar", :timeout => 1)
32
+ assert_equal ["s2"], r.lrange("{qux}bar", 0, -1)
33
+ end
34
+
35
+ def test_rpoplpush
36
+ r.rpush "{qux}foo", "s1"
37
+ r.rpush "{qux}foo", "s2"
38
+
39
+ assert_equal "s2", r.rpoplpush("{qux}foo", "{qux}bar")
40
+ assert_equal ["s2"], r.lrange("{qux}bar", 0, -1)
41
+ assert_equal "s1", r.rpoplpush("{qux}foo", "{qux}bar")
42
+ assert_equal ["s1", "s2"], r.lrange("{qux}bar", 0, -1)
43
+ end
44
+
45
+ def test_smove
46
+ r.sadd "{qux}foo", "s1"
47
+ r.sadd "{qux}bar", "s2"
48
+
49
+ assert r.smove("{qux}foo", "{qux}bar", "s1")
50
+ assert r.sismember("{qux}bar", "s1")
51
+ end
52
+
53
+ def test_sinter
54
+ r.sadd "{qux}foo", "s1"
55
+ r.sadd "{qux}foo", "s2"
56
+ r.sadd "{qux}bar", "s2"
57
+
58
+ assert_equal ["s2"], r.sinter("{qux}foo", "{qux}bar")
59
+ end
60
+
61
+ def test_sinterstore
62
+ r.sadd "{qux}foo", "s1"
63
+ r.sadd "{qux}foo", "s2"
64
+ r.sadd "{qux}bar", "s2"
65
+
66
+ r.sinterstore("{qux}baz", "{qux}foo", "{qux}bar")
67
+
68
+ assert_equal ["s2"], r.smembers("{qux}baz")
69
+ end
70
+
71
+ def test_sunion
72
+ r.sadd "{qux}foo", "s1"
73
+ r.sadd "{qux}foo", "s2"
74
+ r.sadd "{qux}bar", "s2"
75
+ r.sadd "{qux}bar", "s3"
76
+
77
+ assert_equal ["s1", "s2", "s3"], r.sunion("{qux}foo", "{qux}bar").sort
78
+ end
79
+
80
+ def test_sunionstore
81
+ r.sadd "{qux}foo", "s1"
82
+ r.sadd "{qux}foo", "s2"
83
+ r.sadd "{qux}bar", "s2"
84
+ r.sadd "{qux}bar", "s3"
85
+
86
+ r.sunionstore("{qux}baz", "{qux}foo", "{qux}bar")
87
+
88
+ assert_equal ["s1", "s2", "s3"], r.smembers("{qux}baz").sort
89
+ end
90
+
91
+ def test_sdiff
92
+ r.sadd "{qux}foo", "s1"
93
+ r.sadd "{qux}foo", "s2"
94
+ r.sadd "{qux}bar", "s2"
95
+ r.sadd "{qux}bar", "s3"
96
+
97
+ assert_equal ["s1"], r.sdiff("{qux}foo", "{qux}bar")
98
+ assert_equal ["s3"], r.sdiff("{qux}bar", "{qux}foo")
99
+ end
100
+
101
+ def test_sdiffstore
102
+ r.sadd "{qux}foo", "s1"
103
+ r.sadd "{qux}foo", "s2"
104
+ r.sadd "{qux}bar", "s2"
105
+ r.sadd "{qux}bar", "s3"
106
+
107
+ r.sdiffstore("{qux}baz", "{qux}foo", "{qux}bar")
108
+
109
+ assert_equal ["s1"], r.smembers("{qux}baz")
110
+ end
111
+
112
+ def test_sort
113
+ r.set("{qux}foo:1", "s1")
114
+ r.set("{qux}foo:2", "s2")
115
+
116
+ r.rpush("{qux}bar", "1")
117
+ r.rpush("{qux}bar", "2")
118
+
119
+ assert_equal ["s1"], r.sort("{qux}bar", :get => "{qux}foo:*", :limit => [0, 1])
120
+ assert_equal ["s2"], r.sort("{qux}bar", :get => "{qux}foo:*", :limit => [0, 1], :order => "desc alpha")
121
+ end
122
+
123
+ def test_sort_with_an_array_of_gets
124
+ r.set("{qux}foo:1:a", "s1a")
125
+ r.set("{qux}foo:1:b", "s1b")
126
+
127
+ r.set("{qux}foo:2:a", "s2a")
128
+ r.set("{qux}foo:2:b", "s2b")
129
+
130
+ r.rpush("{qux}bar", "1")
131
+ r.rpush("{qux}bar", "2")
132
+
133
+ assert_equal [["s1a", "s1b"]], r.sort("{qux}bar", :get => ["{qux}foo:*:a", "{qux}foo:*:b"], :limit => [0, 1])
134
+ assert_equal [["s2a", "s2b"]], r.sort("{qux}bar", :get => ["{qux}foo:*:a", "{qux}foo:*:b"], :limit => [0, 1], :order => "desc alpha")
135
+ assert_equal [["s1a", "s1b"], ["s2a", "s2b"]], r.sort("{qux}bar", :get => ["{qux}foo:*:a", "{qux}foo:*:b"])
136
+ end
137
+
138
+ def test_sort_with_store
139
+ r.set("{qux}foo:1", "s1")
140
+ r.set("{qux}foo:2", "s2")
141
+
142
+ r.rpush("{qux}bar", "1")
143
+ r.rpush("{qux}bar", "2")
144
+
145
+ r.sort("{qux}bar", :get => "{qux}foo:*", :store => "{qux}baz")
146
+ assert_equal ["s1", "s2"], r.lrange("{qux}baz", 0, -1)
147
+ end
148
+
149
+ def test_bitop
150
+ target_version "2.5.10" do
151
+ r.set("{qux}foo", "a")
152
+ r.set("{qux}bar", "b")
153
+
154
+ r.bitop(:and, "{qux}foo&bar", "{qux}foo", "{qux}bar")
155
+ assert_equal "\x60", r.get("{qux}foo&bar")
156
+ r.bitop(:or, "{qux}foo|bar", "{qux}foo", "{qux}bar")
157
+ assert_equal "\x63", r.get("{qux}foo|bar")
158
+ r.bitop(:xor, "{qux}foo^bar", "{qux}foo", "{qux}bar")
159
+ assert_equal "\x03", r.get("{qux}foo^bar")
160
+ r.bitop(:not, "{qux}~foo", "{qux}foo")
161
+ assert_equal "\x9E", r.get("{qux}~foo")
162
+ end
163
+ end
164
+ end