run-tests.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #!/usr/bin/python
  2. #
  3. # AP tests
  4. # Copyright (c) 2013, Jouni Malinen <j@w1.fi>
  5. #
  6. # This software may be distributed under the terms of the BSD license.
  7. # See README for more details.
  8. import os
  9. import re
  10. import sys
  11. import time
  12. from datetime import datetime
  13. import argparse
  14. import subprocess
  15. import logging
  16. logger = logging.getLogger(__name__)
  17. sys.path.append('../../wpaspy')
  18. from wpasupplicant import WpaSupplicant
  19. from hostapd import HostapdGlobal
  20. def reset_devs(dev, apdev):
  21. hapd = HostapdGlobal()
  22. for d in dev:
  23. try:
  24. d.reset()
  25. except Exception, e:
  26. logger.info("Failed to reset device " + d.ifname)
  27. print str(e)
  28. for ap in apdev:
  29. hapd.remove(ap['ifname'])
  30. def report(conn, build, commit, run, test, result, diff):
  31. if conn:
  32. if not build:
  33. build = ''
  34. if not commit:
  35. commit = ''
  36. sql = "INSERT INTO results(test,result,run,time,duration,build,commitid) VALUES(?, ?, ?, ?, ?, ?, ?)"
  37. params = (test.replace('test_', '', 1), result, run, time.time(), diff.total_seconds(), build, commit)
  38. try:
  39. conn.execute(sql, params)
  40. conn.commit()
  41. except Exception, e:
  42. print "sqlite: " + str(e)
  43. print "sql: %r" % (params, )
  44. class Tracer(object):
  45. def __init__(self, tracedir, testname):
  46. self._tracedir = tracedir
  47. self._testname = testname
  48. def __enter__(self):
  49. if not self._tracedir:
  50. return
  51. output = os.path.join(self._tracedir, '%s.dat' % (self._testname, ))
  52. self._trace_cmd = subprocess.Popen(['sudo', 'trace-cmd', 'record', '-o', output, '-e', 'mac80211', '-e', 'cfg80211', 'sh', '-c', 'echo STARTED ; read l'],
  53. stdin=subprocess.PIPE,
  54. stdout=subprocess.PIPE,
  55. stderr=open('/dev/null', 'w'),
  56. cwd=self._tracedir)
  57. l = self._trace_cmd.stdout.read(7)
  58. while not 'STARTED' in l:
  59. l += self._trace_cmd.stdout.read(1)
  60. def __exit__(self, type, value, traceback):
  61. if not self._tracedir:
  62. return
  63. self._trace_cmd.stdin.write('DONE\n')
  64. self._trace_cmd.wait()
  65. def main():
  66. tests = []
  67. test_modules = []
  68. for t in os.listdir("."):
  69. m = re.match(r'(test_.*)\.py$', t)
  70. if m:
  71. logger.debug("Import test cases from " + t)
  72. mod = __import__(m.group(1))
  73. test_modules.append(mod.__name__)
  74. for s in dir(mod):
  75. if s.startswith("test_"):
  76. func = mod.__dict__.get(s)
  77. tests.append(func)
  78. test_names = list(set([t.__name__ for t in tests]))
  79. run = None
  80. print_res = False
  81. parser = argparse.ArgumentParser(description='hwsim test runner')
  82. group = parser.add_mutually_exclusive_group()
  83. group.add_argument('-d', const=logging.DEBUG, action='store_const',
  84. dest='loglevel', default=logging.INFO,
  85. help="verbose debug output")
  86. group.add_argument('-q', const=logging.WARNING, action='store_const',
  87. dest='loglevel', help="be quiet")
  88. group.add_argument('-l', metavar='<filename>', dest='logfile',
  89. help='debug log filename')
  90. parser.add_argument('-e', metavar="<filename>", dest='errorfile',
  91. help='error filename')
  92. parser.add_argument('-r', metavar="<filename>", dest='resultsfile',
  93. help='results filename')
  94. parser.add_argument('-S', metavar='<sqlite3 db>', dest='database',
  95. help='database to write results to')
  96. parser.add_argument('--commit', metavar='<commit id>',
  97. help='commit ID, only for database')
  98. parser.add_argument('-b', metavar='<build>', dest='build', help='build ID')
  99. parser.add_argument('-L', action='store_true', dest='update_tests_db',
  100. help='List tests (and update descriptions in DB)')
  101. parser.add_argument('-T', metavar='<dir>', dest='tracedir',
  102. help='tracing directory - will get a trace file per test')
  103. parser.add_argument('-f', dest='testmodules', metavar='<test module>',
  104. help='execute only tests from these test modules',
  105. type=str, choices=[[]] + test_modules, nargs='+')
  106. parser.add_argument('tests', metavar='<test>', nargs='*', type=str,
  107. help='tests to run (only valid without -f)',
  108. choices=[[]] + test_names)
  109. args = parser.parse_args()
  110. if args.tests and args.testmodules:
  111. print 'Invalid arguments - both test module and tests given'
  112. sys.exit(2)
  113. if args.logfile:
  114. logging.basicConfig(filename=args.logfile,
  115. level=logging.DEBUG)
  116. log_to_file = True
  117. else:
  118. logging.basicConfig(level=args.loglevel)
  119. log_to_file = False
  120. if args.loglevel == logging.WARNING:
  121. print_res = True
  122. error_file = args.errorfile
  123. results_file = args.resultsfile
  124. if args.database:
  125. import sqlite3
  126. conn = sqlite3.connect(args.database)
  127. else:
  128. conn = None
  129. if conn:
  130. run = str(int(time.time()))
  131. if args.update_tests_db:
  132. for t in tests:
  133. print t.__name__ + " - " + t.__doc__
  134. if conn:
  135. sql = 'INSERT OR REPLACE INTO tests(test,description) VALUES (?, ?)'
  136. params = (t.__name__.replace('test_', '', 1), t.__doc__)
  137. try:
  138. conn.execute(sql, params)
  139. except Exception, e:
  140. print "sqlite: " + str(e)
  141. print "sql: %r" % (params,)
  142. if conn:
  143. conn.commit()
  144. conn.close()
  145. sys.exit(0)
  146. dev0 = WpaSupplicant('wlan0', '/tmp/wpas-wlan0')
  147. dev1 = WpaSupplicant('wlan1', '/tmp/wpas-wlan1')
  148. dev2 = WpaSupplicant('wlan2', '/tmp/wpas-wlan2')
  149. dev = [ dev0, dev1, dev2 ]
  150. apdev = [ ]
  151. apdev.append({"ifname": 'wlan3', "bssid": "02:00:00:00:03:00"})
  152. apdev.append({"ifname": 'wlan4', "bssid": "02:00:00:00:04:00"})
  153. for d in dev:
  154. if not d.ping():
  155. logger.info(d.ifname + ": No response from wpa_supplicant")
  156. return
  157. logger.info("DEV: " + d.ifname + ": " + d.p2p_dev_addr())
  158. for ap in apdev:
  159. logger.info("APDEV: " + ap['ifname'])
  160. passed = []
  161. skipped = []
  162. failed = []
  163. for t in tests:
  164. if args.tests:
  165. if not t.__name__ in args.tests:
  166. continue
  167. if args.testmodules:
  168. if not t.__module__ in args.testmodules:
  169. continue
  170. with Tracer(args.tracedir, t.__name__):
  171. reset_devs(dev, apdev)
  172. logger.info("START " + t.__name__)
  173. if log_to_file:
  174. print "START " + t.__name__
  175. sys.stdout.flush()
  176. if t.__doc__:
  177. logger.info("Test: " + t.__doc__)
  178. start = datetime.now()
  179. for d in dev:
  180. try:
  181. d.request("NOTE TEST-START " + t.__name__)
  182. except Exception, e:
  183. logger.info("Failed to issue TEST-START before " + t.__name__ + " for " + d.ifname)
  184. logger.info(e)
  185. print "FAIL " + t.__name__ + " - could not start test"
  186. if conn:
  187. conn.close()
  188. conn = None
  189. sys.exit(1)
  190. try:
  191. if t.func_code.co_argcount > 1:
  192. res = t(dev, apdev)
  193. else:
  194. res = t(dev)
  195. end = datetime.now()
  196. diff = end - start
  197. if res == "skip":
  198. skipped.append(t.__name__)
  199. result = "SKIP"
  200. else:
  201. passed.append(t.__name__)
  202. result = "PASS"
  203. report(conn, args.build, args.commit, run, t.__name__, result, diff)
  204. result = result + " " + t.__name__ + " "
  205. result = result + str(diff.total_seconds()) + " " + str(end)
  206. logger.info(result)
  207. if log_to_file or print_res:
  208. print result
  209. sys.stdout.flush()
  210. if results_file:
  211. f = open(results_file, 'a')
  212. f.write(result + "\n")
  213. f.close()
  214. except Exception, e:
  215. end = datetime.now()
  216. diff = end - start
  217. logger.info(e)
  218. failed.append(t.__name__)
  219. report(conn, args.build, args.commit, run, t.__name__, "FAIL", diff)
  220. result = "FAIL " + t.__name__ + " " + str(diff.total_seconds()) + " " + str(end)
  221. logger.info(result)
  222. if log_to_file:
  223. print result
  224. sys.stdout.flush()
  225. if results_file:
  226. f = open(results_file, 'a')
  227. f.write(result + "\n")
  228. f.close()
  229. for d in dev:
  230. try:
  231. d.request("NOTE TEST-STOP " + t.__name__)
  232. except Exception, e:
  233. logger.info("Failed to issue TEST-STOP after " + t.__name__ + " for " + d.ifname)
  234. logger.info(e)
  235. if not args.tests:
  236. reset_devs(dev, apdev)
  237. if conn:
  238. conn.close()
  239. if len(failed):
  240. logger.info("passed " + str(len(passed)) + " test case(s)")
  241. logger.info("skipped " + str(len(skipped)) + " test case(s)")
  242. logger.info("failed tests: " + str(failed))
  243. if error_file:
  244. f = open(error_file, 'w')
  245. f.write(str(failed) + '\n')
  246. f.close()
  247. sys.exit(1)
  248. logger.info("passed all " + str(len(passed)) + " test case(s)")
  249. if len(skipped):
  250. logger.info("skipped " + str(len(skipped)) + " test case(s)")
  251. if log_to_file:
  252. print "passed all " + str(len(passed)) + " test case(s)"
  253. if len(skipped):
  254. print "skipped " + str(len(skipped)) + " test case(s)"
  255. if __name__ == "__main__":
  256. main()