blob: 39ad6d90f7ccc0702b8731ea527cad266e7df5a4 [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.
#include <cstdint>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "kudu/client/shared_ptr.h" // IWYU pragma: keep
#include "kudu/integration-tests/linked_list-test-util.h"
#include "kudu/integration-tests/log_verifier.h"
#include "kudu/mini-cluster/external_mini_cluster.h"
#include "kudu/util/monotime.h"
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"
DEFINE_string(test_version_a_bin, "", "Directory to find the binaries for \"Version A\"");
DEFINE_string(test_version_b_bin, "", "Directory to find the binaries for \"Version B\"");
// For linked list testing
DEFINE_int32(seconds_to_run, 5, "Number of seconds for which to run the test");
DEFINE_int32(num_chains, 50, "Number of parallel chains to generate");
DEFINE_int32(num_tablets, 3, "Number of tablets over which to split the data");
DEFINE_bool(enable_mutation, true, "Enable periodic mutation of inserted rows");
DEFINE_int32(num_snapshots, 3, "Number of snapshots to verify across replicas and reboots.");
DEFINE_int32(num_replicas, 3, "Number of replicas per tablet");
using std::string;
using std::unique_ptr;
using std::vector;
const char* kTableName = "test_table";
const int kNumTabletServers = 3;
namespace kudu {
using cluster::ExternalMiniCluster;
using cluster::ExternalMiniClusterOptions;
namespace client {
class KuduClient;
}
namespace itest {
// A test suite designed to test the ability to migrate between two (or more)
// versions of Kudu. Not invoked by "ctest".
class VersionMigrationTest : public KuduTest {
protected:
void SetUp() override {
if (FLAGS_test_version_a_bin.empty() || FLAGS_test_version_b_bin.empty()) {
FAIL() << "Must specify --test_version_a_bin and --test_version_b_bin flags";
}
KuduTest::SetUp();
}
void StartCluster(const vector<string>& extra_ts_flags = {},
const vector<string>& extra_master_flags = {},
int num_tablet_servers = 3,
const string& bin_path = "");
unique_ptr<ExternalMiniCluster> cluster_;
client::sp::shared_ptr<client::KuduClient> client_;
unique_ptr<LinkedListTester> tester_;
unique_ptr<LogVerifier> verifier_;
};
void VersionMigrationTest::StartCluster(const vector<string>& extra_ts_flags,
const vector<string>& extra_master_flags,
int num_tablet_servers,
const string& bin_path) {
ExternalMiniClusterOptions opts;
if (!bin_path.empty()) opts.daemon_bin_path = bin_path;
opts.num_tablet_servers = num_tablet_servers;
opts.extra_master_flags = extra_master_flags;
opts.extra_master_flags.emplace_back("--undefok=unlock_experimental_flags,unlock_unsafe_flags");
opts.extra_tserver_flags = extra_ts_flags;
opts.extra_tserver_flags.emplace_back("--undefok=unlock_experimental_flags,unlock_unsafe_flags");
cluster_.reset(new ExternalMiniCluster(std::move(opts)));
verifier_.reset(new LogVerifier(cluster_.get()));
ASSERT_OK(cluster_->Start());
ASSERT_OK(cluster_->CreateClient(nullptr, &client_));
tester_.reset(new LinkedListTester(client_, kTableName,
FLAGS_num_chains,
FLAGS_num_tablets,
FLAGS_num_replicas,
FLAGS_enable_mutation));
}
// Test that a tablet created with "Version A" does not lose data and can be
// read after upgrading to "Version B" of the software.
TEST_F(VersionMigrationTest, TestLinkedListSimpleMigration) {
LOG(INFO) << "Starting cluster using binaries at " << FLAGS_test_version_a_bin;
NO_FATALS(StartCluster({}, {}, kNumTabletServers, FLAGS_test_version_a_bin));
// Create the linked list and verify it with Version A.
int64_t written = 0;
ASSERT_OK(tester_->CreateLinkedListTable());
ASSERT_OK(tester_->LoadLinkedList(MonoDelta::FromSeconds(FLAGS_seconds_to_run),
FLAGS_num_snapshots,
&written));
ASSERT_OK(tester_->WaitAndVerify(FLAGS_seconds_to_run, written));
ASSERT_OK(verifier_->VerifyCommittedOpIdsMatch());
NO_FATALS(cluster_->AssertNoCrashes());
// Now switch from Version A to Version B.
cluster_->Shutdown();
LOG(INFO) << "Restarting cluster using binaries at " << FLAGS_test_version_b_bin;
cluster_->SetDaemonBinPath(FLAGS_test_version_b_bin);
// Verify the linked list with Version B.
// We loop this twice, in case we've introduced a bug where tablet bootstrap
// might fail on the second restart after migrating between versions of Kudu.
for (int i = 0; i < 2; i++) {
cluster_->Restart();
ASSERT_OK(tester_->WaitAndVerify(FLAGS_seconds_to_run, written));
ASSERT_OK(verifier_->VerifyCommittedOpIdsMatch());
NO_FATALS(cluster_->AssertNoCrashes());
cluster_->Shutdown();
}
}
} // namespace itest
} // namespace kudu