blob: c87c2c24878faf597277a7fe2c422d4eba0b7af1 [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 "information_schema/schema_extensions_scanner.h"
#include <gen_cpp/Descriptors_types.h>
#include <gtest/gtest.h>
#include "common/object_pool.h"
#include "common/status.h"
#include "core/block/block.h"
#include "core/data_type/define_primitive_type.h"
#include "information_schema/schema_scanner.h"
#include "runtime/runtime_state.h"
#include "testutil/mock/mock_runtime_state.h"
namespace doris {
// The RPC data path (_get_extensions_block_from_fe) requires a live FE and is
// covered by the FE-side regression test; ThriftRpcHelper has no result-injection
// hook, so these unit tests exercise the FE-independent surface only: the factory
// registration, the column schema, and the pre-/post-init guard branches of
// start() and get_next_block_internal().
class SchemaExtensionsScannerTest : public testing::Test {
void SetUp() override {}
void TearDown() override {}
};
TEST_F(SchemaExtensionsScannerTest, test_create_extensions_scanner) {
auto scanner = SchemaScanner::create(TSchemaTableType::SCH_EXTENSIONS);
ASSERT_NE(nullptr, scanner);
EXPECT_EQ(TSchemaTableType::SCH_EXTENSIONS, scanner->type());
const auto& columns = scanner->get_column_desc();
ASSERT_EQ(5, columns.size());
EXPECT_STREQ("EXTENSION_NAME", columns[0].name);
EXPECT_STREQ("EXTENSION_TYPE", columns[1].name);
EXPECT_STREQ("EXTENSION_VERSION", columns[2].name);
EXPECT_STREQ("SOURCE", columns[3].name);
EXPECT_STREQ("DESCRIPTION", columns[4].name);
// All extension columns are nullable strings (e.g. unknown EXTENSION_VERSION
// is surfaced as SQL NULL rather than an empty string).
for (const auto& column : columns) {
EXPECT_EQ(TYPE_STRING, column.type);
EXPECT_TRUE(column.is_null);
}
}
TEST_F(SchemaExtensionsScannerTest, test_start_before_init) {
SchemaExtensionsScanner scanner;
// start() must reject use before init() regardless of the RuntimeState.
auto st = scanner.start(nullptr);
EXPECT_FALSE(st.ok());
}
TEST_F(SchemaExtensionsScannerTest, test_get_next_block_before_init) {
SchemaExtensionsScanner scanner;
auto block = Block::create_unique();
bool eos = false;
auto st = scanner.get_next_block_internal(block.get(), &eos);
EXPECT_FALSE(st.ok());
EXPECT_FALSE(eos);
}
// After init(), start() still fails when the session has no query context, since
// extensions are fetched from the FE recorded on the query context.
TEST_F(SchemaExtensionsScannerTest, test_start_without_query_context) {
// A default RuntimeState has a null query context.
RuntimeState state;
SchemaScannerParam param;
ObjectPool pool;
SchemaExtensionsScanner scanner;
ASSERT_TRUE(scanner.init(&state, &param, &pool).ok());
auto st = scanner.start(&state);
EXPECT_FALSE(st.ok());
}
// With a query context present, start() succeeds and stashes the per-session
// state (batch size, rpc timeout, connected FE) used by the later RPC.
TEST_F(SchemaExtensionsScannerTest, test_start_with_query_context) {
MockRuntimeState state;
SchemaScannerParam param;
ObjectPool pool;
SchemaExtensionsScanner scanner;
ASSERT_TRUE(scanner.init(&state, &param, &pool).ok());
auto st = scanner.start(&state);
EXPECT_TRUE(st.ok());
}
// After init(), get_next_block_internal() rejects null output pointers before
// attempting any FE RPC.
TEST_F(SchemaExtensionsScannerTest, test_get_next_block_null_output) {
RuntimeState state;
SchemaScannerParam param;
ObjectPool pool;
SchemaExtensionsScanner scanner;
ASSERT_TRUE(scanner.init(&state, &param, &pool).ok());
bool eos = false;
EXPECT_FALSE(scanner.get_next_block_internal(nullptr, &eos).ok());
auto block = Block::create_unique();
EXPECT_FALSE(scanner.get_next_block_internal(block.get(), nullptr).ok());
}
} // namespace doris