AU/unittest: parameterize test_http_server port

This eliminates the constant definition of the test HTTP server port,
replacing it with a command-line parameter (which defaults to 8080, the
well-known userland HTTP port). This is needed for allowing parallel
invocations of unit tests.

BUG=chromium:236465
TEST=Passes unit tests

Change-Id: I91904dc360ec1b993cbaae93554fb0dd9e5adaad
Reviewed-on: https://gerrit.chromium.org/gerrit/60626
Tested-by: Gilad Arnold <garnold@chromium.org>
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Commit-Queue: Gilad Arnold <garnold@chromium.org>
diff --git a/http_fetcher_unittest.cc b/http_fetcher_unittest.cc
index e6204d3..b638411 100644
--- a/http_fetcher_unittest.cc
+++ b/http_fetcher_unittest.cc
@@ -18,7 +18,6 @@
 #include <gtest/gtest.h>
 
 #include "update_engine/http_common.h"
-#include "update_engine/http_fetcher_unittest.h"
 #include "update_engine/libcurl_http_fetcher.h"
 #include "update_engine/mock_connection_manager.h"
 #include "update_engine/mock_http_fetcher.h"
@@ -46,6 +45,8 @@
 const int kFlakySleepEvery     = 3;
 const int kFlakySleepSecs      = 10;
 
