backend/schema/updater/schema_updater_tests/proto_bundle.cc (452 lines of code) (raw):

// // Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include <memory> #include <string> #include "google/protobuf/descriptor.pb.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "zetasql/base/testing/status_matchers.h" #include "tests/common/proto_matchers.h" #include "absl/container/btree_set.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/types/span.h" #include "backend/schema/updater/schema_updater_tests/base.h" #include "tests/common/test.pb.h" #include "tests/common/test_2.pb.h" #include "zetasql/base/status_macros.h" namespace google { namespace spanner { namespace emulator { namespace backend { namespace test { // Proto bundles are not supported in PG yet and we skip the tests for PG. using database_api::DatabaseDialect::POSTGRESQL; using ::testing::HasSubstr; using ::zetasql_base::testing::StatusIs; namespace { std::string read_descriptors() { google::protobuf::FileDescriptorSet proto_files; ::emulator::tests::common::Simple::descriptor()->file()->CopyTo( proto_files.add_file()); ::emulator::tests::common::ImportingParent::descriptor()->file()->CopyTo( proto_files.add_file()); return proto_files.SerializeAsString(); } TEST_P(SchemaUpdaterTest, CreateProtoBundle_SetsTheProtoBundle) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, emulator.tests.common.ImportingAndParentingLevelTwo, emulator.tests.common.TestEnum, emulator.tests.common.EnumContainer.TestEnum, ) )sql"}, read_descriptors())); EXPECT_THAT(schema->proto_bundle()->types(), testing::UnorderedElementsAre( "emulator.tests.common.Simple", "emulator.tests.common.ImportingAndParentingLevelTwo", "emulator.tests.common.TestEnum", "emulator.tests.common.EnumContainer.TestEnum")); ZETASQL_EXPECT_OK(schema->proto_bundle()->GetTypeDescriptor( "emulator.tests.common.Simple")); ZETASQL_EXPECT_OK(schema->proto_bundle()->GetEnumTypeDescriptor( "emulator.tests.common.TestEnum")); } TEST_P(SchemaUpdaterTest, CreateProtoBundle_InUpdateSchema_SetsTheProtoBundle) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema({ R"sql( CREATE TABLE T ( col1 INT64, col2 STRING(MAX) ) PRIMARY KEY(col1) )sql"})); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, ) )sql"}, read_descriptors())); EXPECT_THAT(schema->proto_bundle()->types(), testing::UnorderedElementsAre("emulator.tests.common.Simple")); ZETASQL_EXPECT_OK(schema->proto_bundle()->GetTypeDescriptor( "emulator.tests.common.Simple")); } TEST_P(SchemaUpdaterTest, ProtoBundle_WithoutCreateProtoBundle_IsEmpty) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE TABLE T ( col1 INT64, col2 STRING(MAX) ) PRIMARY KEY(col1) )sql"}, read_descriptors())); EXPECT_TRUE(schema->proto_bundle()->empty()); EXPECT_THAT( schema->proto_bundle()->GetTypeDescriptor("emulator.tests.common.Simple"), zetasql_base::testing::StatusIs(absl::StatusCode::kNotFound)); } TEST_P(SchemaUpdaterTest, AlterProtoBundle_WithoutCreateProtoBundle_Fails) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); EXPECT_THAT(CreateSchema( { R"sql( ALTER PROTO BUNDLE INSERT ( emulator.tests.common.TestMessage, ) )sql"}, read_descriptors()), zetasql_base::testing::StatusIs(absl::StatusCode::kFailedPrecondition)); } TEST_P(SchemaUpdaterTest, AlterProtoBundleAltersTypes) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, emulator.tests.common.TestEnum ) )sql", }, read_descriptors())); ASSERT_THAT(schema->proto_bundle()->types(), testing::UnorderedElementsAre("emulator.tests.common.Simple", "emulator.tests.common.TestEnum")); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( ALTER PROTO BUNDLE INSERT ( emulator.tests.common.ImportingParent, emulator.tests.common.EnumContainer.TestEnum, ) UPDATE (emulator.tests.common.Simple) DELETE (emulator.tests.common.TestEnum) )sql", }, read_descriptors())); EXPECT_THAT(schema->proto_bundle()->types(), testing::UnorderedElementsAre( "emulator.tests.common.Simple", "emulator.tests.common.ImportingParent", "emulator.tests.common.EnumContainer.TestEnum")); ZETASQL_EXPECT_OK(schema->proto_bundle()->GetTypeDescriptor( "emulator.tests.common.ImportingParent")); ZETASQL_EXPECT_OK(schema->proto_bundle()->GetEnumTypeDescriptor( "emulator.tests.common.EnumContainer.TestEnum")); } TEST_P(SchemaUpdaterTest, AlterProtoBundle_UpdateNonExistent_Fails) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, ) )sql", }, read_descriptors())); EXPECT_THAT(UpdateSchema(schema.get(), { R"sql( ALTER PROTO BUNDLE UPDATE ( emulator.tests.common.Parent ) )sql", }, read_descriptors()), zetasql_base::testing::StatusIs(absl::StatusCode::kNotFound)); } TEST_P(SchemaUpdaterTest, AlterProtoBundle_DeleteNonExistent_Fails) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, ) )sql", }, read_descriptors())); EXPECT_THAT(UpdateSchema(schema.get(), { R"sql( ALTER PROTO BUNDLE DELETE ( emulator.tests.common.Parent ) )sql", }, read_descriptors()), zetasql_base::testing::StatusIs(absl::StatusCode::kNotFound)); } TEST_P(SchemaUpdaterTest, DropProtoBundle_Succeeds) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, emulator.tests.common.TestEnum ) )sql", }, read_descriptors())); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( DROP PROTO BUNDLE )sql", }, read_descriptors())); EXPECT_TRUE(schema->proto_bundle()->empty()); EXPECT_THAT( schema->proto_bundle()->GetTypeDescriptor("emulator.tests.common.Simple"), zetasql_base::testing::StatusIs(absl::StatusCode::kNotFound)); } TEST_P(SchemaUpdaterTest, DropProtoBundleWithoutExistingProtoBundle_Fails) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); EXPECT_THAT(CreateSchema( { R"sql( DROP PROTO BUNDLE )sql", }, read_descriptors()), zetasql_base::testing::StatusIs(absl::StatusCode::kFailedPrecondition)); } TEST_P(SchemaUpdaterTest, CreateAfterDropProtoBundle_Succeeds) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, emulator.tests.common.TestEnum ) )sql", }, read_descriptors())); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( DROP PROTO BUNDLE )sql", }, read_descriptors())); ASSERT_TRUE(schema->proto_bundle()->empty()); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, ) )sql", }, read_descriptors())); ZETASQL_EXPECT_OK(schema->proto_bundle()->GetTypeDescriptor( "emulator.tests.common.Simple")); EXPECT_THAT(schema->proto_bundle()->GetEnumTypeDescriptor( "emulator.tests.common.TestEnum"), zetasql_base::testing::StatusIs(absl::StatusCode::kNotFound)); } TEST_P(SchemaUpdaterTest, AlterAfterDropProtoBundle_Fails) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, emulator.tests.common.TestEnum ) )sql", }, read_descriptors())); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( DROP PROTO BUNDLE )sql", }, read_descriptors())); ASSERT_TRUE(schema->proto_bundle()->empty()); EXPECT_THAT(UpdateSchema(schema.get(), { R"sql( ALTER PROTO BUNDLE INSERT ( emulator.tests.common.Simple, ) )sql", }, read_descriptors()), zetasql_base::testing::StatusIs(absl::StatusCode::kFailedPrecondition)); } TEST_P(SchemaUpdaterTest, AlterProtoBundleUpdatesProtoColumnTypes) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.Simple, ) )sql", R"sql( CREATE TABLE Albums ( AlbumId INT64 NOT NULL, AlbumInfo emulator.tests.common.Simple, ArrayAlbumInfo ARRAY<emulator.tests.common.Simple>, ) PRIMARY KEY(AlbumId) )sql", }, read_descriptors())); auto table = schema->FindTable("Albums"); auto column = table->FindColumn("AlbumInfo"); auto array_column = table->FindColumn("ArrayAlbumInfo"); const zetasql::Type* column_type = column->GetType(); const zetasql::Type* array_column_element_type = array_column->GetType()->AsArray()->element_type(); ASSERT_NE(column_type->AsProto()->descriptor()->DebugString().find( "optional string field = 1"), std::string::npos); ASSERT_NE( array_column_element_type->AsProto()->descriptor()->DebugString().find( "optional string field = 1"), std::string::npos); google::protobuf::FileDescriptorSet file_descriptor_set; ::emulator::tests::common::Simple::descriptor()->file()->CopyTo( file_descriptor_set.add_file()); google::protobuf::FileDescriptorProto* file_descriptor_proto = file_descriptor_set.mutable_file(0); google::protobuf::DescriptorProto* descriptor_proto = file_descriptor_proto->mutable_message_type(0); descriptor_proto->mutable_field(0)->set_name("new_field"); std::string serialized_descriptor_bytes = file_descriptor_set.SerializeAsString(); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( ALTER PROTO BUNDLE UPDATE ( emulator.tests.common.Simple, ) )sql", }, serialized_descriptor_bytes)); auto new_table = schema->FindTable("Albums"); auto new_column = new_table->FindColumn("AlbumInfo"); auto new_array_column = new_table->FindColumn("ArrayAlbumInfo"); const zetasql::Type* new_column_type = new_column->GetType(); const zetasql::Type* new_array_column_element_type = new_array_column->GetType()->AsArray()->element_type(); EXPECT_NE(new_column_type->AsProto()->descriptor()->DebugString().find( "optional string new_field = 1"), std::string::npos); EXPECT_NE(new_array_column_element_type->AsProto() ->descriptor() ->DebugString() .find("optional string new_field = 1"), std::string::npos); } TEST_P(SchemaUpdaterTest, AlterProtoBundleUpdatesEnumColumnTypes) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema( { R"sql( CREATE PROTO BUNDLE ( emulator.tests.common.TestEnum, ) )sql", R"sql( CREATE TABLE Albums ( AlbumId INT64 NOT NULL, AlbumTypes emulator.tests.common.TestEnum, AlbumTypesArray ARRAY<emulator.tests.common.TestEnum>, ) PRIMARY KEY(AlbumId) )sql", }, read_descriptors())); auto table = schema->FindTable("Albums"); auto column = table->FindColumn("AlbumTypes"); auto array_column = table->FindColumn("AlbumTypesArray"); const zetasql::Type* column_type = column->GetType(); const zetasql::Type* array_column_element_type = array_column->GetType()->AsArray()->element_type(); ASSERT_NE(column_type->AsEnum()->enum_descriptor()->DebugString().find( "TEST_ENUM_ONE"), std::string::npos); ASSERT_NE(array_column_element_type->AsEnum() ->enum_descriptor() ->DebugString() .find("TEST_ENUM_ONE"), std::string::npos); google::protobuf::FileDescriptorSet file_descriptor_set; ::emulator::tests::common::Simple::descriptor()->file()->CopyTo( file_descriptor_set.add_file()); google::protobuf::FileDescriptorProto* file_descriptor_proto = file_descriptor_set.mutable_file(0); google::protobuf::EnumDescriptorProto* descriptor_proto = file_descriptor_proto->mutable_enum_type(0); descriptor_proto->mutable_value(1)->set_name("TEST_ENUM_CHANGED"); std::string serialized_descriptor_bytes = file_descriptor_set.SerializeAsString(); ZETASQL_ASSERT_OK_AND_ASSIGN(schema, UpdateSchema(schema.get(), { R"sql( ALTER PROTO BUNDLE UPDATE ( emulator.tests.common.TestEnum, ) )sql", }, serialized_descriptor_bytes)); auto new_table = schema->FindTable("Albums"); auto new_column = new_table->FindColumn("AlbumTypes"); auto new_array_column = new_table->FindColumn("AlbumTypesArray"); const zetasql::Type* new_column_type = new_column->GetType(); const zetasql::Type* new_array_column_element_type = new_array_column->GetType()->AsArray()->element_type(); EXPECT_NE(new_column_type->AsEnum()->enum_descriptor()->DebugString().find( "TEST_ENUM_CHANGED"), std::string::npos); EXPECT_NE(new_array_column_element_type->AsEnum() ->enum_descriptor() ->DebugString() .find("TEST_ENUM_CHANGED"), std::string::npos); } TEST_P(SchemaUpdaterTest, CreateProtoBundle_AddColumnWithUnrecognizedProtoType) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); EXPECT_THAT(CreateSchema({R"sql( CREATE TABLE T ( col1 INT64, col2 emulator.tests.common.Simple ) PRIMARY KEY(col1) )sql"}), StatusIs(absl::StatusCode::kInternal, HasSubstr("Unrecognized ddl::ColumnDefinition:"))); } TEST_P(SchemaUpdaterTest, CreateProtoBundle_AlterColumnWithUnrecognizedProtoType) { if (GetParam() == POSTGRESQL) GTEST_SKIP(); ZETASQL_ASSERT_OK_AND_ASSIGN(auto schema, CreateSchema({ R"sql( CREATE TABLE T ( col1 INT64, col2 STRING(MAX) ) PRIMARY KEY(col1) )sql"})); EXPECT_THAT(UpdateSchema(schema.get(), {R"sql( ALTER TABLE T ALTER COLUMN col2 emulator.tests.common.Simple )sql"}), StatusIs(absl::StatusCode::kInternal, HasSubstr("Unrecognized ddl::ColumnDefinition:"))); } } // namespace } // namespace test } // namespace backend } // namespace emulator } // namespace spanner } // namespace google