You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by to...@apache.org on 2016/08/25 21:51:05 UTC
[4/5] kudu git commit: tool: basic integration test
tool: basic integration test
So far all it does is spot check some help pages, but in the future we
should augment it to test functionality too. For now that's not a big deal
because every tool function is covered in either master_migration-itest or
master_failover-itest.
Change-Id: Ib386882c1874e987d5824cfe742cc86627cd9eaa
Reviewed-on: http://gerrit.cloudera.org:8080/4058
Tested-by: Kudu Jenkins
Reviewed-by: Todd Lipcon <to...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/7321b38b
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/7321b38b
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/7321b38b
Branch: refs/heads/master
Commit: 7321b38be0303876fcc71b5c73e3e6eddbbdf012
Parents: a1e6b88
Author: Adar Dembo <ad...@cloudera.com>
Authored: Thu Aug 18 20:50:39 2016 -0700
Committer: Todd Lipcon <to...@apache.org>
Committed: Thu Aug 25 21:46:35 2016 +0000
----------------------------------------------------------------------
build-support/dist_test.py | 13 ++-
src/kudu/tools/CMakeLists.txt | 3 +
src/kudu/tools/kudu-tool-test.cc | 154 ++++++++++++++++++++++++++++++++++
src/kudu/util/test_macros.h | 21 ++++-
4 files changed, 188 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/7321b38b/build-support/dist_test.py
----------------------------------------------------------------------
diff --git a/build-support/dist_test.py b/build-support/dist_test.py
index f56513f..d391cf4 100755
--- a/build-support/dist_test.py
+++ b/build-support/dist_test.py
@@ -182,7 +182,10 @@ def ldd_deps(exe):
If the provided 'exe' is not a binary executable, returns
an empty list.
"""
- if exe.endswith(".sh"):
+ if (exe.endswith(".pl") or
+ exe.endswith(".py") or
+ exe.endswith(".sh") or
+ exe.endswith(".txt")):
return []
p = subprocess.Popen(["ldd", exe], stdout=subprocess.PIPE)
out, err = p.communicate()
@@ -243,7 +246,13 @@ def create_archive_input(staging, argv,
if os.path.isdir(d):
d += "/"
deps.append(d)
- for d in deps:
+ # DEPS_FOR_ALL may include binaries whose dependencies are not dependencies
+ # of the test executable. We must include those dependencies in the archive
+ # for the binaries to be usable.
+ deps.extend(ldd_deps(d))
+
+ # Deduplicate dependencies included via DEPS_FOR_ALL.
+ for d in set(deps):
# System libraries will end up being relative paths out
# of the build tree. We need to copy those into the build
# tree somewhere.
http://git-wip-us.apache.org/repos/asf/kudu/blob/7321b38b/src/kudu/tools/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/tools/CMakeLists.txt b/src/kudu/tools/CMakeLists.txt
index c66b314..ce361f0 100644
--- a/src/kudu/tools/CMakeLists.txt
+++ b/src/kudu/tools/CMakeLists.txt
@@ -115,6 +115,9 @@ ADD_KUDU_TEST(ksck_remote-test)
ADD_KUDU_TEST(kudu-admin-test)
ADD_KUDU_TEST_DEPENDENCIES(kudu-admin-test
kudu-admin)
+ADD_KUDU_TEST(kudu-tool-test)
+ADD_KUDU_TEST_DEPENDENCIES(kudu-tool-test
+ kudu)
ADD_KUDU_TEST(kudu-ts-cli-test)
ADD_KUDU_TEST_DEPENDENCIES(kudu-ts-cli-test
kudu-ts-cli)
http://git-wip-us.apache.org/repos/asf/kudu/blob/7321b38b/src/kudu/tools/kudu-tool-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc
new file mode 100644
index 0000000..2700fb1
--- /dev/null
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -0,0 +1,154 @@
+// 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 <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <glog/stl_logging.h>
+
+#include "kudu/gutil/strings/split.h"
+#include "kudu/gutil/strings/substitute.h"
+#include "kudu/util/env.h"
+#include "kudu/util/path_util.h"
+#include "kudu/util/subprocess.h"
+#include "kudu/util/test_macros.h"
+#include "kudu/util/test_util.h"
+
+namespace kudu {
+namespace tools {
+
+using std::string;
+using std::vector;
+
+class ToolTest : public KuduTest {
+ public:
+ ToolTest() {
+ string exe;
+ CHECK_OK(env_->GetExecutablePath(&exe));
+ string bin_root = DirName(exe);
+ string tool_path = JoinPathSegments(bin_root, "kudu");
+ CHECK(env_->FileExists(tool_path)) << "kudu tool not found at " << tool_path;
+ tool_path_ = tool_path;
+ }
+
+ Status RunTool(const string& arg_str,
+ vector<string>* stdout_lines,
+ vector<string>* stderr_lines) const {
+ vector<string> args = { tool_path_ };
+ vector<string> more_args = strings::Split(arg_str, " ",
+ strings::SkipEmpty());
+ args.insert(args.end(), more_args.begin(), more_args.end());
+
+ string stdout;
+ string stderr;
+ Status s = Subprocess::Call(args, &stdout, &stderr);
+ StripWhiteSpace(&stdout);
+ StripWhiteSpace(&stderr);
+ *stdout_lines = strings::Split(stdout, "\n", strings::SkipEmpty());
+ *stderr_lines = strings::Split(stderr, "\n", strings::SkipEmpty());
+ return s;
+
+ }
+
+ void RunTestHelp(const string& arg_str,
+ const vector<string>& regexes,
+ const Status& expected_status = Status::OK()) const {
+ vector<string> stdout;
+ vector<string> stderr;
+ Status s = RunTool(arg_str, &stdout, &stderr);
+ SCOPED_TRACE(stdout);
+ SCOPED_TRACE(stderr);
+
+ // These are always true for showing help.
+ ASSERT_TRUE(s.IsRuntimeError());
+ ASSERT_TRUE(stdout.empty());
+ ASSERT_FALSE(stderr.empty());
+
+ // If it was an invalid command, the usage string is on the second line.
+ int usage_idx = 0;
+ if (!expected_status.ok()) {
+ ASSERT_EQ(expected_status.ToString(), stderr[0]);
+ usage_idx = 1;
+ }
+ ASSERT_EQ(0, stderr[usage_idx].find("Usage: "));
+
+ // Strip away everything up to the usage string to test for regexes.
+ vector<string> remaining_lines;
+ for (int i = usage_idx + 1; i < stderr.size(); i++) {
+ remaining_lines.push_back(stderr[i]);
+ }
+ for (const auto& r : regexes) {
+ ASSERT_STRINGS_ANY_MATCH(remaining_lines, r);
+ }
+ }
+
+ private:
+ string tool_path_;
+};
+
+TEST_F(ToolTest, TestTopLevelHelp) {
+ const vector<string> kTopLevelRegexes = {
+ "fs.*Kudu filesystem",
+ "pbc.*protobuf container",
+ "tablet.*Kudu replica"
+ };
+ NO_FATALS(RunTestHelp("", kTopLevelRegexes));
+ NO_FATALS(RunTestHelp("--help", kTopLevelRegexes));
+ NO_FATALS(RunTestHelp("not_a_mode", kTopLevelRegexes,
+ Status::InvalidArgument("unknown command 'not_a_mode'")));
+}
+
+TEST_F(ToolTest, TestModeHelp) {
+ {
+ const vector<string> kFsModeRegexes = {
+ "format.*new Kudu filesystem",
+ "print_uuid.*UUID of a Kudu filesystem"
+ };
+ NO_FATALS(RunTestHelp("fs", kFsModeRegexes));
+ NO_FATALS(RunTestHelp("fs not_a_mode", kFsModeRegexes,
+ Status::InvalidArgument("unknown command 'not_a_mode'")));
+ }
+ {
+ const vector<string> kTabletModeRegexes = {
+ "cmeta.*consensus metadata file",
+ "copy.*Copy a replica"
+ };
+ NO_FATALS(RunTestHelp("tablet", kTabletModeRegexes));
+ }
+ {
+ const vector<string> kCmetaModeRegexes = {
+ "print_replica_uuids.*Print all replica UUIDs",
+ "rewrite_raft_config.*Rewrite a replica"
+ };
+ NO_FATALS(RunTestHelp("tablet cmeta", kCmetaModeRegexes));
+ }
+}
+
+TEST_F(ToolTest, TestActionHelp) {
+ const vector<string> kFormatActionRegexes = {
+ "-fs_wal_dir \\(Directory",
+ "-fs_data_dirs \\(Comma-separated list",
+ "-uuid \\(The uuid"
+ };
+ NO_FATALS(RunTestHelp("fs format --help", kFormatActionRegexes));
+ NO_FATALS(RunTestHelp("fs format extra_arg", kFormatActionRegexes,
+ Status::InvalidArgument("too many arguments: 'extra_arg'")));
+}
+
+} // namespace tools
+} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/7321b38b/src/kudu/util/test_macros.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/test_macros.h b/src/kudu/util/test_macros.h
index e7950a9..a5f151f 100644
--- a/src/kudu/util/test_macros.h
+++ b/src/kudu/util/test_macros.h
@@ -63,7 +63,9 @@
ASSERT_THAT(str, testing::ContainsRegex(pattern))
// Batched substring regular expressions in extended regex (POSIX) syntax.
-#define ASSERT_STRINGS_MATCH(strings, pattern) do { \
+//
+// All strings must match the pattern.
+#define ASSERT_STRINGS_ALL_MATCH(strings, pattern) do { \
const auto& _strings = (strings); \
const auto& _pattern = (pattern); \
int _str_idx = 0; \
@@ -75,6 +77,23 @@
} \
} while (0)
+// Batched substring regular expressions in extended regex (POSIX) syntax.
+//
+// At least one string must match the pattern.
+#define ASSERT_STRINGS_ANY_MATCH(strings, pattern) do { \
+ const auto& _strings = (strings); \
+ const auto& _pattern = (pattern); \
+ bool matched = false; \
+ for (const auto& str : _strings) { \
+ if (testing::internal::RE::PartialMatch(str, testing::internal::RE(_pattern))) { \
+ matched = true; \
+ break; \
+ } \
+ } \
+ ASSERT_TRUE(matched) \
+ << "not one string matched pattern " << _pattern; \
+} while (0)
+
#define ASSERT_FILE_EXISTS(env, path) do { \
std::string _s = path; \
ASSERT_TRUE(env->FileExists(_s)) \