blob: befbfa52c2362975d1f56396d621e44d1af1f3d7 [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/format/blob/blob_stats_extractor.h"
#include <cstdint>
#include <vector>
#include "arrow/api.h"
#include "gtest/gtest.h"
#include "paimon/common/data/blob_utils.h"
#include "paimon/defs.h"
#include "paimon/format/column_stats.h"
#include "paimon/fs/local/local_file_system.h"
#include "paimon/memory/memory_pool.h"
#include "paimon/status.h"
#include "paimon/testing/utils/testharness.h"
namespace paimon::blob::test {
class BlobStatsExtractorTest : public testing::Test {
public:
void SetUp() override {
pool_ = GetDefaultPool();
// Create a blob schema with one blob field
blob_field_ = BlobUtils::ToArrowField("blob_field", false);
blob_schema_ = arrow::schema({blob_field_});
fs_ = std::make_shared<LocalFileSystem>();
}
private:
std::shared_ptr<MemoryPool> pool_;
std::shared_ptr<arrow::Field> blob_field_;
std::shared_ptr<arrow::Schema> blob_schema_;
std::shared_ptr<FileSystem> fs_;
};
TEST_F(BlobStatsExtractorTest, TestDifferentBlobFiles) {
BlobStatsExtractor extractor(blob_schema_);
std::vector<std::pair<std::string, int64_t>> test_files = {
{"data-d7816e8e-6c6d-4e28-9137-837cdf706350-1.blob", 3},
{"data-d7816e8e-6c6d-4e28-9137-837cdf706350-2.blob", 2},
{"data-d7816e8e-6c6d-4e28-9137-837cdf706350-3.blob", 4},
{"data-d7816e8e-6c6d-4e28-9137-837cdf706350-4.blob", 1}};
for (const auto& [filename, expected_rows] : test_files) {
std::string blob_file_path =
paimon::test::GetDataDir() + "/db_with_blob.db/table_with_blob/bucket-0/" + filename;
ASSERT_OK_AND_ASSIGN(auto stats_with_info,
extractor.ExtractWithFileInfo(fs_, blob_file_path, pool_));
// Check stats structure
ASSERT_EQ(1u, stats_with_info.first.size());
ASSERT_TRUE(stats_with_info.first[0]);
ASSERT_EQ(FieldType::STRING, stats_with_info.first[0]->GetFieldType());
ASSERT_EQ("min null, max null, null count null", stats_with_info.first[0]->ToString());
// Check row count matches expected
ASSERT_EQ(expected_rows, stats_with_info.second.GetRowCount())
<< "Row count mismatch for file: " << filename;
}
}
TEST_F(BlobStatsExtractorTest, TestInvalidCase) {
std::string blob_file_path = paimon::test::GetDataDir() +
"/db_with_blob.db/table_with_blob/bucket-0/"
"data-d7816e8e-6c6d-4e28-9137-837cdf706350-1.blob";
// Should fail because schema has more than 1 field
{
auto int_field = arrow::field("int_field", arrow::int32());
auto multi_field_schema = arrow::schema({blob_field_, int_field});
BlobStatsExtractor extractor(multi_field_schema);
ASSERT_NOK_WITH_MSG(extractor.ExtractWithFileInfo(fs_, blob_file_path, pool_),
"schema field number 2 is not 1");
}
// Should fail because field is not a blob field
{
auto string_field = arrow::field("string_field", arrow::utf8());
auto non_blob_schema = arrow::schema({string_field});
BlobStatsExtractor extractor(non_blob_schema);
ASSERT_NOK_WITH_MSG(extractor.ExtractWithFileInfo(fs_, blob_file_path, pool_),
"field string_field: string is not BLOB");
}
// Should fail because file doesn't exist
{
BlobStatsExtractor extractor(blob_schema_);
std::string non_existent_path = "/path/that/does/not/exist.blob";
ASSERT_NOK_WITH_MSG(extractor.ExtractWithFileInfo(fs_, non_existent_path, pool_),
"File '/path/that/does/not/exist.blob' not exists");
}
}
} // namespace paimon::blob::test