This is an automated email from the ASF dual-hosted git repository.

alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git

commit 27cf7d881f1ab68b7c022d88c5f28160a0d0e518
Author: Alexey Serbin <[email protected]>
AuthorDate: Wed Jun 24 21:04:50 2020 -0700

    [test_util] multiple bind address for WaitFor{Tcp,Udp}Bind()
    
    This patch introduces a way to specify multiple candidate bind addresses
    for WaitForTcpBind() and WaitForUdpBind() test utility functions.  The
    newly introduced functionality will be used in a follow-up changelist.
    
    Change-Id: Iacda85624cb31995adc5910302468d80d5177237
    Reviewed-on: http://gerrit.cloudera.org:8080/16110
    Tested-by: Kudu Jenkins
    Reviewed-by: Alexey Serbin <[email protected]>
---
 src/kudu/hms/mini_hms.cc           |  2 +-
 src/kudu/postgres/mini_postgres.cc |  2 +-
 src/kudu/ranger/mini_ranger.cc     |  7 ++--
 src/kudu/security/test/mini_kdc.cc |  4 +-
 src/kudu/util/test_util.cc         | 85 ++++++++++++++++++++------------------
 src/kudu/util/test_util.h          | 13 +++---
 6 files changed, 60 insertions(+), 53 deletions(-)

