Skip to content

Commit

Permalink
feat(spanner): integration tests for Database.database_dialect (#8589)
Browse files Browse the repository at this point in the history
Extend existing tests to also cover `database_dialect`by setting it
in the CreateDatabaseRequest, and expecting it in Database and Backup
responses.  Include allowances for these being invisible to the Spanner
emulator, and for pending bug #8573.

In particular, BackupIntegrationTest.BackupRestore leaves the dialect
unspecified in CreateDatabase() (but expects to see GOOGLE_STANDARD_SQL
in responses), while it is set explicitly to GOOGLE_STANDARD_SQL in
DatabaseAdminClientTest.VersionRetentionPeriodCreate, and to POSTGRESQL
in BackupExtraIntegrationTest.BackupRestoreWithCMEK.

DatabaseAdminClientTest.DatabasePostgreSQLBasics is a new test case
that also exercises the non-backup parts of an explicit POSTGRESQL
setting.

[Aside: These are only in the tests for the generated database admin
client.]

Finally, add ClientIntegrationTest.DatabaseDialect to enumerate the
`database_dialect` value from `INFORMATION_SCHEMA.DATABASE_OPTIONS`
for a default-dialect database.
  • Loading branch information
devbww authored Mar 24, 2022
1 parent 61bf504 commit 48d0da1
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,10 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
Database db(in, spanner_testing::RandomDatabaseName(generator_));
google::spanner::admin::database::v1::CreateDatabaseRequest creq;
creq.set_parent(db.instance().FullName());
creq.set_create_statement(
absl::StrCat("CREATE DATABASE `", db.database_id(), "`"));
creq.set_create_statement(absl::StrCat("CREATE DATABASE ", db.database_id()));
creq.mutable_encryption_config()->set_kms_key_name(encryption_key.FullName());
creq.set_database_dialect(
google::spanner::admin::database::v1::DatabaseDialect::POSTGRESQL);
auto database = database_admin_client_.CreateDatabase(creq).get();
ASSERT_STATUS_OK(database);
EXPECT_TRUE(database->has_encryption_config());
Expand All @@ -408,6 +409,8 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
encryption_key.FullName());
}
EXPECT_THAT(database->encryption_info(), IsEmpty());
EXPECT_EQ(database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::POSTGRESQL);

auto database_get = database_admin_client_.GetDatabase(db.FullName());
ASSERT_STATUS_OK(database_get);
Expand All @@ -417,6 +420,7 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
EXPECT_EQ(database_get->encryption_config().kms_key_name(),
encryption_key.FullName());
}
EXPECT_EQ(database_get->database_dialect(), database->database_dialect());

auto create_time =
MakeTimestamp(database->create_time()).value().get<absl::Time>().value();
Expand All @@ -441,6 +445,7 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
EXPECT_THAT(backup->encryption_info().kms_key_version(),
HasSubstr(encryption_key.FullName() + "/cryptoKeyVersions/"));
}
EXPECT_EQ(backup->database_dialect(), database->database_dialect());

EXPECT_STATUS_OK(database_admin_client_.DropDatabase(db.FullName()));

Expand All @@ -456,6 +461,7 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
EXPECT_THAT(backup_get->encryption_info().kms_key_version(),
HasSubstr(encryption_key.FullName() + "/cryptoKeyVersions/"));
}
EXPECT_EQ(backup_get->database_dialect(), database->database_dialect());

Database restore_db(in, spanner_testing::RandomDatabaseName(generator_));
google::spanner::admin::database::v1::RestoreDatabaseRequest rreq;
Expand All @@ -473,6 +479,15 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
EXPECT_EQ(restored_database->encryption_config().kms_key_name(),
encryption_key.FullName());
}
if (restored_database->database_dialect() ==
google::spanner::admin::database::v1::DatabaseDialect::
DATABASE_DIALECT_UNSPECIFIED) {
// TODO(#8573): Remove when RestoreDatabase() returns correct dialect.
restored_database->set_database_dialect(
google::spanner::admin::database::v1::DatabaseDialect::POSTGRESQL);
}
EXPECT_EQ(restored_database->database_dialect(),
database->database_dialect());

