#------------------------------------------------------------------------------- | |
# Copyright (c) 2020, Arm Limited. All rights reserved. | |
# | |
# SPDX-License-Identifier: BSD-3-Clause | |
# | |
#------------------------------------------------------------------------------- | |
from irq_test_abstract_debugger import Location | |
import logging | |
import json | |
def create_locations_from_file(breakpoints_file_name): | |
"""Internal function to create Location objects of a breakpoints data file | |
""" | |
# Read in the points to break at | |
logging.info("Reading breakpoints file '%s'", breakpoints_file_name) | |
breakpoints_file = open(breakpoints_file_name) | |
breakpoints = json.load(breakpoints_file) | |
logging.debug("breakpoints: %s", str(breakpoints)) | |
#TODO: go over the breakpoints and try to set them as a sanity check | |
locations = {} | |
for loc_name in breakpoints['breakpoints']: | |
bkpt = breakpoints['breakpoints'][loc_name] | |
offset = 0 | |
if 'file' in bkpt: | |
filename = bkpt['file'] | |
else: | |
filename = None | |
if 'symbol' in bkpt: | |
symbol = bkpt['symbol'] | |
if 'offset' in bkpt: | |
offset = bkpt['offset'] | |
else: | |
offset = 0 | |
else: | |
if 'offset' in bkpt: | |
logging.error("In location %s offset is included without a" | |
" symbol") | |
exit(2) | |
symbol = None | |
if 'line' in bkpt: | |
line = bkpt['line'] | |
try: | |
int(line) | |
except ValueError: | |
logging.error("In location %s line is not a valid int", | |
loc_name) | |
exit(2) | |
else: | |
line = None | |
if symbol: | |
if line or filename: | |
logging.error("In location %s nor filename nor line should" | |
"be present when symbol is present", loc_name) | |
exit(2) | |
if (not line and filename) or (line and not filename): | |
logging.error("In location %s line and filename have to be " | |
"present the same time", loc_name) | |
exit(2) | |
if (not symbol) and (not filename): | |
logging.error("In location %s no symbol nor code location is " | |
"specified at all", loc_name) | |
exit(2) | |
loc = Location(symbol=symbol, offset=offset, filename=filename, line=line) | |
locations[loc_name] = loc | |
return locations | |
class TestExecutor(object): | |
""" This class implements the test logic. | |
It reads the input files, and executes the steps of the testcase. It receives an | |
AbstractDebugger instance on creation. The test execution is implemented in the | |
execute function. | |
""" | |
def __init__(self, debugger): | |
self.debugger = debugger | |
def execute(self, irqs_filename, breakpoints_filename, testcase_filename): | |
""" Execute a testcase | |
Execute the testcase defined in 'testcase_filename', using the IRQs and | |
breakpoints defined in irqs_filename and breakpoints_filename. | |
""" | |
# Read in the list of IRQs | |
logging.info("Reading irqs file '%s'", irqs_filename) | |
irqs_file = open(irqs_filename) | |
irqs = json.load(irqs_file) | |
logging.debug("irqs: %s", str(irqs)) | |
# read in the test sequence | |
logging.info("Reading test sequence file '%s'", testcase_filename) | |
test_file = open(testcase_filename) | |
test = json.load(test_file) | |
logging.debug("testcase: %s", str(test)) | |
# TODO: crosscheck the tests file against the breakpoints and the irq's | |
# available | |
locations = create_locations_from_file(breakpoints_filename) | |
self.debugger.clear_breakpoints() | |
# execute the test | |
steps = test['steps'] | |
for i, step in enumerate(steps): | |
logging.info("---- Step %d ----", i) | |
continue_execution = False | |
if 'wait_for' in step: | |
bp_name = step['wait_for'] | |
self.debugger.set_breakpoint(bp_name, locations[bp_name]) | |
next_to_break_at = bp_name | |
continue_execution = True | |
elif 'expect' in step: | |
bp_name = step['expect'] | |
self.debugger.set_breakpoint(bp_name, locations[bp_name]) | |
next_to_break_at = bp_name | |
# Find the next wait_for in the test sequence, and set a | |
# breakpoint for that as well. So that it can be detected if an | |
# expected breakpoint is missed. | |
wait_for_found = False | |
ii = i+1 | |
while ii < len(steps) and not wait_for_found: | |
next_step = steps[ii] | |
if 'wait_for' in next_step: | |
next_bp_name = next_step['wait_for'] | |
self.debugger.set_breakpoint(next_bp_name, | |
locations[next_bp_name]) | |
wait_for_found = True | |
ii += 1 | |
continue_execution = True | |
if 'trigger' in step: | |
irqs_dict = irqs['irqs'] | |
irq = irqs_dict[step['trigger']] | |
line_nu = irq['line_num'] | |
self.debugger.trigger_interrupt(line_nu) | |
if continue_execution: | |
self.debugger.continue_execution() | |
triggered_breakpoint = self.debugger.get_triggered_breakpoint() | |
if triggered_breakpoint is None: | |
logging.error("No breakpoint was hit?????") | |
exit(0) | |
if triggered_breakpoint != next_to_break_at: | |
logging.error("execution stopped at '%s' instead of '%s'", | |
triggered_breakpoint, next_to_break_at) | |
exit(0) | |
else: | |
logging.error("execution stopped as no breakpoint is set") | |
exit(1) | |
self.debugger.clear_breakpoints() | |
logging.info("All the steps in the test file are executed successfully" | |
" with the expected result.") |