diff --git a/src/kudu/hms/mini_hms.cc b/src/kudu/hms/mini_hms.cc
index fefe53c..1158e30 100644
--- a/src/kudu/hms/mini_hms.cc
+++ b/src/kudu/hms/mini_hms.cc
@@ -168,7 +168,7 @@ Status MiniHms::Start() {
   // Wait for HMS to start listening on its ports and commencing operation
   // with a wildcard binding.
   VLOG(1) << "Waiting for HMS ports";
-  Status wait = WaitForTcpBind(hms_process_->pid(), &port_, /*addr=*/none,
+  Status wait = WaitForTcpBind(hms_process_->pid(), &port_, {},
                                
MonoDelta::FromMilliseconds(kHmsStartTimeoutMs));
   if (!wait.ok()) {
     WARN_NOT_OK(hms_process_->Kill(SIGQUIT), "failed to send SIGQUIT to HMS");
diff --git a/src/kudu/postgres/mini_postgres.cc 
b/src/kudu/postgres/mini_postgres.cc
index ab739d5..8146cef 100644
--- a/src/kudu/postgres/mini_postgres.cc
+++ b/src/kudu/postgres/mini_postgres.cc
@@ -86,7 +86,7 @@ Status MiniPostgres::Start() {
   });
   RETURN_NOT_OK(process_->Start());
 
-  Status wait = WaitForTcpBind(process_->pid(), &port_, host_,
+  Status wait = WaitForTcpBind(process_->pid(), &port_, { host_ },
                                MonoDelta::FromMilliseconds(kPgStartTimeoutMs));
   if (!wait.ok()) {
     // TODO(abukor): implement retry with a different port if it can't bind
diff --git a/src/kudu/ranger/mini_ranger.cc b/src/kudu/ranger/mini_ranger.cc
index fbf9089..8defe47 100644
--- a/src/kudu/ranger/mini_ranger.cc
+++ b/src/kudu/ranger/mini_ranger.cc
@@ -22,7 +22,6 @@
 #include <string>
 #include <vector>
 
-#include <boost/optional/optional.hpp>
 #include <glog/logging.h>
 
 #include "kudu/gutil/map-util.h"
@@ -228,8 +227,10 @@ Status MiniRanger::StartRanger() {
     });
     RETURN_NOT_OK(process_->Start());
     uint16_t port;
-    RETURN_NOT_OK(WaitForTcpBind(process_->pid(), &port, boost::none,
-                  MonoDelta::FromMilliseconds(kRangerStartTimeoutMs)));
+    RETURN_NOT_OK(WaitForTcpBind(process_->pid(),
+                                 &port,
+                                 {},
+                                 
MonoDelta::FromMilliseconds(kRangerStartTimeoutMs)));
     LOG(INFO) << "Ranger bound to " << port;
     LOG(INFO) << "Ranger admin URL: " << ranger_admin_url_;
   }
diff --git a/src/kudu/security/test/mini_kdc.cc 
b/src/kudu/security/test/mini_kdc.cc
index da11d07..727bfe4 100644
--- a/src/kudu/security/test/mini_kdc.cc
+++ b/src/kudu/security/test/mini_kdc.cc
@@ -156,8 +156,8 @@ Status MiniKdc::Start() {
   const bool need_config_update = (options_.port == 0);
   // Wait for KDC to start listening on its ports and commencing operation
   // with a wildcard binding.
-  RETURN_NOT_OK(WaitForUdpBind(kdc_process_->pid(), &options_.port,
-                               /*addr=*/none, MonoDelta::FromSeconds(1)));
+  RETURN_NOT_OK(WaitForUdpBind(
+      kdc_process_->pid(), &options_.port, {}, MonoDelta::FromSeconds(1)));
 
   if (need_config_update) {
     // If we asked for an ephemeral port, grab the actual ports and
diff --git a/src/kudu/util/test_util.cc b/src/kudu/util/test_util.cc
index 693123e..bce1693 100644
--- a/src/kudu/util/test_util.cc
+++ b/src/kudu/util/test_util.cc
@@ -37,7 +37,6 @@
 #include <sys/param.h> // for MAXPATHLEN
 #endif
 
-#include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 #include <gtest/gtest-spi.h>
@@ -68,7 +67,6 @@ DEFINE_int32(test_random_seed, 0, "Random seed to use for 
randomized tests");
 
 DECLARE_string(time_source);
 
-using boost::optional;
 using std::string;
 using std::vector;
 using strings::Substitute;
@@ -406,8 +404,11 @@ int CountOpenFds(Env* env, const string& path_pattern) {
 
 namespace {
 Status WaitForBind(pid_t pid, uint16_t* port,
-                   const optional<const string&>& addr,
-                   const char* kind, MonoDelta timeout) {
+                   const vector<string>& addresses,
+                   const char* kind,
+                   MonoDelta timeout) {
+  static const vector<string> kWildcard = { "0.0.0.0" };
+
   // In general, processes do not expose the port they bind to, and
   // reimplementing lsof involves parsing a lot of files in /proc/. So,
   // requiring lsof for tests and parsing its output seems more
@@ -442,59 +443,63 @@ Status WaitForBind(pid_t pid, uint16_t* port,
   // to be the primary service port. When searching, we use the provided bind
   // address if there is any, otherwise we use '*' (same as '0.0.0.0') which
   // matches all addresses on the local machine.
-  string addr_pattern = Substitute("n$0:", (!addr || *addr == "0.0.0.0") ? "*" 
: *addr);
-  MonoTime deadline = MonoTime::Now() + timeout;
-  string lsof_out;
-  int32_t p = -1;
-
-  for (int64_t i = 1; ; i++) {
-    lsof_out.clear();
-    Status s = Subprocess::Call(cmd, "", &lsof_out).AndThen([&] () {
-      StripTrailingNewline(&lsof_out);
-      vector<string> lines = strings::Split(lsof_out, "\n");
-      for (int index = 2; index < lines.size(); index += 2) {
-        StringPiece cur_line(lines[index]);
-        if (HasPrefixString(cur_line.ToString(), addr_pattern) &&
-            !cur_line.contains("->")) {
-          cur_line.remove_prefix(addr_pattern.size());
-          if (!safe_strto32(cur_line.data(), cur_line.size(), &p)) {
-            return Status::RuntimeError("unexpected lsof output", lsof_out);
+  const MonoTime deadline = MonoTime::Now() + timeout;
+  const auto& addresses_to_check = addresses.empty() ? kWildcard : addresses;
+  for (int64_t i = 1; ; ++i) {
+    for (const auto& addr : addresses_to_check) {
+      string addr_pattern = Substitute("n$0:", addr == "0.0.0.0" ? "*" : addr);
+      string lsof_out;
+      int32_t p = -1;
+      Status s = Subprocess::Call(cmd, "", &lsof_out).AndThen([&] () {
+        StripTrailingNewline(&lsof_out);
+        vector<string> lines = strings::Split(lsof_out, "\n");
+        for (int index = 2; index < lines.size(); index += 2) {
+          StringPiece cur_line(lines[index]);
+          if (HasPrefixString(cur_line.ToString(), addr_pattern) &&
+              !cur_line.contains("->")) {
+            cur_line.remove_prefix(addr_pattern.size());
+            if (!safe_strto32(cur_line.data(), cur_line.size(), &p)) {
+              return Status::RuntimeError("unexpected lsof output", lsof_out);
+            }
+
+            return Status::OK();
           }
-
-          return Status::OK();
         }
-      }
 
-      return Status::RuntimeError("unexpected lsof output", lsof_out);
-    });
+        return Status::RuntimeError("unexpected lsof output", lsof_out);
+      });
 
-    if (s.ok()) {
-      break;
-    }
-    if (deadline < MonoTime::Now()) {
-      return s;
-    }
+      if (s.ok()) {
+        CHECK(p > 0 && p < std::numeric_limits<uint16_t>::max())
+            << "parsed invalid port: " << p;
+        VLOG(1) << "Determined bound port: " << p;
+        *port = static_cast<uint16_t>(p);
 
+        return Status::OK();
+      }
+      if (deadline < MonoTime::Now()) {
+        return s;
+      }
+    }
     SleepFor(MonoDelta::FromMilliseconds(i * 10));
   }
 
-  CHECK(p > 0 && p < std::numeric_limits<uint16_t>::max()) << "parsed invalid 
port: " << p;
-  VLOG(1) << "Determined bound port: " << p;
-  *port = p;
-  return Status::OK();
+  // Should not reach here.
+  LOG(FATAL) << "could not determine bound port the process";
+  __builtin_unreachable();
 }
 } // anonymous namespace
 
 Status WaitForTcpBind(pid_t pid, uint16_t* port,
-                      const optional<const string&>& addr,
+                      const vector<string>& addresses,
                       MonoDelta timeout) {
-  return WaitForBind(pid, port, addr, "4TCP", timeout);
+  return WaitForBind(pid, port, addresses, "4TCP", timeout);
 }
 
 Status WaitForUdpBind(pid_t pid, uint16_t* port,
-                      const optional<const string&>& addr,
+                      const vector<string>& addresses,
                       MonoDelta timeout) {
-  return WaitForBind(pid, port, addr, "4UDP", timeout);
+  return WaitForBind(pid, port, addresses, "4UDP", timeout);
 }
 
 Status FindHomeDir(const string& name, const string& bin_dir, string* 
home_dir) {
diff --git a/src/kudu/util/test_util.h b/src/kudu/util/test_util.h
index d320e3e..9f60aef 100644
--- a/src/kudu/util/test_util.h
+++ b/src/kudu/util/test_util.h
@@ -25,8 +25,8 @@
 #include <functional>
 #include <memory>
 #include <string>
+#include <vector>
 
-#include <boost/optional/optional.hpp>
 #include <gtest/gtest.h>
 
 #include "kudu/gutil/port.h"
@@ -144,16 +144,17 @@ void AssertEventually(const std::function<void(void)>& f,
 // unlike the usual behavior of path globs.
 int CountOpenFds(Env* env, const std::string& path_pattern);
 
-// Waits for the subprocess to bind to any listening TCP port on the provided
-// IP address (if the address is not provided, it is a wildcard binding), and
-// returns the port.
+// Waits for the subprocess to bind to any listening TCP port at least on one
+// of the provided IP addresses and returns the port number. As for values
+// for the 'addresses' parameter, {} (an empty vector) and { "0.0.0.0" }
+// semantically mean the same.
 Status WaitForTcpBind(pid_t pid, uint16_t* port,
-                      const boost::optional<const std::string&>& addr,
+                      const std::vector<std::string>& addresses,
                       MonoDelta timeout) WARN_UNUSED_RESULT;
 
 // Similar to above but binds to any listening UDP port.
 Status WaitForUdpBind(pid_t pid, uint16_t* port,
-                      const boost::optional<const std::string&>& addr,
+                      const std::vector<std::string>& addresses,
                       MonoDelta timeout) WARN_UNUSED_RESULT;
 
 // Find the home directory of a Java-style application, e.g. JAVA_HOME or

Reply via email to