Skip to content

Commit d0e7054

Browse files
committed
add tests for remove schemas
1 parent 38cc693 commit d0e7054

File tree

3 files changed

+219
-9
lines changed

3 files changed

+219
-9
lines changed

src/iceberg/test/partition_spec_test.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,17 @@ TEST(PartitionSpecTest, PartitionTypeTest) {
109109
"fields": [ {
110110
"source-id": 4,
111111
"field-id": 1000,
112-
"name": "ts_day",
112+
"name": "__ts_day",
113113
"transform": "day"
114114
}, {
115115
"source-id": 1,
116116
"field-id": 1001,
117-
"name": "id_bucket",
117+
"name": "__id_bucket",
118118
"transform": "bucket[16]"
119119
}, {
120120
"source-id": 2,
121121
"field-id": 1002,
122-
"name": "id_truncate",
122+
"name": "__id_truncate",
123123
"transform": "truncate[4]"
124124
} ]
125125
})"_json;
@@ -137,9 +137,9 @@ TEST(PartitionSpecTest, PartitionTypeTest) {
137137
ICEBERG_UNWRAP_OR_FAIL(auto parsed_spec, PartitionSpecFromJson(schema, json, 1));
138138
ICEBERG_UNWRAP_OR_FAIL(auto partition_type, parsed_spec->PartitionType(*schema));
139139

140-
SchemaField pt_field1(1000, "ts_day", date(), true);
141-
SchemaField pt_field2(1001, "id_bucket", int32(), true);
142-
SchemaField pt_field3(1002, "id_truncate", string(), true);
140+
SchemaField pt_field1(1000, "__ts_day", date(), true);
141+
SchemaField pt_field2(1001, "__id_bucket", int32(), true);
142+
SchemaField pt_field3(1002, "__id_truncate", string(), true);
143143

144144
ASSERT_EQ(3, partition_type->fields().size());
145145

src/iceberg/test/residual_evaluator_test.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ TEST_F(ResidualEvaluatorTest, IntegerTruncateTransformResiduals) {
406406

407407
// Valid partitions would be 0, 10, 20...90, 100 etc.
408408
auto truncate_transform = Transform::Truncate(10);
409-
PartitionField pt_field(50, 1000, "value", truncate_transform);
409+
PartitionField pt_field(50, 1000, "__value", truncate_transform);
410410
ICEBERG_UNWRAP_OR_FAIL(auto spec_unique,
411411
PartitionSpec::Make(*schema, 0, {pt_field}, false));
412412
auto spec = std::shared_ptr<PartitionSpec>(spec_unique.release());
@@ -523,7 +523,7 @@ TEST_F(ResidualEvaluatorTest, StringTruncateTransformResiduals) {
523523

524524
// Valid partitions would be two letter strings for eg: ab, bc etc
525525
auto truncate_transform = Transform::Truncate(2);
526-
PartitionField pt_field(50, 1000, "value", truncate_transform);
526+
PartitionField pt_field(50, 1000, "__value", truncate_transform);
527527
ICEBERG_UNWRAP_OR_FAIL(auto spec_unique,
528528
PartitionSpec::Make(*schema, 0, {pt_field}, false));
529529
auto spec = std::shared_ptr<PartitionSpec>(spec_unique.release());

src/iceberg/test/table_metadata_builder_test.cc

Lines changed: 211 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,19 +442,61 @@ TEST(TableMetadataBuilderTest, AddSchemaBasic) {
442442
EXPECT_EQ(metadata->last_column_id, 6);
443443
}
444444

445+
TEST(TableMetadataBuilderTest, AddSchemaInvalidColumnIds) {
446+
auto base = CreateBaseMetadata();
447+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
448+
449+
// Try to add schema with column ID lower than existing last_column_id
450+
auto field1 =
451+
SchemaField::MakeRequired(2, "duplicate_id", int64()); // ID 2 already exists
452+
auto invalid_schema = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
453+
builder->AddSchema(invalid_schema);
454+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
455+
// Should still work - AddSchema automatically uses max(existing, highest_in_schema)
456+
ASSERT_EQ(metadata->schemas.size(), 2);
457+
EXPECT_EQ(metadata->last_column_id, 3); // Should remain 3 (from base metadata)
458+
}
459+
460+
TEST(TableMetadataBuilderTest, AddSchemaWithHigherColumnIds) {
461+
auto base = CreateBaseMetadata();
462+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
463+
464+
// Add schema with higher column IDs
465+
auto field1 = SchemaField::MakeRequired(10, "high_id1", int64());
466+
auto field2 = SchemaField::MakeRequired(15, "high_id2", string());
467+
auto new_schema = std::make_shared<Schema>(std::vector<SchemaField>{field1, field2}, 1);
468+
builder->AddSchema(new_schema);
469+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
470+
ASSERT_EQ(metadata->schemas.size(), 2);
471+
EXPECT_EQ(metadata->last_column_id, 15); // Should be updated to highest field ID
472+
}
473+
474+
TEST(TableMetadataBuilderTest, AddSchemaEmptyFields) {
475+
auto base = CreateBaseMetadata();
476+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
477+
478+
// Add schema with no fields
479+
auto empty_schema = std::make_shared<Schema>(std::vector<SchemaField>{}, 1);
480+
builder->AddSchema(empty_schema);
481+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
482+
ASSERT_EQ(metadata->schemas.size(), 2);
483+
EXPECT_EQ(metadata->last_column_id, 3); // Should remain unchanged
484+
}
485+
445486
// Test SetCurrentSchema
446487
TEST(TableMetadataBuilderTest, SetCurrentSchemaBasic) {
447488
auto base = CreateBaseMetadata();
448489
auto builder = TableMetadataBuilder::BuildFrom(base.get());
449490

450-
// 1. Set current schema by Schema object
491+
// 1. Set current schema by Schema object with explicit last_column_id
451492
auto field1 = SchemaField::MakeRequired(4, "new_field", int64());
452493
auto new_schema = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
453494
builder->SetCurrentSchema(new_schema, 4);
454495
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
455496
ASSERT_EQ(metadata->schemas.size(), 2);
456497
EXPECT_EQ(metadata->current_schema_id.value(), 1);
457498
EXPECT_EQ(metadata->schemas[1]->schema_id().value(), 1);
499+
EXPECT_EQ(metadata->last_column_id, 4);
458500

459501
// 2. Set current schema by schema ID
460502
builder = TableMetadataBuilder::BuildFrom(base.get());
@@ -480,6 +522,32 @@ TEST(TableMetadataBuilderTest, SetCurrentSchemaBasic) {
480522
EXPECT_EQ(metadata->current_schema_id.value(), 0);
481523
}
482524

525+
TEST(TableMetadataBuilderTest, SetCurrentSchemaWithInvalidLastColumnId) {
526+
auto base = CreateBaseMetadata();
527+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
528+
529+
// Try to set current schema with last_column_id lower than existing
530+
auto field1 = SchemaField::MakeRequired(4, "new_field", int64());
531+
auto new_schema = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
532+
builder->SetCurrentSchema(new_schema, 2); // 2 < 3 (existing last_column_id)
533+
ASSERT_THAT(builder->Build(), IsError(ErrorKind::kValidationFailed));
534+
ASSERT_THAT(builder->Build(), HasErrorMessage("Invalid last column ID"));
535+
}
536+
537+
TEST(TableMetadataBuilderTest, SetCurrentSchemaUpdatesLastColumnId) {
538+
auto base = CreateBaseMetadata();
539+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
540+
541+
// Set current schema with higher last_column_id
542+
auto field1 = SchemaField::MakeRequired(4, "new_field1", int64());
543+
auto field2 = SchemaField::MakeRequired(8, "new_field2", string());
544+
auto new_schema = std::make_shared<Schema>(std::vector<SchemaField>{field1, field2}, 1);
545+
builder->SetCurrentSchema(new_schema, 10); // Higher than field IDs
546+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
547+
EXPECT_EQ(metadata->current_schema_id.value(), 1);
548+
EXPECT_EQ(metadata->last_column_id, 10);
549+
}
550+
483551
TEST(TableMetadataBuilderTest, SetCurrentSchemaInvalid) {
484552
auto base = CreateBaseMetadata();
485553

@@ -538,4 +606,146 @@ TEST(TableMetadataBuilderTest, SetCurrentSchemaRebuildsSpecsAndOrders) {
538606
ASSERT_EQ(metadata->sort_orders.size(), 2);
539607
}
540608

609+
// Test RemoveSchemas
610+
TEST(TableMetadataBuilderTest, RemoveSchemasBasic) {
611+
auto base = CreateBaseMetadata();
612+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
613+
614+
// Add multiple schemas
615+
auto field1 = SchemaField::MakeRequired(4, "field1", int64());
616+
auto schema1 = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
617+
auto field2 = SchemaField::MakeRequired(5, "field2", float64());
618+
auto schema2 = std::make_shared<Schema>(std::vector<SchemaField>{field2}, 2);
619+
auto field3 = SchemaField::MakeRequired(6, "field3", string());
620+
auto schema3 = std::make_shared<Schema>(std::vector<SchemaField>{field3}, 3);
621+
622+
builder->AddSchema(schema1);
623+
builder->AddSchema(schema2);
624+
builder->AddSchema(schema3);
625+
626+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
627+
ASSERT_EQ(metadata->schemas.size(), 4); // Original + 3 new
628+
629+
// Remove one schema
630+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
631+
builder->RemoveSchemas({1});
632+
ICEBERG_UNWRAP_OR_FAIL(metadata, builder->Build());
633+
ASSERT_EQ(metadata->schemas.size(), 3);
634+
EXPECT_EQ(metadata->schemas[0]->schema_id().value(), 0);
635+
EXPECT_EQ(metadata->schemas[1]->schema_id().value(), 2);
636+
EXPECT_EQ(metadata->schemas[2]->schema_id().value(), 3);
637+
638+
// Remove multiple schemas
639+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
640+
builder->RemoveSchemas({2, 3});
641+
ICEBERG_UNWRAP_OR_FAIL(metadata, builder->Build());
642+
ASSERT_EQ(metadata->schemas.size(), 1);
643+
EXPECT_EQ(metadata->schemas[0]->schema_id().value(), Schema::kInitialSchemaId);
644+
}
645+
646+
TEST(TableMetadataBuilderTest, RemoveSchemasCannotRemoveCurrent) {
647+
auto base = CreateBaseMetadata();
648+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
649+
650+
// Add a new schema
651+
auto field1 = SchemaField::MakeRequired(4, "field1", int64());
652+
auto schema1 = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
653+
builder->AddSchema(schema1);
654+
655+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
656+
ASSERT_EQ(metadata->schemas.size(), 2);
657+
EXPECT_EQ(metadata->current_schema_id.value(), 0);
658+
659+
// Try to remove current schema (ID 0)
660+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
661+
builder->RemoveSchemas({0});
662+
ASSERT_THAT(builder->Build(), IsError(ErrorKind::kValidationFailed));
663+
ASSERT_THAT(builder->Build(), HasErrorMessage("Cannot remove current schema: 0"));
664+
665+
// Try to remove current schema along with others
666+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
667+
builder->RemoveSchemas({0, 1});
668+
ASSERT_THAT(builder->Build(), IsError(ErrorKind::kValidationFailed));
669+
ASSERT_THAT(builder->Build(), HasErrorMessage("Cannot remove current schema: 0"));
670+
}
671+
672+
TEST(TableMetadataBuilderTest, RemoveSchemasNonExistent) {
673+
auto base = CreateBaseMetadata();
674+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
675+
676+
// Add one schema
677+
auto field1 = SchemaField::MakeRequired(4, "field1", int64());
678+
auto schema1 = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
679+
builder->AddSchema(schema1);
680+
681+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
682+
ASSERT_EQ(metadata->schemas.size(), 2);
683+
684+
// Try to remove non-existent schema - should be no-op
685+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
686+
builder->RemoveSchemas({999});
687+
ICEBERG_UNWRAP_OR_FAIL(metadata, builder->Build());
688+
ASSERT_EQ(metadata->schemas.size(), 2);
689+
690+
// Remove mix of existent and non-existent
691+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
692+
builder->RemoveSchemas({1, 999, 888});
693+
ICEBERG_UNWRAP_OR_FAIL(metadata, builder->Build());
694+
ASSERT_EQ(metadata->schemas.size(), 1);
695+
EXPECT_EQ(metadata->schemas[0]->schema_id().value(), Schema::kInitialSchemaId);
696+
}
697+
698+
TEST(TableMetadataBuilderTest, RemoveSchemasEmptySet) {
699+
auto base = CreateBaseMetadata();
700+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
701+
702+
// Add a schema
703+
auto field1 = SchemaField::MakeRequired(4, "field1", int64());
704+
auto schema1 = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
705+
builder->AddSchema(schema1);
706+
707+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
708+
ASSERT_EQ(metadata->schemas.size(), 2);
709+
710+
// Remove empty set - should be no-op
711+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
712+
builder->RemoveSchemas({});
713+
ICEBERG_UNWRAP_OR_FAIL(metadata, builder->Build());
714+
ASSERT_EQ(metadata->schemas.size(), 2);
715+
}
716+
717+
TEST(TableMetadataBuilderTest, RemoveSchemasAfterSchemaChange) {
718+
auto base = CreateBaseMetadata();
719+
auto builder = TableMetadataBuilder::BuildFrom(base.get());
720+
721+
// Add multiple schemas
722+
auto field1 = SchemaField::MakeRequired(4, "field1", int64());
723+
auto schema1 = std::make_shared<Schema>(std::vector<SchemaField>{field1}, 1);
724+
auto field2 = SchemaField::MakeRequired(5, "field2", float64());
725+
auto schema2 = std::make_shared<Schema>(std::vector<SchemaField>{field2}, 2);
726+
727+
builder->AddSchema(schema1);
728+
builder->AddSchema(schema2);
729+
builder->SetCurrentSchema(1); // Set schema1 as current
730+
731+
ICEBERG_UNWRAP_OR_FAIL(auto metadata, builder->Build());
732+
ASSERT_EQ(metadata->schemas.size(), 3);
733+
EXPECT_EQ(metadata->current_schema_id.value(), 1);
734+
735+
// Now remove the old current schema (ID 0)
736+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
737+
builder->RemoveSchemas({0});
738+
ICEBERG_UNWRAP_OR_FAIL(metadata, builder->Build());
739+
ASSERT_EQ(metadata->schemas.size(), 2);
740+
EXPECT_EQ(metadata->current_schema_id.value(), 1);
741+
EXPECT_EQ(metadata->schemas[0]->schema_id().value(), 1);
742+
EXPECT_EQ(metadata->schemas[1]->schema_id().value(), 2);
743+
744+
// Cannot remove the new current schema
745+
builder = TableMetadataBuilder::BuildFrom(metadata.get());
746+
builder->RemoveSchemas({1});
747+
ASSERT_THAT(builder->Build(), IsError(ErrorKind::kValidationFailed));
748+
ASSERT_THAT(builder->Build(), HasErrorMessage("Cannot remove current schema: 1"));
749+
}
750+
541751
} // namespace iceberg

0 commit comments

Comments
 (0)