auto restored_get = database_admin_client_.GetDatabase(restore_db.FullName());
ASSERT_STATUS_OK(restored_get);
Expand All @@ -482,6 +497,7 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
EXPECT_EQ(restored_get->encryption_config().kms_key_name(),
encryption_key.FullName());
}
EXPECT_EQ(restored_get->database_dialect(), database->database_dialect());

EXPECT_STATUS_OK(database_admin_client_.DropDatabase(restore_db.FullName()));

Expand All @@ -503,6 +519,7 @@ TEST_F(BackupExtraIntegrationTest, BackupRestoreWithCMEK) {
b->encryption_info().kms_key_version(),
HasSubstr(encryption_key.FullName() + "/cryptoKeyVersions/"));
}
EXPECT_EQ(b->database_dialect(), backup->database_dialect());
}
}
EXPECT_TRUE(found);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ TEST_F(BackupIntegrationTest, BackupRestore) {
db.database_id(), "`"))
.get();
ASSERT_STATUS_OK(database);
EXPECT_EQ(database->name(), db.FullName());
if (database->database_dialect() ==
google::spanner::admin::database::v1::DatabaseDialect::
DATABASE_DIALECT_UNSPECIFIED) {
// TODO(#8573): Remove when CreateDatabase() returns correct dialect.
database->set_database_dialect(google::spanner::admin::database::v1::
DatabaseDialect::GOOGLE_STANDARD_SQL);
}
EXPECT_EQ(database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::
GOOGLE_STANDARD_SQL);
auto create_time =
MakeTimestamp(database->create_time()).value().get<absl::Time>().value();

Expand Down Expand Up @@ -160,14 +171,18 @@ TEST_F(BackupIntegrationTest, BackupRestore) {
// Verify that the version_time is the same as the creation_time.
EXPECT_EQ(MakeTimestamp(backup->version_time()).value(),
MakeTimestamp(backup->create_time()).value());
EXPECT_EQ(backup->database_dialect(), database->database_dialect());
}

EXPECT_STATUS_OK(database_admin_client_.DropDatabase(db.FullName()));

Backup backup_name(in, db.database_id());
auto backup_get = database_admin_client_.GetBackup(backup_name.FullName());
EXPECT_STATUS_OK(backup_get);
EXPECT_EQ(backup_get->name(), backup->name());
if (backup_get) {
EXPECT_EQ(backup_get->name(), backup->name());
EXPECT_EQ(backup_get->database_dialect(), backup->database_dialect());
}

Database restore_db(in, spanner_testing::RandomDatabaseName(generator_));
auto restored_database =
Expand All @@ -176,6 +191,19 @@ TEST_F(BackupIntegrationTest, BackupRestore) {
restore_db.database_id(), backup_name.FullName())
.get();
EXPECT_STATUS_OK(restored_database);
if (restored_database) {
EXPECT_EQ(restored_database->name(), restore_db.FullName());
if (restored_database->database_dialect() ==
google::spanner::admin::database::v1::DatabaseDialect::
DATABASE_DIALECT_UNSPECIFIED) {
// TODO(#8573): Remove when RestoreDatabase() returns correct dialect.
restored_database->set_database_dialect(
google::spanner::admin::database::v1::DatabaseDialect::
GOOGLE_STANDARD_SQL);
}
EXPECT_EQ(restored_database->database_dialect(),
database->database_dialect());
}

