@@ -315,6 +315,22 @@ def test_fetchone(self):
315
315
self .assertEqual (cursor .fetchone (), lst [i ])
316
316
self .assertIsNone (cursor .fetchone ())
317
317
318
+ @unittest .skipIf (
319
+ sys .version_info [0 ] < 3 , "Python 2 has an outdated iterator definition"
320
+ )
321
+ def test_fetchone_w_autocommit (self ):
322
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
323
+
324
+ connection = self ._make_connection (self .INSTANCE , mock .MagicMock ())
325
+ connection .autocommit = True
326
+ cursor = self ._make_one (connection )
327
+ cursor ._checksum = ResultsChecksum ()
328
+ lst = [1 , 2 , 3 ]
329
+ cursor ._itr = iter (lst )
330
+ for i in range (len (lst )):
331
+ self .assertEqual (cursor .fetchone (), lst [i ])
332
+ self .assertIsNone (cursor .fetchone ())
333
+
318
334
def test_fetchmany (self ):
319
335
from google .cloud .spanner_dbapi .checksum import ResultsChecksum
320
336
@@ -329,6 +345,21 @@ def test_fetchmany(self):
329
345
result = cursor .fetchmany (len (lst ))
330
346
self .assertEqual (result , lst [1 :])
331
347
348
+ def test_fetchmany_w_autocommit (self ):
349
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
350
+
351
+ connection = self ._make_connection (self .INSTANCE , mock .MagicMock ())
352
+ connection .autocommit = True
353
+ cursor = self ._make_one (connection )
354
+ cursor ._checksum = ResultsChecksum ()
355
+ lst = [(1 ,), (2 ,), (3 ,)]
356
+ cursor ._itr = iter (lst )
357
+
358
+ self .assertEqual (cursor .fetchmany (), [lst [0 ]])
359
+
360
+ result = cursor .fetchmany (len (lst ))
361
+ self .assertEqual (result , lst [1 :])
362
+
332
363
def test_fetchall (self ):
333
364
from google .cloud .spanner_dbapi .checksum import ResultsChecksum
334
365
@@ -339,6 +370,17 @@ def test_fetchall(self):
339
370
cursor ._itr = iter (lst )
340
371
self .assertEqual (cursor .fetchall (), lst )
341
372
373
+ def test_fetchall_w_autocommit (self ):
374
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
375
+
376
+ connection = self ._make_connection (self .INSTANCE , mock .MagicMock ())
377
+ connection .autocommit = True
378
+ cursor = self ._make_one (connection )
379
+ cursor ._checksum = ResultsChecksum ()
380
+ lst = [(1 ,), (2 ,), (3 ,)]
381
+ cursor ._itr = iter (lst )
382
+ self .assertEqual (cursor .fetchall (), lst )
383
+
342
384
def test_nextset (self ):
343
385
from google .cloud .spanner_dbapi import exceptions
344
386
@@ -586,3 +628,212 @@ def test_fetchone_retry_aborted_statements_checksums_mismatch(self):
586
628
cursor .fetchone ()
587
629
588
630
run_mock .assert_called_with (statement , retried = True )
631
+
632
+ def test_fetchall_retry_aborted (self ):
633
+ """Check that aborted fetch re-executing transaction."""
634
+ from google .api_core .exceptions import Aborted
635
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
636
+ from google .cloud .spanner_dbapi .connection import connect
637
+
638
+ with mock .patch (
639
+ "google.cloud.spanner_v1.instance.Instance.exists" , return_value = True ,
640
+ ):
641
+ with mock .patch (
642
+ "google.cloud.spanner_v1.database.Database.exists" , return_value = True ,
643
+ ):
644
+ connection = connect ("test-instance" , "test-database" )
645
+
646
+ cursor = connection .cursor ()
647
+ cursor ._checksum = ResultsChecksum ()
648
+
649
+ with mock .patch (
650
+ "google.cloud.spanner_dbapi.cursor.Cursor.__iter__" ,
651
+ side_effect = (Aborted ("Aborted" ), iter ([])),
652
+ ):
653
+ with mock .patch (
654
+ "google.cloud.spanner_dbapi.connection.Connection.retry_transaction"
655
+ ) as retry_mock :
656
+
657
+ cursor .fetchall ()
658
+
659
+ retry_mock .assert_called_with ()
660
+
661
+ def test_fetchall_retry_aborted_statements (self ):
662
+ """Check that retried transaction executing the same statements."""
663
+ from google .api_core .exceptions import Aborted
664
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
665
+ from google .cloud .spanner_dbapi .connection import connect
666
+ from google .cloud .spanner_dbapi .cursor import Statement
667
+
668
+ row = ["field1" , "field2" ]
669
+ with mock .patch (
670
+ "google.cloud.spanner_v1.instance.Instance.exists" , return_value = True ,
671
+ ):
672
+ with mock .patch (
673
+ "google.cloud.spanner_v1.database.Database.exists" , return_value = True ,
674
+ ):
675
+ connection = connect ("test-instance" , "test-database" )
676
+
677
+ cursor = connection .cursor ()
678
+ cursor ._checksum = ResultsChecksum ()
679
+ cursor ._checksum .consume_result (row )
680
+
681
+ statement = Statement ("SELECT 1" , [], {}, cursor ._checksum , False )
682
+ connection ._statements .append (statement )
683
+
684
+ with mock .patch (
685
+ "google.cloud.spanner_dbapi.cursor.Cursor.__iter__" ,
686
+ side_effect = (Aborted ("Aborted" ), iter (row )),
687
+ ):
688
+ with mock .patch (
689
+ "google.cloud.spanner_dbapi.connection.Connection.run_statement" ,
690
+ return_value = ([row ], ResultsChecksum ()),
691
+ ) as run_mock :
692
+ cursor .fetchall ()
693
+
694
+ run_mock .assert_called_with (statement , retried = True )
695
+
696
+ def test_fetchall_retry_aborted_statements_checksums_mismatch (self ):
697
+ """Check transaction retrying with underlying data being changed."""
698
+ from google .api_core .exceptions import Aborted
699
+ from google .cloud .spanner_dbapi .exceptions import RetryAborted
700
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
701
+ from google .cloud .spanner_dbapi .connection import connect
702
+ from google .cloud .spanner_dbapi .cursor import Statement
703
+
704
+ row = ["field1" , "field2" ]
705
+ row2 = ["updated_field1" , "field2" ]
706
+
707
+ with mock .patch (
708
+ "google.cloud.spanner_v1.instance.Instance.exists" , return_value = True ,
709
+ ):
710
+ with mock .patch (
711
+ "google.cloud.spanner_v1.database.Database.exists" , return_value = True ,
712
+ ):
713
+ connection = connect ("test-instance" , "test-database" )
714
+
715
+ cursor = connection .cursor ()
716
+ cursor ._checksum = ResultsChecksum ()
717
+ cursor ._checksum .consume_result (row )
718
+
719
+ statement = Statement ("SELECT 1" , [], {}, cursor ._checksum , False )
720
+ connection ._statements .append (statement )
721
+
722
+ with mock .patch (
723
+ "google.cloud.spanner_dbapi.cursor.Cursor.__iter__" ,
724
+ side_effect = (Aborted ("Aborted" ), iter (row )),
725
+ ):
726
+ with mock .patch (
727
+ "google.cloud.spanner_dbapi.connection.Connection.run_statement" ,
728
+ return_value = ([row2 ], ResultsChecksum ()),
729
+ ) as run_mock :
730
+
731
+ with self .assertRaises (RetryAborted ):
732
+ cursor .fetchall ()
733
+
734
+ run_mock .assert_called_with (statement , retried = True )
735
+
736
+ def test_fetchmany_retry_aborted (self ):
737
+ """Check that aborted fetch re-executing transaction."""
738
+ from google .api_core .exceptions import Aborted
739
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
740
+ from google .cloud .spanner_dbapi .connection import connect
741
+
742
+ with mock .patch (
743
+ "google.cloud.spanner_v1.instance.Instance.exists" , return_value = True ,
744
+ ):
745
+ with mock .patch (
746
+ "google.cloud.spanner_v1.database.Database.exists" , return_value = True ,
747
+ ):
748
+ connection = connect ("test-instance" , "test-database" )
749
+
750
+ cursor = connection .cursor ()
751
+ cursor ._checksum = ResultsChecksum ()
752
+
753
+ with mock .patch (
754
+ "google.cloud.spanner_dbapi.cursor.Cursor.__next__" ,
755
+ side_effect = (Aborted ("Aborted" ), None ),
756
+ ):
757
+ with mock .patch (
758
+ "google.cloud.spanner_dbapi.connection.Connection.retry_transaction"
759
+ ) as retry_mock :
760
+
761
+ cursor .fetchmany ()
762
+
763
+ retry_mock .assert_called_with ()
764
+
765
+ def test_fetchmany_retry_aborted_statements (self ):
766
+ """Check that retried transaction executing the same statements."""
767
+ from google .api_core .exceptions import Aborted
768
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
769
+ from google .cloud .spanner_dbapi .connection import connect
770
+ from google .cloud .spanner_dbapi .cursor import Statement
771
+
772
+ row = ["field1" , "field2" ]
773
+ with mock .patch (
774
+ "google.cloud.spanner_v1.instance.Instance.exists" , return_value = True ,
775
+ ):
776
+ with mock .patch (
777
+ "google.cloud.spanner_v1.database.Database.exists" , return_value = True ,
778
+ ):
779
+ connection = connect ("test-instance" , "test-database" )
780
+
781
+ cursor = connection .cursor ()
782
+ cursor ._checksum = ResultsChecksum ()
783
+ cursor ._checksum .consume_result (row )
784
+
785
+ statement = Statement ("SELECT 1" , [], {}, cursor ._checksum , False )
786
+ connection ._statements .append (statement )
787
+
788
+ with mock .patch (
789
+ "google.cloud.spanner_dbapi.cursor.Cursor.__next__" ,
790
+ side_effect = (Aborted ("Aborted" ), None ),
791
+ ):
792
+ with mock .patch (
793
+ "google.cloud.spanner_dbapi.connection.Connection.run_statement" ,
794
+ return_value = ([row ], ResultsChecksum ()),
795
+ ) as run_mock :
796
+
797
+ cursor .fetchmany (len (row ))
798
+
799
+ run_mock .assert_called_with (statement , retried = True )
800
+
801
+ def test_fetchmany_retry_aborted_statements_checksums_mismatch (self ):
802
+ """Check transaction retrying with underlying data being changed."""
803
+ from google .api_core .exceptions import Aborted
804
+ from google .cloud .spanner_dbapi .exceptions import RetryAborted
805
+ from google .cloud .spanner_dbapi .checksum import ResultsChecksum
806
+ from google .cloud .spanner_dbapi .connection import connect
807
+ from google .cloud .spanner_dbapi .cursor import Statement
808
+
809
+ row = ["field1" , "field2" ]
810
+ row2 = ["updated_field1" , "field2" ]
811
+
812
+ with mock .patch (
813
+ "google.cloud.spanner_v1.instance.Instance.exists" , return_value = True ,
814
+ ):
815
+ with mock .patch (
816
+ "google.cloud.spanner_v1.database.Database.exists" , return_value = True ,
817
+ ):
818
+ connection = connect ("test-instance" , "test-database" )
819
+
820
+ cursor = connection .cursor ()
821
+ cursor ._checksum = ResultsChecksum ()
822
+ cursor ._checksum .consume_result (row )
823
+
824
+ statement = Statement ("SELECT 1" , [], {}, cursor ._checksum , False )
825
+ connection ._statements .append (statement )
826
+
827
+ with mock .patch (
828
+ "google.cloud.spanner_dbapi.cursor.Cursor.__next__" ,
829
+ side_effect = (Aborted ("Aborted" ), None ),
830
+ ):
831
+ with mock .patch (
832
+ "google.cloud.spanner_dbapi.connection.Connection.run_statement" ,
833
+ return_value = ([row2 ], ResultsChecksum ()),
834
+ ) as run_mock :
835
+
836
+ with self .assertRaises (RetryAborted ):
837
+ cursor .fetchmany (len (row ))
838
+
839
+ run_mock .assert_called_with (statement , retried = True )
0 commit comments