#!/usr/bin/python import cliapp import re import subprocess class AssertionFailure(cliapp.AppException): def __init__(self, msg): self._str = msg def __str__(self): return self._str class SystemTest(cliapp.Application): def add_settings(self): self.settings.boolean(['verbose', 'v'], 'print names of tests when run') self.settings.string(['target'], 'target domain name or IP address') self.settings.string(['user'], 'user on target') self.settings.string(['user-password'], 'password for target user') self.settings.boolean(['list-tests'], 'list known tests') def process_args(self, args): if self.settings['list-tests']: for testname in self.list_tests(): self.output.write('%s\n' % testname) elif args: self.execute_tests(args) else: self.execute_tests(self.list_tests()) def execute_tests(self, testnames): for i, testname in enumerate(testnames): methodname = self.mangle(testname) if hasattr(self, methodname): if self.settings['verbose']: self.output.write('test %d/%d: %s\n' % (i+1, len(testnames), testname)) getattr(self, methodname)() else: raise cliapp.AppException('unknown test: %s' % testname) def list_tests(self): return [self.unmangle(x) for x in dir(self) if x.startswith('test')] def mangle(self, testname): return 'test_' + testname.replace('-', '_') def unmangle(self, methodname): assert methodname.startswith('test_') methodname = methodname[len('test_'):] return methodname.replace('_', '-') def hostcmd(self, argv, stdin=None): p = subprocess.Popen(argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate(stdin) if p.returncode: raise cliapp.AppException('host command failed: %s\n%s' % (' '.join(argv), err)) return out def targetcmd(self, argv, *args, **kwargs): return self.hostcmd(['ssh', '-l', self.settings['user'], self.settings['target']] + argv, *args, **kwargs) def assert_(self, cond, automsg=None, msg=None): if not cond: output = 'Assertion failed:' if automsg is None: output += ' ' + repr(cond) else: output += ' ' + automsg if msg is not None: output += ' ' + msg raise AssertionFailure(output) def assertEqual(self, v1, v2, msg=None): self.assert_(v1 == v2, automsg='%s != %s' % (repr(v1), repr(v2)), msg=msg) def assertMatches(self, pat, text, msg=None): self.assert_(re.match(pat, text), automsg='pattern %s does not match %s' % (pat, text), msg=msg) def test_only_ssh_port(self): out = self.hostcmd(['nmap', self.settings['target']]) ports = [line.split()[0] for line in out.splitlines() if ' open ' in line] self.assertEqual(ports, ['22/tcp']) def test_ssh_login(self): user = self.settings['user'] out = self.hostcmd(['ssh', '-l', user, self.settings['target'], 'id']) self.assertMatches(r'^uid=1000\(%s\)' % user, out) def test_simple_dns_lookup(self): out = self.targetcmd(['host', 'www.debian.org']) self.assert_('www.debian.org' in out) def test_ping_localhost(self): self.targetcmd(['ping', '-c1', 'localhost']) def test_ping6_localhost(self): self.targetcmd(['ping6', '-c1', 'ip6-localhost']) def test_cat(self): out = self.targetcmd(['cat'], stdin='foo') self.assertEqual(out, 'foo') # def test_sudo_works(self): # out = self.targetcmd(['sudo', 'id'], stdin=self.password) # self.assertMatches(r'^uid=0\(root\)', out) if __name__ == '__main__': SystemTest().run()