blob: ef55d38cd5d9228c39041416d40809479d43f555 [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.
// Unit tests for DefaultNestedGroupReadProvider, DefaultNestedGroupWriteProvider,
// NestedGroupReader struct, NestedGroupPathMatch struct, and find_in_nested_groups.
//
// See also:
// nested_group_path_test.cpp — nested_group_path.h utilities
// nested_group_path_filter_test.cpp — NestedGroupPathFilter
#include "storage/segment/variant/nested_group_provider.h"
#include <gtest/gtest.h>
#include <roaring/roaring.hh>
#include "core/column/column_variant.h"
#include "storage/iterator/olap_data_convertor.h"
#include "storage/segment/column_writer.h"
#include "storage/segment/variant/variant_column_reader.h"
#include "storage/segment/variant/variant_statistics.h"
namespace doris::segment_v2 {
// ===========================================================================
// Default provider contract tests
// ===========================================================================
TEST(NestedGroupProviderTest, DefaultReadProviderIsDisabled) {
auto provider = create_nested_group_read_provider();
ASSERT_TRUE(provider != nullptr);
if (provider->should_enable_nested_group_read_path()) {
GTEST_SKIP() << "EE build: read provider is enabled";
}
EXPECT_FALSE(provider->should_enable_nested_group_read_path());
}
TEST(NestedGroupProviderTest, DefaultWriteProviderRejectsNestedGroupWritePath) {
auto write_provider = create_nested_group_write_provider();
ASSERT_TRUE(write_provider != nullptr);
// In EE, the write provider may have real behavior, skip these checks.
auto read_provider = create_nested_group_read_provider();
if (read_provider && read_provider->should_enable_nested_group_read_path()) {
GTEST_SKIP() << "EE build: write provider has real implementation";
}
auto column_variant = ColumnVariant::create(0, false);
ColumnWriterOptions opts;
VariantStatistics statistics;
auto status =
write_provider->prepare(*column_variant, nullptr, opts, nullptr, nullptr, &statistics);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::INVALID_ARGUMENT>());
TabletColumn tablet_column;
OlapBlockDataConvertor converter;
int column_id = 0;
status = write_provider->prepare(*column_variant, &tablet_column, opts, &converter, &column_id,
&statistics);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
EXPECT_NE(status.to_string().find("not available"), std::string::npos);
NestedGroupsMap nested_groups;
status = write_provider->prepare_with_built_groups(nested_groups, &tablet_column, opts,
&converter, &column_id, &statistics);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
EXPECT_NE(status.to_string().find("not available"), std::string::npos);
EXPECT_EQ(0, write_provider->estimate_buffer_size());
EXPECT_TRUE(write_provider->finish().ok());
EXPECT_TRUE(write_provider->write_data().ok());
EXPECT_TRUE(write_provider->write_ordinal_index().ok());
EXPECT_TRUE(write_provider->write_zone_map().ok());
EXPECT_TRUE(write_provider->write_inverted_index().ok());
EXPECT_TRUE(write_provider->write_bloom_filter_index().ok());
}
// ===========================================================================
// DefaultNestedGroupReadProvider — detailed method contract
// ===========================================================================
TEST(DefaultNestedGroupReadProviderTest, TryBuildReadPlanReturnsFalse) {
auto provider = create_nested_group_read_provider();
ASSERT_NE(nullptr, provider);
NestedGroupReaders readers;
TabletColumn col;
PathInData path;
bool is_whole = true;
DataTypePtr out_type;
PathInData out_path;
std::string child_path, pruned_path;
std::vector<const NestedGroupReader*> chain;
std::optional<NestedGroupPathFilter> path_filter;
bool result = provider->try_build_read_plan(nullptr, readers, col, nullptr, 0, path, &is_whole,
&out_type, &out_path, &child_path, &pruned_path,
&chain, &path_filter);
EXPECT_FALSE(result);
}
TEST(DefaultNestedGroupReadProviderTest, CreateNestedGroupIteratorCEBehavior) {
auto provider = create_nested_group_read_provider();
ASSERT_NE(nullptr, provider);
if (provider->should_enable_nested_group_read_path()) {
GTEST_SKIP() << "EE build: create_nested_group_iterator has real implementation";
}
std::vector<const NestedGroupReader*> chain;
ColumnIteratorUPtr iter;
DataTypePtr out_type;
std::optional<NestedGroupPathFilter> filter;
auto status =
provider->create_nested_group_iterator(false, chain, "", "", filter, &iter, &out_type);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
EXPECT_NE(status.to_string().find("not available"), std::string::npos);
}
TEST(DefaultNestedGroupReadProviderTest, GetTotalElementsCEBehavior) {
auto provider = create_nested_group_read_provider();
ASSERT_NE(nullptr, provider);
if (provider->should_enable_nested_group_read_path()) {
GTEST_SKIP() << "EE build: get_total_elements has real implementation";
}
ColumnIteratorOptions opts;
uint64_t total = 0;
auto status = provider->get_total_elements(opts, nullptr, &total);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
}
TEST(DefaultNestedGroupReadProviderTest, MapElementsToParentOrdsCEBehavior) {
auto provider = create_nested_group_read_provider();
ASSERT_NE(nullptr, provider);
if (provider->should_enable_nested_group_read_path()) {
GTEST_SKIP() << "EE build: map_elements_to_parent_ords has real implementation";
}
std::vector<const NestedGroupReader*> chain;
ColumnIteratorOptions opts;
roaring::Roaring element_bitmap;
roaring::Roaring parent_bitmap;
auto status =
provider->map_elements_to_parent_ords(chain, opts, element_bitmap, &parent_bitmap);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
EXPECT_NE(status.to_string().find("not available"), std::string::npos);
}
TEST(DefaultNestedGroupReadProviderTest, InitReadersCEBehavior) {
auto provider = create_nested_group_read_provider();
ASSERT_NE(nullptr, provider);
if (provider->should_enable_nested_group_read_path()) {
GTEST_SKIP() << "EE build: init_readers requires real footer";
}
ColumnReaderOptions opts;
NestedGroupReaders out_readers;
auto status = provider->init_readers(opts, nullptr, nullptr, nullptr, 0, 0, out_readers);
EXPECT_TRUE(status.ok());
EXPECT_TRUE(out_readers.empty());
}
// ===========================================================================
// NestedGroupReader struct
// ===========================================================================
TEST(NestedGroupReaderTest, IsValidWhenOffsetsReaderIsNull) {
NestedGroupReader reader;
EXPECT_FALSE(reader.is_valid());
EXPECT_TRUE(reader.array_path.empty());
EXPECT_EQ(1, reader.depth);
}
TEST(NestedGroupReaderTest, DefaultDepthIsOne) {
NestedGroupReader reader;
EXPECT_EQ(1, reader.depth);
}
TEST(NestedGroupReaderTest, ChildReadersEmptyByDefault) {
NestedGroupReader reader;
EXPECT_TRUE(reader.child_readers.empty());
EXPECT_TRUE(reader.nested_group_readers.empty());
}
// ===========================================================================
// NestedGroupPathMatch struct
// ===========================================================================
TEST(NestedGroupPathMatchTest, DefaultValues) {
NestedGroupPathMatch match;
EXPECT_EQ(nullptr, match.reader);
EXPECT_TRUE(match.chain.empty());
EXPECT_TRUE(match.child_path.empty());
EXPECT_FALSE(match.found);
}
// ===========================================================================
// find_in_nested_groups
// ===========================================================================
TEST(NestedGroupProviderTest, FindInNestedGroupsReturnsEmpty) {
NestedGroupReaders readers;
auto result = find_in_nested_groups(readers, "some.path", false);
EXPECT_FALSE(result.found);
EXPECT_TRUE(result.chain.empty());
}
TEST(NestedGroupProviderTest, FindInNestedGroupsEmptyPath) {
NestedGroupReaders readers;
auto result = find_in_nested_groups(readers, "", false);
EXPECT_FALSE(result.found);
}
TEST(NestedGroupProviderTest, FindInNestedGroupsEmptyReadersWithChain) {
NestedGroupReaders readers;
auto result = find_in_nested_groups(readers, "some.path", true);
EXPECT_FALSE(result.found);
EXPECT_TRUE(result.chain.empty());
EXPECT_TRUE(result.child_path.empty());
}
TEST(NestedGroupProviderTest, FindInNestedGroupsMultiplePaths) {
NestedGroupReaders readers;
auto result1 = find_in_nested_groups(readers, "items.msg", false);
EXPECT_FALSE(result1.found);
auto result2 = find_in_nested_groups(readers, "items.title", true);
EXPECT_FALSE(result2.found);
}
} // namespace doris::segment_v2