// List the database operations
std::ostringstream db_op_filter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,27 @@ TEST_F(DatabaseAdminClientTest, DatabaseBasicCRUD) {
EXPECT_THAT(database->name(), EndsWith(database_.database_id()));
EXPECT_FALSE(database->has_encryption_config());
EXPECT_THAT(database->encryption_info(), IsEmpty());
if (emulator_) {
EXPECT_EQ(database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::
DATABASE_DIALECT_UNSPECIFIED);
} else {
if (database->database_dialect() ==
google::spanner::admin::database::v1::DatabaseDialect::
DATABASE_DIALECT_UNSPECIFIED) {
// TODO(#8573): Remove when CreateDatabase() returns correct dialect.
database->set_database_dialect(google::spanner::admin::database::v1::
DatabaseDialect::GOOGLE_STANDARD_SQL);
}
EXPECT_EQ(database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::
GOOGLE_STANDARD_SQL);
}

auto get_result = client_.GetDatabase(database_.FullName());
ASSERT_STATUS_OK(get_result);
EXPECT_EQ(database->name(), get_result->name());
EXPECT_EQ(database->database_dialect(), get_result->database_dialect());
EXPECT_FALSE(get_result->has_encryption_config());
if (emulator_) {
EXPECT_THAT(get_result->encryption_info(), IsEmpty());
Expand All @@ -145,6 +162,17 @@ TEST_F(DatabaseAdminClientTest, DatabaseBasicCRUD) {
}
}

auto list_db = [&] {
for (auto const& db : client_.ListDatabases(instance_.FullName())) {
if (db && db->name() == database_.FullName()) return db;
}
return StatusOr<google::spanner::admin::database::v1::Database>{
Status{StatusCode::kNotFound, "disappeared"}};
}();
ASSERT_THAT(list_db, IsOk());
EXPECT_EQ(database->name(), list_db->name());
EXPECT_EQ(database->database_dialect(), list_db->database_dialect());

if (!emulator_) {
auto current_policy = client_.GetIamPolicy(database_.FullName());
ASSERT_STATUS_OK(current_policy);
Expand Down Expand Up @@ -294,6 +322,8 @@ TEST_F(DatabaseAdminClientTest, VersionRetentionPeriodCreate) {
creq.add_extra_statements(
absl::StrCat("ALTER DATABASE `", database_.database_id(),
"` SET OPTIONS (version_retention_period='7d')"));
creq.set_database_dialect(google::spanner::admin::database::v1::
DatabaseDialect::GOOGLE_STANDARD_SQL);
auto database = client_.CreateDatabase(creq).get();
if (emulator_) {
// TODO(#5479): Awaiting emulator support for version_retention_period.
Expand All @@ -303,11 +333,15 @@ TEST_F(DatabaseAdminClientTest, VersionRetentionPeriodCreate) {
ASSERT_THAT(database, IsOk());
EXPECT_EQ(database_.FullName(), database->name());
EXPECT_EQ("7d", database->version_retention_period());
EXPECT_EQ(database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::
GOOGLE_STANDARD_SQL);

// Verify that version_retention_period is returned from GetDatabase().
auto get = client_.GetDatabase(database_.FullName());
ASSERT_THAT(get, IsOk());
EXPECT_EQ(database->name(), get->name());
EXPECT_EQ(database->database_dialect(), get->database_dialect());
EXPECT_EQ("7d", get->version_retention_period());

// Verify that earliest_version_time doesn't go past database create_time.
Expand All @@ -316,6 +350,24 @@ TEST_F(DatabaseAdminClientTest, VersionRetentionPeriodCreate) {
EXPECT_LE(MakeTimestamp(get->create_time()).value(),
MakeTimestamp(get->earliest_version_time()).value());

// Verify that version_retention_period is returned via ListDatabases().
auto list_db = [&] {
for (auto const& db : client_.ListDatabases(instance_.FullName())) {
if (db && db->name() == database_.FullName()) return db;
}
return StatusOr<google::spanner::admin::database::v1::Database>{
Status{StatusCode::kNotFound, "disappeared"}};
}();
ASSERT_THAT(list_db, IsOk());
EXPECT_EQ(database->name(), list_db->name());
EXPECT_EQ(database->database_dialect(), list_db->database_dialect());
if (emulator_) {
// TODO(#5479): Awaiting emulator support for version_retention_period.
EXPECT_EQ("", list_db->version_retention_period());
} else {
EXPECT_EQ("7d", list_db->version_retention_period());
}

auto drop = client_.DropDatabase(database_.FullName());
EXPECT_THAT(drop, IsOk());
}
Expand Down Expand Up @@ -462,7 +514,7 @@ TEST_F(DatabaseAdminClientTest, VersionRetentionPeriodUpdateFailure) {
EXPECT_THAT(drop, IsOk());
}

// @test Verify we can create a database with an encryption key.
/// @test Verify we can create a database with an encryption key.
TEST_F(DatabaseAdminClientTest, CreateWithEncryptionKey) {
if (emulator_) GTEST_SKIP() << "emulator does not support CMEK";
KmsKeyName encryption_key(instance_.project_id(), location_, kKeyRing,
Expand Down Expand Up @@ -509,8 +561,8 @@ TEST_F(DatabaseAdminClientTest, CreateWithEncryptionKey) {
EXPECT_STATUS_OK(client_.DropDatabase(database_.FullName()));
}

// @test Verify creating a database fails if a nonexistent encryption key is
// supplied.
/// @test Verify creating a database fails if a nonexistent encryption key is
/// supplied.
TEST_F(DatabaseAdminClientTest, CreateWithNonexistentEncryptionKey) {
if (emulator_) GTEST_SKIP() << "emulator does not support CMEK";
KmsKeyName nonexistent_encryption_key(instance_.project_id(), location_,
Expand All @@ -526,6 +578,49 @@ TEST_F(DatabaseAdminClientTest, CreateWithNonexistentEncryptionKey) {
HasSubstr("KMS Key provided is not usable")));
}

/// @test Verify basic operations for PostgreSQL-type databases.
TEST_F(DatabaseAdminClientTest, DatabasePostgreSQLBasics) {
google::spanner::admin::database::v1::CreateDatabaseRequest creq;
creq.set_parent(database_.instance().FullName());
creq.set_create_statement(
absl::StrCat("CREATE DATABASE ", database_.database_id()));
creq.set_database_dialect(
google::spanner::admin::database::v1::DatabaseDialect::POSTGRESQL);
auto database = client_.CreateDatabase(creq).get();
ASSERT_STATUS_OK(database);
EXPECT_THAT(database->name(), EndsWith(database_.database_id()));
if (emulator_) {
EXPECT_EQ(database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::
DATABASE_DIALECT_UNSPECIFIED);
} else {
EXPECT_EQ(
database->database_dialect(),
google::spanner::admin::database::v1::DatabaseDialect::POSTGRESQL);
}

// Verify that GetDatabase() returns the correct dialect.
auto get = client_.GetDatabase(database->name());
ASSERT_THAT(get, IsOk());
EXPECT_EQ(database->name(), get->name());
EXPECT_EQ(database->database_dialect(), get->database_dialect());

// Verify that ListDatabases() returns the correct dialect.
auto list_db = [&] {
for (auto const& db : client_.ListDatabases(instance_.FullName())) {
if (db && db->name() == database_.FullName()) return db;
}
return StatusOr<google::spanner::admin::database::v1::Database>{
Status{StatusCode::kNotFound, "disappeared"}};
}();
ASSERT_THAT(list_db, IsOk());
EXPECT_EQ(database->name(), list_db->name());
EXPECT_EQ(database->database_dialect(), list_db->database_dialect());

auto drop_status = client_.DropDatabase(database->name());
EXPECT_STATUS_OK(drop_status);
}

} // namespace
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace spanner
Expand Down
19 changes: 19 additions & 0 deletions google/cloud/spanner/integration_tests/client_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,25 @@ TEST_F(ClientIntegrationTest, ProfileDml) {
}
}

/// @test Verify database_dialect is returned in information schema.
TEST_F(ClientIntegrationTest, DatabaseDialect) {
auto rows = client_->ExecuteQuery(SqlStatement(R"""(
SELECT s.OPTION_VALUE
FROM INFORMATION_SCHEMA.DATABASE_OPTIONS s
WHERE s.OPTION_NAME = 'database_dialect'
)"""));
using RowType = std::tuple<std::string>;
for (auto& row : StreamOf<RowType>(rows)) {
if (emulator_) {
EXPECT_THAT(row, StatusIs(StatusCode::kInvalidArgument));
} else {
EXPECT_THAT(row, IsOk());
}
if (!row) break;
EXPECT_EQ("GOOGLE_STANDARD_SQL", std::get<0>(*row));
}
}

/// @test Verify version_retention_period is returned in information schema.
TEST_F(ClientIntegrationTest, VersionRetentionPeriod) {
auto rows = client_->ExecuteQuery(SqlStatement(R"""(
Expand Down

0 comments on commit 48d0da1

Please sign in to comment.