blob: 3ac2cf95d9fe1332efde3b70f8bfdc083ab74a3c [file] [log] [blame]
// 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.
//
// Tests for the client which are true unit tests and don't require a cluster, etc.
#include <cstddef>
#include <string>
#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <gtest/gtest.h>
#include "kudu/client/client.h"
#include "kudu/client/client-internal.h"
#include "kudu/client/error_collector.h"
#include "kudu/client/schema.h"
#include "kudu/client/value.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/util/monotime.h"
#include "kudu/util/status.h"
#include "kudu/util/test_macros.h"
using std::string;
using std::vector;
using kudu::client::internal::ErrorCollector;
namespace kudu {
namespace client {
TEST(ClientUnitTest, TestSchemaBuilder_EmptySchema) {
KuduSchema s;
KuduSchemaBuilder b;
ASSERT_EQ("Invalid argument: no primary key specified",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_KeyNotSpecified) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull();
b.AddColumn("b")->Type(KuduColumnSchema::INT32)->NotNull();
ASSERT_EQ("Invalid argument: no primary key specified",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_DuplicateColumn) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("key")->Type(KuduColumnSchema::INT32)->NotNull()->PrimaryKey();
b.AddColumn("x")->Type(KuduColumnSchema::INT32);
b.AddColumn("x")->Type(KuduColumnSchema::INT32);
ASSERT_EQ("Invalid argument: Duplicate column name: x",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_KeyNotFirstColumn) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("key")->Type(KuduColumnSchema::INT32);
b.AddColumn("x")->Type(KuduColumnSchema::INT32)->NotNull()->PrimaryKey();;
b.AddColumn("x")->Type(KuduColumnSchema::INT32);
ASSERT_EQ("Invalid argument: primary key column must be the first column",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_TwoPrimaryKeys) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->PrimaryKey();
b.AddColumn("b")->Type(KuduColumnSchema::INT32)->PrimaryKey();
ASSERT_EQ("Invalid argument: multiple columns specified for primary key: a, b",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_PrimaryKeyOnColumnAndSet) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->PrimaryKey();
b.AddColumn("b")->Type(KuduColumnSchema::INT32);
b.SetPrimaryKey({ "a", "b" });
ASSERT_EQ("Invalid argument: primary key specified by both "
"SetPrimaryKey() and on a specific column: a",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_SingleKey_GoodSchema) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull()->PrimaryKey();
b.AddColumn("b")->Type(KuduColumnSchema::INT32);
b.AddColumn("c")->Type(KuduColumnSchema::INT32)->NotNull();
ASSERT_EQ("OK", b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_CompoundKey_GoodSchema) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull();
b.AddColumn("b")->Type(KuduColumnSchema::INT32)->NotNull();
b.SetPrimaryKey({ "a", "b" });
ASSERT_EQ("OK", b.Build(&s).ToString());
vector<int> key_columns;
s.GetPrimaryKeyColumnIndexes(&key_columns);
ASSERT_EQ(vector<int>({ 0, 1 }), key_columns);
}
TEST(ClientUnitTest, TestSchemaBuilder_DefaultValues) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull()->PrimaryKey();
b.AddColumn("b")->Type(KuduColumnSchema::INT32)->NotNull()
->Default(KuduValue::FromInt(12345));
ASSERT_EQ("OK", b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_DefaultValueString) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull()->PrimaryKey();
b.AddColumn("b")->Type(KuduColumnSchema::STRING)->NotNull()
->Default(KuduValue::CopyString("abc"));
b.AddColumn("c")->Type(KuduColumnSchema::BINARY)->NotNull()
->Default(KuduValue::CopyString("def"));
ASSERT_EQ("OK", b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_CompoundKey_KeyNotFirst) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("x")->Type(KuduColumnSchema::INT32)->NotNull();
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull();
b.AddColumn("b")->Type(KuduColumnSchema::INT32)->NotNull();
b.SetPrimaryKey({ "a", "b" });
ASSERT_EQ("Invalid argument: primary key columns must be listed "
"first in the schema: a",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestSchemaBuilder_CompoundKey_BadColumnName) {
KuduSchema s;
KuduSchemaBuilder b;
b.AddColumn("a")->Type(KuduColumnSchema::INT32)->NotNull();
b.AddColumn("b")->Type(KuduColumnSchema::INT32)->NotNull();
b.SetPrimaryKey({ "foo" });
ASSERT_EQ("Invalid argument: primary key column not defined: foo",
b.Build(&s).ToString());
}
TEST(ClientUnitTest, TestDisableSslFailsIfNotInitialized) {
// If we try to disable SSL initialization without setting up SSL properly,
// it should return an error.
Status s = DisableOpenSSLInitialization();
ASSERT_STR_MATCHES(s.ToString(), "Locking callback not initialized");
}
namespace {
Status TestFunc(const MonoTime& deadline, bool* retry, int* counter) {
(*counter)++;
*retry = true;
return Status::RuntimeError("x");
}
} // anonymous namespace
TEST(ClientUnitTest, TestRetryFunc) {
MonoTime deadline = MonoTime::Now() + MonoDelta::FromMilliseconds(100);
int counter = 0;
Status s = RetryFunc(deadline, "retrying test func", "timed out",
boost::bind(TestFunc, _1, _2, &counter));
ASSERT_TRUE(s.IsTimedOut());
ASSERT_GT(counter, 5);
ASSERT_LT(counter, 20);
}
TEST(ClientUnitTest, TestErrorCollector) {
{
scoped_refptr<ErrorCollector> ec(new ErrorCollector);
// Setting the max memory size limit to 'unlimited'.
EXPECT_OK(ec->SetMaxMemSize(0));
// Setting the max memory size to 1 byte.
EXPECT_OK(ec->SetMaxMemSize(1));
}
// Check that the error collector does not allow to set the memory size limit
// if at least one error has been dropped since last flush.
{
scoped_refptr<ErrorCollector> ec(new ErrorCollector);
ec->dropped_errors_cnt_ = 1;
Status s = ec->SetMaxMemSize(0);
EXPECT_TRUE(s.IsIllegalState());
ASSERT_STR_CONTAINS(s.ToString(),
"cannot set new limit: already dropped some errors");
}
// Check that the error collector does not overflow post-factum on call of the
// SetMaxMemSize() method.
{
const size_t size_bytes = 8;
scoped_refptr<ErrorCollector> ec(new ErrorCollector);
ec->mem_size_bytes_ = size_bytes;
EXPECT_OK(ec->SetMaxMemSize(0));
EXPECT_OK(ec->SetMaxMemSize(size_bytes));
Status s = ec->SetMaxMemSize(size_bytes - 1);
EXPECT_TRUE(s.IsIllegalState());
ASSERT_STR_CONTAINS(s.ToString(), "already accumulated errors for");
}
}
TEST(ClientUnitTest, TestKuduSchemaToString) {
// Test on unique PK.
KuduSchema s1;
KuduSchemaBuilder b1;
b1.AddColumn("key")->Type(KuduColumnSchema::INT32)->NotNull()->PrimaryKey();
b1.AddColumn("int_val")->Type(KuduColumnSchema::INT32)->NotNull();
b1.AddColumn("string_val")->Type(KuduColumnSchema::STRING)->Nullable();
b1.AddColumn("non_null_with_default")->Type(KuduColumnSchema::INT32)->NotNull()
->Default(KuduValue::FromInt(12345));
ASSERT_OK(b1.Build(&s1));
string schema_str_1 = "Schema [\n"
"\tprimary key (key),\n"
"\tkey[int32 NOT NULL],\n"
"\tint_val[int32 NOT NULL],\n"
"\tstring_val[string NULLABLE],\n"
"\tnon_null_with_default[int32 NOT NULL]\n"
"]";
EXPECT_EQ(schema_str_1, s1.ToString());
// Test empty schema.
KuduSchema s2;
EXPECT_EQ("Schema []", s2.ToString());
// Test on composite PK.
// Create a different schema with a multi-column PK.
KuduSchemaBuilder b2;
b2.AddColumn("k1")->Type(KuduColumnSchema::INT32)->NotNull();
b2.AddColumn("k2")->Type(KuduColumnSchema::UNIXTIME_MICROS)->NotNull();
b2.AddColumn("k3")->Type(KuduColumnSchema::INT8)->NotNull();
b2.AddColumn("dec_val")->Type(KuduColumnSchema::DECIMAL)->Nullable()->Precision(9)->Scale(2);
b2.AddColumn("int_val")->Type(KuduColumnSchema::INT32)->NotNull();
b2.AddColumn("string_val")->Type(KuduColumnSchema::STRING)->Nullable();
b2.AddColumn("non_null_with_default")->Type(KuduColumnSchema::INT32)->NotNull()
->Default(KuduValue::FromInt(12345));
b2.SetPrimaryKey({"k1", "k2", "k3"});
ASSERT_OK(b2.Build(&s2));
string schema_str_2 = "Schema [\n"
"\tprimary key (k1, k2, k3),\n"
"\tk1[int32 NOT NULL],\n"
"\tk2[unixtime_micros NOT NULL],\n"
"\tk3[int8 NOT NULL],\n"
"\tdec_val[decimal(9, 2) NULLABLE],\n"
"\tint_val[int32 NOT NULL],\n"
"\tstring_val[string NULLABLE],\n"
"\tnon_null_with_default[int32 NOT NULL]\n"
"]";
EXPECT_EQ(schema_str_2, s2.ToString());
}
} // namespace client
} // namespace kudu