225 lines
7.0 KiB
C++
Executable File
225 lines
7.0 KiB
C++
Executable 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 "udf/udf_test_harness.hpp"
|
|
|
|
#include <iostream>
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
#include <gtest/gtest.h>
|
|
#include "util/logging.h"
|
|
#include "common/logging.h"
|
|
|
|
namespace doris_udf {
|
|
|
|
DoubleVal zero_udf(FunctionContext* context) {
|
|
return DoubleVal(0);
|
|
}
|
|
|
|
StringVal log_udf(FunctionContext* context, const StringVal& arg1) {
|
|
std::cerr << (arg1.is_null ? "NULL" : std::string((char*)arg1.ptr, arg1.len)) << std::endl;
|
|
return arg1;
|
|
}
|
|
|
|
StringVal upper_udf(FunctionContext* context, const StringVal& input) {
|
|
if (input.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
|
|
// Create a new StringVal object that's the same length as the input
|
|
StringVal result = StringVal(context, input.len);
|
|
|
|
for (int i = 0; i < input.len; ++i) {
|
|
result.ptr[i] = toupper(input.ptr[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
FloatVal min3(FunctionContext* context, const FloatVal& f1,
|
|
const FloatVal& f2, const FloatVal& f3) {
|
|
bool is_null = true;
|
|
float v = 0.0;
|
|
|
|
if (!f1.is_null) {
|
|
if (is_null) {
|
|
v = f1.val;
|
|
is_null = false;
|
|
} else {
|
|
v = std::min(v, f1.val);
|
|
}
|
|
}
|
|
|
|
if (!f2.is_null) {
|
|
if (is_null) {
|
|
v = f2.val;
|
|
is_null = false;
|
|
} else {
|
|
v = std::min(v, f2.val);
|
|
}
|
|
}
|
|
|
|
if (!f3.is_null) {
|
|
if (is_null) {
|
|
v = f3.val;
|
|
is_null = false;
|
|
} else {
|
|
v = std::min(v, f3.val);
|
|
}
|
|
}
|
|
|
|
return is_null ? FloatVal::null() : FloatVal(v);
|
|
}
|
|
|
|
StringVal concat(FunctionContext* context, int n, const StringVal* args) {
|
|
int size = 0;
|
|
bool all_null = true;
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
if (args[i].is_null) {
|
|
continue;
|
|
}
|
|
|
|
size += args[i].len;
|
|
all_null = false;
|
|
}
|
|
|
|
if (all_null) {
|
|
return StringVal::null();
|
|
}
|
|
|
|
int offset = 0;
|
|
StringVal result(context, size);
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
if (args[i].is_null) {
|
|
continue;
|
|
}
|
|
|
|
memcpy(result.ptr + offset, args[i].ptr, args[i].len);
|
|
offset += args[i].len;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
IntVal num_var_args(FunctionContext*, const BigIntVal& dummy, int n, const IntVal* args) {
|
|
return IntVal(n);
|
|
}
|
|
|
|
IntVal validat_udf(FunctionContext* context) {
|
|
EXPECT_EQ(context->version(), FunctionContext::V2_0);
|
|
EXPECT_FALSE(context->has_error());
|
|
EXPECT_TRUE(context->error_msg() == NULL);
|
|
return IntVal::null();
|
|
}
|
|
|
|
IntVal validate_fail(FunctionContext* context) {
|
|
EXPECT_FALSE(context->has_error());
|
|
EXPECT_TRUE(context->error_msg() == NULL);
|
|
context->set_error("Fail");
|
|
EXPECT_TRUE(context->has_error());
|
|
EXPECT_TRUE(strcmp(context->error_msg(), "Fail") == 0);
|
|
return IntVal::null();
|
|
}
|
|
|
|
IntVal validate_mem(FunctionContext* context) {
|
|
EXPECT_TRUE(context->allocate(0) == NULL);
|
|
uint8_t* buffer = context->allocate(10);
|
|
EXPECT_TRUE(buffer != NULL);
|
|
memset(buffer, 0, 10);
|
|
context->free(buffer);
|
|
return IntVal::null();
|
|
}
|
|
|
|
StringVal time_to_string(FunctionContext* context, const TimestampVal& time) {
|
|
boost::posix_time::ptime t(*(boost::gregorian::date*)&time.date);
|
|
t += boost::posix_time::nanoseconds(time.time_of_day);
|
|
std::stringstream ss;
|
|
ss << boost::posix_time::to_iso_extended_string(t)
|
|
<< " " << boost::posix_time::to_simple_string(t.time_of_day());
|
|
std::string s = ss.str();
|
|
StringVal result(context, s.size());
|
|
memcpy(result.ptr, s.data(), result.len);
|
|
return result;
|
|
}
|
|
|
|
TEST(UdfTest, TestFunctionContext) {
|
|
EXPECT_TRUE(UdfTestHarness::validat_udf<IntVal>(validat_udf, IntVal::null()));
|
|
EXPECT_FALSE(UdfTestHarness::validat_udf<IntVal>(validate_fail, IntVal::null()));
|
|
EXPECT_TRUE(UdfTestHarness::validat_udf<IntVal>(validate_mem, IntVal::null()));
|
|
}
|
|
|
|
TEST(UdfTest, TestValidate) {
|
|
EXPECT_TRUE(UdfTestHarness::validat_udf<DoubleVal>(zero_udf, DoubleVal(0)));
|
|
EXPECT_FALSE(UdfTestHarness::validat_udf<DoubleVal>(zero_udf, DoubleVal(10)));
|
|
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<StringVal, StringVal>(
|
|
log_udf, StringVal("abcd"), StringVal("abcd"))));
|
|
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<StringVal, StringVal>(
|
|
upper_udf, StringVal("abcd"), StringVal("ABCD"))));
|
|
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<FloatVal, FloatVal, FloatVal, FloatVal>(
|
|
min3, FloatVal(1), FloatVal(2), FloatVal(3), FloatVal(1))));
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<FloatVal, FloatVal, FloatVal, FloatVal>(
|
|
min3, FloatVal(1), FloatVal::null(), FloatVal(3), FloatVal(1))));
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<FloatVal, FloatVal, FloatVal, FloatVal>(
|
|
min3, FloatVal::null(), FloatVal::null(),
|
|
FloatVal::null(), FloatVal::null())));
|
|
}
|
|
|
|
TEST(UdfTest, TestTimestampVal) {
|
|
boost::gregorian::date d(2003, 3, 15);
|
|
TimestampVal t1(*(int32_t*)&d);
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<StringVal, TimestampVal>(
|
|
time_to_string, t1, "2003-03-15 00:00:00")));
|
|
|
|
TimestampVal t2(*(int32_t*)&d, 1000L * 1000L * 5000L);
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<StringVal, TimestampVal>(
|
|
time_to_string, t2, "2003-03-15 00:00:05")));
|
|
}
|
|
|
|
TEST(UdfTest, TestVarArgs) {
|
|
std::vector<StringVal> input;
|
|
input.push_back(StringVal("Hello"));
|
|
input.push_back(StringVal("World"));
|
|
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<StringVal, StringVal>(
|
|
concat, input, StringVal("HelloWorld"))));
|
|
|
|
input.push_back(StringVal("More"));
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<StringVal, StringVal>(
|
|
concat, input, StringVal("HelloWorldMore"))));
|
|
|
|
std::vector<IntVal> args;
|
|
args.resize(10);
|
|
EXPECT_TRUE((UdfTestHarness::validat_udf<IntVal, BigIntVal, IntVal>(
|
|
num_var_args, BigIntVal(0), args, IntVal(args.size()))));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
std::string conffile = std::string(getenv("DORIS_HOME")) + "/conf/be.conf";
|
|
if (!doris::config::init(conffile.c_str(), false)) {
|
|
fprintf(stderr, "error read config file. \n");
|
|
return -1;
|
|
}
|
|
init_glog("be-test");
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|