+const int kServerPort = 8088;
+
 }  // namespace
 
 namespace chromeos_update_engine {
@@ -82,7 +83,11 @@
 class PythonHttpServer : public HttpServer {
  public:
   PythonHttpServer() {
-    char *argv[2] = {strdup("./test_http_server"), NULL};
+    char *port_str = NULL;
+    char *argv[] = {
+      strdup("./test_http_server"),
+      asprintf(&port_str, "%d", kServerPort) >= 0 ? port_str : NULL,
+      NULL};
     GError *err;
     started_ = false;
     validate_quit_ = true;
@@ -125,7 +130,8 @@
      started_ = false;
     }
 
-    free(argv[0]);
+    for (unsigned i = 0; i < arraysize(argv); i++)
+      free(argv[i]);
     LOG(INFO) << "gdb attach now!";
   }
 
diff --git a/http_fetcher_unittest.h b/http_fetcher_unittest.h
deleted file mode 100644
index 5d17903..0000000
--- a/http_fetcher_unittest.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Definition of unit testing constants, to be shared by different testing
-// related modules.
-
-#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_HTTP_FETCHER_TEST_H__
-#define CHROMEOS_PLATFORM_UPDATE_ENGINE_HTTP_FETCHER_TEST_H__
-
-namespace {
-
-const int kServerPort = 8088;
-
-}  // namespace
-
-#endif  // CHROMEOS_PLATFORM_UPDATE_ENGINE_HTTP_FETCHER_TEST_H__
diff --git a/subprocess_unittest.cc b/subprocess_unittest.cc
index d23040d..427f7e3 100644
--- a/subprocess_unittest.cc
+++ b/subprocess_unittest.cc
@@ -114,6 +114,7 @@
   CancelTestData* cancel_test_data = reinterpret_cast<CancelTestData*>(data);
   vector<string> cmd;
   cmd.push_back("./test_http_server");
+  cmd.push_back(StringPrintf("%d", kLocalHttpPort));
   uint32_t tag = Subprocess::Get().Exec(cmd, CallbackBad, NULL);
   EXPECT_NE(0, tag);
   cancel_test_data->spawned = true;
diff --git a/test_http_server.cc b/test_http_server.cc
index 514f786..2272052 100644
--- a/test_http_server.cc
+++ b/test_http_server.cc
@@ -10,6 +10,7 @@
 // To use this, simply make an HTTP connection to localhost:port and
 // GET a url.
 
+#include <err.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <netinet/in.h>
@@ -31,7 +32,6 @@
 #include <base/stringprintf.h>
 
 #include "update_engine/http_common.h"
-#include "update_engine/http_fetcher_unittest.h"
 
 
 // HTTP end-of-line delimiter; sorry, this needs to be a macro.
@@ -44,6 +44,19 @@
 
 namespace chromeos_update_engine {
 
+// Allowed port range and default value.
+const long kPortMin = static_cast<long>(1) << 10;
+const long kPortMax = (static_cast<long>(1) << 16) - 1;
+const in_port_t kPortDefault = 8080;
+
+enum {
+  RC_OK = 0,
+  RC_BAD_ARGS,
+  RC_ERR_READ,
+  RC_ERR_SETSOCKOPT,
+  RC_ERR_BIND,
+};
+
 struct HttpRequest {
   HttpRequest()
       : start_offset(0), end_offset(0), return_code(kHttpResponseOk) {}
@@ -61,7 +74,7 @@
     ssize_t r = read(fd, buf, sizeof(buf));
     if (r < 0) {
       perror("read");
-      exit(1);
+      exit(RC_ERR_READ);
     }
     headers.append(buf, r);
   } while (!EndsWith(headers, EOL EOL, true));
@@ -249,7 +262,7 @@
 void HandleQuit(int fd) {
   WriteHeaders(fd, 0, 0, kHttpResponseOk);
   LOG(INFO) << "pid(" << getpid() <<  "): HTTP server exiting ...";
-  exit(0);
+  exit(RC_OK);
 }
 
 
@@ -501,15 +514,40 @@
 
 using namespace chromeos_update_engine;
 
+void usage(const char *prog_arg) {
+  static const char usage_str[] =
+      "Usage: %s [ PORT ]\n"
+      "where PORT is an integer between %ld and %ld (default is %d).\n";
+  fprintf(stderr, usage_str, basename(prog_arg), kPortMin, kPortMax,
+          kPortDefault);
+}
+
 int main(int argc, char** argv) {
+  // Check invocation.
+  if (argc > 2)
+    errx(RC_BAD_ARGS, "unexpected number of arguments (use -h for usage)");
+
+  // Parse inbound port number argument (in host byte-order, as of yet).
+  in_port_t port = kPortDefault;
+  if (argc == 2) {
+    if (!strcmp(argv[1], "-h")) {
+      usage(argv[0]);
+      exit(RC_OK);
+    }
+
+    char *end_ptr;
+    long raw_port = strtol(argv[1], &end_ptr, 10);
+    if (*end_ptr || raw_port < kPortMin || raw_port > kPortMax)
+      errx(RC_BAD_ARGS, "invalid port: %s", argv[1]);
+    port = static_cast<int>(raw_port);
+  }
+
   // Ignore SIGPIPE on write() to sockets.
   signal(SIGPIPE, SIG_IGN);
 
   socklen_t clilen;
-  struct sockaddr_in server_addr;
-  struct sockaddr_in client_addr;
-  memset(&server_addr, 0, sizeof(server_addr));
-  memset(&client_addr, 0, sizeof(client_addr));
+  struct sockaddr_in server_addr = sockaddr_in();
+  struct sockaddr_in client_addr = sockaddr_in();
 
   int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
   if (listen_fd < 0)
@@ -517,7 +555,7 @@
 
   server_addr.sin_family = AF_INET;
   server_addr.sin_addr.s_addr = INADDR_ANY;
-  server_addr.sin_port = htons(kServerPort);
+  server_addr.sin_port = htons(port);  // byte-order conversion is necessary!
 
   {
     // Get rid of "Address in use" error
@@ -525,18 +563,19 @@
     if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &tr,
                    sizeof(int)) == -1) {
       perror("setsockopt");
-      exit(2);
+      exit(RC_ERR_SETSOCKOPT);
     }
   }
 
   if (bind(listen_fd, reinterpret_cast<struct sockaddr *>(&server_addr),
            sizeof(server_addr)) < 0) {
     perror("bind");
-    exit(3);
+    exit(RC_ERR_BIND);
   }
   CHECK_EQ(listen(listen_fd,5), 0);
   while (1) {
-    LOG(INFO) << "pid(" << getpid() <<  "): waiting to accept new connection";
+    LOG(INFO) << "pid(" << getpid()
+              <<  "): waiting to accept new connection on port " << port;
     clilen = sizeof(client_addr);
     int client_fd = accept(listen_fd,
                            (struct sockaddr *) &client_addr,