Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix tests to deal with addition of ticket_catchup() to setup() phase (f…

…16e6d1)

Now boothd site/arbitrator will hang in setup phase while attempting to connect
to an unreachable peer during ticket_catchup().  In a test environment we don't
have any reachable peers.  Fortunately, we can still successfully launch a
daemon by only listing our own IP in the config file.  But now our tests now
have to explicitly say whether they expect the server to successfully start up
via a new expect_daemon argument to ServerTestEnvironment.run_booth().
  • Loading branch information...
commit 84b6583b39ceb63a398ee40f54c23d49fe96e193 1 parent 70e5a71
@aspiers aspiers authored
View
2  test/assertions.py
@@ -6,7 +6,7 @@ class BoothAssertions:
def configFileMissingMyIP(self, config_file=None, lock_file=None):
(pid, ret, stdout, stderr, runner) = \
self.run_booth(config_file=config_file, lock_file=lock_file,
- expected_exitcode=1)
+ expected_exitcode=1, expected_daemon=False)
expected_error = "ERROR: can't find myself in config file"
self.assertRegexpMatches(self.read_log(), expected_error)
View
12 test/boothtestenv.py
@@ -61,13 +61,11 @@ def check_return_code(self, pid, return_code, expected_exitcode):
self.fail("expected exit code %d, not long-running process" % expected_exitcode)
else:
print "pid %d exited with code %d" % (pid, return_code)
- msg = "should exit with code %s" % expected_exitcode
- msg += "\nlog follows (see %s)" % self.log_file
+ if expected_exitcode is None:
+ msg = "should not exit"
+ else:
+ msg = "should exit with code %s" % expected_exitcode
+ msg += "\nLog follows (see %s)" % self.log_file
msg += "\nN.B. expect mlockall/setscheduler errors when running tests non-root"
msg += "\n-----------\n%s" % self.read_log()
self.assertEqual(return_code, expected_exitcode, msg)
-
- def _test_buffer_overflow(self, expected_error, **args):
- (pid, ret, stdout, stderr, runner) = \
- self.run_booth(expected_exitcode=1, **args)
- self.assertRegexpMatches(stderr, expected_error)
View
5 test/clientenv.py
@@ -22,3 +22,8 @@ def run_booth(self, config_text=None, config_file=None, lock_file=True, args=[],
self.check_return_code(pid, return_code, expected_exitcode)
return (pid, return_code, stdout, stderr, runner)
+
+ def _test_buffer_overflow(self, expected_error, **args):
+ (pid, ret, stdout, stderr, runner) = \
+ self.run_booth(expected_exitcode=1, **args)
+ self.assertRegexpMatches(stderr, expected_error)
View
85 test/serverenv.py
@@ -11,28 +11,75 @@
from utils import get_IP
class ServerTestEnvironment(BoothTestEnvironment):
+ '''
+ boothd site/arbitrator will hang in setup phase while attempting to connect
+ to an unreachable peer during ticket_catchup(). In a test environment we don't
+ have any reachable peers. Fortunately, we can still successfully launch a
+ daemon by only listing our own IP in the config file.
+ '''
typical_config = """\
# This is like the config in the manual
transport="UDP"
port="6666"
# Here's another comment
-arbitrator="147.2.207.14"
+#arbitrator="147.2.207.14"
site="147.4.215.19"
-site="147.18.2.1"
+#site="147.18.2.1"
ticket="ticketA"
ticket="ticketB"
"""
- working_config = re.sub('site=".+"', 'site="%s"' % get_IP(), typical_config, 1)
+ site_re = re.compile('^site=".+"', re.MULTILINE)
+ working_config = re.sub(site_re, 'site="%s"' % get_IP(), typical_config, 1)
- def run_booth(self, config_text=None, config_file=None, lock_file=True, args=[],
- expected_exitcode=0, debug=False):
+ def run_booth(self, expected_exitcode, expected_daemon,
+ config_text=None, config_file=None, lock_file=True,
+ args=[], debug=False):
'''
- Runs boothd. Defaults to using a temporary lock file and
- the standard config file path.
+ Runs boothd. Defaults to using a temporary lock file and the
+ standard config file path. There are four possible types of
+ outcome:
+
+ - boothd exits non-zero without launching a daemon (setup phase failed,
+ e.g. due to invalid configuration file)
+ - boothd exits zero after launching a daemon (successful operation)
+ - boothd does not exit (running in foreground / debug mode)
+ - boothd does not exit (setup phase hangs, e.g. while attempting
+ to connect to peer during ticket_catchup())
+
+ Arguments:
+ config_text
+ a string containing the contents of a configuration file to use
+ config_file
+ path to a configuration file to use
+ lock_file
+ False: don't pass a lockfile parameter to booth via -l
+ True: pass a temporary lockfile parameter to booth via -l
+ string: pass the given lockfile path to booth via -l
+ args
+ array of extra args to pass to booth
+ expected_exitcode
+ an integer, or False if booth is not expected to terminate
+ within the timeout
+ expected_daemon
+ True iff a daemon is expected to be launched (this includes
+ running the server in debug / foreground mode via -D; even
+ though in this case the server's not technically not a daemon,
+ we still want to treat it like one by checking the lockfile
+ before and after we kill it)
+ debug
+ True means pass the -D parameter
Returns a (pid, return_code, stdout, stderr, runner) tuple,
where return_code/stdout/stderr are None iff pid is still running.
'''
+ if expected_daemon and expected_exitcode is not None and expected_exitcode != 0:
+ raise RuntimeError, \
+ "Shouldn't ever expect daemon to start and then failure"
+
+ if not expected_daemon and expected_exitcode == 0:
+ raise RuntimeError, \
+ "Shouldn't ever expect success without starting daemon"
+
self.init_log()
runner = BoothRunner(self.boothd_path, self.mode, args)
@@ -54,11 +101,13 @@ def run_booth(self, config_text=None, config_file=None, lock_file=True, args=[],
(pid, return_code, stdout, stderr) = runner.run()
self.check_return_code(pid, return_code, expected_exitcode)
- expected_daemon = expected_exitcode == 0 or expected_exitcode is None
- got_daemon = return_code == 0 or return_code is None
-
- if got_daemon:
+ if expected_daemon:
self.check_daemon_handling(runner, expected_daemon)
+ elif return_code is None:
+ # This isn't strictly necessary because we ensure no
+ # daemon is running from within test setUp(), but it's
+ # probably a good idea to tidy up after ourselves anyway.
+ self.kill_pid(pid)
return (pid, return_code, stdout, stderr, runner)
@@ -69,6 +118,11 @@ def write_config_file(self, config_text):
c.close()
return config_file
+ def kill_pid(self, pid):
+ print "killing %d ..." % pid
+ os.kill(pid, 15)
+ print "killed"
+
def check_daemon_handling(self, runner, expected_daemon):
'''
Check that the lock file contains a pid referring to a running
@@ -86,9 +140,7 @@ def check_daemon_handling(self, runner, expected_daemon):
self.assertTrue(daemon_running, err)
if daemon_running:
- print "killing %s ..." % daemon_pid
- os.kill(int(daemon_pid), 15)
- print "killed"
+ self.kill_pid(int(daemon_pid))
time.sleep(1)
daemon_pid = self.get_daemon_pid_from_lock_file(runner.lock_file)
self.assertTrue(daemon_pid is not None,
@@ -144,3 +196,8 @@ def is_pid_running_daemon(self, pid):
# )
return True
+
+ def _test_buffer_overflow(self, expected_error, **args):
+ (pid, ret, stdout, stderr, runner) = \
+ self.run_booth(expected_exitcode=1, expected_daemon=False, **args)
+ self.assertRegexpMatches(stderr, expected_error)
View
35 test/servertests.py
@@ -24,7 +24,8 @@ class ServerTests(ServerTestEnvironment):
# self.configFileMissingMyIP(lock_file=False)
#
# def test_custom_lock_file(self):
- # (pid, ret, stdout, stderr, runner) = self.run_booth(expected_exitcode=1)
+ # (pid, ret, stdout, stderr, runner) = \
+ # self.run_booth(expected_exitcode=1, expected_daemon=False)
# self.assertRegexpMatches(
# stderr,
# 'failed to open %s: ' % runner.config_file_used(),
@@ -48,7 +49,8 @@ def test_lock_file_buffer_overflow(self):
def test_working_config(self):
(pid, ret, stdout, stderr, runner) = \
- self.run_booth(config_text=self.working_config)
+ self.run_booth(expected_exitcode=0, expected_daemon=True,
+ config_text=self.working_config)
def test_missing_quotes(self):
orig_lines = self.working_config.split("\n")
@@ -57,16 +59,20 @@ def test_missing_quotes(self):
new_lines[i] = new_lines[i].replace('"', '')
new_config = "\n".join(new_lines)
- line_contains_IP = re.search('=.+\.', orig_lines[i])
+ line_contains_IP = re.search('^\s*(site|arbitrator)=.*[0-9]\.', orig_lines[i])
if line_contains_IP:
- # IP addresses need to be surrounded by quotes
+ # IP addresses need to be surrounded by quotes,
+ # so stripping them should cause it to fail
expected_exitcode = 1
+ expected_daemon = False
else:
expected_exitcode = 0
+ expected_daemon = True
(pid, ret, stdout, stderr, runner) = \
self.run_booth(config_text=new_config,
- expected_exitcode=expected_exitcode)
+ expected_exitcode=expected_exitcode,
+ expected_daemon=expected_daemon)
if line_contains_IP:
self.assertRegexpMatches(
@@ -78,12 +84,12 @@ def test_missing_quotes(self):
def test_debug_mode(self):
(pid, ret, stdout, stderr, runner) = \
self.run_booth(config_text=self.working_config, debug=True,
- expected_exitcode=None)
+ expected_exitcode=None, expected_daemon=True)
def test_missing_transport(self):
config = re.sub('transport=.+\n', '', self.typical_config)
(pid, ret, stdout, stderr, runner) = \
- self.run_booth(config_text=config, expected_exitcode=1)
+ self.run_booth(config_text=config, expected_exitcode=1, expected_daemon=False)
self.assertRegexpMatches(
self.read_log(),
'config file was missing transport line'
@@ -92,7 +98,7 @@ def test_missing_transport(self):
def test_invalid_transport_protocol(self):
config = re.sub('transport=.+', 'transport=SNEAKERNET', self.typical_config)
(pid, ret, stdout, stderr, runner) = \
- self.run_booth(config_text=config, expected_exitcode=1)
+ self.run_booth(config_text=config, expected_exitcode=1, expected_daemon=False)
self.assertRegexpMatches(
self.read_log(),
'invalid transport protocol'
@@ -101,29 +107,34 @@ def test_invalid_transport_protocol(self):
def test_missing_final_newline(self):
config = re.sub('\n$', '', self.working_config)
(pid, ret, stdout, stderr, runner) = \
- self.run_booth(config_text=config)
+ self.run_booth(config_text=config, expected_exitcode=0, expected_daemon=True)
def test_a_few_trailing_whitespaces(self):
for ws in (' ', ' '):
new_config = self.working_config.replace("\n", ws + "\n", 3)
(pid, ret, stdout, stderr, runner) = \
self.run_booth(config_text=new_config,
- expected_exitcode=0)
+ expected_exitcode=0, expected_daemon=True)
def test_trailing_space_everywhere(self):
for ws in (' ', ' '):
new_config = self.working_config.replace("\n", ws + "\n")
(pid, ret, stdout, stderr, runner) = \
self.run_booth(config_text=new_config,
- expected_exitcode=0)
+ expected_exitcode=0, expected_daemon=True)
def test_unquoted_space(self):
for ticket in ('unquoted space', 'unquoted space man'):
new_config = re.sub('ticket=.+', 'ticket=' + ticket,
self.working_config, 1)
(pid, ret, stdout, stderr, runner) = \
- self.run_booth(config_text=new_config, expected_exitcode=1)
+ self.run_booth(config_text=new_config, expected_exitcode=1, expected_daemon=False)
self.assertRegexpMatches(
self.read_log(),
'invalid config file format: unquoted whitespace'
)
+
+ def test_unreachable_peer(self):
+ config = re.sub('#(.+147.+)', lambda m: m.group(1), self.working_config)
+ self.run_booth(config_text=config,
+ expected_exitcode=None, expected_daemon=False)
Please sign in to comment.
Something went wrong with that request. Please try again.