diff --git a/.github/workflows/emulator-system-tests-spanner.yaml b/.github/workflows/emulator-system-tests-spanner.yaml index 16ba9df46bc3..92dc68ddf488 100644 --- a/.github/workflows/emulator-system-tests-spanner.yaml +++ b/.github/workflows/emulator-system-tests-spanner.yaml @@ -18,7 +18,7 @@ jobs: runs-on: 'ubuntu-24.04' services: emulator: - image: gcr.io/cloud-spanner-emulator/emulator:1.5.34 + image: gcr.io/cloud-spanner-emulator/emulator:1.5.42 ports: - 9010:9010 - 9020:9020 @@ -41,7 +41,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.4' ini-values: grpc.enable_fork_support=1 tools: pecl extensions: bcmath, grpc, pcntl diff --git a/Core/src/Testing/System/SystemTestCase.php b/Core/src/Testing/System/SystemTestCase.php index 9f21d8472bb8..1b1e257c5aec 100644 --- a/Core/src/Testing/System/SystemTestCase.php +++ b/Core/src/Testing/System/SystemTestCase.php @@ -28,7 +28,6 @@ use Google\Cloud\Storage\StorageClient; use Google\Cloud\Core\Testing\System\DeletionQueue; use PHPUnit\Framework\TestCase; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; /** * SystemTestCase can be extended to implement system tests @@ -287,11 +286,4 @@ public static function skipIfEmulatorUsed($reason = null) self::markTestSkipped($reason ?: 'This test is not supported by the emulator.'); } } - - protected static function getCacheItemPool() - { - return new FilesystemAdapter( - directory: __DIR__ . '/../../../../.cache' - ); - } } diff --git a/Spanner/src/Result.php b/Spanner/src/Result.php index 482dc7b82de8..43d66775edfe 100644 --- a/Spanner/src/Result.php +++ b/Spanner/src/Result.php @@ -520,7 +520,7 @@ private function setSnapshotOrTransaction(array $result): void [], $this->mapper ); - if (isset($result['precommitToken'])) { + if (isset($result['precommitToken']['precommitToken'])) { // @TODO: Can we move this logic to the serializer or value mapper? $this->transaction->setPrecommitToken( (new MultiplexedSessionPrecommitToken()) diff --git a/Spanner/tests/System/AdminTest.php b/Spanner/tests/System/AdminTest.php index fa2790440775..383c60a0eeba 100644 --- a/Spanner/tests/System/AdminTest.php +++ b/Spanner/tests/System/AdminTest.php @@ -19,6 +19,7 @@ use Google\Cloud\Core\Exception\FailedPreconditionException; use Google\Cloud\Core\LongRunning\LongRunningOperation; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient; use Google\Cloud\Spanner\Admin\Database\V1\DatabaseDialect; use Google\Cloud\Spanner\Admin\Instance\V1\Client\InstanceAdminClient; @@ -31,8 +32,10 @@ * @group spanner * @group admin */ -class AdminTest extends SpannerTestCase +class AdminTest extends SystemTestCase { + use SystemTestCaseTrait; + /** * @beforeClass */ @@ -123,15 +126,7 @@ public function testDatabase() $this->assertInstanceOf(Database::class, current($database)); $this->assertTrue($db->exists()); - - $expectedDatabaseDialect = DatabaseDialect::GOOGLE_STANDARD_SQL; - - // TODO: Remove this, when the emulator supports PGSQL - if ((bool) getenv('SPANNER_EMULATOR_HOST')) { - $expectedDatabaseDialect = DatabaseDialect::DATABASE_DIALECT_UNSPECIFIED; - } - - $this->assertEquals($db->info()['databaseDialect'], $expectedDatabaseDialect); + $this->assertEquals($db->info()['databaseDialect'], DatabaseDialect::GOOGLE_STANDARD_SQL); $stmt = "CREATE TABLE Ids (\n" . " id INT64 NOT NULL,\n" . diff --git a/Spanner/tests/System/BackupTest.php b/Spanner/tests/System/BackupTest.php index 6b3dcbf55bd4..1e91d8076859 100644 --- a/Spanner/tests/System/BackupTest.php +++ b/Spanner/tests/System/BackupTest.php @@ -20,6 +20,7 @@ use Google\Cloud\Core\Exception\BadRequestException; use Google\Cloud\Core\Exception\ConflictException; use Google\Cloud\Core\LongRunning\LongRunningOperation; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient; use Google\Cloud\Spanner\Admin\Database\V1\CreateBackupEncryptionConfig; use Google\Cloud\Spanner\Admin\Database\V1\EncryptionInfo\Type; @@ -30,8 +31,10 @@ /** * @group spanner */ -class BackupTest extends SpannerTestCase +class BackupTest extends SystemTestCase { + use SystemTestCaseTrait; + const BACKUP_PREFIX = 'spanner_backup_'; protected static $backupId1; @@ -47,7 +50,7 @@ class BackupTest extends SpannerTestCase protected static $project; - private static $hasSetUp = false; + private static $hasSetUpBackup = false; /** * @beforeClass @@ -59,7 +62,7 @@ public static function setUpTestFixtures(): void self::emulatorOnly(); self::setUpTestDatabase(); - if (self::$hasSetUp) { + if (self::$hasSetUpBackup) { return; } @@ -112,7 +115,7 @@ public static function setUpTestFixtures(): void self::$backupId1 = uniqid(self::BACKUP_PREFIX); self::$backupId2 = uniqid('users-'); self::$copyBackupId = uniqid('copy-'); - self::$hasSetUp = true; + self::$hasSetUpBackup = true; } public function testCreateBackup() diff --git a/Spanner/tests/System/BatchTest.php b/Spanner/tests/System/BatchTest.php index f90537099581..651e97682e66 100644 --- a/Spanner/tests/System/BatchTest.php +++ b/Spanner/tests/System/BatchTest.php @@ -18,6 +18,7 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Admin\Database\V1\DatabaseDialect; use Google\Cloud\Spanner\Batch\BatchClient; use Google\Cloud\Spanner\Batch\BatchSnapshot; @@ -28,8 +29,9 @@ * @group spanner * @group spanner-batch */ -class BatchTest extends SpannerTestCase +class BatchTest extends SystemTestCase { + use SystemTestCaseTrait; use DatabaseRoleTrait; private static $tableName; @@ -56,26 +58,26 @@ public static function setUpTestFixtures(): void ))->pollUntilComplete(); if (self::$database->info()['databaseDialect'] == DatabaseDialect::GOOGLE_STANDARD_SQL) { - self::$database->updateDdlBatch([ - sprintf( - 'CREATE ROLE %s', - self::$dbRole - ), - sprintf( - 'CREATE ROLE %s', - self::$restrictiveDbRole - ), - sprintf( + $statements = [ + sprintf('CREATE ROLE %s', self::$dbRole), + sprintf('CREATE ROLE %s', self::$restrictiveDbRole), + ]; + + if (!self::isEmulatorUsed()) { + $statements[] = sprintf( 'GRANT SELECT(id) ON TABLE %s TO ROLE %s', self::$tableName, self::$restrictiveDbRole - ), - sprintf( - 'GRANT SELECT ON TABLE %s TO ROLE %s', - self::$tableName, - self::$dbRole - ) - ])->pollUntilComplete(); + ); + } + + $statements[] = sprintf( + 'GRANT SELECT ON TABLE %s TO ROLE %s', + self::$tableName, + self::$dbRole + ); + + self::$database->updateDdlBatch($statements)->pollUntilComplete(); } self::seedTable(); diff --git a/Spanner/tests/System/BatchWriteTest.php b/Spanner/tests/System/BatchWriteTest.php index 2bc30b34bd60..a6e93f74f99f 100644 --- a/Spanner/tests/System/BatchWriteTest.php +++ b/Spanner/tests/System/BatchWriteTest.php @@ -18,12 +18,15 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Rpc\Code; +use Google\Cloud\Core\Testing\System\SystemTestCase; /** * @group spanner */ -class BatchWriteTest extends SpannerTestCase +class BatchWriteTest extends SystemTestCase { + use SystemTestCaseTrait; + const TABLE_NAME = 'BatchWrites'; /** * @beforeClass diff --git a/Spanner/tests/System/DatabaseRoleTrait.php b/Spanner/tests/System/DatabaseRoleTrait.php index b602d8bb666d..123749a87056 100644 --- a/Spanner/tests/System/DatabaseRoleTrait.php +++ b/Spanner/tests/System/DatabaseRoleTrait.php @@ -46,7 +46,7 @@ public function insertDbProvider() self::getDbWithRestrictiveRole(), [ 'id' => rand(1, 346464), - 'name' => uniqid(SpannerTestCase::TESTING_PREFIX), + 'name' => uniqid(self::TESTING_PREFIX), 'birthday' => new Date(new \DateTime('2000-01-01')) ], 'PERMISSION_DENIED' @@ -55,7 +55,7 @@ public function insertDbProvider() self::getDbWithRestrictiveRole(), [ 'id' => rand(1, 346464), - 'name' => uniqid(SpannerTestCase::TESTING_PREFIX) + 'name' => uniqid(self::TESTING_PREFIX) ], null ] diff --git a/Spanner/tests/System/GeneratedAdminEmulatorTest.php b/Spanner/tests/System/GeneratedAdminEmulatorTest.php index cef39e7faef7..fe86fdbe6de2 100644 --- a/Spanner/tests/System/GeneratedAdminEmulatorTest.php +++ b/Spanner/tests/System/GeneratedAdminEmulatorTest.php @@ -17,6 +17,7 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient; use Google\Cloud\Spanner\Admin\Database\V1\CreateDatabaseRequest; use Google\Cloud\Spanner\Admin\Database\V1\GetDatabaseRequest; @@ -28,8 +29,10 @@ /** * @group spanner */ -class GeneratedAdminEmulatorTest extends SpannerTestCase +class GeneratedAdminEmulatorTest extends SystemTestCase { + use SystemTestCaseTrait; + private static $projectId; /** @@ -42,9 +45,7 @@ public static function setUpTestFixtures(): void public function testAdminClientEmulatorSupport() { - if (!getenv('SPANNER_EMULATOR_HOST')) { - self::markTestSkipped('This test is required to run only in the emulator.'); - } + self::emulatorOnly(); $instanceId = uniqid(self::INSTANCE_NAME); $databaseId = uniqid(self::TESTING_PREFIX); diff --git a/Spanner/tests/System/LargeReadTest.php b/Spanner/tests/System/LargeReadTest.php index d54583db0822..cf9530f7280c 100644 --- a/Spanner/tests/System/LargeReadTest.php +++ b/Spanner/tests/System/LargeReadTest.php @@ -17,6 +17,7 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Bytes; use Google\Cloud\Spanner\KeySet; @@ -24,8 +25,10 @@ * @group spanner * @group spanner-large-read */ -class LargeReadTest extends SpannerTestCase +class LargeReadTest extends SystemTestCase { + use SystemTestCaseTrait; + private static $tableName; private static $row = []; diff --git a/Spanner/tests/System/OperationsTest.php b/Spanner/tests/System/OperationsTest.php index 82a6a645210e..ca21dc7e375c 100644 --- a/Spanner/tests/System/OperationsTest.php +++ b/Spanner/tests/System/OperationsTest.php @@ -17,6 +17,7 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Core\Exception\ServiceException; use Google\Cloud\Spanner\Date; use Google\Cloud\Spanner\Timestamp; @@ -24,9 +25,10 @@ /** * @group spanner */ -class OperationsTest extends SpannerTestCase +class OperationsTest extends SystemTestCase { use DatabaseRoleTrait; + use SystemTestCaseTrait; private static $id1; private static $id2; diff --git a/Spanner/tests/System/PartitionedDmlTest.php b/Spanner/tests/System/PartitionedDmlTest.php index 7f512c884b1f..ecf4b3fb6f1a 100644 --- a/Spanner/tests/System/PartitionedDmlTest.php +++ b/Spanner/tests/System/PartitionedDmlTest.php @@ -17,12 +17,16 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Testing\System\SystemTestCase; + /** * @group spanner * @group spanner-pdml */ -class PartitionedDmlTest extends SpannerTestCase +class PartitionedDmlTest extends SystemTestCase { + use SystemTestCaseTrait; + const PDML_TABLE = 'partitionedDml'; /** diff --git a/Spanner/tests/System/PgBatchTest.php b/Spanner/tests/System/PgBatchTest.php index 15d592491be2..7849bc2fa334 100644 --- a/Spanner/tests/System/PgBatchTest.php +++ b/Spanner/tests/System/PgBatchTest.php @@ -18,6 +18,7 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Admin\Database\V1\DatabaseDialect; use Google\Cloud\Spanner\Batch\BatchClient; use Google\Cloud\Spanner\Batch\BatchSnapshot; @@ -27,19 +28,24 @@ * @group spanner-batch * @group spanner-postgres */ -class PgBatchTest extends SpannerPgTestCase +class PgBatchTest extends SystemTestCase { + use PgSystemTestCaseTrait; use DatabaseRoleTrait; private static $tableName; - private static $isSetup = false; + private static $hasSetupBatch = false; /** * @beforeClass */ public static function setUpTestFixtures(): void { - if (self::$isSetup) { + // Skip setting up fixutres for the emulator as there's only one test which does not suppport the emulator. + // NOTE: remove this if new tests tests are added which support the emulator. + self::skipEmulatorTests(); + + if (self::$hasSetupBatch) { return; } self::setUpTestDatabase(); @@ -55,30 +61,29 @@ public static function setUpTestFixtures(): void ))->pollUntilComplete(); if (self::$database->info()['databaseDialect'] == DatabaseDialect::POSTGRESQL) { - self::$database->updateDdlBatch([ - sprintf( - 'CREATE ROLE %s', - self::$dbRole - ), - sprintf( - 'CREATE ROLE %s', - self::$restrictiveDbRole - ), - sprintf( + $statements = [ + sprintf('CREATE ROLE %s', self::$dbRole), + sprintf('CREATE ROLE %s', self::$restrictiveDbRole), + ]; + + if (!self::isEmulatorUsed()) { + $statements[] = sprintf( 'GRANT SELECT(id) ON TABLE %s TO %s', self::$tableName, self::$restrictiveDbRole - ), - sprintf( + ); + $statements[] = sprintf( 'GRANT SELECT ON TABLE %s TO %s', self::$tableName, self::$dbRole - ) - ])->pollUntilComplete(); + ); + } + + self::$database->updateDdlBatch($statements)->pollUntilComplete(); } self::seedTable(); - self::$isSetup = true; + self::$hasSetupBatch = true; } /** diff --git a/Spanner/tests/System/PgBatchWriteTest.php b/Spanner/tests/System/PgBatchWriteTest.php index 69bbe39a7fcb..ffd775daaeeb 100644 --- a/Spanner/tests/System/PgBatchWriteTest.php +++ b/Spanner/tests/System/PgBatchWriteTest.php @@ -17,14 +17,17 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Rpc\Code; /** * @group spanner * @group spanner-postgres */ -class PgBatchWriteTest extends SpannerPgTestCase +class PgBatchWriteTest extends SystemTestCase { + use PgSystemTestCaseTrait; + const TABLE_NAME = 'BatchWrites'; /** * @beforeClass diff --git a/Spanner/tests/System/PgOperationsTest.php b/Spanner/tests/System/PgOperationsTest.php index 016a1407eb97..b9fb6c88b120 100644 --- a/Spanner/tests/System/PgOperationsTest.php +++ b/Spanner/tests/System/PgOperationsTest.php @@ -18,6 +18,7 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Date; /** @@ -25,9 +26,10 @@ * @group spanner-operations * @group spanner-postgres */ -class PgOperationsTest extends SpannerPgTestCase +class PgOperationsTest extends SystemTestCase { use DatabaseRoleTrait; + use PgSystemTestCaseTrait; private static $row = []; diff --git a/Spanner/tests/System/PgPartitionedDmlTest.php b/Spanner/tests/System/PgPartitionedDmlTest.php index 840cbcdad7e6..48bce3dbf0e2 100644 --- a/Spanner/tests/System/PgPartitionedDmlTest.php +++ b/Spanner/tests/System/PgPartitionedDmlTest.php @@ -17,13 +17,17 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Testing\System\SystemTestCase; + /** * @group spanner * @group spanner-pdml * @group spanner-postgres */ -class PgPartitionedDmlTest extends SpannerPgTestCase +class PgPartitionedDmlTest extends SystemTestCase { + use PgSystemTestCaseTrait; + const PDML_TABLE = 'partitionedDml'; /** diff --git a/Spanner/tests/System/PgQueryTest.php b/Spanner/tests/System/PgQueryTest.php index 2bcf5419c9f6..9129fec7fb51 100644 --- a/Spanner/tests/System/PgQueryTest.php +++ b/Spanner/tests/System/PgQueryTest.php @@ -19,6 +19,7 @@ use Google\Cloud\Core\Exception\BadRequestException; use Google\Cloud\Core\Int64; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\ArrayType; use Google\Cloud\Spanner\Bytes; use Google\Cloud\Spanner\Database; @@ -35,8 +36,10 @@ * @group spanner-query * @group spanner-postgres */ -class PgQueryTest extends SpannerPgTestCase +class PgQueryTest extends SystemTestCase { + use PgSystemTestCaseTrait; + const TABLE_NAME = 'test'; public static $timestampVal; diff --git a/Spanner/tests/System/PgReadTest.php b/Spanner/tests/System/PgReadTest.php index b4a9b6600ae8..317c9b36895f 100644 --- a/Spanner/tests/System/PgReadTest.php +++ b/Spanner/tests/System/PgReadTest.php @@ -19,6 +19,7 @@ use Google\Cloud\Core\Exception\DeadlineExceededException; use Google\Cloud\Core\Exception\NotFoundException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\KeyRange; use Google\Cloud\Spanner\KeySet; @@ -27,8 +28,10 @@ * @group spanner-read * @group spanner-postgres */ -class PgReadTest extends SpannerPgTestCase +class PgReadTest extends SystemTestCase { + use PgSystemTestCaseTrait; + private static $readTableName; private static $rangeTableName; private static $indexes = []; diff --git a/Spanner/tests/System/PgSystemTestCaseTrait.php b/Spanner/tests/System/PgSystemTestCaseTrait.php new file mode 100644 index 000000000000..4acf8ec3d0c9 --- /dev/null +++ b/Spanner/tests/System/PgSystemTestCaseTrait.php @@ -0,0 +1,78 @@ +instance(self::INSTANCE_NAME); + + self::$dbName = uniqid(self::TESTING_PREFIX); + + // create a PG DB first + $op = self::$instance->createDatabase(self::$dbName, [ + 'databaseDialect' => DatabaseDialect::POSTGRESQL + ]); + // wait for the DB to be ready + $op->pollUntilComplete(); + + $db = self::getDatabaseInstance(self::$dbName); + + self::$deletionQueue->add(function () use ($db) { + $db->drop(); + }); + + self::$database = $db; + + $db->updateDdlBatch( + [ + 'CREATE TABLE ' . self::TEST_TABLE_NAME . ' ( + id bigint PRIMARY KEY, + name varchar(1024) NOT NULL, + birthday date + )', + ] + )->pollUntilComplete(); + + // Currently, the emulator doesn't support setting roles for the PG + // dialect. + if (!self::isEmulatorUsed()) { + $db->updateDdlBatch( + [ + 'CREATE ROLE ' . self::DATABASE_ROLE, + 'CREATE ROLE ' . self::RESTRICTIVE_DATABASE_ROLE, + 'GRANT SELECT ON TABLE ' . self::TEST_TABLE_NAME . + ' TO ' . self::DATABASE_ROLE, + 'GRANT SELECT(id, name), INSERT(id, name), UPDATE(id, name) ON TABLE ' + . self::TEST_TABLE_NAME . ' TO ' . self::RESTRICTIVE_DATABASE_ROLE, + ] + )->pollUntilComplete(); + } + + self::$hasSetUp = true; + } +} diff --git a/Spanner/tests/System/PgTransactionTest.php b/Spanner/tests/System/PgTransactionTest.php index 187211b69e80..e0718a5f07d7 100644 --- a/Spanner/tests/System/PgTransactionTest.php +++ b/Spanner/tests/System/PgTransactionTest.php @@ -18,6 +18,7 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Date; use Google\Cloud\Spanner\KeySet; use Google\Cloud\Spanner\Timestamp; @@ -28,9 +29,10 @@ * @group spanner-transaction * @group spanner-postgres */ -class PgTransactionTest extends SpannerPgTestCase +class PgTransactionTest extends SystemTestCase { use DatabaseRoleTrait; + use PgSystemTestCaseTrait; private static $row = []; diff --git a/Spanner/tests/System/PgWriteTest.php b/Spanner/tests/System/PgWriteTest.php index 1217716956e7..5cb8be03f341 100644 --- a/Spanner/tests/System/PgWriteTest.php +++ b/Spanner/tests/System/PgWriteTest.php @@ -20,6 +20,7 @@ use Google\Cloud\Core\Exception\BadRequestException; use Google\Cloud\Core\Exception\FailedPreconditionException; use Google\Cloud\Core\Exception\NotFoundException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Spanner\Bytes; use Google\Cloud\Spanner\CommitTimestamp; @@ -35,8 +36,9 @@ * @group spanner-write * @group spanner-postgres */ -class PgWriteTest extends SpannerPgTestCase +class PgWriteTest extends SystemTestCase { + use PgSystemTestCaseTrait; use TimeTrait; const TABLE_NAME = 'Writes'; diff --git a/Spanner/tests/System/QueryTest.php b/Spanner/tests/System/QueryTest.php index 8016b1138a60..4aa5a2b45de8 100644 --- a/Spanner/tests/System/QueryTest.php +++ b/Spanner/tests/System/QueryTest.php @@ -19,6 +19,7 @@ use Google\Cloud\Core\Exception\BadRequestException; use Google\Cloud\Core\Int64; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\ArrayType; use Google\Cloud\Spanner\Bytes; use Google\Cloud\Spanner\Database; @@ -35,8 +36,10 @@ * @group spanner * @group spanner-query */ -class QueryTest extends SpannerTestCase +class QueryTest extends SystemTestCase { + use SystemTestCaseTrait; + /** * @beforeClass */ diff --git a/Spanner/tests/System/ReadTest.php b/Spanner/tests/System/ReadTest.php index c96528c475c7..7c8c314e40e5 100644 --- a/Spanner/tests/System/ReadTest.php +++ b/Spanner/tests/System/ReadTest.php @@ -21,6 +21,7 @@ use Google\Cloud\Core\Exception\ConflictException; use Google\Cloud\Core\Exception\DeadlineExceededException; use Google\Cloud\Core\Exception\NotFoundException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Database; use Google\Cloud\Spanner\KeyRange; use Google\Cloud\Spanner\KeySet; @@ -31,8 +32,10 @@ * @group spanner * @group spanner-read */ -class ReadTest extends SpannerTestCase +class ReadTest extends SystemTestCase { + use SystemTestCaseTrait; + private static $readTableName; private static $rangeTableName; private static $indexes = []; diff --git a/Spanner/tests/System/SnapshotTest.php b/Spanner/tests/System/SnapshotTest.php index 6cb2fbc966ff..780eaca1bf5d 100644 --- a/Spanner/tests/System/SnapshotTest.php +++ b/Spanner/tests/System/SnapshotTest.php @@ -18,6 +18,7 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Cloud\Core\Exception\BadRequestException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\KeySet; use Google\Cloud\Spanner\Timestamp; use Google\Cloud\Spanner\V1\ReadRequest\LockHint; @@ -28,8 +29,10 @@ * @group spanner * @group spanner-snapshot */ -class SnapshotTest extends SpannerTestCase +class SnapshotTest extends SystemTestCase { + use SystemTestCaseTrait; + const TABLE_NAME = 'Snapshots'; private static $tableName; diff --git a/Spanner/tests/System/SpannerPgTestCase.php b/Spanner/tests/System/SpannerPgTestCase.php deleted file mode 100644 index 45c8eaab85e3..000000000000 --- a/Spanner/tests/System/SpannerPgTestCase.php +++ /dev/null @@ -1,199 +0,0 @@ -instance(self::INSTANCE_NAME); - - self::$dbName = uniqid(self::TESTING_PREFIX); - - // create a PG DB first - $op = self::$instance->createDatabase(self::$dbName, [ - 'databaseDialect' => DatabaseDialect::POSTGRESQL - ]); - // wait for the DB to be ready - $op->pollUntilComplete(); - - $db = self::getDatabaseInstance(self::$dbName); - - self::$deletionQueue->add(function () use ($db) { - $db->drop(); - }); - - self::$database = $db; - self::$database2 = self::getDatabaseInstance(self::$dbName); - - $db->updateDdlBatch( - [ - 'CREATE TABLE ' . self::TEST_TABLE_NAME . ' ( - id bigint PRIMARY KEY, - name varchar(1024) NOT NULL, - birthday date - )', - ] - )->pollUntilComplete(); - - // Currently, the emulator doesn't support setting roles for the PG - // dialect. - if (!getenv('SPANNER_EMULATOR_HOST')) { - $db->updateDdlBatch( - [ - 'CREATE ROLE ' . self::DATABASE_ROLE, - 'CREATE ROLE ' . self::RESTRICTIVE_DATABASE_ROLE, - 'GRANT SELECT ON TABLE ' . self::TEST_TABLE_NAME . - ' TO ' . self::DATABASE_ROLE, - 'GRANT SELECT(id, name), INSERT(id, name), UPDATE(id, name) ON TABLE ' - . self::TEST_TABLE_NAME . ' TO ' . self::RESTRICTIVE_DATABASE_ROLE, - ] - )->pollUntilComplete(); - } - - self::$hasSetUp = true; - } - - public static function getDatabaseFromInstance($instance, $dbName, $options = []) - { - $instance = self::$client->instance($instance); - return $instance->database($dbName, $options); - } - - public static function getDatabaseWithSessionPool($dbName, $options = []) - { - $sessionCache = new MemoryCacheItemPool(); - $sessionPool = new CacheSessionPool( - $sessionCache, - $options - ); - - return self::$client->connect( - self::INSTANCE_NAME, - $dbName, - [ - 'sessionPool' => $sessionPool - ] - ); - } - - public static function getDatabaseInstance($dbName) - { - return self::$client->connect(self::INSTANCE_NAME, $dbName); - } - - public static function skipEmulatorTests() - { - if ((bool) getenv('SPANNER_EMULATOR_HOST')) { - self::markTestSkipped('This test is not supported by the emulator.'); - } - } - - public static function getDbWithReaderRole() - { - return self::getDatabaseFromInstance( - self::INSTANCE_NAME, - self::$dbName, - ['databaseRole' => self::DATABASE_ROLE] - ); - } - - public static function getDbWithRestrictiveRole() - { - return self::getDatabaseFromInstance( - self::INSTANCE_NAME, - self::$dbName, - ['databaseRole' => self::RESTRICTIVE_DATABASE_ROLE] - ); - } - - public static function getDbWithSessionPoolRestrictiveRole() - { - return self::getDatabaseWithSessionPool( - self::$dbName, - ['minSessions' => 1, 'maxSession' => 2, 'databaseRole' => self::RESTRICTIVE_DATABASE_ROLE] - ); - } - - private static function getClient() - { - if (self::$client) { - return self::$client; - } - - $keyFilePath = getenv('GOOGLE_CLOUD_PHP_TESTS_KEY_PATH'); - - $clientConfig = [ - 'keyFilePath' => $keyFilePath, - 'cacheItemPool' => self::getCacheItemPool(), - ]; - - $serviceAddress = getenv('SPANNER_SERVICE_ADDRESS'); - if ($serviceAddress) { - $gapicConfig = [ - 'serviceAddress' => $serviceAddress - ]; - - $clientConfig['gapicSpannerClient'] = new Spanner\V1\SpannerClient($gapicConfig); - $clientConfig['gapicSpannerDatabaseAdminClient'] = - new Spanner\Admin\Database\V1\DatabaseAdminClient($gapicConfig); - $clientConfig['gapicSpannerInstanceAdminClient'] = - new Spanner\Admin\Instance\V1\InstanceAdminClient($gapicConfig); - - echo 'Using Service Address: ' . $serviceAddress . PHP_EOL; - } - - self::$client = new SpannerClient($clientConfig); - - return self::$client; - } -} diff --git a/Spanner/tests/System/SpannerTestCase.php b/Spanner/tests/System/SystemTestCaseTrait.php similarity index 70% rename from Spanner/tests/System/SpannerTestCase.php rename to Spanner/tests/System/SystemTestCaseTrait.php index 7566789b4b3f..4dbb4b1f36cf 100644 --- a/Spanner/tests/System/SpannerTestCase.php +++ b/Spanner/tests/System/SystemTestCaseTrait.php @@ -1,6 +1,6 @@ $keyFilePath, + 'cacheItemPool' => self::getCacheItemPool(), + ]; - private static $hasSetUp = false; + $serviceAddress = getenv('SPANNER_SERVICE_ADDRESS'); + if ($serviceAddress) { + $gapicConfig = [ + 'serviceAddress' => $serviceAddress + ]; + + $clientConfig['gapicSpannerClient'] = new SpannerGapicClient($gapicConfig); + $clientConfig['gapicSpannerDatabaseAdminClient'] = + new DatabaseAdminClient($gapicConfig); + $clientConfig['gapicSpannerInstanceAdminClient'] = + new InstanceAdminClient($gapicConfig); + + echo 'Using Service Address: ' . $serviceAddress . PHP_EOL; + } - protected static function setUpTestDatabase(): void + return self::$client = new SpannerClient($clientConfig); + } + + private static function setUpTestDatabase(): void { if (self::$hasSetUp) { return; } - self::getClient(); - - self::$instance = self::$client->instance(self::INSTANCE_NAME); + self::$instance = self::getClient()->instance(self::INSTANCE_NAME); if (!self::$dbName = getenv('GOOGLE_CLOUD_SPANNER_TEST_DATABASE')) { self::$dbName = uniqid(self::TESTING_PREFIX); @@ -78,7 +103,9 @@ protected static function setUpTestDatabase(): void ); $op->pollUntilComplete(); - if (self::$database->info()['databaseDialect'] == DatabaseDialect::GOOGLE_STANDARD_SQL) { + if (self::$database->info()['databaseDialect'] == DatabaseDialect::GOOGLE_STANDARD_SQL + && !self::isEmulatorUsed() + ) { self::$database->updateDdlBatch( [ 'CREATE ROLE ' . self::DATABASE_ROLE, @@ -92,55 +119,15 @@ protected static function setUpTestDatabase(): void } } - self::$database2 = self::getDatabaseInstance(self::$dbName); self::$hasSetUp = true; } - private static function getClient() - { - if (self::$client) { - return self::$client; - } - - $keyFilePath = getenv('GOOGLE_CLOUD_PHP_TESTS_KEY_PATH'); - - $clientConfig = [ - 'keyFilePath' => $keyFilePath, - 'cacheItemPool' => self::getCacheItemPool(), - ]; - - $serviceAddress = getenv('SPANNER_SERVICE_ADDRESS'); - if ($serviceAddress) { - $gapicConfig = [ - 'serviceAddress' => $serviceAddress - ]; - - $clientConfig['gapicSpannerClient'] = new Spanner\V1\Client\SpannerClient($gapicConfig); - $clientConfig['gapicSpannerDatabaseAdminClient'] = - new Spanner\Admin\Database\V1\Client\DatabaseAdminClient($gapicConfig); - $clientConfig['gapicSpannerInstanceAdminClient'] = - new Spanner\Admin\Instance\V1\Client\InstanceAdminClient($gapicConfig); - - echo 'Using Service Address: ' . $serviceAddress . PHP_EOL; - } - - self::$client = new SpannerClient($clientConfig); - - return self::$client; - } - - public static function getDatabaseInstance($dbName, $options = []) + private static function getDatabaseInstance($dbName, $options = []) { return self::getClient()->connect(self::INSTANCE_NAME, $dbName, $options); } - public static function getDatabaseFromInstance($instance, $dbName, $options = []) - { - $instance = self::$client->instance($instance); - return $instance->database($dbName, $options); - } - - public static function skipEmulatorTests() + private static function skipEmulatorTests() { if (self::isEmulatorUsed()) { self::markTestSkipped('This test is not supported by the emulator.'); @@ -159,7 +146,7 @@ public static function isEmulatorUsed(): bool return (bool) getenv('SPANNER_EMULATOR_HOST'); } - public static function getDbWithReaderRole() + private static function getDbWithReaderRole() { return self::getDatabaseFromInstance( self::INSTANCE_NAME, @@ -168,7 +155,7 @@ public static function getDbWithReaderRole() ); } - public static function getDbWithRestrictiveRole() + private static function getDbWithRestrictiveRole() { return self::getDatabaseFromInstance( self::INSTANCE_NAME, @@ -176,4 +163,17 @@ public static function getDbWithRestrictiveRole() ['databaseRole' => self::RESTRICTIVE_DATABASE_ROLE] ); } + + private static function getDatabaseFromInstance($instance, $dbName, $options = []) + { + $instance = self::getClient()->instance($instance); + return $instance->database($dbName, $options); + } + + private static function getCacheItemPool() + { + return new FilesystemAdapter( + directory: __DIR__ . '/../../../.cache' + ); + } } diff --git a/Spanner/tests/System/TransactionTest.php b/Spanner/tests/System/TransactionTest.php index 121e2f1b1398..c74ac820b72c 100644 --- a/Spanner/tests/System/TransactionTest.php +++ b/Spanner/tests/System/TransactionTest.php @@ -18,6 +18,7 @@ namespace Google\Cloud\Spanner\Tests\System; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Spanner\Date; use Google\Cloud\Spanner\KeySet; use Google\Cloud\Spanner\Timestamp; @@ -33,9 +34,11 @@ * @group spanner * @group spanner-transaction */ -class TransactionTest extends SpannerTestCase +class TransactionTest extends SystemTestCase { use DatabaseRoleTrait; + use SystemTestCaseTrait; + const TABLE_NAME = 'Transactions'; @@ -176,7 +179,6 @@ public function testAbortedErrorCausesRetry() } $db = self::$database; - $db2 = self::$database2; $id = $this->randId(); $db->insert(self::$tableName, [ diff --git a/Spanner/tests/System/UniverseDomainTest.php b/Spanner/tests/System/UniverseDomainTest.php index c010f4cef4fb..23f9aaa59f8d 100644 --- a/Spanner/tests/System/UniverseDomainTest.php +++ b/Spanner/tests/System/UniverseDomainTest.php @@ -24,11 +24,9 @@ class UniverseDomainTest extends SystemTestCase { - private static $client; - private static $instance; + use SystemTestCaseTrait; + private static $instanceId; - private static $database; - private static $dbName; private static $tableName; /** @@ -52,9 +50,9 @@ public static function setUpTestFixtures(): void ]); // Create a unique instance ID for this test - self::$instanceId = uniqid(SpannerTestCase::INSTANCE_NAME); - self::$dbName = uniqid(SpannerTestCase::TESTING_PREFIX); - self::$tableName = uniqid(SpannerTestCase::TESTING_PREFIX); + self::$instanceId = uniqid(self::INSTANCE_NAME); + self::$dbName = uniqid(self::TESTING_PREFIX); + self::$tableName = uniqid(self::TESTING_PREFIX); } /** diff --git a/Spanner/tests/System/WriteTest.php b/Spanner/tests/System/WriteTest.php index 2d63db8a23e6..ef0d17979fa9 100644 --- a/Spanner/tests/System/WriteTest.php +++ b/Spanner/tests/System/WriteTest.php @@ -20,6 +20,7 @@ use Google\Cloud\Core\Exception\BadRequestException; use Google\Cloud\Core\Exception\FailedPreconditionException; use Google\Cloud\Core\Exception\NotFoundException; +use Google\Cloud\Core\Testing\System\SystemTestCase; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Spanner\Bytes; use Google\Cloud\Spanner\CommitTimestamp; @@ -36,9 +37,10 @@ * @group spanner * @group spanner-write */ -class WriteTest extends SpannerTestCase +class WriteTest extends SystemTestCase { use TimeTrait; + use SystemTestCaseTrait; const TABLE_NAME = 'Writes'; const COMMIT_TIMESTAMP_TABLE_NAME = 'CommitTimestamps'; diff --git a/Spanner/tests/System/pcntl/AbortedErrorCausesRetry.php b/Spanner/tests/System/pcntl/AbortedErrorCausesRetry.php index 9dfbb3639f86..6c4389b49cc9 100644 --- a/Spanner/tests/System/pcntl/AbortedErrorCausesRetry.php +++ b/Spanner/tests/System/pcntl/AbortedErrorCausesRetry.php @@ -4,53 +4,68 @@ include __DIR__ . '/forked-process-test.php'; use Google\Cloud\Core\Exception\AbortedException; -use Google\Cloud\Spanner\Tests\System\SpannerTestCase; +use Google\Cloud\Spanner\Tests\System\SystemTestCaseTrait; list($dbName, $tableName, $id) = getInputArgs(); $delay = 5000; -if ($childPID1 = pcntl_fork()) { - usleep($delay); - $iteration = 0; - $db1 = SpannerTestCase::getDatabaseInstance($dbName); - $db1->runTransaction(function ($t) use ($id, $tableName, $delay, &$iteration) { - $iteration++; - usleep(2 * $delay); - $row = $t->execute('SELECT id, number FROM ' . $tableName . ' WHERE ID = @id', [ - 'parameters' => ['id' => (int) $id] - ])->rows()->current(); - - if ($iteration === 1) { - throw new AbortedException('foo', 409, null, [ - [ - 'retryDelay' => [ - 'seconds' => 1, - 'nanos' => 0 - ] - ] - ]); +$abortedErrorRetry = new class($dbName, $tableName, $id, $delay) { + use SystemTestCaseTrait; + + public function __construct( + string $dbName, + private string $tableName, + private int $id, + private int $delay, + ) { + self::$dbName = $dbName; + } + + public function run(): int + { + if ($childPID1 = pcntl_fork()) { + usleep($this->delay); + $iteration = 0; + $db1 = self::getDatabaseInstance(self::$dbName); + $db1->runTransaction(function ($t) use (&$iteration) { + $iteration++; + usleep(2 * $this->delay); + $row = $t->execute('SELECT id, number FROM ' . $this->tableName . ' WHERE ID = @id', [ + 'parameters' => ['id' => $this->id] + ])->rows()->current(); + + if ($iteration === 1) { + throw new AbortedException('foo', 409, null, [ + [ + 'retryDelay' => [ + 'seconds' => 1, + 'nanos' => 0 + ] + ] + ]); + } + $row['number'] += 1; + $t->update($this->tableName, $row); + $t->commit(); + }); + + echo $iteration; + pcntl_waitpid($childPID1, $status1); + } else { + $db2 = self::getDatabaseInstance(self::$dbName); + $db2->runTransaction(function ($t) { + $row = $t->execute('SELECT id, number FROM ' . $this->tableName . ' WHERE ID = @id', [ + 'parameters' => ['id' => $this->id] + ])->rows()->current(); + + $row['number'] += 1; + $t->update($this->tableName, $row); + $t->commit(); + }); } - $row['number'] += 1; - $t->update($tableName, $row); - $t->commit(); - }); - - echo $iteration; - pcntl_waitpid($childPID1, $status1); -} else { - $db2 = SpannerTestCase::getDatabaseInstance($dbName); - $db2->runTransaction(function ($t) use ($id, $tableName) { - $row = $t->execute('SELECT id, number FROM ' . $tableName . ' WHERE ID = @id', [ - 'parameters' => ['id' => (int) $id] - ])->rows()->current(); - - $row['number'] += 1; - $t->update($tableName, $row); - $t->commit(); - }); - - exit(0); -} - -exit(0); + return 0; + } +}; + +exit($abortedErrorRetry->run()); diff --git a/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithExecute.php b/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithExecute.php index 5818f0541b50..bc868ab1cb80 100644 --- a/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithExecute.php +++ b/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithExecute.php @@ -3,37 +3,53 @@ include __DIR__ . '/../../../vendor/autoload.php'; include __DIR__ . '/forked-process-test.php'; -use Google\Cloud\Spanner\Tests\System\SpannerTestCase; +use Google\Cloud\Spanner\Tests\System\SystemTestCaseTrait; list($dbName, $tableName, $id) = getInputArgs(); $tmpFile = sys_get_temp_dir() . '/ConcurrentTransactionsIncremementValueWithExecute.txt'; setupIterationTracker($tmpFile); -$callable = function ($dbName, $tableName, $id) use ($tmpFile) { - $iterations = 0; - $db = SpannerTestCase::getDatabaseInstance($dbName); - if (getenv('SPANNER_EMULATOR_HOST')) { - // the emulator requires us to manually request a new session - // presumably because multiplexed sessions aren't properly supported - $db->session()->refresh(); - } - $db->runTransaction(function ($transaction) use ($id, $tableName, &$iterations) { - $iterations++; - - $row = $transaction->execute('SELECT * FROM ' . $tableName . ' WHERE id = @id', [ - 'parameters' => [ - 'id' => (int) $id - ] - ])->rows()->current(); - - $row['number'] += 1; +$concurrentExecute = new class($dbName, $tableName, $id, $tmpFile) { + use SystemTestCaseTrait; - $transaction->update($tableName, $row); - $transaction->commit(); - }); + public function __construct( + string $dbName, + private string $tableName, + private int $id, + private string $tmpFile, + ) { + self::$dbName = $dbName; + } - updateIterationTracker($tmpFile, $iterations); + public function run(): int + { + $iterations = 0; + $db = self::getDatabaseInstance(self::$dbName); + if (self::isEmulatorUsed()) { + // the emulator requires us to manually request a new session + // presumably because multiplexed sessions aren't properly supported + $db->session()->refresh(); + } + $db->runTransaction(function ($transaction) use (&$iterations) { + $iterations++; + + $row = $transaction->execute('SELECT * FROM ' . $this->tableName . ' WHERE id = @id', [ + 'parameters' => [ + 'id' => $this->id, + ] + ])->rows()->current(); + + $row['number'] += 1; + + $transaction->update($this->tableName, $row); + $transaction->commit(); + }); + + updateIterationTracker($this->tmpFile, $iterations); + + return 0; + } }; $delay = 2000; @@ -41,20 +57,17 @@ if ($childPID1 = pcntl_fork()) { usleep($delay); - $callable($dbName, $tableName, $id); + $status = $concurrentExecute->run(); while (pcntl_waitpid($childPID1, $status1, WNOHANG) == 0 && $retryLimit) { usleep(2 * $delay); $retryLimit--; } + + echo file_get_contents($tmpFile); + exit($status); } else { usleep(2 * $delay); - $callable($dbName, $tableName, $id); - - exit(0); + exit($concurrentExecute->run()); } - -echo file_get_contents($tmpFile); - -exit(0); diff --git a/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithRead.php b/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithRead.php index 9ec00ec07bfe..9f83cd433af4 100644 --- a/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithRead.php +++ b/Spanner/tests/System/pcntl/ConcurrentTransactionsIncrementValueWithRead.php @@ -4,7 +4,7 @@ include __DIR__ . '/forked-process-test.php'; use Google\Cloud\Spanner\KeySet; -use Google\Cloud\Spanner\Tests\System\SpannerTestCase; +use Google\Cloud\Spanner\Tests\System\SystemTestCaseTrait; list($dbName, $tableName, $id) = getInputArgs(); @@ -14,25 +14,42 @@ $keyset = new KeySet(['keys' => [$id]]); $columns = ['id', 'number']; -$callable = function ($dbName, KeySet $keyset, array $columns, $tableName) use ($tmpFile) { - $iterations = 0; - $db = SpannerTestCase::getDatabaseInstance($dbName); - if (getenv('SPANNER_EMULATOR_HOST')) { - // the emulator requires us to manually request a new session - // presumably because multiplexed sessions aren't properly supported - $db->session()->refresh(); +$concurrentRead = new class($dbName, $keyset, $columns, $tableName, $tmpFile) { + use SystemTestCaseTrait; + + public function __construct( + string $dbName, + private KeySet $keyset, + private array $columns, + private string $tableName, + private string $tmpFile + ) { + self::$dbName = $dbName; } - $db->runTransaction(function ($transaction) use ($keyset, $columns, $tableName, &$iterations) { - $iterations++; - $row = $transaction->read($tableName, $keyset, $columns)->rows()->current(); - $row['number'] += 1; + public function run(): int + { + $iterations = 0; + $db = self::getDatabaseInstance(self::$dbName); + if (self::isEmulatorUsed()) { + // the emulator requires us to manually request a new session + // presumably because multiplexed sessions aren't properly supported + $db->session()->refresh(); + } + $db->runTransaction(function ($transaction) use (&$iterations) { + $iterations++; + $row = $transaction->read($this->tableName, $this->keyset, $this->columns)->rows()->current(); - $transaction->update($tableName, $row); - $transaction->commit(); - }); + $row['number'] += 1; - updateIterationTracker($tmpFile, $iterations); + $transaction->update($this->tableName, $row); + $transaction->commit(); + }); + + updateIterationTracker($this->tmpFile, $iterations); + + return 0; + } }; $delay = 2000; @@ -40,20 +57,17 @@ if ($childPID1 = pcntl_fork()) { usleep($delay); - $callable($dbName, $keyset, $columns, $tableName); + $status = $concurrentRead->run(); while (pcntl_waitpid($childPID1, $status1, WNOHANG) == 0 && $retryLimit) { usleep(2 * $delay); $retryLimit--; } + + echo file_get_contents($tmpFile); + exit($status); } else { usleep(2 * $delay); - $callable($dbName, $keyset, $columns, $tableName); - - exit(0); + exit($concurrentRead->run()); } - -echo file_get_contents($tmpFile); - -exit(0);