@@ -57,6 +57,52 @@ def test_compare_and_swap_collision
5757 end
5858 end
5959
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+
60106 def test_compare_and_swap_async
61107 connection = Couchbase . new ( :hostname => @mock . host , :port => @mock . port ,
62108 :default_format => :document )
@@ -113,6 +159,71 @@ def test_compare_and_swap_async_collision
113159 assert_equal 2 , calls
114160 end
115161
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+
116227 def test_flags_replication
117228 connection = Couchbase . new ( :hostname => @mock . host , :port => @mock . port ,
118229 :default_format => :document )
0 commit comments