@@ -906,6 +906,193 @@ def test_spans_get_and_leave_empty_pool(self):
906906 self .assertSpanEvents ("pool.Get" , wantEventNames )
907907
908908
909+ class TestTransactionPingingPool (unittest .TestCase ):
910+ def _getTargetClass (self ):
911+ from google .cloud .spanner_v1 .pool import TransactionPingingPool
912+
913+ return TransactionPingingPool
914+
915+ def _make_one (self , * args , ** kwargs ):
916+ return self ._getTargetClass ()(* args , ** kwargs )
917+
918+ def test_ctor_defaults (self ):
919+ pool = self ._make_one ()
920+ self .assertIsNone (pool ._database )
921+ self .assertEqual (pool .size , 10 )
922+ self .assertEqual (pool .default_timeout , 10 )
923+ self .assertEqual (pool ._delta .seconds , 3000 )
924+ self .assertTrue (pool ._sessions .empty ())
925+ self .assertTrue (pool ._pending_sessions .empty ())
926+ self .assertEqual (pool .labels , {})
927+ self .assertIsNone (pool .database_role )
928+
929+ def test_ctor_explicit (self ):
930+ labels = {"foo" : "bar" }
931+ database_role = "dummy-role"
932+ pool = self ._make_one (
933+ size = 4 ,
934+ default_timeout = 30 ,
935+ ping_interval = 1800 ,
936+ labels = labels ,
937+ database_role = database_role ,
938+ )
939+ self .assertIsNone (pool ._database )
940+ self .assertEqual (pool .size , 4 )
941+ self .assertEqual (pool .default_timeout , 30 )
942+ self .assertEqual (pool ._delta .seconds , 1800 )
943+ self .assertTrue (pool ._sessions .empty ())
944+ self .assertTrue (pool ._pending_sessions .empty ())
945+ self .assertEqual (pool .labels , labels )
946+ self .assertEqual (pool .database_role , database_role )
947+
948+ def test_ctor_explicit_w_database_role_in_db (self ):
949+ database_role = "dummy-role"
950+ pool = self ._make_one ()
951+ database = pool ._database = _Database ("name" )
952+ SESSIONS = [_Session (database )] * 10
953+ database ._sessions .extend (SESSIONS )
954+ database ._database_role = database_role
955+ pool .bind (database )
956+ self .assertEqual (pool .database_role , database_role )
957+
958+ def test_bind (self ):
959+ pool = self ._make_one ()
960+ database = _Database ("name" )
961+ SESSIONS = [_Session (database ) for _ in range (10 )]
962+ database ._sessions .extend (SESSIONS )
963+ pool .bind (database )
964+
965+ self .assertIs (pool ._database , database )
966+ self .assertEqual (pool .size , 10 )
967+ self .assertEqual (pool .default_timeout , 10 )
968+ self .assertEqual (pool ._delta .seconds , 3000 )
969+ self .assertTrue (pool ._sessions .full ())
970+
971+ api = database .spanner_api
972+ self .assertEqual (api .batch_create_sessions .call_count , 5 )
973+ for session in SESSIONS :
974+ session .create .assert_not_called ()
975+ txn = session ._transaction
976+ txn .begin .assert_not_called ()
977+
978+ self .assertTrue (pool ._pending_sessions .empty ())
979+
980+ def test_bind_w_timestamp_race (self ):
981+ import datetime
982+ from google .cloud ._testing import _Monkey
983+ from google .cloud .spanner_v1 import pool as MUT
984+
985+ NOW = datetime .datetime .utcnow ()
986+ pool = self ._make_one ()
987+ database = _Database ("name" )
988+ SESSIONS = [_Session (database ) for _ in range (10 )]
989+ database ._sessions .extend (SESSIONS )
990+
991+ with _Monkey (MUT , _NOW = lambda : NOW ):
992+ pool .bind (database )
993+
994+ self .assertIs (pool ._database , database )
995+ self .assertEqual (pool .size , 10 )
996+ self .assertEqual (pool .default_timeout , 10 )
997+ self .assertEqual (pool ._delta .seconds , 3000 )
998+ self .assertTrue (pool ._sessions .full ())
999+
1000+ api = database .spanner_api
1001+ self .assertEqual (api .batch_create_sessions .call_count , 5 )
1002+ for session in SESSIONS :
1003+ session .create .assert_not_called ()
1004+ txn = session ._transaction
1005+ txn .begin .assert_not_called ()
1006+
1007+ self .assertTrue (pool ._pending_sessions .empty ())
1008+
1009+ def test_put_full (self ):
1010+ import queue
1011+
1012+ pool = self ._make_one (size = 4 )
1013+ database = _Database ("name" )
1014+ SESSIONS = [_Session (database ) for _ in range (4 )]
1015+ database ._sessions .extend (SESSIONS )
1016+ pool .bind (database )
1017+
1018+ with self .assertRaises (queue .Full ):
1019+ pool .put (_Session (database ))
1020+
1021+ self .assertTrue (pool ._sessions .full ())
1022+
1023+ def test_put_non_full_w_active_txn (self ):
1024+ pool = self ._make_one (size = 1 )
1025+ session_queue = pool ._sessions = _Queue ()
1026+ pending = pool ._pending_sessions = _Queue ()
1027+ database = _Database ("name" )
1028+ session = _Session (database )
1029+ txn = session .transaction ()
1030+
1031+ pool .put (session )
1032+
1033+ self .assertEqual (len (session_queue ._items ), 1 )
1034+ _ , queued = session_queue ._items [0 ]
1035+ self .assertIs (queued , session )
1036+
1037+ self .assertEqual (len (pending ._items ), 0 )
1038+ txn .begin .assert_not_called ()
1039+
1040+ def test_put_non_full_w_committed_txn (self ):
1041+ pool = self ._make_one (size = 1 )
1042+ session_queue = pool ._sessions = _Queue ()
1043+ pending = pool ._pending_sessions = _Queue ()
1044+ database = _Database ("name" )
1045+ session = _Session (database )
1046+ committed = session .transaction ()
1047+ committed .committed = True
1048+
1049+ pool .put (session )
1050+
1051+ self .assertEqual (len (session_queue ._items ), 0 )
1052+
1053+ self .assertEqual (len (pending ._items ), 1 )
1054+ self .assertIs (pending ._items [0 ], session )
1055+ self .assertIsNot (session ._transaction , committed )
1056+ session ._transaction .begin .assert_not_called ()
1057+
1058+ def test_put_non_full (self ):
1059+ pool = self ._make_one (size = 1 )
1060+ session_queue = pool ._sessions = _Queue ()
1061+ pending = pool ._pending_sessions = _Queue ()
1062+ database = _Database ("name" )
1063+ session = _Session (database )
1064+
1065+ pool .put (session )
1066+
1067+ self .assertEqual (len (session_queue ._items ), 0 )
1068+ self .assertEqual (len (pending ._items ), 1 )
1069+ self .assertIs (pending ._items [0 ], session )
1070+
1071+ self .assertFalse (pending .empty ())
1072+
1073+ def test_begin_pending_transactions_empty (self ):
1074+ pool = self ._make_one (size = 1 )
1075+ pool .begin_pending_transactions () # no raise
1076+
1077+ def test_begin_pending_transactions_non_empty (self ):
1078+ pool = self ._make_one (size = 1 )
1079+ pool ._sessions = _Queue ()
1080+
1081+ database = _Database ("name" )
1082+ TRANSACTIONS = [_make_transaction (object ())]
1083+ PENDING_SESSIONS = [_Session (database , transaction = txn ) for txn in TRANSACTIONS ]
1084+
1085+ pending = pool ._pending_sessions = _Queue (* PENDING_SESSIONS )
1086+ self .assertFalse (pending .empty ())
1087+
1088+ pool .begin_pending_transactions () # no raise
1089+
1090+ for txn in TRANSACTIONS :
1091+ txn .begin .assert_not_called ()
1092+
1093+ self .assertTrue (pending .empty ())
1094+
1095+
9091096class TestSessionCheckout (unittest .TestCase ):
9101097 def _getTargetClass (self ):
9111098 from google .cloud .spanner_v1 .pool import SessionCheckout
0 commit comments