couchbase 1.0.0 → 1.1.0
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/.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
|