From 4c8059110f45740c5da83b81d046497c5bb085d6 Mon Sep 17 00:00:00 2001 From: Vishwaraj Anand Date: Tue, 28 Mar 2023 14:09:34 +0000 Subject: [PATCH] feat(Spanner): enable drop db protection --- .../src/Connection/ConnectionInterface.php | 5 +++ Spanner/src/Connection/Grpc.php | 16 +++++++ Spanner/src/Database.php | 35 +++++++++++++++ Spanner/tests/System/AdminTest.php | 45 +++++++++++++++++++ Spanner/tests/Unit/DatabaseTest.php | 21 +++++++++ 5 files changed, 122 insertions(+) diff --git a/Spanner/src/Connection/ConnectionInterface.php b/Spanner/src/Connection/ConnectionInterface.php index 52a87f1a35af..d3d7b77369d8 100644 --- a/Spanner/src/Connection/ConnectionInterface.php +++ b/Spanner/src/Connection/ConnectionInterface.php @@ -148,6 +148,11 @@ public function listDatabases(array $args); */ public function createDatabase(array $args); + /** + * @param array $args + */ + public function updateDatabase(array $args); + /** * @param array $args */ diff --git a/Spanner/src/Connection/Grpc.php b/Spanner/src/Connection/Grpc.php index 6c6c9ef483b0..c37fa33d24ab 100644 --- a/Spanner/src/Connection/Grpc.php +++ b/Spanner/src/Connection/Grpc.php @@ -680,6 +680,22 @@ public function createDatabase(array $args) return $this->operationToArray($res, $this->serializer, $this->lroResponseMappers); } + /** + * @param array $args + */ + public function updateDatabase(array $args) + { + $database = $this->pluck('database', $args); + $databaseInfo = $this->serializer->decodeMessage(new Database(), $database); + $databaseName = $databaseInfo->getName(); + $updateMask = $this->serializer->decodeMessage(new FieldMask(), $this->pluck('updateMask', $args)); + return $this->send([$this->getDatabaseAdminClient(), 'updateDatabase'], [ + $databaseInfo, + $updateMask, + $this->addResourcePrefixHeader($args, $databaseName) + ]); + } + /** * @param array $args */ diff --git a/Spanner/src/Database.php b/Spanner/src/Database.php index 0c9f7c23dbc6..34082409a242 100644 --- a/Spanner/src/Database.php +++ b/Spanner/src/Database.php @@ -427,6 +427,41 @@ public function create(array $options = []) return $this->resumeOperation($operation['name'], $operation); } + /** + * Update an existing Cloud Spanner database. + * + * Example: + * ``` + * $operation = $database->updateDatabase(['enableDropProtection' => true]); + * ``` + * + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#updatedatabaserequest UpdateDatabaseRequest + * @codingStandardsIgnoreEnd + * + * @param array $options [optional] { + * Configuration Options + * + * @type bool $enableDropProtection If true, delete operations for Database + * and Instance will be blocked. **Defaults to** `false`. + * } + * @return LongRunningOperation + */ + public function updateDatabase(array $options = []) + { + return $this->info = $this->connection->updateDatabase([ + 'database' => [ + 'name' => $this->name, + 'enableDropProtection' => isset($options['enableDropProtection']) + ? $options['enableDropProtection'] + : false, + ], + 'updateMask' => [ + 'paths' => ['enable_drop_protection'] + ] + ] + $options); + } + /** * Restores to this database from a backup. * diff --git a/Spanner/tests/System/AdminTest.php b/Spanner/tests/System/AdminTest.php index 60ac9a735f05..f91a71c4e766 100644 --- a/Spanner/tests/System/AdminTest.php +++ b/Spanner/tests/System/AdminTest.php @@ -17,6 +17,7 @@ namespace Google\Cloud\Spanner\Tests\System; +use Google\Cloud\Core\Exception\FailedPreconditionException; use Google\Cloud\Core\LongRunning\LongRunningOperation; use Google\Cloud\Spanner\Admin\Database\V1\DatabaseAdminClient; use Google\Cloud\Spanner\Admin\Database\V1\DatabaseDialect; @@ -129,6 +130,50 @@ public function testDatabase() $this->assertEquals($db->ddl()[0], $stmt); } + public function testDatabaseDropProtection() + { + $instance = self::$instance; + + $dbName = uniqid(self::TESTING_PREFIX); + $op = $instance->createDatabase($dbName); + + $this->assertInstanceOf(LongRunningOperation::class, $op); + $db = $op->pollUntilComplete(); + $this->assertInstanceOf(Database::class, $db); + + $info = $db->reload(); + $this->assertFalse($info['enableDropProtection']); + + $op = $db->updateDatabase(['enableDropProtection' => true]); + $op->pollUntilComplete(); + $info = $db->reload(); + $this->assertTrue($info['enableDropProtection']); + + // delete database should throw + $isDropThrows = false; + try { + $db->drop(); + } catch (FailedPreconditionException $ex) { + $isDropThrows = true; + $this->assertStringContainsStringIgnoringCase( + 'enable_drop_protection', + $ex->getMessage() + ); + } + $this->assertTrue($isDropThrows); + $this->assertTrue($db->exists()); + + // disable drop databases config + $op = $db->updateDatabase(['enableDropProtection' => false]); + $op->pollUntilComplete(); + $info = $db->reload(); + $this->assertFalse($info['enableDropProtection']); + + // drop should succeed + $db->drop(); + $this->assertFalse($db->exists()); + } + public function testCreateCustomerManagedInstanceConfiguration() { $this->skipEmulatorTests(); diff --git a/Spanner/tests/Unit/DatabaseTest.php b/Spanner/tests/Unit/DatabaseTest.php index eab4ee63671d..95245b0a90e3 100644 --- a/Spanner/tests/Unit/DatabaseTest.php +++ b/Spanner/tests/Unit/DatabaseTest.php @@ -333,6 +333,27 @@ public function testCreate() $this->assertInstanceOf(LongRunningOperation::class, $op); } + /** + * @group spanner-admin + */ + public function testUpdateDatabase() + { + $this->connection->updateDatabase(Argument::allOf( + Argument::withEntry('database', [ + 'name' => DatabaseAdminClient::databaseName(self::PROJECT, self::INSTANCE, self::DATABASE), + 'enableDropProtection' => true, + ]), + Argument::withEntry('updateMask', ['paths' => ['enable_drop_protection']]) + ))->shouldBeCalled()->willReturn([ + 'enableDropProtection' => true + ]); + + $this->database->___setProperty('connection', $this->connection->reveal()); + + $res = $this->database->updateDatabase(['enableDropProtection' => true]); + $this->assertTrue($res['enableDropProtection']); + } + /** * @group spanner-admin */