| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you 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 "iceberg/table_requirement.h" | |
| #include <memory> | |
| #include <string> | |
| #include <gtest/gtest.h> | |
| #include "iceberg/snapshot.h" | |
| #include "iceberg/table_metadata.h" | |
| #include "iceberg/test/matchers.h" | |
| namespace iceberg { | |
| TEST(TableRequirementTest, AssertUUID) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| base->table_uuid = "test-uuid-1234"; | |
| // Success - UUID matches | |
| table::AssertUUID requirement("test-uuid-1234"); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertUUID, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // UUID mismatch | |
| table::AssertUUID wrong_uuid("wrong-uuid"); | |
| auto status = wrong_uuid.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("UUID does not match")); | |
| // Null base metadata | |
| table::AssertUUID any_uuid("any-uuid"); | |
| status = any_uuid.Validate(nullptr); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("metadata is missing")); | |
| // Case insensitive UUID comparison | |
| base->table_uuid = "TEST-UUID-1234"; | |
| table::AssertUUID lowercase_uuid("test-uuid-1234"); | |
| ASSERT_THAT(lowercase_uuid.Validate(base.get()), IsOk()); | |
| } | |
| TEST(TableRequirementTest, AssertCurrentSchemaID) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| base->current_schema_id = 5; | |
| // Success - schema ID matches | |
| table::AssertCurrentSchemaID requirement(5); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertCurrentSchemaID, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // Schema ID mismatch | |
| table::AssertCurrentSchemaID wrong_id(10); | |
| auto status = wrong_id.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("schema ID does not match")); | |
| // Null base metadata | |
| table::AssertCurrentSchemaID req_for_null(5); | |
| status = req_for_null.Validate(nullptr); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("metadata is missing")); | |
| } | |
| TEST(TableRequirementTest, AssertDoesNotExist) { | |
| // Success - table does not exist (null metadata) | |
| table::AssertDoesNotExist requirement; | |
| EXPECT_EQ(TableRequirement::Kind::kAssertDoesNotExist, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(nullptr), IsOk()); | |
| // Table already exists | |
| auto base = std::make_unique<TableMetadata>(); | |
| auto status = requirement.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("table already exists")); | |
| } | |
| TEST(TableRequirementTest, AssertRefSnapshotID) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| auto ref = std::make_shared<SnapshotRef>(); | |
| ref->snapshot_id = 100; | |
| ref->retention = SnapshotRef::Branch{}; | |
| base->refs["main"] = ref; | |
| // Success - ref snapshot ID matches | |
| table::AssertRefSnapshotID requirement("main", 100); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertRefSnapshotID, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // Snapshot ID mismatch | |
| table::AssertRefSnapshotID wrong_id("main", 200); | |
| auto status = wrong_id.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("has changed")); | |
| // Ref missing | |
| table::AssertRefSnapshotID missing_ref("missing-ref", 100); | |
| status = missing_ref.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("is missing")); | |
| // Ref should not exist and doesn't (nullopt snapshot ID) | |
| table::AssertRefSnapshotID nonexistent("nonexistent", std::nullopt); | |
| ASSERT_THAT(nonexistent.Validate(base.get()), IsOk()); | |
| // Ref should not exist but does (nullopt snapshot ID but ref exists) | |
| table::AssertRefSnapshotID exists_but_shouldnt("main", std::nullopt); | |
| status = exists_but_shouldnt.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("created concurrently")); | |
| } | |
| TEST(TableRequirementTest, AssertLastAssignedFieldId) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| base->last_column_id = 10; | |
| // Success - field ID matches | |
| table::AssertLastAssignedFieldId requirement(10); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertLastAssignedFieldId, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // Field ID mismatch | |
| table::AssertLastAssignedFieldId wrong_id(15); | |
| auto status = wrong_id.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("last assigned field ID does not match")); | |
| // Null base metadata (should succeed) | |
| table::AssertLastAssignedFieldId req_for_null(10); | |
| EXPECT_THAT(req_for_null.Validate(nullptr), IsOk()); | |
| } | |
| TEST(TableRequirementTest, AssertLastAssignedPartitionId) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| base->last_partition_id = 5; | |
| // Success - partition ID matches | |
| table::AssertLastAssignedPartitionId requirement(5); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertLastAssignedPartitionId, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // Partition ID mismatch | |
| table::AssertLastAssignedPartitionId wrong_id(8); | |
| auto status = wrong_id.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("last assigned partition ID does not match")); | |
| // Null base metadata | |
| table::AssertLastAssignedPartitionId req_for_null(5); | |
| status = req_for_null.Validate(nullptr); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("metadata is missing")); | |
| } | |
| TEST(TableRequirementTest, AssertDefaultSpecID) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| base->default_spec_id = 3; | |
| // Success - spec ID matches | |
| table::AssertDefaultSpecID requirement(3); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertDefaultSpecID, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // Spec ID mismatch | |
| table::AssertDefaultSpecID wrong_id(7); | |
| auto status = wrong_id.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("spec changed")); | |
| } | |
| TEST(TableRequirementTest, AssertDefaultSortOrderID) { | |
| auto base = std::make_unique<TableMetadata>(); | |
| base->default_sort_order_id = 2; | |
| // Success - sort order ID matches | |
| table::AssertDefaultSortOrderID requirement(2); | |
| EXPECT_EQ(TableRequirement::Kind::kAssertDefaultSortOrderID, requirement.kind()); | |
| ASSERT_THAT(requirement.Validate(base.get()), IsOk()); | |
| // Sort order ID mismatch | |
| table::AssertDefaultSortOrderID wrong_id(4); | |
| auto status = wrong_id.Validate(base.get()); | |
| EXPECT_THAT(status, IsError(ErrorKind::kCommitFailed)); | |
| EXPECT_THAT(status, HasErrorMessage("sort order changed")); | |
| } | |
| } // namespace iceberg |