blob: feb534a59d5f7fea2de29c75938bd253b27162dc [file] [log] [blame]
# Copyright (c) 2012 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.
import logging
import os
import pwd
import subprocess
import tempfile
from autotest_lib.client.bin import test
from autotest_lib.client.common_lib import error
class TLSDate:
"""
A single tlsdate invocation. Takes care of setting up a temporary cachedir
for it, along with collecting output from both it and its helper processes.
"""
def __init__(self, test_obj):
self._proc = None
self._testdir = tempfile.mkdtemp(suffix='tlsdate')
self._cachedir = self._testdir + '/cache'
self._outfile = self._testdir + '/out'
self._subprog = '?'
self._test_obj = test_obj
self._output = None
self._tlsdate_uid = pwd.getpwnam('tlsdate').pw_uid
os.mkdir(self._cachedir)
# Let the tlsdate user (tlsdate) write.
os.chown(self._testdir, self._tlsdate_uid, -1)
# Allow support shell library to be sourced.
os.chown(self._test_obj.srcdir + '/time.sh', self._tlsdate_uid, -1)
def start(self, subprog):
logging.info('running with %s/%s', self._test_obj.srcdir, subprog)
self._subprog = subprog
# Make sure the tlsdate user can access the files
fake_tlsdate = self._test_obj.srcdir + '/' + subprog
os.chown(fake_tlsdate, self._tlsdate_uid, -1)
args = ['/usr/bin/tlsdated', '-p',
'-f', self._test_obj.srcdir + '/test.conf',
'-c', self._cachedir,
'-v',
fake_tlsdate,
self._outfile]
self._proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stderr=subprocess.PIPE)
def route_up(self):
self._proc.stdin.write('n')
self._proc.stdin.flush()
def kill(self):
self._proc.terminate()
def output(self):
if not self._output:
self._output = self._proc.communicate()[1].split('\n')
return self._output
def in_output(self, string):
for x in self.output():
if string in x:
return True
return False
def subproc_output(self):
with open(self._outfile) as f:
return [x.rstrip() for x in f.readlines()]
def ok(self):
return 'ok' in self.subproc_output()
class platform_TLSDate(test.test):
version = 1
def require_ok(self, t):
if not t.ok():
raise error.TestFail('Expected success, got:' +
';'.join(t.subproc_output()))
def require_output(self, t, string):
if not t.in_output(string):
raise error.TestFail('Needed "%s" but got "%s"' % (string,
';'.join(t.output())))
def require_not_output(self, t, string):
if t.in_output(string):
raise error.TestFail('Needed no "%s" but got "%s"' % (string,
';'.join(t.output())))
def test_delay_subproc(self):
"""
Tests that a subprocess that delays for one second is waited on
successfully the second time.
"""
t = TLSDate(self)
t.start('delay_subproc')
self.require_output(t, 'attempt 1 backoff')
self.require_output(t, 'time set from the network')
self.require_ok(t)
def test_hang_subproc(self):
"""
Tests that a subprocess that delays for too long is considered hung and
killed.
"""
t = TLSDate(self)
t.start('hang_subproc')
self.require_output(t, 'attempt 1 backoff')
self.require_output(t, 'tlsdate timed out')
self.require_ok(t)
def test_fail_routes(self):
"""
Tests that if the initial tlsdate call fails, we wait for a route to
appear, then rerun tlsdate.
"""
t = TLSDate(self)
t.start('fail_routes')
t.route_up()
self.require_output(t, 'status:2')
self.require_output(t, 'stdin')
self.require_output(t, 'time set from the network')
self.require_ok(t)
def run_once(self):
self.test_delay_subproc()
self.test_hang_subproc()
self.test_fail_routes()