redis 3.0.0.rc1 → 3.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.travis.yml +50 -0
  2. data/.travis/Gemfile +11 -0
  3. data/CHANGELOG.md +47 -19
  4. data/README.md +160 -149
  5. data/Rakefile +15 -50
  6. data/examples/pubsub.rb +1 -1
  7. data/examples/unicorn/config.ru +1 -1
  8. data/examples/unicorn/unicorn.rb +1 -1
  9. data/lib/redis.rb +790 -390
  10. data/lib/redis/client.rb +137 -49
  11. data/lib/redis/connection/hiredis.rb +26 -15
  12. data/lib/redis/connection/ruby.rb +170 -53
  13. data/lib/redis/connection/synchrony.rb +23 -35
  14. data/lib/redis/distributed.rb +92 -32
  15. data/lib/redis/errors.rb +4 -2
  16. data/lib/redis/pipeline.rb +17 -6
  17. data/lib/redis/version.rb +1 -1
  18. data/redis.gemspec +4 -6
  19. data/test/blocking_commands_test.rb +42 -0
  20. data/test/command_map_test.rb +18 -17
  21. data/test/commands_on_hashes_test.rb +13 -12
  22. data/test/commands_on_lists_test.rb +35 -45
  23. data/test/commands_on_sets_test.rb +55 -54
  24. data/test/commands_on_sorted_sets_test.rb +106 -105
  25. data/test/commands_on_strings_test.rb +64 -55
  26. data/test/commands_on_value_types_test.rb +66 -54
  27. data/test/connection_handling_test.rb +136 -151
  28. data/test/distributed_blocking_commands_test.rb +33 -40
  29. data/test/distributed_commands_on_hashes_test.rb +6 -7
  30. data/test/distributed_commands_on_lists_test.rb +13 -14
  31. data/test/distributed_commands_on_sets_test.rb +57 -58
  32. data/test/distributed_commands_on_sorted_sets_test.rb +11 -12
  33. data/test/distributed_commands_on_strings_test.rb +31 -32
  34. data/test/distributed_commands_on_value_types_test.rb +61 -46
  35. data/test/distributed_commands_requiring_clustering_test.rb +108 -108
  36. data/test/distributed_connection_handling_test.rb +14 -15
  37. data/test/distributed_internals_test.rb +7 -19
  38. data/test/distributed_key_tags_test.rb +36 -36
  39. data/test/distributed_persistence_control_commands_test.rb +17 -14
  40. data/test/distributed_publish_subscribe_test.rb +61 -69
  41. data/test/distributed_remote_server_control_commands_test.rb +39 -28
  42. data/test/distributed_sorting_test.rb +12 -13
  43. data/test/distributed_test.rb +40 -41
  44. data/test/distributed_transactions_test.rb +20 -21
  45. data/test/encoding_test.rb +12 -9
  46. data/test/error_replies_test.rb +42 -36
  47. data/test/helper.rb +118 -85
  48. data/test/helper_test.rb +20 -6
  49. data/test/internals_test.rb +167 -103
  50. data/test/lint/blocking_commands.rb +124 -0
  51. data/test/lint/hashes.rb +115 -93
  52. data/test/lint/lists.rb +86 -80
  53. data/test/lint/sets.rb +68 -62
  54. data/test/lint/sorted_sets.rb +200 -195
  55. data/test/lint/strings.rb +112 -94
  56. data/test/lint/value_types.rb +76 -55
  57. data/test/persistence_control_commands_test.rb +17 -12
  58. data/test/pipelining_commands_test.rb +135 -126
  59. data/test/publish_subscribe_test.rb +105 -110
  60. data/test/remote_server_control_commands_test.rb +74 -58
  61. data/test/sorting_test.rb +31 -29
  62. data/test/support/connection/hiredis.rb +1 -0
  63. data/test/support/connection/ruby.rb +1 -0
  64. data/test/support/connection/synchrony.rb +17 -0
  65. data/test/{redis_mock.rb → support/redis_mock.rb} +24 -21
  66. data/test/support/wire/synchrony.rb +24 -0
  67. data/test/support/wire/thread.rb +5 -0
  68. data/test/synchrony_driver.rb +9 -9
  69. data/test/test.conf +1 -1
  70. data/test/thread_safety_test.rb +21 -19
  71. data/test/transactions_test.rb +189 -118
  72. data/test/unknown_commands_test.rb +9 -8
  73. data/test/url_param_test.rb +46 -41
  74. metadata +28 -43
  75. data/TODO.md +0 -4
  76. data/benchmarking/thread_safety.rb +0 -38
  77. data/test/lint/internals.rb +0 -36
