blob: 77efab3a77941ea0e5972eda3c6651cfb08604f8 [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 <cstdlib>
#include <functional>
#include <map>
#include <ostream>
#include <string>
#include <utility>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "kudu/gutil/macros.h"
#include "kudu/util/debug/leakcheck_disabler.h"
#include "kudu/util/flags.h"
#include "kudu/util/flag_validators.h"
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"
DEFINE_string(grouped_0, "", "First flag to set.");
DEFINE_string(grouped_1, "", "Second flag to set.");
DEFINE_string(grouped_2, "", "Third flag to set.");
DEFINE_string(grouped_3, "", "Fourth flag to set.");
namespace kudu {
static bool CheckGroupedFlags01() {
const bool is_set_0 = !FLAGS_grouped_0.empty();
const bool is_set_1 = !FLAGS_grouped_1.empty();
if (is_set_0 != is_set_1) {
LOG(ERROR) << "--grouped_0 and --grouped_1 must be set as a group";
return false;
}
return true;
}
GROUP_FLAG_VALIDATOR(test_group_validator01, CheckGroupedFlags01)
static bool CheckGroupedFlags23() {
const bool is_set_2 = !FLAGS_grouped_2.empty();
const bool is_set_3 = !FLAGS_grouped_3.empty();
if (is_set_2 != is_set_3) {
LOG(ERROR) << "--grouped_2 and --grouped_3 must be set as a group";
return false;
}
return true;
}
GROUP_FLAG_VALIDATOR(test_group_validator23, CheckGroupedFlags23)
class FlagsValidatorsBasicTest : public KuduTest {
public:
void RunTest(const char** argv, int argc) {
char** casted_argv = const_cast<char**>(argv);
// ParseCommandLineFlags() calls exit(1) if it finds inconsistency in flags.
ASSERT_EQ(1, ParseCommandLineFlags(&argc, &casted_argv, true));
}
};
TEST_F(FlagsValidatorsBasicTest, Grouped) {
const auto& validators = GetFlagValidators();
ASSERT_EQ(2, validators.size());
const auto& it = validators.find("test_group_validator01");
ASSERT_NE(validators.end(), it);
const auto& validator = it->second;
EXPECT_TRUE(validator());
FLAGS_grouped_0 = "0";
EXPECT_FALSE(validator());
FLAGS_grouped_1 = "1";
EXPECT_TRUE(validator());
FLAGS_grouped_0 = "";
EXPECT_FALSE(validator());
FLAGS_grouped_1 = "";
EXPECT_TRUE(validator());
}
class FlagsValidatorsDeathTest : public KuduTest {
public:
void Run(const char** argv, int argc) {
debug::ScopedLeakCheckDisabler disabler;
char** casted_argv = const_cast<char**>(argv);
// ParseCommandLineFlags() calls exit(1) if one of the custom validators
// finds inconsistency in flags.
ParseCommandLineFlags(&argc, &casted_argv, true);
exit(0);
}
void RunSuccess(const char** argv, int argc) {
EXPECT_EXIT(Run(argv, argc), ::testing::ExitedWithCode(0), ".*");
}
void RunFailure(const char** argv, int argc) {
EXPECT_EXIT(Run(argv, argc), ::testing::ExitedWithCode(1),
".* Detected inconsistency in command-line flags; exiting");
}
};
TEST_F(FlagsValidatorsDeathTest, GroupedSuccessNoFlags) {
const char* argv[] = { "argv_set_0" };
NO_FATALS(RunSuccess(argv, ARRAYSIZE(argv)));
}
TEST_F(FlagsValidatorsDeathTest, GroupedSuccessSimple) {
static const size_t kArgvSize = 1 + 2;
const char* argv_sets[][kArgvSize] = {
{
"argv_set_0",
"--grouped_0=first",
"--grouped_1=second",
},
{
"argv_set_1",
"--grouped_0=second",
"--grouped_1=first",
},
{
"argv_set_2",
"--grouped_0=",
"--grouped_1=",
},
{
"argv_set_3",
"--grouped_1=",
"--grouped_0=",
},
{
"argv_set_4",
"--grouped_2=2",
"--grouped_3=3",
},
{
"argv_set_5",
"--grouped_3=",
"--grouped_2=",
},
};
for (auto argv : argv_sets) {
RunSuccess(argv, kArgvSize);
}
}
TEST_F(FlagsValidatorsDeathTest, GroupedFailureSimple) {
static const size_t kArgvSize = 1 + 1;
const char* argv_sets[][kArgvSize] = {
{
"argv_set_0",
"--grouped_0=a",
},
{
"argv_set_1",
"--grouped_1=b",
},
{
"argv_set_2",
"--grouped_2=2",
},
{
"argv_set_3",
"--grouped_3=3",
},
};
for (auto argv : argv_sets) {
RunFailure(argv, kArgvSize);
}
}
// Test for correct behavior when only one of two group validators is failing.
TEST_F(FlagsValidatorsDeathTest, GroupedFailureOneOfTwoValidators) {
static const size_t kArgvSize = 4 + 1;
const char* argv_sets[][kArgvSize] = {
{
"argv_set_0",
"--grouped_0=0",
"--grouped_1=1",
"--grouped_2=",
"--grouped_3=3",
},
{
"argv_set_1",
"--grouped_2=",
"--grouped_3=3",
"--grouped_0=0",
"--grouped_1=1",
},
{
"argv_set_2",
"--grouped_0=0",
"--grouped_1=",
"--grouped_2=2",
"--grouped_3=3",
},
{
"argv_set_3",
"--grouped_3=3",
"--grouped_2=2",
"--grouped_1=1",
"--grouped_0=",
},
};
for (auto argv : argv_sets) {
RunFailure(argv, kArgvSize);
}
}
TEST_F(FlagsValidatorsDeathTest, GroupedFailureWithEmptyValues) {
static const size_t kArgvSize = 1 + 2;
const char* argv_sets[][kArgvSize] = {
{
"argv_set_0",
"--grouped_0=a",
"--grouped_1=",
},
{
"argv_set_1",
"--grouped_1=",
"--grouped_0=a",
},
{
"argv_set_2",
"--grouped_0=",
"--grouped_1=b",
},
{
"argv_set_3",
"--grouped_1=b",
"--grouped_0=",
},
};
for (auto argv : argv_sets) {
RunFailure(argv, kArgvSize);
}
}
} // namespace kudu