couchbase 1.3.4-x64-mingw32
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +22 -0
- data/.yardopts +5 -0
- data/CONTRIBUTING.markdown +75 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/Makefile +3 -0
- data/README.markdown +649 -0
- data/RELEASE_NOTES.markdown +796 -0
- data/Rakefile +20 -0
- data/couchbase.gemspec +49 -0
- data/examples/chat-em/Gemfile +7 -0
- data/examples/chat-em/README.markdown +45 -0
- data/examples/chat-em/server.rb +82 -0
- data/examples/chat-goliath-grape/Gemfile +5 -0
- data/examples/chat-goliath-grape/README.markdown +50 -0
- data/examples/chat-goliath-grape/app.rb +67 -0
- data/examples/chat-goliath-grape/config/app.rb +20 -0
- data/examples/transcoders/Gemfile +3 -0
- data/examples/transcoders/README.markdown +59 -0
- data/examples/transcoders/cb-zcat +40 -0
- data/examples/transcoders/cb-zcp +45 -0
- data/examples/transcoders/gzip_transcoder.rb +49 -0
- data/examples/transcoders/options.rb +54 -0
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +956 -0
- data/ext/couchbase_ext/arithmetic.c +307 -0
- data/ext/couchbase_ext/bucket.c +1370 -0
- data/ext/couchbase_ext/context.c +65 -0
- data/ext/couchbase_ext/couchbase_ext.c +1364 -0
- data/ext/couchbase_ext/couchbase_ext.h +644 -0
- data/ext/couchbase_ext/delete.c +163 -0
- data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
- data/ext/couchbase_ext/extconf.rb +168 -0
- data/ext/couchbase_ext/get.c +316 -0
- data/ext/couchbase_ext/gethrtime.c +129 -0
- data/ext/couchbase_ext/http.c +432 -0
- data/ext/couchbase_ext/multithread_plugin.c +1090 -0
- data/ext/couchbase_ext/observe.c +171 -0
- data/ext/couchbase_ext/plugin_common.c +171 -0
- data/ext/couchbase_ext/result.c +129 -0
- data/ext/couchbase_ext/stats.c +163 -0
- data/ext/couchbase_ext/store.c +542 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +186 -0
- data/ext/couchbase_ext/unlock.c +176 -0
- data/ext/couchbase_ext/utils.c +551 -0
- data/ext/couchbase_ext/version.c +142 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +430 -0
- data/lib/couchbase.rb +155 -0
- data/lib/couchbase/bucket.rb +457 -0
- data/lib/couchbase/cluster.rb +119 -0
- data/lib/couchbase/connection_pool.rb +58 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/transcoder.rb +120 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +21 -0
- data/lib/couchbase/view.rb +506 -0
- data/lib/couchbase/view_row.rb +272 -0
- data/lib/ext/multi_json_fix.rb +56 -0
- data/lib/rack/session/couchbase.rb +108 -0
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +158 -0
- data/tasks/test.rake +100 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +178 -0
- data/test/test_arithmetic.rb +185 -0
- data/test/test_async.rb +316 -0
- data/test/test_bucket.rb +250 -0
- data/test/test_cas.rb +235 -0
- data/test/test_couchbase.rb +77 -0
- data/test/test_couchbase_connection_pool.rb +77 -0
- data/test/test_couchbase_rails_cache_store.rb +361 -0
- data/test/test_delete.rb +120 -0
- data/test/test_errors.rb +82 -0
- data/test/test_eventmachine.rb +70 -0
- data/test/test_format.rb +164 -0
- data/test/test_get.rb +407 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +216 -0
- data/test/test_timer.rb +42 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +119 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +52 -0
- metadata +336 -0
data/test/test_bucket.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
|
20
|
+
class TestBucket < MiniTest::Test
|
21
|
+
|
22
|
+
def test_it_substitute_default_parts_to_url
|
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
|
38
|
+
|
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
|
49
|
+
|
50
|
+
with_mock(:host => 'localhost') do |mock| # pick first free port
|
51
|
+
connections = [
|
52
|
+
Couchbase.new("http://#{mock.host}:#{mock.port}"),
|
53
|
+
Couchbase.new(:port => mock.port),
|
54
|
+
Couchbase.new("http://#{mock.host}:8091", :port => mock.port)
|
55
|
+
]
|
56
|
+
connections.each do |connection|
|
57
|
+
assert_equal mock.port, connection.port
|
58
|
+
assert_equal "#{mock.host}:#{mock.port}", connection.authority
|
59
|
+
assert_equal "http://#{mock.host}:#{mock.port}/pools/default/buckets/default/", connection.url
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
with_mock(:host => '127.0.0.1') do |mock|
|
64
|
+
connections = [
|
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)
|
68
|
+
]
|
69
|
+
connections.each do |connection|
|
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
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_it_raises_network_error_if_server_not_found
|
78
|
+
refute(`netstat -tnl` =~ /12345/)
|
79
|
+
assert_raises Couchbase::Error::Connect do
|
80
|
+
Couchbase.new(:port => 12345)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_it_raises_argument_error_for_illegal_url
|
85
|
+
illegal = [
|
86
|
+
"ftp://localhost:8091/",
|
87
|
+
"http:/localhost:8091/",
|
88
|
+
""
|
89
|
+
]
|
90
|
+
illegal.each do |url|
|
91
|
+
assert_raises ArgumentError do
|
92
|
+
Couchbase.new(url)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_it_able_to_connect_to_protected_buckets
|
98
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
99
|
+
connection = Couchbase.new(:hostname => mock.host,
|
100
|
+
:port => mock.port,
|
101
|
+
:bucket => 'protected',
|
102
|
+
:username => 'protected',
|
103
|
+
:password => 'secret')
|
104
|
+
assert_equal "protected", connection.bucket
|
105
|
+
assert_equal "protected", connection.username
|
106
|
+
assert_equal "secret", connection.password
|
107
|
+
end
|
108
|
+
end
|
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
|
+
|
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
|
+
:password => 'wrong_password')
|
126
|
+
end
|
127
|
+
assert_raises Couchbase::Error::InvalidUsername do
|
128
|
+
Couchbase.new(:hostname => mock.host,
|
129
|
+
:port => mock.port,
|
130
|
+
:bucket => 'default',
|
131
|
+
:username => 'wrong.username',
|
132
|
+
:password => 'wrong_password')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_it_unable_to_connect_to_protected_buckets_with_wrong_credentials
|
138
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
139
|
+
assert_raises Couchbase::Error::InvalidUsername do
|
140
|
+
Couchbase.new(:hostname => mock.host,
|
141
|
+
:port => mock.port,
|
142
|
+
:bucket => 'protected',
|
143
|
+
:username => 'wrong',
|
144
|
+
:password => 'secret')
|
145
|
+
end
|
146
|
+
assert_raises Couchbase::Error::Auth do
|
147
|
+
Couchbase.new(:hostname => mock.host,
|
148
|
+
:port => mock.port,
|
149
|
+
:bucket => 'protected',
|
150
|
+
:username => 'protected',
|
151
|
+
:password => 'wrong')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_it_allows_change_quiet_flag
|
157
|
+
with_mock do |mock|
|
158
|
+
connection = Couchbase.new(:hostname => mock.host,
|
159
|
+
:port => mock.port)
|
160
|
+
refute connection.quiet?
|
161
|
+
|
162
|
+
connection = Couchbase.new(:hostname => mock.host,
|
163
|
+
:port => mock.port,
|
164
|
+
:quiet => true)
|
165
|
+
assert connection.quiet?
|
166
|
+
|
167
|
+
connection.quiet = nil
|
168
|
+
assert_equal false, connection.quiet?
|
169
|
+
|
170
|
+
connection.quiet = :foo
|
171
|
+
assert_equal true, connection.quiet?
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_it_is_connected
|
176
|
+
with_mock do |mock|
|
177
|
+
connection = Couchbase.new(:hostname => mock.host,
|
178
|
+
:port => mock.port)
|
179
|
+
assert connection.connected?
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_it_is_possible_to_disconnect_instance
|
184
|
+
with_mock do |mock|
|
185
|
+
connection = Couchbase.new(:hostname => mock.host,
|
186
|
+
:port => mock.port)
|
187
|
+
connection.disconnect
|
188
|
+
refute connection.connected?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_it_raises_error_on_double_disconnect
|
193
|
+
with_mock do |mock|
|
194
|
+
connection = Couchbase.new(:hostname => mock.host,
|
195
|
+
:port => mock.port)
|
196
|
+
connection.disconnect
|
197
|
+
assert_raises Couchbase::Error::Connect do
|
198
|
+
connection.disconnect
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_it_allows_to_reconnect_the_instance
|
204
|
+
with_mock do |mock|
|
205
|
+
connection = Couchbase.new(:hostname => mock.host,
|
206
|
+
:port => mock.port)
|
207
|
+
connection.disconnect
|
208
|
+
refute connection.connected?
|
209
|
+
connection.reconnect
|
210
|
+
assert connection.connected?
|
211
|
+
assert connection.set(uniq_id, "foo")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_it_allows_to_change_configuration_during_reconnect
|
216
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
217
|
+
connection = Couchbase.new(:hostname => mock.host,
|
218
|
+
:port => mock.port,
|
219
|
+
:bucket => 'protected',
|
220
|
+
:username => 'protected',
|
221
|
+
:password => 'secret')
|
222
|
+
connection.disconnect
|
223
|
+
assert_raises Couchbase::Error::Auth do
|
224
|
+
connection.reconnect(:password => 'incorrect')
|
225
|
+
end
|
226
|
+
refute connection.connected?
|
227
|
+
|
228
|
+
connection.reconnect(:password => 'secret')
|
229
|
+
assert connection.connected?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_it_uses_bucket_name_as_username_if_username_is_empty
|
234
|
+
with_mock(:buckets_spec => 'protected:secret') do |mock|
|
235
|
+
connection = Couchbase.new(:hostname => mock.host,
|
236
|
+
:port => mock.port,
|
237
|
+
:bucket => 'protected',
|
238
|
+
:password => 'secret')
|
239
|
+
assert connection.connected?
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_it_doesnt_try_to_destroy_handle_in_case_of_lcb_create_failure
|
244
|
+
assert_raises(Couchbase::Error::InvalidHostFormat) do
|
245
|
+
Couchbase.connect(:hostname => "foobar:baz")
|
246
|
+
end
|
247
|
+
GC.start # make sure it won't touch handle in finalizer
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
data/test/test_cas.rb
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
|
20
|
+
class TestCas < MiniTest::Test
|
21
|
+
|
22
|
+
def setup
|
23
|
+
@mock = start_mock
|
24
|
+
end
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
stop_mock(@mock)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_compare_and_swap
|
31
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
32
|
+
:default_format => :document)
|
33
|
+
connection.set(uniq_id, {"bar" => 1})
|
34
|
+
connection.cas(uniq_id) do |val|
|
35
|
+
val["baz"] = 2
|
36
|
+
val
|
37
|
+
end
|
38
|
+
val = connection.get(uniq_id)
|
39
|
+
expected = {"bar" => 1, "baz" => 2}
|
40
|
+
assert_equal expected, val
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_compare_and_swap_collision
|
44
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
45
|
+
:default_format => :document)
|
46
|
+
connection.set(uniq_id, {"bar" => 1})
|
47
|
+
assert_raises(Couchbase::Error::KeyExists) do
|
48
|
+
connection.cas(uniq_id) do |val|
|
49
|
+
# Simulate collision with a separate writer. This will
|
50
|
+
# change the CAS value to be different than what #cas just loaded.
|
51
|
+
connection.set(uniq_id, {"bar" => 2})
|
52
|
+
|
53
|
+
# Complete the modification we desire, which should fail when set.
|
54
|
+
val["baz"] = 3
|
55
|
+
val
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_compare_and_swap_retry
|
61
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
62
|
+
:default_format => :document)
|
63
|
+
connection.set(uniq_id, {"bar" => 1})
|
64
|
+
calls = 0
|
65
|
+
connection.cas(uniq_id, :retry => 1) do |val|
|
66
|
+
calls += 1
|
67
|
+
if calls == 1
|
68
|
+
# Simulate collision with a separate writer. This will
|
69
|
+
# change the CAS value to be different than what #cas just loaded.
|
70
|
+
# Only do this the first time this block is executed.
|
71
|
+
connection.set(uniq_id, {"bar" => 2})
|
72
|
+
end
|
73
|
+
|
74
|
+
# Complete the modification we desire, which should fail when set.
|
75
|
+
val["baz"] = 3
|
76
|
+
val
|
77
|
+
end
|
78
|
+
assert_equal 2, calls
|
79
|
+
val = connection.get(uniq_id)
|
80
|
+
expected = {"bar" => 2, "baz" => 3}
|
81
|
+
assert_equal expected, val
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_compare_and_swap_too_many_retries
|
85
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
86
|
+
:default_format => :document)
|
87
|
+
connection.set(uniq_id, {"bar" => 0})
|
88
|
+
calls = 0
|
89
|
+
assert_raises(Couchbase::Error::KeyExists) do
|
90
|
+
connection.cas(uniq_id, :retry => 10) do |val|
|
91
|
+
calls += 1
|
92
|
+
|
93
|
+
# Simulate collision with a separate writer. This will
|
94
|
+
# change the CAS value to be different than what #cas just loaded.
|
95
|
+
# Do it every time so we just keep retrying and failing.
|
96
|
+
connection.set(uniq_id, {"bar" => calls})
|
97
|
+
|
98
|
+
# Complete the modification we desire, which should fail when set.
|
99
|
+
val["baz"] = 3
|
100
|
+
val
|
101
|
+
end
|
102
|
+
end
|
103
|
+
assert_equal 11, calls
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_compare_and_swap_async
|
107
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
108
|
+
:default_format => :document)
|
109
|
+
connection.set(uniq_id, {"bar" => 1})
|
110
|
+
calls = 0
|
111
|
+
connection.run do |conn|
|
112
|
+
conn.cas(uniq_id) do |ret|
|
113
|
+
calls += 1
|
114
|
+
case ret.operation
|
115
|
+
when :get
|
116
|
+
new_val = ret.value
|
117
|
+
new_val["baz"] = 2
|
118
|
+
new_val
|
119
|
+
when :set
|
120
|
+
assert ret.success?
|
121
|
+
else
|
122
|
+
flunk "Unexpected operation: #{ret.operation.inspect}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
assert_equal 2, calls
|
127
|
+
val = connection.get(uniq_id)
|
128
|
+
expected = {"bar" => 1, "baz" => 2}
|
129
|
+
assert_equal expected, val
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_compare_and_swap_async_collision
|
133
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
134
|
+
:default_format => :document)
|
135
|
+
connection.set(uniq_id, {"bar" => 1})
|
136
|
+
calls = 0
|
137
|
+
connection.run do |conn|
|
138
|
+
conn.cas(uniq_id) do |ret|
|
139
|
+
calls += 1
|
140
|
+
case ret.operation
|
141
|
+
when :get
|
142
|
+
new_val = ret.value
|
143
|
+
|
144
|
+
# Simulate collision with a separate writer. This will
|
145
|
+
# change the CAS value to be different than what #cas just loaded.
|
146
|
+
connection.set(uniq_id, {"bar" => 2})
|
147
|
+
|
148
|
+
|
149
|
+
# Complete the modification we desire, which should fail when set.
|
150
|
+
new_val["baz"] = 3
|
151
|
+
new_val
|
152
|
+
when :set
|
153
|
+
assert ret.error.is_a? Couchbase::Error::KeyExists
|
154
|
+
else
|
155
|
+
flunk "Unexpected operation: #{ret.operation.inspect}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
assert_equal 2, calls
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_compare_and_swap_async_retry
|
163
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
164
|
+
:default_format => :document)
|
165
|
+
connection.set(uniq_id, {"bar" => 1})
|
166
|
+
calls = 0
|
167
|
+
connection.run do |conn|
|
168
|
+
conn.cas(uniq_id, :retry => 1) do |ret|
|
169
|
+
calls += 1
|
170
|
+
case ret.operation
|
171
|
+
when :get
|
172
|
+
new_val = ret.value
|
173
|
+
|
174
|
+
if calls == 1
|
175
|
+
# Simulate collision with a separate writer. This will
|
176
|
+
# change the CAS value to be different than what #cas just loaded.
|
177
|
+
# Only do this the first time this block is executed.
|
178
|
+
connection.set(uniq_id, {"bar" => 2})
|
179
|
+
end
|
180
|
+
|
181
|
+
# Complete the modification we desire, which should fail when set.
|
182
|
+
new_val["baz"] = 3
|
183
|
+
new_val
|
184
|
+
when :set
|
185
|
+
assert ret.success?
|
186
|
+
else
|
187
|
+
flunk "Unexpected operation: #{ret.operation.inspect}"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
assert_equal 3, calls
|
192
|
+
val = connection.get(uniq_id)
|
193
|
+
expected = {"bar" => 2, "baz" => 3}
|
194
|
+
assert_equal expected, val
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_compare_and_swap_async_too_many_retries
|
198
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
199
|
+
:default_format => :document)
|
200
|
+
connection.set(uniq_id, {"bar" => 0})
|
201
|
+
calls = 0
|
202
|
+
connection.run do |conn|
|
203
|
+
conn.cas(uniq_id, :retry => 10) do |ret|
|
204
|
+
calls += 1
|
205
|
+
case ret.operation
|
206
|
+
when :get
|
207
|
+
new_val = ret.value
|
208
|
+
|
209
|
+
# Simulate collision with a separate writer. This will
|
210
|
+
# change the CAS value to be different than what #cas just loaded.
|
211
|
+
# Do it every time so we just keep retrying and failing.
|
212
|
+
connection.set(uniq_id, {"bar" => calls})
|
213
|
+
|
214
|
+
# Complete the modification we desire, which should fail when set.
|
215
|
+
new_val["baz"] = 3
|
216
|
+
new_val
|
217
|
+
when :set
|
218
|
+
assert ret.error.is_a? Couchbase::Error::KeyExists
|
219
|
+
else
|
220
|
+
flunk "Unexpected operation: #{ret.operation.inspect}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
assert_equal 12, calls
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_flags_replication
|
228
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
|
229
|
+
:default_format => :document)
|
230
|
+
connection.set(uniq_id, "bar", :flags => 0x100)
|
231
|
+
connection.cas(uniq_id) { "baz" }
|
232
|
+
_, flags, _ = connection.get(uniq_id, :extended => true)
|
233
|
+
assert_equal 0x100, flags
|
234
|
+
end
|
235
|
+
end
|