@@ -1,158 +1,153 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
3
+ require "helper"
4
4
 
5
- setup do
6
- init Redis.new(OPTIONS)
7
- end
5
+ class TestPublishSubscribe < Test::Unit::TestCase
8
6
 
9
- test "SUBSCRIBE and UNSUBSCRIBE" do |r|
10
- listening = false
7
+ include Helper::Client
11
8
 
12
- wire = Wire.new do
13
- r.subscribe("foo") do |on|
14
- on.subscribe do |channel, total|
15
- @subscribed = true
16
- @t1 = total
17
- end
9
+ def test_subscribe_and_unsubscribe
10
+ @subscribed = false
11
+ @unsubscribed = false
18
12
 
19
- on.message do |channel, message|
20
- if message == "s1"
21
- r.unsubscribe
22
- @message = message
13
+ wire = Wire.new do
14
+ r.subscribe("foo") do |on|
15
+ on.subscribe do |channel, total|
16
+ @subscribed = true
17
+ @t1 = total
23
18
  end
24
- end
25
19
 
26
- on.unsubscribe do |channel, total|
27
- @unsubscribed = true
28
- @t2 = total
29
- end
20
+ on.message do |channel, message|
21
+ if message == "s1"
22
+ r.unsubscribe
23
+ @message = message
24
+ end
25
+ end
30
26
 
31
- listening = true
27
+ on.unsubscribe do |channel, total|
28
+ @unsubscribed = true
29
+ @t2 = total
30
+ end
31
+ end
32
32
  end
33
- end
34
33
 
35
- Wire.pass while !listening
34
+ # Wait until the subscription is active before publishing
35
+ Wire.pass while !@subscribed
36
36
 
37
- Redis.new(OPTIONS).publish("foo", "s1")
37
+ Redis.new(OPTIONS).publish("foo", "s1")
38
38
 
39
- wire.join
39
+ wire.join
40
40
 
41
- assert @subscribed
42
- assert 1 == @t1
43
- assert @unsubscribed
44
- assert 0 == @t2
45
- assert "s1" == @message
46
- end
41
+ assert @subscribed
42
+ assert_equal 1, @t1
43
+ assert @unsubscribed
44
+ assert_equal 0, @t2
45
+ assert_equal "s1", @message
46
+ end
47
47
 
48
- test "PSUBSCRIBE and PUNSUBSCRIBE" do |r|
49
- listening = false
48
+ def test_psubscribe_and_punsubscribe
49
+ @subscribed = false
50
+ @unsubscribed = false
50
51
 
51
- wire = Wire.new do
52
- r.psubscribe("f*") do |on|
53
- on.psubscribe do |pattern, total|
54
- @subscribed = true
55
- @t1 = total
56
- end
52
+ wire = Wire.new do
53
+ r.psubscribe("f*") do |on|
54
+ on.psubscribe do |pattern, total|
55
+ @subscribed = true
56
+ @t1 = total
57
+ end
57
58
 
58
- on.pmessage do |pattern, channel, message|
59
- if message == "s1"
60
- r.punsubscribe
61
- @message = message
59
+ on.pmessage do |pattern, channel, message|
60
+ if message == "s1"
61
+ r.punsubscribe
62
+ @message = message
63
+ end
62
64
  end
63
- end
64
65
 
65
- on.punsubscribe do |pattern, total|
66
- @unsubscribed = true
67
- @t2 = total
68
- end
66
+ on.punsubscribe do |pattern, total|
67
+ @unsubscribed = true
68
+ @t2 = total
69
+ end
69
70
 
70
- listening = true
71
+ listening = true
72
+ end
71
73
  end
72
- end
73
74
 
74
- Wire.pass while !listening
75
+ # Wait until the subscription is active before publishing
76
+ Wire.pass while !@subscribed
75
77
 
