2626 DocumentNotFoundException ,
2727 DocumentUnretrievableException ,
2828 FeatureUnavailableException ,
29+ InvalidIndexException ,
2930 ParsingFailedException ,
3031 TransactionExpired ,
3132 TransactionFailed ,
3233 TransactionOperationFailed )
3334from couchbase .n1ql import QueryProfile , QueryScanConsistency
3435from couchbase .options import (TransactionConfig ,
36+ TransactionGetMultiOptions ,
37+ TransactionGetMultiReplicasFromPreferredServerGroupOptions ,
3538 TransactionGetOptions ,
3639 TransactionInsertOptions ,
3740 TransactionOptions ,
3841 TransactionQueryOptions ,
3942 TransactionReplaceOptions )
40- from couchbase .transactions import TransactionKeyspace , TransactionResult
43+ from couchbase .transactions import (TransactionGetMultiMode ,
44+ TransactionGetMultiReplicasFromPreferredServerGroupMode ,
45+ TransactionGetMultiReplicasFromPreferredServerGroupResult ,
46+ TransactionGetMultiReplicasFromPreferredServerGroupSpec ,
47+ TransactionGetMultiResult ,
48+ TransactionGetMultiSpec ,
49+ TransactionKeyspace ,
50+ TransactionResult )
4151from couchbase .transcoder import RawBinaryTranscoder
4252from tests .environments import CollectionType
4353from tests .environments .test_environment import AsyncTestEnvironment
@@ -61,6 +71,16 @@ class TransactionTestSuite:
6171 'test_get_inner_exc_doc_not_found' ,
6272 'test_get_replica_from_preferred_server_group_unretrievable' ,
6373 'test_get_replica_from_preferred_server_group_propagate_unretrievable_exc' ,
74+ 'test_get_multi_binary' ,
75+ 'test_get_multi_not_exists' ,
76+ 'test_get_multi_invalid_index' ,
77+ 'test_get_multi_options' ,
78+ 'test_get_multi_simple' ,
79+ 'test_get_multi_replicas_from_preferred_server_group_binary' ,
80+ 'test_get_multi_replicas_from_preferred_server_group_not_exists' ,
81+ 'test_get_multi_replicas_from_preferred_server_group_invalid_index' ,
82+ 'test_get_multi_replicas_from_preferred_server_group_options' ,
83+ 'test_get_multi_replicas_from_preferred_server_group_simple' ,
6484 'test_insert' ,
6585 'test_insert_lambda_raises_doc_exists' ,
6686 'test_insert_inner_exc_doc_exists' ,
@@ -334,6 +354,268 @@ async def txn_logic(ctx):
334354
335355 assert num_attempts == 1
336356
357+ @pytest .mark .asyncio
358+ async def test_get_multi_binary (self , cb_env ):
359+ key1 = cb_env .get_new_doc (key_only = True )
360+ tc = RawBinaryTranscoder ()
361+ value1 = 'bytes content' .encode ('utf-8' )
362+ key2 , value2 = cb_env .get_new_doc ()
363+
364+ await cb_env .collection .insert (key1 , value1 , transcoder = tc )
365+ await cb_env .collection .insert (key2 , value2 )
366+
367+ async def txn_logic (ctx ):
368+ specs = [
369+ TransactionGetMultiSpec (cb_env .collection , key1 , transcoder = tc ),
370+ TransactionGetMultiSpec (cb_env .collection , key2 ),
371+ ]
372+ res = await ctx .get_multi (specs )
373+ assert isinstance (res , TransactionGetMultiResult )
374+ assert res .content_as [bytes ](0 ) == value1
375+ assert res .content_as [dict ](1 ) == value2
376+
377+ await cb_env .cluster .transactions .run (txn_logic )
378+
379+ for k in [key1 , key2 ]:
380+ try :
381+ await cb_env .collection .remove (k )
382+ except DocumentNotFoundException :
383+ pass
384+
385+ @pytest .mark .asyncio
386+ async def test_get_multi_not_exists (self , cb_env ):
387+ key1 , value1 = cb_env .get_new_doc ()
388+ key2 = cb_env .get_new_doc (key_only = True )
389+ await cb_env .collection .insert (key1 , value1 )
390+
391+ async def txn_logic (ctx ):
392+ specs = (
393+ TransactionGetMultiSpec (cb_env .collection , key1 ),
394+ TransactionGetMultiSpec (cb_env .collection , key2 )
395+ )
396+ res = await ctx .get_multi (specs )
397+ assert isinstance (res , TransactionGetMultiResult )
398+ assert res .exists (0 ) is True
399+ assert res .exists (1 ) is False
400+
401+ with pytest .raises (DocumentNotFoundException ):
402+ res .content_as [dict ](1 )
403+
404+ await cb_env .cluster .transactions .run (txn_logic )
405+ try :
406+ await cb_env .collection .remove (key1 )
407+ except DocumentNotFoundException :
408+ pass
409+
410+ @pytest .mark .asyncio
411+ async def test_get_multi_invalid_index (self , cb_env ):
412+ key1 , value1 = cb_env .get_new_doc ()
413+ key2 = cb_env .get_new_doc (key_only = True )
414+ await cb_env .collection .insert (key1 , value1 )
415+
416+ async def txn_logic (ctx ):
417+ specs = [
418+ TransactionGetMultiSpec (cb_env .collection , key1 ),
419+ TransactionGetMultiSpec (cb_env .collection , key2 )
420+ ]
421+ res = await ctx .get_multi (specs )
422+ assert isinstance (res , TransactionGetMultiResult )
423+ assert res .exists (0 ) is True
424+ assert res .exists (1 ) is False
425+ with pytest .raises (InvalidIndexException ):
426+ res .content_as [dict ](2 )
427+
428+ await cb_env .cluster .transactions .run (txn_logic )
429+ try :
430+ await cb_env .collection .remove (key1 )
431+ except DocumentNotFoundException :
432+ pass
433+
434+ @pytest .mark .asyncio
435+ async def test_get_multi_options (self , cb_env ):
436+ key1 , value1 = cb_env .get_new_doc ()
437+ key2 , value2 = cb_env .get_new_doc ()
438+ await cb_env .collection .insert (key1 , value1 )
439+ await cb_env .collection .insert (key2 , value2 )
440+
441+ async def txn_logic (ctx ):
442+ specs = (
443+ TransactionGetMultiSpec (cb_env .collection , key1 ),
444+ TransactionGetMultiSpec (cb_env .collection , key2 )
445+ )
446+ opts = TransactionGetMultiOptions (mode = TransactionGetMultiMode .DISABLE_READ_SKEW_DETECTION )
447+ res = await ctx .get_multi (specs , opts )
448+ assert isinstance (res , TransactionGetMultiResult )
449+ assert res .content_as [dict ](0 ) == value1
450+ assert res .content_as [dict ](1 ) == value2
451+
452+ await cb_env .cluster .transactions .run (txn_logic )
453+
454+ for k in [key1 , key2 ]:
455+ try :
456+ await cb_env .collection .remove (k )
457+ except DocumentNotFoundException :
458+ pass
459+
460+ @pytest .mark .asyncio
461+ async def test_get_multi_simple (self , cb_env ):
462+ keys_and_docs = []
463+ for _ in range (3 ):
464+ key , value = cb_env .get_new_doc ()
465+ keys_and_docs .append ((key , value ))
466+ await cb_env .collection .insert (key , value )
467+
468+ async def txn_logic (ctx ):
469+ specs = (
470+ TransactionGetMultiSpec (cb_env .collection , keys_and_docs [0 ][0 ]),
471+ TransactionGetMultiSpec (cb_env .collection , keys_and_docs [1 ][0 ]),
472+ TransactionGetMultiSpec (cb_env .collection , keys_and_docs [2 ][0 ])
473+ )
474+ res = await ctx .get_multi (specs )
475+ assert isinstance (res , TransactionGetMultiResult )
476+ for idx in range (len (keys_and_docs )):
477+ assert res .exists (idx ) is True
478+ assert res .content_as [dict ](idx ) == keys_and_docs [idx ][1 ]
479+
480+ await cb_env .cluster .transactions .run (txn_logic )
481+
482+ for kd in keys_and_docs :
483+ try :
484+ await cb_env .collection .remove (kd [0 ])
485+ except DocumentNotFoundException :
486+ pass
487+
488+ @pytest .mark .asyncio
489+ async def test_get_multi_replicas_from_preferred_server_group_binary (self , cb_env ):
490+ key1 = cb_env .get_new_doc (key_only = True )
491+ tc = RawBinaryTranscoder ()
492+ value1 = 'bytes content' .encode ('utf-8' )
493+ key2 , value2 = cb_env .get_new_doc ()
494+
495+ await cb_env .collection .insert (key1 , value1 , transcoder = tc )
496+ await cb_env .collection .insert (key2 , value2 )
497+
498+ async def txn_logic (ctx ):
499+ specs = [
500+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key1 , transcoder = tc ),
501+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key2 ),
502+ ]
503+ res = await ctx .get_multi_replicas_from_preferred_server_group (specs )
504+ assert isinstance (res , TransactionGetMultiReplicasFromPreferredServerGroupResult )
505+ assert res .content_as [bytes ](0 ) == value1
506+ assert res .content_as [dict ](1 ) == value2
507+
508+ await cb_env .cluster .transactions .run (txn_logic )
509+
510+ for k in [key1 , key2 ]:
511+ try :
512+ await cb_env .collection .remove (k )
513+ except DocumentNotFoundException :
514+ pass
515+
516+ @pytest .mark .asyncio
517+ async def test_get_multi_replicas_from_preferred_server_group_not_exists (self , cb_env ):
518+ key1 , value1 = cb_env .get_new_doc ()
519+ key2 = cb_env .get_new_doc (key_only = True )
520+ await cb_env .collection .insert (key1 , value1 )
521+
522+ async def txn_logic (ctx ):
523+ specs = (
524+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key1 ),
525+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key2 )
526+ )
527+ res = await ctx .get_multi_replicas_from_preferred_server_group (specs )
528+ assert isinstance (res , TransactionGetMultiReplicasFromPreferredServerGroupResult )
529+ assert res .exists (0 ) is True
530+ assert res .exists (1 ) is False
531+
532+ with pytest .raises (DocumentNotFoundException ):
533+ res .content_as [dict ](1 )
534+
535+ await cb_env .cluster .transactions .run (txn_logic )
536+ try :
537+ await cb_env .collection .remove (key1 )
538+ except DocumentNotFoundException :
539+ pass
540+
541+ @pytest .mark .asyncio
542+ async def test_get_multi_replicas_from_preferred_server_group_invalid_index (self , cb_env ):
543+ key1 , value1 = cb_env .get_new_doc ()
544+ key2 = cb_env .get_new_doc (key_only = True )
545+ await cb_env .collection .insert (key1 , value1 )
546+
547+ async def txn_logic (ctx ):
548+ specs = [
549+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key1 ),
550+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key2 )
551+ ]
552+ res = await ctx .get_multi_replicas_from_preferred_server_group (specs )
553+ assert isinstance (res , TransactionGetMultiReplicasFromPreferredServerGroupResult )
554+ assert res .exists (0 ) is True
555+ assert res .exists (1 ) is False
556+ with pytest .raises (InvalidIndexException ):
557+ res .content_as [dict ](2 )
558+
559+ cb_env .cluster .transactions .run (txn_logic )
560+ try :
561+ await cb_env .collection .remove (key1 )
562+ except DocumentNotFoundException :
563+ pass
564+
565+ @pytest .mark .asyncio
566+ async def test_get_multi_replicas_from_preferred_server_group_options (self , cb_env ):
567+ key1 , value1 = cb_env .get_new_doc ()
568+ key2 , value2 = cb_env .get_new_doc ()
569+ await cb_env .collection .insert (key1 , value1 )
570+ await cb_env .collection .insert (key2 , value2 )
571+
572+ async def txn_logic (ctx ):
573+ specs = (
574+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key1 ),
575+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , key2 )
576+ )
577+ opts = TransactionGetMultiReplicasFromPreferredServerGroupOptions (mode = TransactionGetMultiReplicasFromPreferredServerGroupMode .DISABLE_READ_SKEW_DETECTION ) # noqa: E501
578+ res = await ctx .get_multi_replicas_from_preferred_server_group (specs , opts )
579+ assert isinstance (res , TransactionGetMultiReplicasFromPreferredServerGroupResult )
580+ assert res .content_as [dict ](0 ) == value1
581+ assert res .content_as [dict ](1 ) == value2
582+
583+ await cb_env .cluster .transactions .run (txn_logic )
584+
585+ for k in [key1 , key2 ]:
586+ try :
587+ await cb_env .collection .remove (k )
588+ except DocumentNotFoundException :
589+ pass
590+
591+ @pytest .mark .asyncio
592+ async def test_get_multi_replicas_from_preferred_server_group_simple (self , cb_env ):
593+ keys_and_docs = []
594+ for _ in range (3 ):
595+ key , value = cb_env .get_new_doc ()
596+ keys_and_docs .append ((key , value ))
597+ await cb_env .collection .insert (key , value )
598+
599+ async def txn_logic (ctx ):
600+ specs = (
601+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , keys_and_docs [0 ][0 ]),
602+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , keys_and_docs [1 ][0 ]),
603+ TransactionGetMultiReplicasFromPreferredServerGroupSpec (cb_env .collection , keys_and_docs [2 ][0 ])
604+ )
605+ res = await ctx .get_multi_replicas_from_preferred_server_group (specs )
606+ assert isinstance (res , TransactionGetMultiReplicasFromPreferredServerGroupResult )
607+ for idx in range (len (keys_and_docs )):
608+ assert res .exists (idx ) is True
609+ assert res .content_as [dict ](idx ) == keys_and_docs [idx ][1 ]
610+
611+ await cb_env .cluster .transactions .run (txn_logic )
612+
613+ for kd in keys_and_docs :
614+ try :
615+ await cb_env .collection .remove (kd [0 ])
616+ except DocumentNotFoundException :
617+ pass
618+
337619 @pytest .mark .asyncio
338620 async def test_insert (self , cb_env ):
339621 key , value = cb_env .get_new_doc ()
0 commit comments