| // 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 "kudu/util/test_util.h" |
| |
| #include <gflags/gflags.h> |
| #include <glog/logging.h> |
| |
| #include "kudu/gutil/strings/strcat.h" |
| #include "kudu/gutil/strings/substitute.h" |
| #include "kudu/gutil/strings/util.h" |
| #include "kudu/gutil/walltime.h" |
| #include "kudu/util/env.h" |
| #include "kudu/util/path_util.h" |
| #include "kudu/util/random.h" |
| #include "kudu/util/spinlock_profiling.h" |
| |
| DEFINE_string(test_leave_files, "on_failure", |
| "Whether to leave test files around after the test run. " |
| " Valid values are 'always', 'on_failure', or 'never'"); |
| |
| DEFINE_int32(test_random_seed, 0, "Random seed to use for randomized tests"); |
| |
| using std::string; |
| using strings::Substitute; |
| |
| namespace kudu { |
| |
| static const char* const kSlowTestsEnvVariable = "KUDU_ALLOW_SLOW_TESTS"; |
| |
| static const uint64 kTestBeganAtMicros = Env::Default()->NowMicros(); |
| |
| /////////////////////////////////////////////////// |
| // KuduTest |
| /////////////////////////////////////////////////// |
| |
| KuduTest::KuduTest() |
| : env_(new EnvWrapper(Env::Default())), |
| test_dir_(GetTestDataDirectory()) { |
| } |
| |
| // env passed in from subclass, for tests that run in-memory |
| KuduTest::KuduTest(Env *env) |
| : env_(env), |
| test_dir_(GetTestDataDirectory()) { |
| } |
| |
| KuduTest::~KuduTest() { |
| // Clean up the test directory in the destructor instead of a TearDown |
| // method. This is better because it ensures that the child-class |
| // dtor runs first -- so, if the child class is using a minicluster, etc, |
| // we will shut that down before we remove files underneath. |
| if (FLAGS_test_leave_files == "always") { |
| LOG(INFO) << "-----------------------------------------------"; |
| LOG(INFO) << "--test_leave_files specified, leaving files in " << test_dir_; |
| } else if (FLAGS_test_leave_files == "on_failure" && HasFatalFailure()) { |
| LOG(INFO) << "-----------------------------------------------"; |
| LOG(INFO) << "Had fatal failures, leaving test files at " << test_dir_; |
| } else { |
| VLOG(1) << "Cleaning up temporary test files..."; |
| WARN_NOT_OK(env_->DeleteRecursively(test_dir_), |
| "Couldn't remove test files"); |
| } |
| } |
| |
| void KuduTest::SetUp() { |
| InitSpinLockContentionProfiling(); |
| } |
| |
| string KuduTest::GetTestPath(const string& relative_path) { |
| CHECK(!test_dir_.empty()) << "Call SetUp() first"; |
| return JoinPathSegments(test_dir_, relative_path); |
| } |
| |
| /////////////////////////////////////////////////// |
| // Test utility functions |
| /////////////////////////////////////////////////// |
| |
| bool AllowSlowTests() { |
| char *e = getenv(kSlowTestsEnvVariable); |
| if ((e == nullptr) || |
| (strlen(e) == 0) || |
| (strcasecmp(e, "false") == 0) || |
| (strcasecmp(e, "0") == 0) || |
| (strcasecmp(e, "no") == 0)) { |
| return false; |
| } |
| if ((strcasecmp(e, "true") == 0) || |
| (strcasecmp(e, "1") == 0) || |
| (strcasecmp(e, "yes") == 0)) { |
| return true; |
| } |
| LOG(FATAL) << "Unrecognized value for " << kSlowTestsEnvVariable << ": " << e; |
| return false; |
| } |
| |
| void OverrideFlagForSlowTests(const std::string& flag_name, |
| const std::string& new_value) { |
| // Ensure that the flag is valid. |
| google::GetCommandLineFlagInfoOrDie(flag_name.c_str()); |
| |
| // If we're not running slow tests, don't override it. |
| if (!AllowSlowTests()) { |
| return; |
| } |
| google::SetCommandLineOptionWithMode(flag_name.c_str(), new_value.c_str(), |
| google::SET_FLAG_IF_DEFAULT); |
| } |
| |
| int SeedRandom() { |
| int seed; |
| // Initialize random seed |
| if (FLAGS_test_random_seed == 0) { |
| // Not specified by user |
| seed = static_cast<int>(GetCurrentTimeMicros()); |
| } else { |
| seed = FLAGS_test_random_seed; |
| } |
| LOG(INFO) << "Using random seed: " << seed; |
| srand(seed); |
| return seed; |
| } |
| |
| string GetTestDataDirectory() { |
| const ::testing::TestInfo* const test_info = |
| ::testing::UnitTest::GetInstance()->current_test_info(); |
| CHECK(test_info) << "Must be running in a gtest unit test to call this function"; |
| string dir; |
| CHECK_OK(Env::Default()->GetTestDirectory(&dir)); |
| |
| // The directory name includes some strings for specific reasons: |
| // - program name: identifies the directory to the test invoker |
| // - timestamp and pid: disambiguates with prior runs of the same test |
| // |
| // e.g. "env-test.TestEnv.TestReadFully.1409169025392361-23600" |
| dir += Substitute("/$0.$1.$2.$3-$4", |
| StringReplace(google::ProgramInvocationShortName(), "/", "_", true), |
| StringReplace(test_info->test_case_name(), "/", "_", true), |
| StringReplace(test_info->name(), "/", "_", true), |
| kTestBeganAtMicros, |
| getpid()); |
| Status s = Env::Default()->CreateDir(dir); |
| CHECK(s.IsAlreadyPresent() || s.ok()) |
| << "Could not create directory " << dir << ": " << s.ToString(); |
| if (s.ok()) { |
| string metadata; |
| |
| StrAppend(&metadata, Substitute("PID=$0\n", getpid())); |
| |
| StrAppend(&metadata, Substitute("PPID=$0\n", getppid())); |
| |
| char* jenkins_build_id = getenv("BUILD_ID"); |
| if (jenkins_build_id) { |
| StrAppend(&metadata, Substitute("BUILD_ID=$0\n", jenkins_build_id)); |
| } |
| |
| CHECK_OK(WriteStringToFile(Env::Default(), metadata, |
| Substitute("$0/test_metadata", dir))); |
| } |
| return dir; |
| } |
| |
| } // namespace kudu |