76
- Redis.new(OPTIONS).publish("foo", "s1")
78
+ Redis.new(OPTIONS).publish("foo", "s1")
77
79
 
78
- wire.join
79
-
80
- assert @subscribed
81
- assert 1 == @t1
82
- assert @unsubscribed
83
- assert 0 == @t2
84
- assert "s1" == @message
85
- end
80
+ wire.join
86
81
 
87
- test "SUBSCRIBE within SUBSCRIBE" do |r|
88
- listening = false
82
+ assert @subscribed
83
+ assert_equal 1, @t1
84
+ assert @unsubscribed
85
+ assert_equal 0, @t2
86
+ assert_equal "s1", @message
87
+ end
89
88
 
90
- @channels = []
89
+ def test_subscribe_within_subscribe
90
+ @channels = []
91
91
 
92
- wire = Wire.new do
93
- r.subscribe("foo") do |on|
94
- on.subscribe do |channel, total|
95
- @channels << channel
92
+ wire = Wire.new do
93
+ r.subscribe("foo") do |on|
94
+ on.subscribe do |channel, total|
95
+ @channels << channel
96
96
 
97
- r.subscribe("bar") if channel == "foo"
98
- r.unsubscribe if channel == "bar"
97
+ r.subscribe("bar") if channel == "foo"
98
+ r.unsubscribe if channel == "bar"
99
+ end
99
100
  end
100
-
101
- listening = true
102
101
  end
103
- end
104
-
105
- Wire.pass while !listening
106
102
 
107
- Redis.new(OPTIONS).publish("foo", "s1")
103
+ wire.join
108
104
 
109
- wire.join
110
-
111
- assert ["foo", "bar"] == @channels
112
- end
105
+ assert_equal ["foo", "bar"], @channels
106
+ end
113
107
 
114
- test "other commands within a SUBSCRIBE" do |r|
115
- assert_raise Redis::CommandError do
116
- r.subscribe("foo") do |on|
117
- on.subscribe do |channel, total|
118
- r.set("bar", "s2")
108
+ def test_other_commands_within_a_subscribe
109
+ assert_raise Redis::CommandError do
110
+ r.subscribe("foo") do |on|
111
+ on.subscribe do |channel, total|
112
+ r.set("bar", "s2")
113
+ end
119
114
  end
120
115
  end
121
116
  end
122
- end
123
117
 
124
- test "SUBSCRIBE without a block" do |r|
125
- assert_raise LocalJumpError do
126
- r.subscribe("foo")
118
+ def test_subscribe_without_a_block
119
+ assert_raise LocalJumpError do
120
+ r.subscribe("foo")
121
+ end
127
122
  end
128
- end
129
123
 
130
- test "UNSUBSCRIBE without a SUBSCRIBE" do |r|
131
- assert_raise RuntimeError do
132
- r.unsubscribe
133
- end
124
+ def test_unsubscribe_without_a_subscribe
125
+ assert_raise RuntimeError do
126
+ r.unsubscribe
127
+ end
134
128
 
135
- assert_raise RuntimeError do
136
- r.punsubscribe
129
+ assert_raise RuntimeError do
130
+ r.punsubscribe
131
+ end
137
132
  end
138
- end
139
133
 
