blob: d50d9f41301b520a54d05fa13156f3055d3723a4 [file]
/*
* 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