couchbase 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +11 -0
- data/HISTORY.markdown +17 -0
- data/README.markdown +99 -59
- data/couchbase.gemspec +1 -0
- data/ext/couchbase_ext/couchbase_ext.c +1557 -425
- data/ext/couchbase_ext/extconf.rb +60 -49
- data/lib/couchbase.rb +41 -7
- data/lib/couchbase/bucket.rb +5 -3
- data/lib/couchbase/version.rb +1 -1
- data/tasks/compile.rake +72 -0
- data/tasks/test.rake +2 -2
- data/test/setup.rb +52 -2
- data/test/test_arithmetic.rb +37 -26
- data/test/test_async.rb +68 -44
- data/test/test_bucket.rb +130 -45
- data/test/test_cas.rb +8 -8
- data/test/test_couchbase.rb +1 -1
- data/test/test_delete.rb +15 -15
- data/test/test_errors.rb +6 -6
- data/test/test_flush.rb +3 -3
- data/test/test_format.rb +14 -14
- data/test/test_get.rb +144 -69
- data/test/test_stats.rb +18 -14
- data/test/test_store.rb +40 -40
- data/test/test_touch.rb +26 -14
- data/test/test_version.rb +30 -2
- metadata +34 -17
data/test/test_async.rb
CHANGED
@@ -39,7 +39,7 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_it_requires_block_for_running_loop
|
42
|
-
connection = Couchbase.new(:port => @mock.port)
|
42
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
43
43
|
refute connection.async?
|
44
44
|
assert_raises(LocalJumpError) do
|
45
45
|
connection.run
|
@@ -50,40 +50,40 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def test_it_resets_async_flag_when_raising_exception_from_callback
|
53
|
-
connection = Couchbase.new(:port => @mock.port)
|
53
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
54
54
|
|
55
55
|
assert_raises(RuntimeError) do
|
56
56
|
connection.run do |conn|
|
57
|
-
conn.set(
|
57
|
+
conn.set(uniq_id, "foo") { raise }
|
58
58
|
end
|
59
59
|
end
|
60
60
|
refute connection.async?
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_nested_async_get_set
|
64
|
-
connection = Couchbase.new(:port => @mock.port)
|
65
|
-
connection.set(
|
66
|
-
connection.set(
|
64
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
65
|
+
connection.set(uniq_id, {"bar" => 1})
|
66
|
+
connection.set(uniq_id(:hit), 0)
|
67
67
|
|
68
68
|
connection.run do |conn|
|
69
|
-
conn.get(
|
70
|
-
conn.get(
|
71
|
-
conn.set(
|
69
|
+
conn.get(uniq_id) do
|
70
|
+
conn.get(uniq_id(:hit)) do |res|
|
71
|
+
conn.set(uniq_id(:hit), res.value + 1)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
val = connection.get(
|
76
|
+
val = connection.get(uniq_id(:hit))
|
77
77
|
assert_equal 1, val
|
78
78
|
end
|
79
79
|
|
80
80
|
def test_nested_async_set_get
|
81
|
-
connection = Couchbase.new(:port => @mock.port)
|
81
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
82
82
|
val = nil
|
83
83
|
|
84
84
|
connection.run do |conn|
|
85
|
-
conn.set(
|
86
|
-
conn.get(
|
85
|
+
conn.set(uniq_id, "foo") do
|
86
|
+
conn.get(uniq_id) do |res|
|
87
87
|
val = res.value
|
88
88
|
end
|
89
89
|
end
|
@@ -93,15 +93,15 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def test_nested_async_touch_get
|
96
|
-
connection = Couchbase.new(:port => @mock.port)
|
97
|
-
connection.set(
|
96
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
97
|
+
connection.set(uniq_id, "foo")
|
98
98
|
success = false
|
99
99
|
val = nil
|
100
100
|
|
101
101
|
connection.run do |conn|
|
102
|
-
conn.touch(
|
102
|
+
conn.touch(uniq_id, :ttl => 1) do |res1|
|
103
103
|
success = res1.success?
|
104
|
-
conn.get(
|
104
|
+
conn.get(uniq_id) do |res2|
|
105
105
|
val = res2.value
|
106
106
|
end
|
107
107
|
end
|
@@ -109,20 +109,20 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
109
109
|
|
110
110
|
assert success
|
111
111
|
assert_equal "foo", val
|
112
|
-
sleep(
|
113
|
-
refute connection.get(
|
112
|
+
sleep(2)
|
113
|
+
refute connection.get(uniq_id)
|
114
114
|
end
|
115
115
|
|
116
116
|
def test_nested_async_delete_get
|
117
|
-
connection = Couchbase.new(:port => @mock.port)
|
118
|
-
cas = connection.set(
|
117
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
118
|
+
cas = connection.set(uniq_id, "foo")
|
119
119
|
success = false
|
120
120
|
val = :unknown
|
121
121
|
|
122
122
|
connection.run do |conn|
|
123
|
-
conn.delete(
|
123
|
+
conn.delete(uniq_id, :cas => cas) do |res1|
|
124
124
|
success = res1.success?
|
125
|
-
conn.get(
|
125
|
+
conn.get(uniq_id) do |res2|
|
126
126
|
val = res2.value
|
127
127
|
end
|
128
128
|
end
|
@@ -133,12 +133,12 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def test_nested_async_stats_set
|
136
|
-
connection = Couchbase.new(:port => @mock.port)
|
136
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
137
137
|
stats = {}
|
138
138
|
|
139
139
|
connection.run do |conn|
|
140
140
|
conn.stats do |res1|
|
141
|
-
id =
|
141
|
+
id = uniq_id(res1.node, res1.key)
|
142
142
|
stats[id] = false
|
143
143
|
conn.set(id, res1.value) do |res2|
|
144
144
|
stats[id] = res2.cas
|
@@ -152,14 +152,14 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def test_nested_async_flush_set
|
155
|
-
connection = Couchbase.new(:port => @mock.port)
|
156
|
-
cas = connection.set(
|
155
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
156
|
+
cas = connection.set(uniq_id, "foo")
|
157
157
|
res = {}
|
158
158
|
|
159
159
|
connection.run do |conn|
|
160
160
|
conn.flush do |res1|
|
161
161
|
assert res1.success?
|
162
|
-
id =
|
162
|
+
id = uniq_id(res1.node)
|
163
163
|
res[id] = false
|
164
164
|
conn.set(id, true) do |res2|
|
165
165
|
res[id] = res2.cas
|
@@ -167,7 +167,7 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
170
|
-
refute connection.get(
|
170
|
+
refute connection.get(uniq_id)
|
171
171
|
res.keys.each do |key|
|
172
172
|
assert res[key].is_a?(Numeric)
|
173
173
|
assert connection.get(key)
|
@@ -175,13 +175,13 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def test_nested_async_incr_get
|
178
|
-
connection = Couchbase.new(:port => @mock.port)
|
179
|
-
cas = connection.set(
|
178
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
179
|
+
cas = connection.set(uniq_id, 1)
|
180
180
|
val = nil
|
181
181
|
|
182
182
|
connection.run do |conn|
|
183
|
-
conn.incr(
|
184
|
-
conn.get(
|
183
|
+
conn.incr(uniq_id) do
|
184
|
+
conn.get(uniq_id) do |res|
|
185
185
|
val = res.value
|
186
186
|
end
|
187
187
|
end
|
@@ -191,21 +191,45 @@ class TestAsync < MiniTest::Unit::TestCase
|
|
191
191
|
end
|
192
192
|
|
193
193
|
def test_it_doesnt_accept_callbacks_in_synchronous_mode
|
194
|
-
connection = Couchbase.new(:port => @mock.port)
|
194
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
195
195
|
refute connection.async?
|
196
196
|
|
197
|
-
assert_raises(ArgumentError) { connection.add(
|
198
|
-
assert_raises(ArgumentError) { connection.set(
|
199
|
-
assert_raises(ArgumentError) { connection.replace(
|
200
|
-
assert_raises(ArgumentError) { connection.get(
|
201
|
-
assert_raises(ArgumentError) { connection.touch(
|
202
|
-
assert_raises(ArgumentError) { connection.incr(
|
203
|
-
assert_raises(ArgumentError) { connection.decr(
|
204
|
-
assert_raises(ArgumentError) { connection.delete(
|
205
|
-
assert_raises(ArgumentError) { connection.append(
|
206
|
-
assert_raises(ArgumentError) { connection.prepend(
|
197
|
+
assert_raises(ArgumentError) { connection.add(uniq_id, "foo") {} }
|
198
|
+
assert_raises(ArgumentError) { connection.set(uniq_id, "foo") {} }
|
199
|
+
assert_raises(ArgumentError) { connection.replace(uniq_id, "foo") {} }
|
200
|
+
assert_raises(ArgumentError) { connection.get(uniq_id) {} }
|
201
|
+
assert_raises(ArgumentError) { connection.touch(uniq_id) {} }
|
202
|
+
assert_raises(ArgumentError) { connection.incr(uniq_id) {} }
|
203
|
+
assert_raises(ArgumentError) { connection.decr(uniq_id) {} }
|
204
|
+
assert_raises(ArgumentError) { connection.delete(uniq_id) {} }
|
205
|
+
assert_raises(ArgumentError) { connection.append(uniq_id, "bar") {} }
|
206
|
+
assert_raises(ArgumentError) { connection.prepend(uniq_id, "bar") {} }
|
207
207
|
assert_raises(ArgumentError) { connection.flush {} }
|
208
208
|
assert_raises(ArgumentError) { connection.stats {} }
|
209
209
|
end
|
210
210
|
|
211
|
+
def test_it_disallow_nested_run
|
212
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
213
|
+
assert_raises(Couchbase::Error::Invalid) do
|
214
|
+
connection.run do
|
215
|
+
connection.run do
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_it_extends_timeout_in_async_mode_if_needed
|
222
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
223
|
+
connection.set(uniq_id, "foo")
|
224
|
+
|
225
|
+
connection.timeout = 100 # 100 us
|
226
|
+
connection.run do
|
227
|
+
connection.get(uniq_id) do |ret|
|
228
|
+
assert ret.success?
|
229
|
+
assert_equal "foo", ret.value
|
230
|
+
end
|
231
|
+
sleep(1.5)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
211
235
|
end
|
data/test/test_bucket.rb
CHANGED
@@ -20,64 +20,63 @@ require File.join(File.dirname(__FILE__), 'setup')
|
|
20
20
|
class TestBucket < MiniTest::Unit::TestCase
|
21
21
|
|
22
22
|
def test_it_substitute_default_parts_to_url
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
23
|
+
# with_mock(:host => 'localhost', :port => 8091, :buckets_spec => 'default,foo') do |mock|
|
24
|
+
# connections = [
|
25
|
+
# Couchbase.new,
|
26
|
+
# Couchbase.new("http://#{mock.host}:8091"),
|
27
|
+
# Couchbase.new("http://#{mock.host}:8091/pools/default"),
|
28
|
+
# Couchbase.new(:hostname => mock.host),
|
29
|
+
# Couchbase.new(:hostname => mock.host, :port => 8091)
|
30
|
+
# ]
|
31
|
+
# connections.each do |connection|
|
32
|
+
# assert_equal mock.host, connection.hostname
|
33
|
+
# assert_equal 8091, connection.port
|
34
|
+
# assert_equal "#{mock.host}:8091", connection.authority
|
35
|
+
# assert_equal 'default', connection.bucket
|
36
|
+
# assert_equal "http://#{mock.host}:8091/pools/default/buckets/default/", connection.url
|
37
|
+
# end
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
39
|
+
# connections = [
|
40
|
+
# Couchbase.new("http://#{mock.host}:8091/pools/default/buckets/foo"),
|
41
|
+
# Couchbase.new(:bucket => 'foo'),
|
42
|
+
# Couchbase.new("http://#{mock.host}:8091/pools/default/buckets/default", :bucket => 'foo')
|
43
|
+
# ]
|
44
|
+
# connections.each do |connection|
|
45
|
+
# assert_equal 'foo', connection.bucket
|
46
|
+
# assert_equal "http://#{mock.host}:8091/pools/default/buckets/foo/", connection.url
|
47
|
+
# end
|
48
|
+
# end
|
50
49
|
|
51
|
-
with_mock do |mock| # pick first free port
|
50
|
+
with_mock(:host => 'localhost') do |mock| # pick first free port
|
52
51
|
connections = [
|
53
|
-
Couchbase.new("http
|
52
|
+
Couchbase.new("http://#{mock.host}:#{mock.port}"),
|
54
53
|
Couchbase.new(:port => mock.port),
|
55
|
-
Couchbase.new(
|
54
|
+
Couchbase.new("http://#{mock.host}:8091", :port => mock.port)
|
56
55
|
]
|
57
56
|
connections.each do |connection|
|
58
57
|
assert_equal mock.port, connection.port
|
59
|
-
assert_equal "
|
60
|
-
assert_equal "http
|
58
|
+
assert_equal "#{mock.host}:#{mock.port}", connection.authority
|
59
|
+
assert_equal "http://#{mock.host}:#{mock.port}/pools/default/buckets/default/", connection.url
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
64
63
|
with_mock(:host => '127.0.0.1') do |mock|
|
65
64
|
connections = [
|
66
|
-
Couchbase.new("http
|
67
|
-
Couchbase.new(:hostname =>
|
68
|
-
Couchbase.new('http://
|
65
|
+
Couchbase.new("http://#{mock.host}:#{mock.port}"),
|
66
|
+
Couchbase.new(:hostname => mock.host, :port => mock.port),
|
67
|
+
Couchbase.new('http://example.com:8091', :hostname => mock.host, :port => mock.port)
|
69
68
|
]
|
70
69
|
connections.each do |connection|
|
71
|
-
assert_equal
|
72
|
-
assert_equal "
|
73
|
-
assert_equal "http
|
70
|
+
assert_equal mock.host, connection.hostname
|
71
|
+
assert_equal "#{mock.host}:#{mock.port}", connection.authority
|
72
|
+
assert_equal "http://#{mock.host}:#{mock.port}/pools/default/buckets/default/", connection.url
|
74
73
|
end
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
77
|
def test_it_raises_network_error_if_server_not_found
|
79
78
|
refute(`netstat -tnl` =~ /12345/)
|
80
|
-
assert_raises Couchbase::Error::
|
79
|
+
assert_raises Couchbase::Error::Connect do
|
81
80
|
Couchbase.new(:port => 12345)
|
82
81
|
end
|
83
82
|
end
|
@@ -97,7 +96,8 @@ class TestBucket < MiniTest::Unit::TestCase
|
|
97
96
|
|
98
97
|
def test_it_able_to_connect_to_protected_buckets
|
99
98
|
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
100
|
-
connection = Couchbase.new(:
|
99
|
+
connection = Couchbase.new(:hostname => mock.host,
|
100
|
+
:port => mock.port,
|
101
101
|
:bucket => 'protected',
|
102
102
|
:username => 'protected',
|
103
103
|
:password => 'secret')
|
@@ -107,16 +107,39 @@ class TestBucket < MiniTest::Unit::TestCase
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
def test_it_allows_to_specify_credentials_in_url
|
111
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
112
|
+
connection = Couchbase.new("http://protected:secret@#{mock.host}:#{mock.port}/pools/default/buckets/protected/")
|
113
|
+
assert_equal "protected", connection.bucket
|
114
|
+
assert_equal "protected", connection.username
|
115
|
+
assert_equal "secret", connection.password
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
110
119
|
def test_it_raises_error_with_wrong_credentials
|
120
|
+
with_mock do |mock|
|
121
|
+
assert_raises Couchbase::Error::Auth do
|
122
|
+
Couchbase.new(:hostname => mock.host,
|
123
|
+
:port => mock.port,
|
124
|
+
:bucket => 'default',
|
125
|
+
:username => 'wrong.username',
|
126
|
+
:password => 'wrong_password')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_it_unable_to_connect_to_protected_buckets_with_wrond_credentials
|
111
132
|
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
112
|
-
assert_raises Couchbase::Error::
|
113
|
-
Couchbase.new(:
|
133
|
+
assert_raises Couchbase::Error::Auth do
|
134
|
+
Couchbase.new(:hostname => mock.host,
|
135
|
+
:port => mock.port,
|
114
136
|
:bucket => 'protected',
|
115
137
|
:username => 'wrong',
|
116
138
|
:password => 'secret')
|
117
139
|
end
|
118
|
-
assert_raises Couchbase::Error::
|
119
|
-
Couchbase.new(:
|
140
|
+
assert_raises Couchbase::Error::Auth do
|
141
|
+
Couchbase.new(:hostname => mock.host,
|
142
|
+
:port => mock.port,
|
120
143
|
:bucket => 'protected',
|
121
144
|
:username => 'protected',
|
122
145
|
:password => 'wrong')
|
@@ -126,10 +149,13 @@ class TestBucket < MiniTest::Unit::TestCase
|
|
126
149
|
|
127
150
|
def test_it_allows_change_quiet_flag
|
128
151
|
with_mock do |mock|
|
129
|
-
connection = Couchbase.new(:
|
152
|
+
connection = Couchbase.new(:hostname => mock.host,
|
153
|
+
:port => mock.port)
|
130
154
|
assert connection.quiet?
|
131
155
|
|
132
|
-
connection = Couchbase.new(:
|
156
|
+
connection = Couchbase.new(:hostname => mock.host,
|
157
|
+
:port => mock.port,
|
158
|
+
:quiet => true)
|
133
159
|
assert connection.quiet?
|
134
160
|
|
135
161
|
connection.quiet = nil
|
@@ -139,4 +165,63 @@ class TestBucket < MiniTest::Unit::TestCase
|
|
139
165
|
assert_equal true, connection.quiet?
|
140
166
|
end
|
141
167
|
end
|
168
|
+
|
169
|
+
def test_it_is_connected
|
170
|
+
with_mock do |mock|
|
171
|
+
connection = Couchbase.new(:hostname => mock.host,
|
172
|
+
:port => mock.port)
|
173
|
+
assert connection.connected?
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_it_is_possible_to_disconnect_instance
|
178
|
+
with_mock do |mock|
|
179
|
+
connection = Couchbase.new(:hostname => mock.host,
|
180
|
+
:port => mock.port)
|
181
|
+
connection.disconnect
|
182
|
+
refute connection.connected?
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_it_raises_error_on_double_disconnect
|
187
|
+
with_mock do |mock|
|
188
|
+
connection = Couchbase.new(:hostname => mock.host,
|
189
|
+
:port => mock.port)
|
190
|
+
connection.disconnect
|
191
|
+
assert_raises Couchbase::Error::Connect do
|
192
|
+
connection.disconnect
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_it_allows_to_reconnect_the_instance
|
198
|
+
with_mock do |mock|
|
199
|
+
connection = Couchbase.new(:hostname => mock.host,
|
200
|
+
:port => mock.port)
|
201
|
+
connection.disconnect
|
202
|
+
refute connection.connected?
|
203
|
+
connection.reconnect
|
204
|
+
assert connection.connected?
|
205
|
+
assert connection.set(uniq_id, "foo")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_it_allows_to_change_configuration_during_reconnect
|
210
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
211
|
+
connection = Couchbase.new(:hostname => mock.host,
|
212
|
+
:port => mock.port,
|
213
|
+
:bucket => 'protected',
|
214
|
+
:username => 'protected',
|
215
|
+
:password => 'secret')
|
216
|
+
connection.disconnect
|
217
|
+
assert_raises Couchbase::Error::Auth do
|
218
|
+
connection.reconnect(:password => 'incorrect')
|
219
|
+
end
|
220
|
+
refute connection.connected?
|
221
|
+
|
222
|
+
connection.reconnect(:password => 'secret')
|
223
|
+
assert connection.connected?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
142
227
|
end
|