140
- test "SUBSCRIBE past a timeout" do |r|
141
- # For some reason, a thread here doesn't reproduce the issue.
142
- sleep = %{sleep #{OPTIONS[:timeout] + 1}}
143
- publish = %{echo "publish foo bar\r\n" | nc localhost #{OPTIONS[:port]}}
144
- cmd = [sleep, publish].join("; ")
134
+ def test_subscribe_past_a_timeout
135
+ # For some reason, a thread here doesn't reproduce the issue.
136
+ sleep = %{sleep #{OPTIONS[:timeout] * 2}}
137
+ publish = %{echo "publish foo bar\r\n" | nc localhost #{OPTIONS[:port]}}
138
+ cmd = [sleep, publish].join("; ")
145
139
 
146
- IO.popen(cmd, "r+") do |pipe|
147
- received = false
140
+ IO.popen(cmd, "r+") do |pipe|
141
+ received = false
148
142
 
149
- r.subscribe "foo" do |on|
150
- on.message do |channel, message|
151
- received = true
152
- r.unsubscribe
143
+ r.subscribe "foo" do |on|
144
+ on.message do |channel, message|
145
+ received = true
146
+ r.unsubscribe
147
+ end
153
148
  end
154
- end
155
149
 
156
- assert received
150
+ assert received
151
+ end
157
152
  end
158
153
  end
@@ -1,88 +1,104 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
- require File.expand_path("./redis_mock", File.dirname(__FILE__))
3
+ require "helper"
5
4
 
6
- include RedisMock::Helper
5
+ class TestRemoteServerControlCommands < Test::Unit::TestCase
7
6
 
8
- setup do
9
- init Redis.new(OPTIONS)
10
- end
7
+ include Helper::Client
11
8
 
12
- test "INFO" do |r|
13
- %w(last_save_time redis_version total_connections_received connected_clients total_commands_processed connected_slaves uptime_in_seconds used_memory uptime_in_days changes_since_last_save).each do |x|
14
- assert r.info.keys.include?(x)
9
+ def test_info
10
+ %w(last_save_time redis_version total_connections_received connected_clients total_commands_processed connected_slaves uptime_in_seconds used_memory uptime_in_days changes_since_last_save).each do |x|
11
+ assert r.info.keys.include?(x)
12
+ end
15
13
  end
16
- end
17
14
 
18
- test "INFO COMMANDSTATS" do |r|
19
- # Only available on Redis >= 2.9.0
20
- next if version(r) < 209000
15
+ def test_info_commandstats
16
+ return if version < "2.9.0"
21
17
 
22
- r.config(:resetstat)
23
- r.ping
18
+ r.config(:resetstat)
19
+ r.ping
24
20
 
25
- result = r.info(:commandstats)
26
- assert "1" == result["ping"]["calls"]
27
- end
21
+ result = r.info(:commandstats)
22
+ assert_equal "1", result["ping"]["calls"]
23
+ end
24
+
25
+ def test_monitor_redis_lt_2_5_0
26
+ return unless version < "2.5.0"
28
27
 
29
- test "MONITOR" do |r|
30
- log = []
28
+ log = []
31
29
 
32
- wire = Wire.new do
33
- Redis.new(OPTIONS).monitor do |line|
34
- log << line
35
- break if log.size == 3
30
+ wire = Wire.new do
31
+ Redis.new(OPTIONS).monitor do |line|
32
+ log << line
33
+ break if log.size == 3
34
+ end
36
35
  end
36
+
37
+ Wire.pass while log.empty? # Faster than sleep
38
+
39
+ r.set "foo", "s1"
40
+
41
+ wire.join
42
+
43
+ assert log[-1][%q{(db 15) "set" "foo" "s1"}]
37
44
  end
38
45
 
39
- Wire.pass while log.empty? # Faster than sleep
46
+ def test_monitor_redis_gte_2_5_0
47
+ return unless version >= "2.5.0"
40
48
 
41
- r.set "foo", "s1"
49
+ log = []
42
50
 
43
- wire.join
51
+ wire = Wire.new do
52
+ Redis.new(OPTIONS).monitor do |line|
53
+ log << line
54
+ break if line =~ /set/
55
+ end
56
+ end
44
57
 
45
- assert log[-1][%q{(db 15) "set" "foo" "s1"}]
46
- end
58
+ Wire.pass while log.empty? # Faster than sleep
47
59
 
48
- test "MONITOR returns value for break" do |r|
49
- result = r.monitor do |line|
50
- break line
51
- end
60
+ r.set "foo", "s1"
52
61
 
53
- assert result == "OK"
54
- end
62
+ wire.join
55
63
 
56
- test "ECHO" do |r|
57
- assert "foo bar baz\n" == r.echo("foo bar baz\n")
58
- end
64
+ assert log[-1] =~ /\b15\b.* "set" "foo" "s1"/
65
+ end
59
66
 
60
- test "DEBUG" do |r|
61
- r.set "foo", "s1"
67
+ def test_monitor_returns_value_for_break
68
+ result = r.monitor do |line|
69
+ break line
70
+ end
62
71
 
63
- assert r.debug(:object, "foo").kind_of?(String)
64
- end
72
+ assert_equal result, "OK"
73
+ end
65
74
 
66
- test "OBJECT" do |r|
67
- r.lpush "list", "value"
75
+ def test_echo
76
+ assert_equal "foo bar baz\n", r.echo("foo bar baz\n")
77
+ end
68
78
 
69
- assert r.object(:refcount, "list") == 1
70
- assert r.object(:encoding, "list") == "ziplist"
71
- assert r.object(:idletime, "list").kind_of?(Fixnum)
72
- end
79
+ def test_debug
80
+ r.set "foo", "s1"
73
81
 
74
- test "SYNC" do |r|
75
- replies = {:sync => lambda { "+OK" }}
82
+ assert r.debug(:object, "foo").kind_of?(String)
83
+ end
76
84
 
77
- redis_mock(replies) do
78
- redis = Redis.new(OPTIONS.merge(:port => 6380))
85
+ def test_object
86
+ r.lpush "list", "value"
79
87
 
80
- assert "OK" == redis.sync
88
+ assert_equal r.object(:refcount, "list"), 1
89
+ assert_equal r.object(:encoding, "list"), "ziplist"
90
+ assert r.object(:idletime, "list").kind_of?(Fixnum)
91
+ end
92
+
93
+ def test_sync
94
+ redis_mock(:sync => lambda { "+OK" }) do |redis|
95
+ assert_equal "OK", redis.sync
96
+ end
81
97
  end
82
- end
83
98
 
84
- test "SLOWLOG" do |r|
85
- r.slowlog(:reset)
86
- result = r.slowlog(:len)
87
- assert result == 0
99
+ def test_slowlog
100
+ r.slowlog(:reset)
101
+ result = r.slowlog(:len)
102
+ assert_equal result, 0
103
+ end
88
104
  end
@@ -1,43 +1,45 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
3
+ require "helper"
4
4
 
5
- setup do
6
- init Redis.new(OPTIONS)
7
- end
5
+ class TestSorting < Test::Unit::TestCase
8
6
 
9
- test "SORT" do |r|
10
- r.set("foo:1", "s1")
11
- r.set("foo:2", "s2")
7
+ include Helper::Client
12
8
 
13
- r.rpush("bar", "1")
14
- r.rpush("bar", "2")
9
+ def test_sort
10
+ r.set("foo:1", "s1")
11
+ r.set("foo:2", "s2")
15
12
 
16
- assert ["s1"] == r.sort("bar", :get => "foo:*", :limit => [0, 1])
17
- assert ["s2"] == r.sort("bar", :get => "foo:*", :limit => [0, 1], :order => "desc alpha")
18
- end
13
+ r.rpush("bar", "1")
14
+ r.rpush("bar", "2")
19
15
 
20
- test "SORT with an array of GETs" do |r|
21
- r.set("foo:1:a", "s1a")
22
- r.set("foo:1:b", "s1b")
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
23
19
 
24
- r.set("foo:2:a", "s2a")
25
- r.set("foo:2:b", "s2b")
20
+ def test_sort_with_an_array_of_gets
21
+ r.set("foo:1:a", "s1a")
22
+ r.set("foo:1:b", "s1b")
26
23
 
27
- r.rpush("bar", "1")
28
- r.rpush("bar", "2")
24
+ r.set("foo:2:a", "s2a")
25
+ r.set("foo:2:b", "s2b")
29
26
 
30
- assert ["s1a", "s1b"] == r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1])
31
- assert ["s2a", "s2b"] == r.sort("bar", :get => ["foo:*:a", "foo:*:b"], :limit => [0, 1], :order => "desc alpha")
32
- end
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
33
34
 
34
- test "SORT with STORE" do |r|
35
- r.set("foo:1", "s1")
36
- r.set("foo:2", "s2")
35
+ def test_sort_with_store
36
+ r.set("foo:1", "s1")
37
+ r.set("foo:2", "s2")
37
38
 
38
- r.rpush("bar", "1")
39
- r.rpush("bar", "2")
39
+ r.rpush("bar", "1")
40
+ r.rpush("bar", "2")
40
41
 
41
- r.sort("bar", :get => "foo:*", :store => "baz")
42
- assert ["s1", "s2"] == r.lrange("baz", 0, -1)
42
+ r.sort("bar", :get => "foo:*", :store => "baz")
43
+ assert_equal ["s1", "s2"], r.lrange("baz", 0, -1)
44
+ end
43
45
  end