Skip to content
Snippets Groups Projects
Commit 12d9d1d3 authored by Oz Linden's avatar Oz Linden
Browse files

merge changes for chop-661

parents b850c346 92caead4
No related branches found
No related tags found
No related merge requests found
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "llsd.h" #include "llsd.h"
#include "llhost.h" #include "llhost.h"
#include "stringize.h" #include "stringize.h"
#include <map>
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
...@@ -43,6 +44,58 @@ struct CommtestError: public std::runtime_error ...@@ -43,6 +44,58 @@ struct CommtestError: public std::runtime_error
CommtestError(const std::string& what): std::runtime_error(what) {} CommtestError(const std::string& what): std::runtime_error(what) {}
}; };
static bool query_verbose()
{
const char* cbose = getenv("INTEGRATION_TEST_VERBOSE");
if (! cbose)
{
cbose = "1";
}
std::string strbose(cbose);
return (! (strbose == "0" || strbose == "off" ||
strbose == "false" || strbose == "quiet"));
}
bool verbose()
{
// This should only be initialized once.
static bool vflag = query_verbose();
return vflag;
}
static int query_port(const std::string& var)
{
const char* cport = getenv(var.c_str());
if (! cport)
{
throw CommtestError(STRINGIZE("missing environment variable" << var));
}
// This will throw, too, if the value of PORT isn't numeric.
int port(boost::lexical_cast<int>(cport));
if (verbose())
{
std::cout << "getport('" << var << "') = " << port << std::endl;
}
return port;
}
static int getport(const std::string& var)
{
typedef std::map<std::string, int> portsmap;
static portsmap ports;
// We can do this with a single map lookup with map::insert(). Either it
// returns an existing entry and 'false' (not newly inserted), or it
// inserts the specified value and 'true'.
std::pair<portsmap::iterator, bool> inserted(ports.insert(portsmap::value_type(var, 0)));
if (inserted.second)
{
// We haven't yet seen this var. Remember its value.
inserted.first->second = query_port(var);
}
// Return the (existing or new) iterator's value.
return inserted.first->second;
}
/** /**
* This struct is shared by a couple of standalone comm tests (ADD_COMM_BUILD_TEST). * This struct is shared by a couple of standalone comm tests (ADD_COMM_BUILD_TEST).
*/ */
...@@ -71,13 +124,10 @@ struct commtest_data ...@@ -71,13 +124,10 @@ struct commtest_data
static int getport(const std::string& var) static int getport(const std::string& var)
{ {
const char* port = getenv(var.c_str()); // We have a couple consumers of commtest_data::getport(). But we've
if (! port) // since moved it out to the global namespace. So this is just a
{ // facade.
throw CommtestError("missing $PORT environment variable"); return ::getport(var);
}
// This will throw, too, if the value of PORT isn't numeric.
return boost::lexical_cast<int>(port);
} }
bool outcome(const LLSD& _result, bool _success) bool outcome(const LLSD& _result, bool _success)
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
from indra.util.fastest_elementtree import parse as xml_parse from indra.util.fastest_elementtree import parse as xml_parse
from indra.base import llsd from indra.base import llsd
from testrunner import freeport, run, debug from testrunner import freeport, run, debug, VERBOSE
class TestHTTPRequestHandler(BaseHTTPRequestHandler): class TestHTTPRequestHandler(BaseHTTPRequestHandler):
"""This subclass of BaseHTTPRequestHandler is to receive and echo """This subclass of BaseHTTPRequestHandler is to receive and echo
...@@ -72,10 +72,10 @@ def read_xml(self): ...@@ -72,10 +72,10 @@ def read_xml(self):
## # assuming that the underlying XML parser reads its input file ## # assuming that the underlying XML parser reads its input file
## # incrementally. Unfortunately I haven't been able to make it work. ## # incrementally. Unfortunately I haven't been able to make it work.
## tree = xml_parse(self.rfile) ## tree = xml_parse(self.rfile)
## debug("Finished raw parse\n") ## debug("Finished raw parse")
## debug("parsed XML tree %s\n" % tree) ## debug("parsed XML tree %s", tree)
## debug("parsed root node %s\n" % tree.getroot()) ## debug("parsed root node %s", tree.getroot())
## debug("root node tag %s\n" % tree.getroot().tag) ## debug("root node tag %s", tree.getroot().tag)
## return llsd.to_python(tree.getroot()) ## return llsd.to_python(tree.getroot())
def do_GET(self): def do_GET(self):
...@@ -88,8 +88,10 @@ def do_POST(self): ...@@ -88,8 +88,10 @@ def do_POST(self):
self.answer(self.read_xml()) self.answer(self.read_xml())
def answer(self, data): def answer(self, data):
debug("%s.answer(%s): self.path = %r", self.__class__.__name__, data, self.path)
if "fail" not in self.path: if "fail" not in self.path:
response = llsd.format_xml(data.get("reply", llsd.LLSD("success"))) response = llsd.format_xml(data.get("reply", llsd.LLSD("success")))
debug("success: %s", response)
self.send_response(200) self.send_response(200)
self.send_header("Content-type", "application/llsd+xml") self.send_header("Content-type", "application/llsd+xml")
self.send_header("Content-Length", str(len(response))) self.send_header("Content-Length", str(len(response)))
...@@ -106,16 +108,21 @@ def answer(self, data): ...@@ -106,16 +108,21 @@ def answer(self, data):
("fail requested", ("fail requested",
"Your request specified failure status %s " "Your request specified failure status %s "
"without providing a reason" % status))[1]) "without providing a reason" % status))[1])
debug("fail requested: %s: %r", status, reason)
self.send_error(status, reason) self.send_error(status, reason)
def log_request(self, code, size=None): if not VERBOSE:
# For present purposes, we don't want the request splattered onto # When VERBOSE is set, skip both these overrides because they exist to
# stderr, as it would upset devs watching the test run # suppress output.
pass
def log_error(self, format, *args): def log_request(self, code, size=None):
# Suppress error output as well # For present purposes, we don't want the request splattered onto
pass # stderr, as it would upset devs watching the test run
pass
def log_error(self, format, *args):
# Suppress error output as well
pass
if __name__ == "__main__": if __name__ == "__main__":
# Instantiate an HTTPServer(TestHTTPRequestHandler) on the first free port # Instantiate an HTTPServer(TestHTTPRequestHandler) on the first free port
...@@ -130,4 +137,5 @@ def log_error(self, format, *args): ...@@ -130,4 +137,5 @@ def log_error(self, format, *args):
# command-line parsing -- and anyway, for C++ integration tests, that's # command-line parsing -- and anyway, for C++ integration tests, that's
# performed in TUT code rather than our own. # performed in TUT code rather than our own.
os.environ["PORT"] = str(port) os.environ["PORT"] = str(port)
debug("$PORT = %s", port)
sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:])) sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:]))
...@@ -29,14 +29,21 @@ ...@@ -29,14 +29,21 @@
import os import os
import sys import sys
import re
import errno import errno
import socket import socket
def debug(*args): VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "1") # default to verbose
sys.stdout.writelines(args) # Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if
sys.stdout.flush() # that construct actually turns on verbosity...
# comment out the line below to enable debug output VERBOSE = not re.match(r"(0|off|false|quiet)$", VERBOSE, re.IGNORECASE)
debug = lambda *args: None
if VERBOSE:
def debug(fmt, *args):
print fmt % args
sys.stdout.flush()
else:
debug = lambda *args: None
def freeport(portlist, expr): def freeport(portlist, expr):
""" """
...@@ -78,44 +85,53 @@ def freeport(portlist, expr): ...@@ -78,44 +85,53 @@ def freeport(portlist, expr):
# pass 'port' to client code # pass 'port' to client code
# call server.serve_forever() # call server.serve_forever()
""" """
# If portlist is completely empty, let StopIteration propagate: that's an try:
# error because we can't return meaningful values. We have no 'port', # If portlist is completely empty, let StopIteration propagate: that's an
# therefore no 'expr(port)'. # error because we can't return meaningful values. We have no 'port',
portiter = iter(portlist) # therefore no 'expr(port)'.
port = portiter.next() portiter = iter(portlist)
port = portiter.next()
while True:
try: while True:
# If this value of port works, return as promised.
return expr(port), port
except socket.error, err:
# Anything other than 'Address already in use', propagate
if err.args[0] != errno.EADDRINUSE:
raise
# Here we want the next port from portiter. But on StopIteration,
# we want to raise the original exception rather than
# StopIteration. So save the original exc_info().
type, value, tb = sys.exc_info()
try: try:
# If this value of port works, return as promised.
value = expr(port)
except socket.error, err:
# Anything other than 'Address already in use', propagate
if err.args[0] != errno.EADDRINUSE:
raise
# Here we want the next port from portiter. But on StopIteration,
# we want to raise the original exception rather than
# StopIteration. So save the original exc_info().
type, value, tb = sys.exc_info()
try: try:
port = portiter.next() try:
except StopIteration: port = portiter.next()
raise type, value, tb except StopIteration:
finally: raise type, value, tb
# Clean up local traceback, see docs for sys.exc_info() finally:
del tb # Clean up local traceback, see docs for sys.exc_info()
del tb
# Recap of the control flow above:
# If expr(port) doesn't raise, return as promised. else:
# If expr(port) raises anything but EADDRINUSE, propagate that debug("freeport() returning %s on port %s", value, port)
# exception. return value, port
# If portiter.next() raises StopIteration -- that is, if the port
# value we just passed to expr(port) was the last available -- reraise # Recap of the control flow above:
# the EADDRINUSE exception. # If expr(port) doesn't raise, return as promised.
# If we've actually arrived at this point, portiter.next() delivered a # If expr(port) raises anything but EADDRINUSE, propagate that
# new port value. Loop back to pass that to expr(port). # exception.
# If portiter.next() raises StopIteration -- that is, if the port
# value we just passed to expr(port) was the last available -- reraise
# the EADDRINUSE exception.
# If we've actually arrived at this point, portiter.next() delivered a
# new port value. Loop back to pass that to expr(port).
except Exception, err:
debug("*** freeport() raising %s: %s", err.__class__.__name__, err)
raise
def run(*args, **kwds): def run(*args, **kwds):
"""All positional arguments collectively form a command line, executed as """All positional arguments collectively form a command line, executed as
...@@ -144,8 +160,7 @@ def run(*args, **kwds): ...@@ -144,8 +160,7 @@ def run(*args, **kwds):
# - [no p] don't use the PATH because we specifically want to invoke the # - [no p] don't use the PATH because we specifically want to invoke the
# executable passed as our first arg, # executable passed as our first arg,
# - [no e] child should inherit this process's environment. # - [no e] child should inherit this process's environment.
debug("Running %s...\n" % (" ".join(args))) debug("Running %s...", " ".join(args))
sys.stdout.flush()
rc = os.spawnv(os.P_WAIT, args[0], args) rc = os.spawnv(os.P_WAIT, args[0], args)
debug("%s returned %s\n" % (args[0], rc)) debug("%s returned %s", args[0], rc)
return rc return rc
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment