| /* | |
| * 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/update/update_location.h" | |
| #include <memory> | |
| #include <string> | |
| #include <arrow/filesystem/mockfs.h> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "iceberg/arrow/arrow_io_internal.h" | |
| #include "iceberg/result.h" | |
| #include "iceberg/test/matchers.h" | |
| #include "iceberg/test/update_test_base.h" | |
| namespace iceberg { | |
| class UpdateLocationTest : public UpdateTestBase {}; | |
| TEST_F(UpdateLocationTest, SetLocationSuccess) { | |
| const std::string new_location = "/warehouse/new_location"; | |
| // Create metadata directory for the new location | |
| auto arrow_fs = std::dynamic_pointer_cast<::arrow::fs::internal::MockFileSystem>( | |
| static_cast<arrow::ArrowFileSystemFileIO&>(*file_io_).fs()); | |
| ASSERT_TRUE(arrow_fs != nullptr); | |
| ASSERT_TRUE(arrow_fs->CreateDir(new_location + "/metadata").ok()); | |
| ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateLocation()); | |
| update->SetLocation(new_location); | |
| ICEBERG_UNWRAP_OR_FAIL(auto result, update->Apply()); | |
| EXPECT_EQ(result, new_location); | |
| // Commit and verify the location was persisted | |
| EXPECT_THAT(update->Commit(), IsOk()); | |
| ICEBERG_UNWRAP_OR_FAIL(auto reloaded, catalog_->LoadTable(table_ident_)); | |
| EXPECT_EQ(reloaded->location(), new_location); | |
| } | |
| TEST_F(UpdateLocationTest, SetLocationMultipleTimes) { | |
| // Test that setting location multiple times uses the last value | |
| const std::string final_location = "/warehouse/final_location"; | |
| // Create metadata directory for the new location | |
| auto arrow_fs = std::dynamic_pointer_cast<::arrow::fs::internal::MockFileSystem>( | |
| static_cast<arrow::ArrowFileSystemFileIO&>(*file_io_).fs()); | |
| ASSERT_TRUE(arrow_fs != nullptr); | |
| ASSERT_TRUE(arrow_fs->CreateDir(final_location + "/metadata").ok()); | |
| ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateLocation()); | |
| update->SetLocation("/warehouse/first_location") | |
| .SetLocation("/warehouse/second_location") | |
| .SetLocation(final_location); | |
| ICEBERG_UNWRAP_OR_FAIL(auto result, update->Apply()); | |
| EXPECT_EQ(result, final_location); | |
| // Commit and verify the final location was persisted | |
| EXPECT_THAT(update->Commit(), IsOk()); | |
| ICEBERG_UNWRAP_OR_FAIL(auto reloaded, catalog_->LoadTable(table_ident_)); | |
| EXPECT_EQ(reloaded->location(), final_location); | |
| } | |
| TEST_F(UpdateLocationTest, SetEmptyLocation) { | |
| ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateLocation()); | |
| update->SetLocation(""); | |
| auto result = update->Apply(); | |
| EXPECT_THAT(result, IsError(ErrorKind::kValidationFailed)); | |
| EXPECT_THAT(result, HasErrorMessage("Location cannot be empty")); | |
| } | |
| TEST_F(UpdateLocationTest, ApplyWithoutSettingLocation) { | |
| ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateLocation()); | |
| auto result = update->Apply(); | |
| EXPECT_THAT(result, IsError(ErrorKind::kInvalidArgument)); | |
| EXPECT_THAT(result, HasErrorMessage("Location must be set before applying")); | |
| } | |
| TEST_F(UpdateLocationTest, MultipleUpdatesSequentially) { | |
| // Get arrow_fs for creating directories | |
| auto arrow_fs = std::dynamic_pointer_cast<::arrow::fs::internal::MockFileSystem>( | |
| static_cast<arrow::ArrowFileSystemFileIO&>(*file_io_).fs()); | |
| ASSERT_TRUE(arrow_fs != nullptr); | |
| // First update | |
| const std::string first_location = "/warehouse/first"; | |
| ASSERT_TRUE(arrow_fs->CreateDir(first_location + "/metadata").ok()); | |
| ICEBERG_UNWRAP_OR_FAIL(auto update, table_->NewUpdateLocation()); | |
| update->SetLocation(first_location); | |
| ICEBERG_UNWRAP_OR_FAIL(auto result, update->Apply()); | |
| EXPECT_EQ(result, first_location); | |
| EXPECT_THAT(update->Commit(), IsOk()); | |
| // Reload and verify | |
| ICEBERG_UNWRAP_OR_FAIL(auto reloaded, catalog_->LoadTable(table_ident_)); | |
| EXPECT_EQ(reloaded->location(), first_location); | |
| // Second update | |
| const std::string second_location = "/warehouse/second"; | |
| ASSERT_TRUE(arrow_fs->CreateDir(second_location + "/metadata").ok()); | |
| ICEBERG_UNWRAP_OR_FAIL(update, reloaded->NewUpdateLocation()); | |
| update->SetLocation(second_location); | |
| ICEBERG_UNWRAP_OR_FAIL(result, update->Apply()); | |
| EXPECT_EQ(result, second_location); | |
| EXPECT_THAT(update->Commit(), IsOk()); | |
| // Reload and verify | |
| ICEBERG_UNWRAP_OR_FAIL(reloaded, catalog_->LoadTable(table_ident_)); | |
| EXPECT_EQ(reloaded->location(), second_location); | |
| } | |
| } // namespace iceberg |