// 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 #include #include #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(validat_udf, IntVal::null())); EXPECT_FALSE(UdfTestHarness::validat_udf(validate_fail, IntVal::null())); EXPECT_TRUE(UdfTestHarness::validat_udf(validate_mem, IntVal::null())); } TEST(UdfTest, TestValidate) { EXPECT_TRUE(UdfTestHarness::validat_udf(zero_udf, DoubleVal(0))); EXPECT_FALSE(UdfTestHarness::validat_udf(zero_udf, DoubleVal(10))); EXPECT_TRUE((UdfTestHarness::validat_udf( log_udf, StringVal("abcd"), StringVal("abcd")))); EXPECT_TRUE((UdfTestHarness::validat_udf( upper_udf, StringVal("abcd"), StringVal("ABCD")))); EXPECT_TRUE((UdfTestHarness::validat_udf( min3, FloatVal(1), FloatVal(2), FloatVal(3), FloatVal(1)))); EXPECT_TRUE((UdfTestHarness::validat_udf( min3, FloatVal(1), FloatVal::null(), FloatVal(3), FloatVal(1)))); EXPECT_TRUE((UdfTestHarness::validat_udf( 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( time_to_string, t1, "2003-03-15 00:00:00"))); TimestampVal t2(*(int32_t*)&d, 1000L * 1000L * 5000L); EXPECT_TRUE((UdfTestHarness::validat_udf( time_to_string, t2, "2003-03-15 00:00:05"))); } TEST(UdfTest, TestVarArgs) { std::vector input; input.push_back(StringVal("Hello")); input.push_back(StringVal("World")); EXPECT_TRUE((UdfTestHarness::validat_udf( concat, input, StringVal("HelloWorld")))); input.push_back(StringVal("More")); EXPECT_TRUE((UdfTestHarness::validat_udf( concat, input, StringVal("HelloWorldMore")))); std::vector args; args.resize(10); EXPECT_TRUE((UdfTestHarness::validat_udf( 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(); }