summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Chen <twothreecc@google.com>2016-07-25 16:53:14 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-08-08 13:53:25 -0700
commitc2a841a489eb2a9a2f3efbc73664681b0f7839e8 (patch)
tree7fbaaa94f50c1fafe66bc4b19fb5d89a9d697b0b
parent1e6cbc725f90784bbe80361e9c1dd07da1ab6a79 (diff)
downloadchrome-ec-c2a841a489eb2a9a2f3efbc73664681b0f7839e8.tar.gz
cts: Refactored script
Added in classes for Board (parent), DeviceUnderTest, and TestHarness. Reading, etc. should be easier now BRANCH=None BUG=None TEST=Manual - Build default - Flash default - Run - Open /tmp/cts_results/nucleo-f072rb/gpio.html - Should see a clean results page Change-Id: Ide3f75281f0b5b8b40dabd36f8c239737dc527d6 Reviewed-on: https://chromium-review.googlesource.com/364236 Commit-Ready: Chris Chen <twothreecc@google.com> Tested-by: Chris Chen <twothreecc@google.com> Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rwxr-xr-xcts/cts.py694
1 files changed, 398 insertions, 296 deletions
diff --git a/cts/cts.py b/cts/cts.py
index 8eb57f6100..aa1203ebe4 100755
--- a/cts/cts.py
+++ b/cts/cts.py
@@ -12,296 +12,401 @@ import os
import select
import subprocess as sp
import time
+from copy import deepcopy
+from abc import ABCMeta, abstractmethod
# For most tests, error codes should never conflict
CTS_CONFLICTING_CODE = -1
CTS_SUCCESS_CODE = 0
+TH_BOARD = 'stm32l476g-eval'
+OCD_SCRIPT_DIR = '/usr/local/share/openocd/scripts'
+MAX_SUITE_TIME_SEC = 3
+class Board(object):
+ """Class representing a single board connected to a host machine
-class Cts(object):
- """Class that represents a CTS testing setup and provides
- interface to boards (building, flashing, etc.)
+ This class is abstract, subclasses must define the updateSerial()
+ method
Attributes:
- ocd_script_dir: String containing locations of openocd's config files
- th_board: String containing name of the Test Harness (th) board
- results_dir: String containing test output directory path
- dut_board: Name of Device Under Test (DUT) board
- module: Name of module to build/run tests for
- ec_directory: String containing path to EC top level directory
- th_hla: String containing hla_serial for the th
- dut_hla: String containing hla_serial for the dut, only used for
- boards which have an st-link v2.1 debugger
- th_ser_path: String which contains full path to th serial file
- test_names: List of strings of test names contained in given module
- test_results: Dictionary of results of each test from module
- return_codes: List of strings of return codes, with a code's integer
- value being the index for the corresponding string representation
+ board: String containing actual type of board, i.e. nucleo-f072rb
+ config: Directory of board config file relative to openocd's
+ scripts directory
+ hla_serial: String containing board's hla_serial number (if board
+ is an stm32 board)
+ tty_port: String that is the path to the tty port which board's
+ UART outputs to
+ _tty_descriptor: String of file descriptor for tty_port
"""
- def __init__(self, ec_dir, dut_board='nucleo-f072rb', module='gpio'):
- """Initializes cts class object with given arguments.
+ configs = {
+ 'stm32l476g-eval': 'board/stm32l4discovery.cfg',
+ 'nucleo-f072rb': 'board/st_nucleo_f0.cfg'
+ }
+
+ __metaclass__ = ABCMeta # This is an Abstract Base Class (ABC)
+ def __init__(self, board, hla_serial=None, flash_offset='0x08000000'):
+ """Initializes a board object with given attributes
Args:
- dut_board: Name of Device Under Test (DUT) board
- module: Name of module to build/run tests for
+ board: String containing board name
+ hla_serial: Serial number if board's adaptor is an HLA
"""
- self.ocd_script_dir = '/usr/local/share/openocd/scripts'
- self.th_board = 'stm32l476g-eval'
- self.results_dir = '/tmp/cts_results'
- self.dut_board = dut_board
- self.module = module
- self.ec_directory = ec_dir
- self.th_hla = ''
- self.dut_hla = ''
- self.th_ser_path = os.path.join(
- self.ec_directory,
- 'build',
- self.th_board,
- 'th_hla_serial')
- testlist_path = os.path.join(
- self.ec_directory,
- 'cts',
- self.module,
- 'cts.testlist')
- self.test_names = self.getMacroArgs(testlist_path, 'CTS_TEST')
- return_codes_path = os.path.join(self.ec_directory,
- 'cts',
- 'common',
- 'cts.rc')
- self.return_codes = self.getMacroArgs(
- return_codes_path, 'CTS_RC_')
- self.test_results = collections.OrderedDict()
+ self.board = board
+ self.hla_serial = hla_serial
+ self.tty_port = None
+ self._tty_descriptor = None
+ self.flash_offset = flash_offset
- def set_dut_board(self, brd):
- """Sets the dut_board instance variable
+ @abstractmethod
+ def updateSerial(self):
+ """Subclass should implement this"""
+ pass
+
+ def sendOpenOcdCommands(self, commands):
+ """Send a command to the board via openocd
Args:
- brd: String of board name
+ commands: A list of commands to send
"""
- self.dut_board = brd
+ args = ['openocd', '-s', OCD_SCRIPT_DIR,
+ '-f', Board.configs[self.board], '-c', 'hla_serial ' + self.hla_serial]
- def set_module(self, mod):
- """Sets the module instance variable
+ for cmd in commands:
+ args += ['-c', cmd]
+ args += ['-c', 'shutdown']
+ sp.call(args)
- Args:
- brd: String of board name
+ def make(self, module, ec_dir):
+ """Builds test suite module for board"""
+ cmds = ['make',
+ '--directory=' + ec_dir,
+ 'BOARD=' + self.board,
+ 'CTS_MODULE=' + module,
+ '-j',
+ '-B']
+
+ print 'EC directory is ' + ec_dir
+ print 'Building module \'' + module + '\' for ' + self.board
+ sp.call(cmds)
+
+ def flash(self):
+ """Flashes board with most recent build ec.bin"""
+ flash_cmds = [
+ 'reset_config connect_assert_srst',
+ 'init',
+ 'reset init',
+ 'flash write_image erase build/' +
+ self.board +
+ '/ec.bin ' +
+ self.flash_offset,
+ 'reset']
+
+ self.sendOpenOcdCommands(flash_cmds)
+
+ def toString(self):
+ s = ('Type: Board\n'
+ 'board: ' + self.board + '\n'
+ 'hla_serial: ' + self.hla_serial + '\n'
+ 'config: ' + Board.configs[self.board] + '\n'
+ 'tty_port ' + self.tty_port + '\n'
+ '_tty_descriptor: ' + str(self._tty_descriptor) + '\n')
+ return s
+
+ def reset(self):
+ """Reset board (used when can't connect to TTY)"""
+ self.sendOpenOcdCommands(['init', 'reset init', 'resume'])
+
+ def setupForOutput(self):
+ """Call this before trying to call readOutput for the first time.
+ This is not in the initialization because caller only should call
+ this function after serial numbers are setup
"""
- self.module = mod
+ self.updateSerial()
+ self.reset()
+ self._identifyTtyPort()
+
+ # In testing 3 retries is enough to reset board (2 can fail)
+ num_file_setup_retries = 3
+ # In testing, 10 seconds is sufficient to allow board to reconnect
+ reset_wait_time_seconds = 10
+ try:
+ self._getDevFileDescriptor()
+ # If board was just connected, must be reset to be read from
+ except (IOError, OSError):
+ for i in range(num_file_setup_retries):
+ self.reset()
+ time.sleep(reset_wait_time_seconds)
+ try:
+ self._getDevFileDescriptor()
+ break
+ except (IOError, OSError):
+ continue
+ if self._tty_descriptor is None:
+ raise ValueError('Unable to read ' + self.name + '\n'
+ 'If you are running cat on a ttyACMx file,\n'
+ 'please kill that process and try again')
- def make(self):
- """Builds test suite module for given th/dut boards"""
- print 'Building module \'' + self.module + '\' for th ' + self.th_board
- sp.call(['make',
- '--directory=' + str(self.ec_directory),
- 'BOARD=' + self.th_board,
- 'CTS_MODULE=' + self.module,
- '-j'])
-
- print 'Building module \'' + self.module + '\' for dut ' + self.dut_board
- sp.call(['make',
- '--directory=' + str(self.ec_directory),
- 'BOARD=' + self.dut_board,
- 'CTS_MODULE=' + self.module,
- '-j'])
-
- def openocdCmd(self, command_list, board):
- """Sends the specified commands to openocd for a board
+ def readAvailableBytes(self):
+ """Read info from a serial port described by a file descriptor
- Args:
- board: String that contains board name
+ Return:
+ Bytes that UART has output
"""
+ buf = []
+ while True:
+ if select.select([self._tty_descriptor], [], [], 1)[0]:
+ buf.append(os.read(self._tty_descriptor, 1))
+ else:
+ break
+ result = ''.join(buf)
+ return result
- board_cfg = self.getBoardConfigName(board)
+ def _identifyTtyPort(self):
+ """Saves this board's serial port"""
+ dev_dir = '/dev/'
+ id_prefix = 'ID_SERIAL_SHORT='
+ num_reset_tries = 3
+ reset_wait_time_s = 10
+ com_devices = [f for f in os.listdir(
+ dev_dir) if f.startswith('ttyACM')]
+
+ for i in range(num_reset_tries):
+ for device in com_devices:
+ self.tty_port = os.path.join(dev_dir, device)
+ properties = sp.check_output(['udevadm',
+ 'info',
+ '-a',
+ '-n',
+ self.tty_port,
+ '--query=property'])
+ for line in [l.strip() for l in properties.split('\n')]:
+ if line.startswith(id_prefix):
+ if self.hla_serial == line[len(id_prefix):]:
+ return
+ if i != num_reset_tries - 1: # No need to reset the obard the last time
+ self.reset() # May need to reset to connect
+ time.sleep(reset_wait_time_s)
+
+ # If we get here without returning, something is wrong
+ raise RuntimeError('The device dev path could not be found')
+
+ def _getDevFileDescriptor(self):
+ """Read available bytes from device dev path"""
+ fd = os.open(self.tty_port, os.O_RDONLY)
+ flag = fcntl.fcntl(fd, fcntl.F_GETFL)
+ fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
+ self._tty_descriptor = fd
- args = ['openocd', '-s', self.ocd_script_dir,
- '-f', board_cfg]
- for cmd in command_list:
- args.append('-c')
- args.append(cmd)
- args.append('-c')
- args.append('shutdown')
- sp.call(args)
+class TestHarness(Board):
+ """Subclass of Board representing a Test Harness
- def getStLinkSerialNumbers(self):
- """Gets serial numbers of all st-link v2.1 board attached to host
+ Attributes:
+ serial_path: Path to file containing serial number
+ """
- Returns:
- List of serials
+ def __init__(self, serial_path=None):
+ """Initializes a board object with given attributes
+
+ Args:
+ serial_path: Path to file containing serial number
"""
- usb_args = ['lsusb', '-v', '-d', '0x0483:0x374b']
- usb_process = sp.Popen(usb_args, stdout=sp.PIPE, shell=False)
- st_link_info = usb_process.communicate()[0]
- st_serials = []
- for line in st_link_info.split('\n'):
- if 'iSerial' in line:
- st_serials.append(line.split()[2])
- return st_serials
+ Board.__init__(self, TH_BOARD)
+ self.serial_path = serial_path
- # params: th_hla_serial is your personal th board's serial
- def saveDutSerial(self):
- """If dut uses same debugger as th, save its serial"""
- stlink_serials = self.getStLinkSerialNumbers()
- if len(stlink_serials) == 1: # dut doesn't use same debugger
- return ''
- elif len(stlink_serials) == 2:
- dut = [s for s in stlink_serials if self.th_hla not in s]
- if len(dut) != 1:
- raise RuntimeError('Incorrect TH hla_serial')
- else:
- return dut[0] # Found your other st-link device serial!
- else:
- msg = ('Please connect TH and your DUT\n'
- 'and remove all other st-link devices')
+ def updateSerial(self):
+ """Loads serial number from saved location"""
+ if self.hla_serial:
+ return # serial was already loaded
+ try:
+ with open(self.serial_path, mode='r') as ser_f:
+ self.hla_serial = ser_f.read()
+ return
+ except IOError:
+ msg = ('Your th hla_serial may not have been saved.\n'
+ 'Connect only your th and run ./cts --setup, then try again.')
raise RuntimeError(msg)
- def saveThSerial(self):
- """Saves the th serial number to a file located at th_ser_path
+ def saveSerial(self):
+ """Saves the th serial number to a file
Return: the serial number saved
"""
- serial = self.getStLinkSerialNumbers()
+ serial = Cts.getSerialNumbers()
if len(serial) != 1:
msg = ('TH could not be identified.\n'
'\nConnect your TH and remove other st-link devices')
raise RuntimeError(msg)
else:
ser = serial[0]
- if not os.path.exists(os.path.dirname(self.th_ser_path)):
- os.makedirs(os.path.dirname(self.th_ser_path))
- with open(self.th_ser_path, mode='w') as ser_f:
+ if not ser:
+ msg = ('Unable to save serial')
+ raise RuntimeError(msg)
+ if not os.path.exists(os.path.dirname(self.serial_path)):
+ os.makedirs(os.path.dirname(self.serial_path))
+ with open(self.serial_path, mode='w') as ser_f:
ser_f.write(ser)
- return ser
+ self.hla_serial = ser
+ return ser
- def getBoardConfigName(self, board):
- """Gets the path for the config file relative to the
- openocd scripts directory
+class DeviceUnderTest(Board):
+ """Subclass of Board representing a DUT board
- Args:
- board: String containing name of board to get the config file for
+ Attributes:
+ th: Reference to test harness board to which this DUT is attached
+ """
+
+ def __init__(self, board, th, hla_ser=None, f_offset='0x08000000'):
+ """Initializes a Device Under Test object with given attributes
- Returns: String containing relative path to board config file
+ Args:
+ board: String containing board name
+ th: Reference to test harness board to which this DUT is attached
+ hla_serial: Serial number if board uses an HLA adaptor
"""
- board_config_locs = {
- 'stm32l476g-eval': 'board/stm32l4discovery.cfg',
- 'nucleo-f072rb': 'board/st_nucleo_f0.cfg'
- }
+ Board.__init__(self, board, hla_serial=hla_ser, flash_offset=f_offset)
+ self.th = th
- try:
- cfg = board_config_locs[board]
- return cfg
- except KeyError:
- raise ValueError(
- 'The config file for board ' +
- board +
- ' was not found')
+ def updateSerial(self):
+ """Stores the DUT's serial number.
- def flashBoards(self):
- """Flashes th and dut boards with their most recently build ec.bin"""
- self.updateSerials()
- th_flash_cmds = [
- 'hla_serial ' +
- self.th_hla,
- 'reset_config connect_assert_srst',
- 'init',
- 'reset init',
- 'flash write_image erase build/' +
- self.th_board +
- '/ec.bin 0x08000000',
- 'reset halt']
-
- dut_flash_cmds = [
- 'hla_serial ' +
- self.dut_hla,
- 'reset_config connect_assert_srst',
- 'init',
- 'reset init',
- 'flash write_image erase build/' +
- self.dut_board +
- '/ec.bin 0x08000000',
- 'reset halt']
-
- self.openocdCmd(th_flash_cmds, self.th_board)
- self.openocdCmd(dut_flash_cmds, self.dut_board)
- self.openocdCmd(['hla_serial ' + self.th_hla,
- 'init',
- 'reset init',
- 'resume'],
- self.th_board)
- self.openocdCmd(['hla_serial ' + self.dut_hla,
- 'init',
- 'reset init',
- 'resume'],
- self.dut_board)
+ Precondition: The DUT and TH must both be connected, and th.hla_serial
+ must hold the correct value (the th's serial #)
+ """
+ if self.hla_serial != None:
+ return # serial was already set ('' is a valid serial)
+ serials = Cts.getSerialNumbers()
+ dut = [s for s in serials if self.th.hla_serial != s]
+ if len(dut) == 1:
+ self.hla_serial = dut[0]
+ return # Found your other st-link device serial!
+ else:
+ raise RuntimeError('Your TH serial number is incorrect, or your have'
+ ' too many st-link devices attached.')
+ # If len(dut) is 0 then your dut doesn't use an st-link device, so we
+ # don't have to worry about its serial number
- def updateSerials(self):
- """Updates serial #s for th and dut"""
- try:
- with open(self.th_ser_path) as th_f:
- self.th_hla = th_f.read()
- except IOError:
- msg = ('Your th hla_serial may not have been saved.\n'
- 'Connect only your th and run ./cts --setup, then try again.')
- raise RuntimeError(msg)
- self.saveDutSerial()
+class Cts(object):
+ """Class that represents a CTS testing setup and provides
+ interface to boards (building, flashing, etc.)
- def resetBoards(self):
- """Resets the boards and allows them to run tests"""
- self.updateSerials()
- self.openocdCmd(['hla_serial ' + self.dut_hla,
- 'init', 'reset init'], self.dut_board)
- self.openocdCmd(['hla_serial ' + self.th_hla,
- 'init', 'reset init'], self.th_board)
- self.openocdCmd(['hla_serial ' + self.th_hla,
- 'init', 'resume'], self.th_board)
- self.openocdCmd(['hla_serial ' + self.dut_hla,
- 'init', 'resume'], self.dut_board)
-
- def readAvailableBytes(self, fd):
- """Read info from a serial port described by a file descriptor
+ Attributes:
+ dut: DeviceUnderTest object representing dut
+ th: TestHarness object representing th
+ module: Name of module to build/run tests for
+ ec_directory: String containing path to EC top level directory
+ test_names: List of strings of test names contained in given module
+ test_results: Dictionary of results of each test from module, with
+ keys being test name strings and values being test result integers
+ return_codes: List of strings of return codes, with a code's integer
+ value being the index for the corresponding string representation
+ """
+
+ def __init__(self, ec_dir, dut='nucleo-f072rb', module='gpio'):
+ """Initializes cts class object with given arguments.
Args:
- fd: file descriptor for device ttyACM file
+ dut: Name of Device Under Test (DUT) board
+ ec_dir: String path to ec directory
+ module: Name of module to build/run tests for
"""
- buf = []
- while True:
- if select.select([fd], [], [], 1)[0]:
- buf.append(os.read(fd, 1))
- else:
- break
- result = ''.join(buf)
- return result
+ self.results_dir = '/tmp/cts_results'
+ self.ec_directory = ec_dir
+ self.th = TestHarness()
+ self.dut = DeviceUnderTest(dut, self.th) # DUT constructor needs TH
- def getDevFileDescriptor(self, path):
- """Read available bytes from device dev path
+ th_ser_path = os.path.join(
+ self.ec_directory,
+ 'build',
+ self.th.board,
+ 'th_hla_serial')
+
+ self.module = module
+
+ testlist_path = os.path.join(
+ self.ec_directory,
+ 'cts',
+ self.module,
+ 'cts.testlist')
+
+ self.test_names = Cts._getMacroArgs(testlist_path, 'CTS_TEST')
+
+ self.th.serial_path = th_ser_path
+
+ return_codes_path = os.path.join(self.ec_directory,
+ 'cts',
+ 'common',
+ 'cts.rc')
+
+ self.return_codes = Cts._getMacroArgs(
+ return_codes_path, 'CTS_RC_')
+
+ self.test_results = collections.OrderedDict()
+
+ def set_module(self, mod):
+ """Sets the module instance variable. Also sets test_names,
+ since that depends directly on the module we are using
Args:
- path: The serial device file path to read from
+ mod: String of module name
+ """
+ self.module = mod
- Return: the file descriptor for the open serial device file
+
+ def make(self):
+ self.dut.make(self.module, self.ec_directory)
+ self.th.make(self.module, self.ec_directory)
+
+ def flashBoards(self):
+ """Flashes th and dut boards with their most recently build ec.bin"""
+ self.updateSerials()
+ self.th.flash()
+ self.dut.flash()
+
+ def setup(self):
+ """Saves th serial number if th only is connected.
+
+ Return:
+ Serial number that was saved
"""
- fd = os.open(path, os.O_RDONLY)
- flag = fcntl.fcntl(fd, fcntl.F_GETFL)
- fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
- return fd
+ return self.th.saveSerial()
- def getDevFilenames(self):
- """Read available bytes from device dev path
+ def updateSerials(self):
+ """Updates serials of both th and dut, in that order (order matters)"""
+ self.th.updateSerial()
+ self.dut.updateSerial()
- Args:
- path: The serial device file path to read from
+ def resetBoards(self):
+ """Resets the boards and allows them to run tests
+ Due to current (7/27/16) version of sync function,
+ both boards must be rest and halted, with the th
+ resuming first, in order for the test suite to run
+ in sync
+ """
+ self.updateSerials()
+ self.th.sendOpenOcdCommands(['init', 'reset halt'])
+ self.dut.sendOpenOcdCommands(['init', 'reset halt'])
+ self.th.sendOpenOcdCommands(['init', 'resume'])
+ self.dut.sendOpenOcdCommands(['init', 'resume'])
- Return: the file descriptor for the open serial device file
+ @staticmethod
+ def getSerialNumbers():
+ """Gets serial numbers of all st-link v2.1 board attached to host
+
+ Returns:
+ List of serials
"""
- com_files = [f for f in os.listdir('/dev/') if f.startswith('ttyACM')]
- if len(com_files) < 2:
- raise RuntimeError('The device dev paths could not be found')
- elif len(com_files) > 2:
- raise RuntimeError('Too many serial devices connected to host')
- else:
- return ('/dev/' + com_files[0], '/dev/' + com_files[1])
+ usb_args = ['lsusb', '-v', '-d', '0x0483:0x374b']
+ usb_process = sp.Popen(usb_args, stdout=sp.PIPE, shell=False)
+ st_link_info = usb_process.communicate()[0]
+ st_serials = []
+ for line in st_link_info.split('\n'):
+ if 'iSerial' in line:
+ st_serials.append(line.split()[2].strip())
+ return st_serials
- def getMacroArgs(self, filepath, macro):
+ @staticmethod
+ def _getMacroArgs(filepath, macro):
"""Get list of args of a certain macro in a file when macro is used
by itself on a line
@@ -314,10 +419,10 @@ class Cts(object):
for ln in [ln for ln in fl.readlines(
) if ln.strip().startswith(macro)]:
ln = ln.strip()[len(macro):]
- args.append(ln.strip('()').replace(',',''))
+ args.append(ln.strip('()').replace(',', ''))
return args
- def parseOutput(self, r1, r2):
+ def _parseOutput(self, r1, r2):
"""Parse the outputs of the DUT and TH together
Args;
@@ -331,42 +436,59 @@ class Cts(object):
tokens = ln.split()
if len(tokens) != 2:
continue
- elif tokens[0].strip() not in self.test_names:
+ print 'Tokens are: ' + str(tokens)
+ test = tokens[0].strip()
+ try:
+ return_code = int(tokens[1])
+ except ValueError: # Second token is not an int
continue
- elif tokens[0] in self.test_results.keys():
- if self.test_results[tokens[0]] != int(tokens[1]):
- if self.test_results[tokens[0]] == CTS_SUCCESS_CODE:
- self.test_results[tokens[0]] = int(tokens[1])
- elif int(tokens[1]) == CTS_SUCCESS_CODE:
- continue
- else:
- self.test_results[tokens[0]] = CTS_CONFLICTING_CODE
- else:
- continue
- else:
- self.test_results[tokens[0]] = int(tokens[1])
+ if test not in self.test_names:
+ continue
+ elif self.test_results.get(
+ test,
+ CTS_SUCCESS_CODE) == CTS_SUCCESS_CODE:
+ self.test_results[test] = return_code
+ print 'Is ' + str(return_code) + ' the same as ' + str(self.test_results[test])
+ elif return_code != self.test_results[test]:
+ print 'Setting ' + test + ' to CTS_CONFLICTING_CODE'
+ self.test_results[test] = CTS_CONFLICTING_CODE
+
+ def _resultsAsString(self):
+ """Takes saved results and returns a duplicate of their dictionary
+ with the return codes replaces with their string representation
+ Returns:
+ dictionary with test name strings as keys and test result strings
+ as values
+ """
+ result = deepcopy(self.test_results)
# Convert codes to strings
- for test, code in self.test_results.items():
+ for test, code in result.items():
if code == CTS_CONFLICTING_CODE:
- self.test_results[test] = 'RESULTS CONFLICT'
- self.test_results[test] = self.return_codes[code]
+ result[test] = 'RESULTS CONFLICT'
+ else:
+ result[test] = self.return_codes[code]
for tn in self.test_names:
- if tn not in self.test_results.keys():
- self.test_results[tn] = 'NO RESULT RETURNED' # Exceptional case
+ if tn not in result:
+ # Exceptional case
+ result[tn] = 'NO RESULT RETURNED'
- def resultsAsString(self):
+ return result
+
+ def prettyResults(self):
"""Takes saved results and returns a string representation of them
- Return: Saved string that contains results
+ Return: Dictionary similar to self.test_results, but with strings
+ instead of error codes
"""
- t_long = max(len(s) for s in self.test_results.keys())
- e_max_len = max(len(s) for s in self.test_results.values())
+ res = self._resultsAsString()
+ t_long = max(len(s) for s in res.keys())
+ e_max_len = max(len(s) for s in res.values())
pretty_results = 'CTS Test Results for ' + self.module + ' module:\n'
- for test, code in self.test_results.items():
+ for test, code in res.items():
align_str = '\n{0:<' + str(t_long) + \
'} {1:>' + str(e_max_len) + '}'
pretty_results += align_str.format(test, code)
@@ -375,42 +497,27 @@ class Cts(object):
def resetAndRecord(self):
"""Resets boards, records test results in results dir"""
+ self.updateSerials()
+ self.dut.setupForOutput()
+ self.th.setupForOutput()
+ self.dut.readAvailableBytes() # clear buffer
+ self.th.readAvailableBytes()
self.resetBoards()
- # Doesn't matter which is dut or th because we combine their results
- d1, d2 = self.getDevFilenames()
- try:
- fd1 = self.getDevFileDescriptor(d1)
- fd2 = self.getDevFileDescriptor(d2)
- except: # If board was just connected, must be reset to be read from
- for i in range(3):
- self.resetBoards()
- time.sleep(10)
- try:
- fd1 = self.getDevFileDescriptor(d1)
- fd2 = self.getDevFileDescriptor(d2)
- break
- except:
- continue
+ time.sleep(MAX_SUITE_TIME_SEC)
- self.readAvailableBytes(fd1) # clear any junk from buffer
- self.readAvailableBytes(fd2)
- self.resetBoards()
- time.sleep(3)
- res1 = self.readAvailableBytes(fd1)
- res2 = self.readAvailableBytes(fd2)
- if len(res1) == 0 or len(res2) == 0:
+ dut_results = self.dut.readAvailableBytes()
+ th_results = self.th.readAvailableBytes()
+ if not dut_results or not th_results:
raise ValueError('Output missing from boards.\n'
- 'If you are running cat on a ttyACMx file,\n'
- 'please kill that process and try again')
- self.parseOutput(res1, res2)
- pretty_results = self.resultsAsString()
-
- dest = os.path.join(
- self.results_dir,
- self.dut_board,
- self.module + '.txt')
+ 'If you are running cat on a ttyACMx file,\n'
+ 'please kill that process and try again')
+
+ self._parseOutput(dut_results, th_results)
+ pretty_results = self.prettyResults()
+
+ dest = os.path.join(self.results_dir, self.dut.board, self.module + '.txt')
if not os.path.exists(os.path.dirname(dest)):
os.makedirs(os.path.dirname(dest))
@@ -424,7 +531,6 @@ def main():
ec_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
os.chdir(ec_dir)
- cts_suite = Cts(ec_dir)
dut_board = 'nucleo-f072rb' # nucleo by default
module = 'gpio' # gpio by default
@@ -446,31 +552,27 @@ def main():
parser.add_argument('-f',
'--flash',
action='store_true',
- help='Flash boards with last image built for them')
+ help='Flash boards with most recent image and record results')
parser.add_argument('-r',
'--reset',
action='store_true',
- help='Reset boards and save test results')
+ help='Reset boards and save test results (no flashing)')
args = parser.parse_args()
if args.module:
module = args.module
- cts_suite.set_module(module)
if args.dut:
dut_board = args.dut
- cts_suite.set_dut_board(dut_board)
+
+ cts_suite = Cts(ec_dir, module=module, dut=dut_board)
if args.setup:
- serial = cts_suite.saveThSerial()
- if(serial is not None):
- print 'Your th hla_serial # has been saved as: ' + serial
- else:
- print 'Unable to save serial'
- return
+ serial = cts_suite.setup()
+ print 'Your th hla_serial # has been saved as: ' + serial
- if args.reset:
+ elif args.reset:
cts_suite.resetAndRecord()
elif args.build: