YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/tools/ysck-test.cc
Line
Count
Source (jump to first uncovered line)
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
33
#include <memory>
34
#include <unordered_map>
35
36
#include <boost/lexical_cast.hpp>
37
#include <glog/logging.h>
38
#include <gtest/gtest.h>
39
40
#include "yb/gutil/callback.h"
41
#include "yb/gutil/map-util.h"
42
#include "yb/gutil/strings/substitute.h"
43
44
#include "yb/tools/ysck.h"
45
46
#include "yb/util/test_util.h"
47
48
namespace yb {
49
namespace tools {
50
51
using std::shared_ptr;
52
using std::static_pointer_cast;
53
using std::string;
54
using std::unordered_map;
55
using std::vector;
56
using client::YBTableName;
57
58
static const YBTableName kTableName(YQL_DATABASE_CQL, "test");
59
60
class MockYsckTabletServer : public YsckTabletServer {
61
 public:
62
  explicit MockYsckTabletServer(const string& uuid)
63
      : YsckTabletServer(uuid),
64
        connect_status_(Status::OK()),
65
0
        address_("<mock>") {
66
0
  }
67
68
0
  Status Connect() const override {
69
0
    return connect_status_;
70
0
  }
71
72
  virtual void RunTabletChecksumScanAsync(
73
      const std::string& tablet_id,
74
      const Schema& schema,
75
      const ChecksumOptions& options,
76
0
      const ReportResultCallback& callback) override {
77
0
    callback.Run(Status::OK(), 0);
78
0
  }
79
80
0
  Status CurrentHybridTime(uint64_t* hybrid_time) const override {
81
0
    *hybrid_time = 0;
82
0
    return Status::OK();
83
0
  }
84
85
0
  const std::string& address() const override {
86
0
    return address_;
87
0
  }
88
89
  // Public because the unit tests mutate this variable directly.
90
  Status connect_status_;
91
92
 private:
93
  const string address_;
94
};
95
96
class MockYsckMaster : public YsckMaster {
97
 public:
98
  MockYsckMaster()
99
0
      : connect_status_(Status::OK()) {
100
0
  }
101
102
0
  Status Connect() const override {
103
0
    return connect_status_;
104
0
  }
105
106
0
  Status RetrieveTabletServers(TSMap* tablet_servers) override {
107
0
    *tablet_servers = tablet_servers_;
108
0
    return Status::OK();
109
0
  }
110
111
0
  Status RetrieveTablesList(vector<shared_ptr<YsckTable>>* tables) override {
112
0
    tables->assign(tables_.begin(), tables_.end());
113
0
    return Status::OK();
114
0
  }
115
116
0
  Status RetrieveTabletsList(const shared_ptr<YsckTable>& table) override {
117
0
    return Status::OK();
118
0
  }
119
120
  // Public because the unit tests mutate these variables directly.
121
  Status connect_status_;
122
  TSMap tablet_servers_;
123
  vector<shared_ptr<YsckTable>> tables_;
124
};
125
126
class YsckTest : public YBTest {
127
 public:
128
  YsckTest()
129
      : master_(new MockYsckMaster()),
130
        cluster_(new YsckCluster(static_pointer_cast<YsckMaster>(master_))),
131
0
        ysck_(new Ysck(cluster_)) {
132
0
    unordered_map<string, shared_ptr<YsckTabletServer>> tablet_servers;
133
0
    for (int i = 0; i < 3; i++) {
134
0
      string name = strings::Substitute("$0", i);
135
0
      shared_ptr<MockYsckTabletServer> ts(new MockYsckTabletServer(name));
136
0
      InsertOrDie(&tablet_servers, ts->uuid(), ts);
137
0
    }
138
0
    master_->tablet_servers_.swap(tablet_servers);
139
0
  }
140
141
 protected:
142
0
  void CreateDefaultAssignmentPlan(int tablets_count) {
143
0
    while (tablets_count > 0) {
144
0
      for (const YsckMaster::TSMap::value_type& entry : master_->tablet_servers_) {
145
0
        if (tablets_count-- == 0) return;
146
0
        assignment_plan_.push_back(entry.second->uuid());
147
0
      }
148
0
    }
149
0
  }
150
151
0
  void CreateOneTableOneTablet() {
152
0
    CreateDefaultAssignmentPlan(1);
153
154
0
    shared_ptr<YsckTablet> tablet(new YsckTablet("1"));
155
0
    CreateAndFillTablet(tablet, 1, true);
156
157
0
    CreateAndAddTable({tablet}, kTableName, 1);
158
0
  }
159
160
0
  void CreateOneSmallReplicatedTable() {
161
0
    int num_replicas = 3;
162
0
    int num_tablets = 3;
163
0
    vector<shared_ptr<YsckTablet>> tablets;
164
0
    CreateDefaultAssignmentPlan(num_replicas * num_tablets);
165
0
    for (int i = 0; i < num_tablets; i++) {
166
0
      shared_ptr<YsckTablet> tablet(new YsckTablet(boost::lexical_cast<string>(i)));
167
0
      CreateAndFillTablet(tablet, num_replicas, true);
168
0
      tablets.push_back(tablet);
169
0
    }
170
171
0
    CreateAndAddTable(tablets, kTableName, num_replicas);
172
0
  }
173
174
0
  void CreateOneOneTabletReplicatedBrokenTable() {
175
    // We're placing only two tablets, the 3rd goes nowhere.
176
0
    CreateDefaultAssignmentPlan(2);
177
178
0
    shared_ptr<YsckTablet> tablet(new YsckTablet("1"));
179
0
    CreateAndFillTablet(tablet, 2, false);
180
181
0
    CreateAndAddTable({tablet}, kTableName, 3);
182
0
  }
183
184
  void CreateAndAddTable(vector<shared_ptr<YsckTablet>> tablets,
185
0
                         const YBTableName& name, int num_replicas) {
186
0
    shared_ptr<YsckTable> table(new YsckTable(/* id */ "", name, Schema(), num_replicas,
187
0
        TableType::YQL_TABLE_TYPE));
188
0
    table->set_tablets(tablets);
189
190
0
    vector<shared_ptr<YsckTable>> tables = { table };
191
0
    master_->tables_.assign(tables.begin(), tables.end());
192
0
  }
193
194
  void CreateAndFillTablet(const shared_ptr<YsckTablet>& tablet,
195
                           int num_replicas,
196
0
                           bool has_leader) {
197
0
    vector<shared_ptr<YsckTabletReplica>> replicas;
198
0
    if (has_leader) {
199
0
      CreateReplicaAndAdd(&replicas, true);
200
0
      num_replicas--;
201
0
    }
202
0
    for (int i = 0; i < num_replicas; i++) {
203
0
      CreateReplicaAndAdd(&replicas, false);
204
0
    }
205
0
    tablet->set_replicas(replicas);
206
0
  }
207
208
0
  void CreateReplicaAndAdd(vector<shared_ptr<YsckTabletReplica>>* replicas, bool is_leader) {
209
0
    shared_ptr<YsckTabletReplica> replica(new YsckTabletReplica(assignment_plan_.back(),
210
0
                                                                is_leader, !is_leader));
211
0
    assignment_plan_.pop_back();
212
0
    replicas->push_back(replica);
213
0
  }
214
215
  shared_ptr<MockYsckMaster> master_;
216
  shared_ptr<YsckCluster> cluster_;
217
  shared_ptr<Ysck> ysck_;
218
  // This is used as a stack. First the unit test is responsible to create a plan to follow, that
219
  // is the order in which each replica of each tablet will be assigned, starting from the end.
220
  // So if you have 2 tablets with num_replicas=3 and 3 tablet servers, then to distribute evenly
221
  // you should have a list that looks like ts1,ts2,ts3,ts3,ts2,ts1 so that the two LEADERS, which
222
  // are assigned first, end up on ts1 and ts3.
223
  vector<string> assignment_plan_;
224
};
225
226
0
TEST_F(YsckTest, TestMasterOk) {
227
0
  ASSERT_OK(ysck_->CheckMasterRunning());
228
0
}
229
230
0
TEST_F(YsckTest, TestMasterUnavailable) {
231
0
  Status error = STATUS(NetworkError, "Network failure");
232
0
  master_->connect_status_ = error;
233
0
  ASSERT_TRUE(ysck_->CheckMasterRunning().IsNetworkError());
234
0
}
235
236
0
TEST_F(YsckTest, TestTabletServersOk) {
237
0
  ASSERT_OK(ysck_->CheckMasterRunning());
238
0
  ASSERT_OK(ysck_->FetchTableAndTabletInfo());
239
0
  ASSERT_OK(ysck_->CheckTabletServersRunning());
240
0
}
241
242
0
TEST_F(YsckTest, TestBadTabletServer) {
243
0
  ASSERT_OK(ysck_->CheckMasterRunning());
244
0
  Status error = STATUS(NetworkError, "Network failure");
245
0
  static_pointer_cast<MockYsckTabletServer>(master_->tablet_servers_.begin()->second)
246
0
      ->connect_status_ = error;
247
0
  ASSERT_OK(ysck_->FetchTableAndTabletInfo());
248
0
  Status s = ysck_->CheckTabletServersRunning();
249
0
  ASSERT_TRUE(s.IsNetworkError()) << "Status returned: " << s.ToString();
250
0
}
251
252
0
TEST_F(YsckTest, TestZeroTableCheck) {
253
0
  ASSERT_OK(ysck_->CheckMasterRunning());
254
0
  ASSERT_OK(ysck_->FetchTableAndTabletInfo());
255
0
  ASSERT_OK(ysck_->CheckTabletServersRunning());
256
0
  ASSERT_OK(ysck_->CheckTablesConsistency());
257
0
}
258
259
0
TEST_F(YsckTest, TestOneTableCheck) {
260
0
  CreateOneTableOneTablet();
261
0
  ASSERT_OK(ysck_->CheckMasterRunning());
262
0
  ASSERT_OK(ysck_->FetchTableAndTabletInfo());
263
0
  ASSERT_OK(ysck_->CheckTabletServersRunning());
264
0
  ASSERT_OK(ysck_->CheckTablesConsistency());
265
0
}
266
267
0
TEST_F(YsckTest, TestOneSmallReplicatedTable) {
268
0
  CreateOneSmallReplicatedTable();
269
0
  ASSERT_OK(ysck_->CheckMasterRunning());
270
0
  ASSERT_OK(ysck_->FetchTableAndTabletInfo());
271
0
  ASSERT_OK(ysck_->CheckTabletServersRunning());
272
0
  ASSERT_OK(ysck_->CheckTablesConsistency());
273
0
}
274
275
0
TEST_F(YsckTest, TestOneOneTabletBrokenTable) {
276
0
  CreateOneOneTabletReplicatedBrokenTable();
277
0
  ASSERT_OK(ysck_->CheckMasterRunning());
278
0
  ASSERT_OK(ysck_->FetchTableAndTabletInfo());
279
0
  ASSERT_OK(ysck_->CheckTabletServersRunning());
280
0
  ASSERT_TRUE(ysck_->CheckTablesConsistency().IsCorruption());
281
0
}
282
283
} // namespace tools
284
} // namespace yb