blob: 1e7bf4eabe4f87bb581a569d596148e87d32c95c [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 "paimon/common/data/blob_view_struct.h"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "paimon/catalog/identifier.h"
#include "paimon/memory/memory_pool.h"
#include "paimon/status.h"
#include "paimon/testing/utils/testharness.h"
namespace paimon::test {
class BlobViewStructTest : public testing::Test {
public:
std::shared_ptr<MemoryPool> pool_ = GetDefaultPool();
Identifier identifier_ = Identifier("test_db", "test_table");
BlobViewStruct view_struct_ = BlobViewStruct(identifier_, /*field_id=*/7, /*row_id=*/1024);
};
TEST_F(BlobViewStructTest, TestConstructorAndGetters) {
ASSERT_EQ(view_struct_.GetIdentifier().GetDatabaseName(), "test_db");
ASSERT_EQ(view_struct_.GetIdentifier().GetTableName(), "test_table");
ASSERT_EQ(view_struct_.FieldId(), 7);
ASSERT_EQ(view_struct_.RowId(), 1024);
}
TEST_F(BlobViewStructTest, TestSerializeDeserializeRoundTrip) {
auto serialized = view_struct_.Serialize(pool_);
ASSERT_NE(serialized, nullptr);
ASSERT_GT(serialized->size(), 0u);
ASSERT_OK_AND_ASSIGN(auto restored,
BlobViewStruct::Deserialize(serialized->data(), serialized->size()));
ASSERT_EQ(restored->GetIdentifier().GetDatabaseName(), "test_db");
ASSERT_EQ(restored->GetIdentifier().GetTableName(), "test_table");
ASSERT_EQ(restored->FieldId(), 7);
ASSERT_EQ(restored->RowId(), 1024);
}
TEST_F(BlobViewStructTest, TestDeserializeWithInvalidVersion) {
auto serialized = view_struct_.Serialize(pool_);
(*serialized)[0] = '\x02'; // invalid version (current is 1).
ASSERT_NOK_WITH_MSG(BlobViewStruct::Deserialize(serialized->data(), serialized->size()),
"Expecting BlobViewStruct version to be 1, but found 2");
}
TEST_F(BlobViewStructTest, TestDeserializeWithInvalidMagic) {
auto serialized = view_struct_.Serialize(pool_);
(*serialized)[1] = '\x00';
ASSERT_NOK_WITH_MSG(BlobViewStruct::Deserialize(serialized->data(), serialized->size()),
"missing magic header");
}
TEST_F(BlobViewStructTest, TestToString) {
std::string debug_str = view_struct_.ToString();
ASSERT_EQ(debug_str, "BlobViewStruct{identifier=test_db.test_table, fieldId=7, rowId=1024}");
}
TEST_F(BlobViewStructTest, TestEqual) {
{
// test equal itself
ASSERT_EQ(view_struct_, view_struct_);
}
{
// test equal
BlobViewStruct other_view_struct =
BlobViewStruct(identifier_, /*field_id=*/7, /*row_id=*/1024);
ASSERT_EQ(view_struct_, other_view_struct);
}
{
// test wrong identifier
Identifier wrong_identifier = Identifier("db", "table");
BlobViewStruct wrong_view_struct =
BlobViewStruct(wrong_identifier, /*field_id=*/7, /*row_id=*/1024);
ASSERT_NE(view_struct_, wrong_view_struct);
}
{
// test wrong field_id
BlobViewStruct wrong_view_struct =
BlobViewStruct(identifier_, /*field_id=*/8, /*row_id=*/1024);
ASSERT_NE(view_struct_, wrong_view_struct);
}
{
// test wrong row_id
BlobViewStruct wrong_view_struct =
BlobViewStruct(identifier_, /*field_id=*/7, /*row_id=*/1000);
ASSERT_NE(view_struct_, wrong_view_struct);
}
}
TEST_F(BlobViewStructTest, TestIsBlobViewStructValid) {
auto serialized = view_struct_.Serialize(pool_);
ASSERT_OK_AND_ASSIGN(bool result,
BlobViewStruct::IsBlobViewStruct(serialized->data(), serialized->size()));
ASSERT_TRUE(result);
}
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithTooShortBuffer) {
// Buffer shorter than 9 bytes should return false
std::vector<char> short_buffer = {0x02, 0x43, 0x53, 0x45, 0x44, 0x42, 0x4F, 0x4C};
ASSERT_OK_AND_ASSIGN(
bool result, BlobViewStruct::IsBlobViewStruct(short_buffer.data(), short_buffer.size()));
ASSERT_FALSE(result);
// Empty buffer
ASSERT_OK_AND_ASSIGN(bool empty_result, BlobViewStruct::IsBlobViewStruct(nullptr, 0));
ASSERT_FALSE(empty_result);
}
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithFutureVersion) {
// Version > CURRENT_VERSION should return false (not an error)
auto serialized = view_struct_.Serialize(pool_);
(*serialized)[0] = '\x02'; // set version to 2 (> CURRENT_VERSION)
ASSERT_OK_AND_ASSIGN(bool result,
BlobViewStruct::IsBlobViewStruct(serialized->data(), serialized->size()));
ASSERT_FALSE(result);
}
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithWrongMagic) {
// Wrong magic number should return false
auto serialized = view_struct_.Serialize(pool_);
// Corrupt the magic bytes (bytes 1-8)
(*serialized)[1] = '\x00';
(*serialized)[2] = '\x00';
ASSERT_OK_AND_ASSIGN(bool result,
BlobViewStruct::IsBlobViewStruct(serialized->data(), serialized->size()));
ASSERT_FALSE(result);
}
TEST_F(BlobViewStructTest, TestIsBlobViewStructWithRandomData) {
// Random data that doesn't match format
std::vector<char> random_data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
ASSERT_OK_AND_ASSIGN(bool result,
BlobViewStruct::IsBlobViewStruct(random_data.data(), random_data.size()));
ASSERT_FALSE(result);
}
} // namespace paimon::test