YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/integration-tests/yb-ts-cli-itest.cc
Line
Count
Source
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include <string>
15
#include <unordered_map>
16
#include <vector>
17
18
#include <gtest/gtest.h>
19
20
#include "yb/integration-tests/cluster_itest_util.h"
21
#include "yb/integration-tests/external_mini_cluster.h"
22
#include "yb/integration-tests/external_mini_cluster_fs_inspector.h"
23
#include "yb/integration-tests/yb_table_test_base.h"
24
25
#include "yb/tserver/tserver_service.proxy.h"
26
27
#include "yb/util/path_util.h"
28
#include "yb/util/status_log.h"
29
#include "yb/util/subprocess.h"
30
#include "yb/util/test_util.h"
31
32
namespace yb {
33
namespace integration_tests {
34
namespace {
35
36
const auto kDefaultTimeout = 30000ms;
37
const auto kServerIndex = 0;
38
39
1
string GetTsCliToolPath() {
40
1
  static const char* const kTsCliToolName = "yb-ts-cli";
41
1
  return GetToolPath(kTsCliToolName);
42
1
}
43
44
} // anonymous namespace
45
46
class YBTsCliITest : public YBTableTestBase {
47
 protected:
48
2
  bool use_yb_admin_client() override { return true; }
49
50
10
  bool use_external_mini_cluster() override { return true; }
51
52
2
  int num_tablets() override {
53
2
    return 12;
54
2
  }
55
56
1
  int num_drives() override {
57
1
    return 2;
58
1
  }
59
60
1
  bool enable_ysql() override {
61
    // Do not create the transaction status table.
62
1
    return false;
63
1
  }
64
65
1
  void WaitForTablet(const string& tablet_id) {
66
1
    ExternalTabletServer* ts = external_mini_cluster()->tablet_server(kServerIndex);
67
1
    tserver::TabletServerServiceProxy proxy(&external_mini_cluster()->proxy_cache(),
68
1
                                                 ts->bound_rpc_addr());
69
1
    ASSERT_OK(WaitFor([&]() -> Result<bool> {
70
1
      rpc::RpcController rpc;
71
1
      tserver::GetTabletStatusRequestPB req;
72
1
      tserver::GetTabletStatusResponsePB resp;
73
1
      rpc.set_timeout(kDefaultTimeout);
74
1
      req.set_tablet_id(tablet_id);
75
1
      RETURN_NOT_OK(proxy.GetTabletStatus(req, &resp, &rpc));
76
1
      if (resp.has_error() || resp.tablet_status().state() != tablet::RaftGroupStatePB::RUNNING) {
77
1
        return false;
78
1
      }
79
1
      return true;
80
1
    }, kDefaultTimeout * 2, "WaitForTablet"));
81
1
  }
82
};
83
84
// Test steps:
85
// Setup a cluster with three drives on each ts, reduce drives on first ts
86
// create table and increase drives on first ts to lead to bad distribution across drives
87
// call rpc DeleteTablet and restart a ts to validate that tablet was moved
88
1
TEST_F(YBTsCliITest, MoveTablet) {
89
1
  auto inspect = std::make_unique<itest::ExternalMiniClusterFsInspector>(external_mini_cluster());
90
91
1
  string tablet_id;
92
1
  string root_dir;
93
94
1
  ExternalTabletServer* ts = external_mini_cluster()->tablet_server(kServerIndex);
95
96
1
  ts->Shutdown();
97
1
  ASSERT_OK(ts->SetNumDrives(3));
98
1
  ASSERT_OK(ts->Restart());
99
100
1
  size_t max_count = 0;
101
  // Look for TS with max number of tablets on one drive and get one tablet to try move it.
102
2
  for (const auto& drive_and_tablets : inspect->DrivesOnTS(kServerIndex)) {
103
2
    const vector<string>& tablets = drive_and_tablets.second;
104
2
    if (tablets.size() > max_count) {
105
1
      root_dir = drive_and_tablets.first;
106
1
      max_count = tablets.size();
107
1
      tablet_id = tablets.front();
108
1
    }
109
2
  }
110
111
  // Tablet id to be moved should not be empty.
112
1
  ASSERT_FALSE(tablet_id.empty());
113
1
  WaitForTablet(tablet_id);
114
115
1
  string exe_path = GetTsCliToolPath();
116
1
  vector<string> argv = {exe_path, "--server_address", AsString(ts->bound_rpc_addr()),
117
1
                         "delete_tablet", "-force", tablet_id, "Deleting for yb-ts-cli-itest"};
118
1
  ASSERT_OK(WaitFor([&]() -> Result<bool> {
119
1
    Status s = Subprocess::Call(argv);
120
1
    return s.ok();
121
1
  }, kDefaultTimeout * 2, "CallTsCli"));
122
123
1
  ts->Shutdown();
124
1
  ASSERT_OK(ts->Restart());
125
126
1
  ASSERT_OK(external_mini_cluster()->WaitForTabletServerCount(num_tablet_servers(),
127
1
                                                              kDefaultTimeout));
128
129
1
  ASSERT_OK(WaitFor([&]() -> Result<bool> {
130
1
      for (const auto& drive_and_tablets : inspect->DrivesOnTS(kServerIndex)) {
131
1
        const vector<string>& tablets = drive_and_tablets.second;
132
1
        if (find(tablets.begin(), tablets.end(), tablet_id) != tablets.end()) {
133
1
          bool same = drive_and_tablets.first == root_dir;
134
1
          if (same) {
135
1
            LOG(INFO) << "TS still have tablet " << tablet_id << " at " << root_dir;
136
1
          }
137
1
          return !same;
138
1
        }
139
1
      }
140
1
      return false;
141
1
    }, kDefaultTimeout * 2, "WaitForTabletMovedFromTS"));
142
1
}
143
144
} // namespace integration_tests
145
} // namespace yb