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 <[email protected]>
Reviewed-by: Don Garrett <[email protected]>
Commit-Queue: Gilad Arnold <[email protected]>
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,