YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/client/client-unittest.cc
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
// Tests for the client which are true unit tests and don't require a cluster, etc.
33
34
#include <functional>
35
#include <string>
36
#include <vector>
37
38
#include <gtest/gtest.h>
39
40
#include "yb/client/client-internal.h"
41
#include "yb/client/schema.h"
42
43
namespace yb {
44
namespace client {
45
46
using std::string;
47
using std::vector;
48
49
using namespace std::literals;
50
using namespace std::placeholders;
51
52
const std::string kNoPrimaryKeyMessage = "Invalid argument: No primary key specified";
53
54
1
TEST(ClientUnitTest, TestSchemaBuilder_EmptySchema) {
55
1
  YBSchema s;
56
1
  YBSchemaBuilder b;
57
1
  ASSERT_EQ(kNoPrimaryKeyMessage, b.Build(&s).ToString(/* no file/line */ false));
58
1
}
59
60
1
TEST(ClientUnitTest, TestSchemaBuilder_KeyNotSpecified) {
61
1
  YBSchema s;
62
1
  YBSchemaBuilder b;
63
1
  b.AddColumn("a")->Type(INT32)->NotNull();
64
1
  b.AddColumn("b")->Type(INT32)->NotNull();
65
1
  ASSERT_EQ(kNoPrimaryKeyMessage, b.Build(&s).ToString(/* no file/line */ false));
66
1
}
67
68
1
TEST(ClientUnitTest, TestSchemaBuilder_DuplicateColumn) {
69
1
  YBSchema s;
70
1
  YBSchemaBuilder b;
71
1
  b.AddColumn("key")->Type(INT32)->NotNull()->PrimaryKey();
72
1
  b.AddColumn("x")->Type(INT32);
73
1
  b.AddColumn("x")->Type(INT32);
74
1
  ASSERT_EQ("Invalid argument: Duplicate column name: x",
75
1
            b.Build(&s).ToString(/* no file/line */ false));
76
1
}
77
78
1
TEST(ClientUnitTest, TestSchemaBuilder_WrongPrimaryKeyOrder) {
79
1
  YBSchema s;
80
1
  YBSchemaBuilder b;
81
1
  b.AddColumn("key")->Type(INT32);
82
1
  b.AddColumn("x")->Type(INT32)->NotNull()->PrimaryKey();
83
1
  b.AddColumn("x")->Type(INT32);
84
1
  const char *expected_status =
85
1
    "Invalid argument: Primary key column 'x' should be before regular column 'key'";
86
1
  ASSERT_EQ(expected_status, b.Build(&s).ToString(/* no file/line */ false));
87
1
}
88
89
1
TEST(ClientUnitTest, TestSchemaBuilder_WrongHashKeyOrder) {
90
1
  YBSchema s;
91
1
  YBSchemaBuilder b;
92
1
  b.AddColumn("a")->Type(INT32)->PrimaryKey();
93
1
  b.AddColumn("b")->Type(INT32)->HashPrimaryKey();
94
1
  const char *expected_status =
95
1
    "Invalid argument: Hash primary key column 'b' should be before primary key 'a'";
96
1
  ASSERT_EQ(expected_status, b.Build(&s).ToString(/* no file/line */ false));
97
1
}
98
99
1
TEST(ClientUnitTest, TestSchemaBuilder_PrimaryKeyOnColumnAndSet) {
100
1
  YBSchema s;
101
1
  YBSchemaBuilder b;
102
1
  b.AddColumn("a")->Type(INT32)->PrimaryKey();
103
1
  b.AddColumn("b")->Type(INT32);
104
1
  b.SetPrimaryKey({ "a", "b" });
105
1
  ASSERT_EQ("Invalid argument: Primary key specified by both "
106
1
            "SetPrimaryKey() and on a specific column: a",
107
1
            b.Build(&s).ToString(/* no file/line */ false));
108
1
}
109
110
1
TEST(ClientUnitTest, TestSchemaBuilder_SingleKey_GoodSchema) {
111
1
  YBSchema s;
112
1
  YBSchemaBuilder b;
113
1
  b.AddColumn("a")->Type(INT32)->NotNull()->PrimaryKey();
114
1
  b.AddColumn("b")->Type(INT32);
115
1
  b.AddColumn("c")->Type(INT32)->NotNull();
116
1
  ASSERT_EQ("OK", b.Build(&s).ToString());
117
1
}
118
119
1
TEST(ClientUnitTest, TestSchemaBuilder_CompoundKey_GoodSchema) {
120
1
  YBSchema s;
121
1
  YBSchemaBuilder b;
122
1
  b.AddColumn("a")->Type(INT32)->NotNull();
123
1
  b.AddColumn("b")->Type(INT32)->NotNull();
124
1
  b.SetPrimaryKey({ "a", "b" });
125
1
  ASSERT_EQ("OK", b.Build(&s).ToString());
126
127
1
  auto key_columns = s.GetPrimaryKeyColumnIndexes();
128
1
  ASSERT_EQ(vector<size_t>({ 0, 1 }), key_columns);
129
1
}
130
131
1
TEST(ClientUnitTest, TestSchemaBuilder_CompoundKey_KeyNotFirst) {
132
1
  YBSchema s;
133
1
  YBSchemaBuilder b;
134
1
  b.AddColumn("x")->Type(INT32)->NotNull();
135
1
  b.AddColumn("a")->Type(INT32)->NotNull();
136
1
  b.AddColumn("b")->Type(INT32)->NotNull();
137
1
  b.SetPrimaryKey({ "a", "b" });
138
1
  ASSERT_EQ("Invalid argument: Primary key columns must be listed "
139
1
            "first in the schema: a",
140
1
            b.Build(&s).ToString(/* no file/line */ false));
141
1
}
142
143
1
TEST(ClientUnitTest, TestSchemaBuilder_CompoundKey_BadColumnName) {
144
1
  YBSchema s;
145
1
  YBSchemaBuilder b;
146
1
  b.AddColumn("a")->Type(INT32)->NotNull();
147
1
  b.AddColumn("b")->Type(INT32)->NotNull();
148
1
  b.SetPrimaryKey({ "foo" });
149
1
  ASSERT_EQ("Invalid argument: Primary key column not defined: foo",
150
1
            b.Build(&s).ToString(/* no file/line */ false));
151
1
}
152
153
namespace {
154
155
7
Status TestFunc(CoarseTimePoint deadline, bool* retry, int* counter) {
156
7
  ++*counter;
157
7
  *retry = true;
158
7
  return STATUS(RuntimeError, "x");
159
7
}
160
161
} // anonymous namespace
162
163
1
TEST(ClientUnitTest, TestRetryFunc) {
164
1
  auto deadline = CoarseMonoClock::Now() + 1s;
165
1
  int counter = 0;
166
1
  Status s =
167
1
      RetryFunc(deadline, "retrying test func", "timed out", std::bind(TestFunc, _1, _2, &counter));
168
1
  ASSERT_TRUE(s.IsTimedOut());
169
  // According to BackoffWaiter, find n such that
170
  //   sum(2^i, 3 + 1, 3 + n) + delays < deadline_duration <= sum(2^i, 3, 3 + (n + 1)) + delays
171
  // n corresponds to the number of _full_ waits.  Assuming we start RetryFunc reasonably before the
172
  // deadline, we do
173
  //   1. call func
174
  //   1. full wait
175
  //   1. call func
176
  //   1. full wait
177
  //   1. ...
178
  //   1. call func
179
  //   1. capped wait
180
  //   1. call func
181
  // After n full waits, we wait once more for a duration capped to the deadline.  We do one more
182
  // func call then exit for passing the deadline.  This means n + 2 func calls.
183
  // For this specific test,
184
  //   sum(2^i, 3 + 1, 3 + n) + delays < 1000 <= sum(2^i, 3, 3 + (n + 1)) + delays
185
  // For n := 5,
186
  //   sum(2^i, 3 + 1, 3 + 5) = 496
187
  // For n := 6,
188
  //   sum(2^i, 3 + 1, 3 + 6) = 1008
189
  // Factoring in delays, expect around 5 full waits and 1 capped wait.  The expected number of
190
  // calls is 7.  Give it +/-1.
191
1
  LOG(INFO) << "num retries: " << counter;
192
1
  ASSERT_GE(counter, 6);
193
1
  ASSERT_LE(counter, 8);
194
1
}
195
196
} // namespace client
197
} // namespace yb
198