blob: a208209b3228254f5b3b751ea7ece9cd0289ec60 [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/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