2525use Google \Cloud \TestUtils \EventuallyConsistentTestTrait ;
2626use Google \Cloud \TestUtils \TestTrait ;
2727use PHPUnit \Framework \TestCase ;
28+ use Google \Cloud \Core \Exception \FailedPreconditionException ;
2829
2930class spannerTest extends TestCase
3031{
@@ -628,11 +629,11 @@ public function testCancelBackup()
628629 */
629630 public function testCreateBackup ()
630631 {
631- $ output = $ this ->traitRunCommand ( 'create-backup ' , [
632+ $ output = $ this ->retry ([ $ this , ' traitRunCommand ' ], [ 'create-backup ' , [
632633 'instance_id ' => self ::$ instanceId ,
633634 'database_id ' => self ::$ databaseId ,
634635 'backup_id ' => self ::$ backupId ,
635- ]);
636+ ]] );
636637 $ this ->assertContains (self ::$ backupId , $ output );
637638 }
638639
@@ -678,11 +679,11 @@ public function testUpdateBackup()
678679 */
679680 public function testRestoreBackup ()
680681 {
681- $ output = $ this ->traitRunCommand ( 'restore-backup ' , [
682+ $ output = $ this ->retry ([ $ this , ' traitRunCommand ' ], [ 'restore-backup ' , [
682683 'instance_id ' => self ::$ instanceId ,
683684 'database_id ' => self ::$ databaseId . '-res ' ,
684685 'backup_id ' => self ::$ backupId ,
685- ]);
686+ ]] );
686687 $ this ->assertContains (self ::$ backupId , $ output );
687688 $ this ->assertContains (self ::$ databaseId , $ output );
688689 }
@@ -713,7 +714,8 @@ public function testDeleteBackup()
713714 $ this ->assertContains (self ::$ backupId , $ output );
714715 }
715716
716- private static function waitForBackupOperations ($ instance ) {
717+ private static function waitForBackupOperations ($ instance )
718+ {
717719 $ filter = "(metadata.@type:type.googleapis.com/ " .
718720 "google.spanner.admin.database.v1.CreateBackupMetadata) " ;
719721
@@ -725,7 +727,8 @@ private static function waitForBackupOperations($instance) {
725727 }
726728 }
727729
728- private static function waitForDatabaseOperations ($ instance ) {
730+ private static function waitForDatabaseOperations ($ instance )
731+ {
729732 $ filter = "(metadata.@type:type.googleapis.com/ " .
730733 "google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata) " ;
731734
@@ -737,6 +740,33 @@ private static function waitForDatabaseOperations($instance) {
737740 }
738741 }
739742
743+ /**
744+ * A workaround for backup creation/restore operation limit
745+ * when several testing scripts using the same Spanner instance run in parallel.
746+ *
747+ * @param callable $call
748+ * @param array $args
749+ * @return mixed
750+ */
751+ private function retry ($ call , $ args )
752+ {
753+ $ cutoffTime = time () + 20 * 60 ;
754+ $ sleepDuration = 10 ;
755+
756+ while (true ) {
757+ try {
758+ return call_user_func_array ($ call , $ args );
759+
760+ } catch (FailedPreconditionException $ e ) {
761+ if (!strstr ($ e ->getMessage (), 'maximum number of pending ' ) or time () >= $ cutoffTime ) {
762+ throw $ e ;
763+ }
764+
765+ sleep ($ sleepDuration );
766+ }
767+ }
768+ }
769+
740770 private function runCommand ($ commandName )
741771 {
742772 return $ this ->traitRunCommand ($ commandName , [
0 commit comments