@@ -57,6 +57,52 @@ def test_compare_and_swap_collision
57
57
end
58
58
end
59
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
+
60
106
def test_compare_and_swap_async
61
107
connection = Couchbase . new ( :hostname => @mock . host , :port => @mock . port ,
62
108
:default_format => :document )
@@ -113,6 +159,71 @@ def test_compare_and_swap_async_collision
113
159
assert_equal 2 , calls
114
160
end
115
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
+
116
227
def test_flags_replication
117
228
connection = Couchbase . new ( :hostname => @mock . host , :port => @mock . port ,
118
229
:default_format => :document )
0 commit comments