tests: gdbstub: Improve test case
Gdbstub test improvements: using pytest fixtures, parametrization, and expected pattern matching on outputs from GDB and the test application. Signed-off-by: Dmitrii Golovanov <dmitrii.golovanov@intel.com>
This commit is contained in:
parent
c9e651b12c
commit
cbbb1cabd6
|
@ -1,4 +1,5 @@
|
|||
CONFIG_GDBSTUB=y
|
||||
CONFIG_GDBSTUB_SERIAL_BACKEND=y
|
||||
CONFIG_NO_OPTIMIZATIONS=y
|
||||
CONFIG_USERSPACE=y
|
||||
CONFIG_KOBJECT_TEXT_AREA=4096
|
||||
|
|
20
tests/subsys/debug/gdbstub/pytest/conftest.py
Normal file
20
tests/subsys/debug/gdbstub/pytest/conftest.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# Copyright (c) 2023 intel Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
import pytest
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption('--gdb_timeout')
|
||||
parser.addoption('--gdb_script')
|
||||
|
||||
@pytest.fixture()
|
||||
def gdb_script(request):
|
||||
return request.config.getoption('--gdb_script')
|
||||
|
||||
@pytest.fixture()
|
||||
def gdb_timeout(request):
|
||||
return int(request.config.getoption('--gdb_timeout', default=60))
|
||||
#
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
import os
|
||||
import subprocess
|
||||
from twister_harness import DeviceAdapter
|
||||
import sys
|
||||
import logging
|
||||
import shlex
|
||||
import re
|
||||
import pytest
|
||||
from twister_harness import DeviceAdapter
|
||||
|
||||
ZEPHYR_BASE = os.getenv("ZEPHYR_BASE")
|
||||
sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts", "pylib", "twister"))
|
||||
|
@ -15,20 +17,54 @@ from twisterlib.cmakecache import CMakeCache
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_gdbstub(dut: DeviceAdapter):
|
||||
"""
|
||||
Test gdbstub feature using a gdb script. We connect to the DUT and run some
|
||||
basic gdb commands and evaluate return code to determine pass or failure.
|
||||
"""
|
||||
@pytest.fixture()
|
||||
def gdb_process(dut: DeviceAdapter, gdb_script, gdb_timeout):
|
||||
build_dir = dut.device_config.build_dir
|
||||
cmake_cache = CMakeCache.from_file(build_dir / 'CMakeCache.txt')
|
||||
gdb = cmake_cache.get('CMAKE_GDB', None)
|
||||
assert gdb
|
||||
cmake_cache = CMakeCache.from_file(os.path.join(build_dir, 'CMakeCache.txt'))
|
||||
gdb_exec = cmake_cache.get('CMAKE_GDB', None)
|
||||
assert gdb_exec
|
||||
source_dir = cmake_cache.get('APPLICATION_SOURCE_DIR', None)
|
||||
assert source_dir
|
||||
cmd = [gdb, '-x', f'{source_dir}/run.gdbinit', f'{build_dir}/zephyr/zephyr.elf']
|
||||
logger.info(f'Test command: {shlex.join(cmd)}')
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=20)
|
||||
logger.debug('Output:\n%s' % result.stdout)
|
||||
assert result.returncode == 0
|
||||
build_image = cmake_cache.get('BYPRODUCT_KERNEL_ELF_NAME', None)
|
||||
assert build_image
|
||||
gdb_log_file = os.path.join(build_dir, 'gdb.log')
|
||||
cmd = [gdb_exec, '-batch', '-ex', f'set logging file {gdb_log_file}',
|
||||
'-x', f'{source_dir}/{gdb_script}', build_image]
|
||||
logger.info(f'Run GDB: {shlex.join(cmd)}')
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=gdb_timeout)
|
||||
logger.info(f'GDB ends rc={result.returncode}')
|
||||
return result
|
||||
#
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def expected_app():
|
||||
return [
|
||||
re.compile(r"Booting from ROM"),
|
||||
re.compile(r"Booting Zephyr OS build"),
|
||||
re.compile(r"main\(\):enter"),
|
||||
]
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def expected_gdb():
|
||||
return [
|
||||
re.compile(r'Breakpoint 1 at 0x'),
|
||||
re.compile(r'Breakpoint 2 at 0x'),
|
||||
re.compile(r'Breakpoint 1, test '),
|
||||
re.compile(r'Breakpoint 2, main '),
|
||||
re.compile(r'GDB:PASSED'),
|
||||
]
|
||||
|
||||
def test_gdbstub(dut: DeviceAdapter, gdb_process, expected_app, expected_gdb):
|
||||
"""
|
||||
Test gdbstub feature using a GDB script. We connect to the DUT, run the
|
||||
GDB script then evaluate return code and expected patterns at the GDB
|
||||
and Test Applicaiton outputs.
|
||||
"""
|
||||
logger.debug(f"GDB output:\n{gdb_process.stdout}\n")
|
||||
assert gdb_process.returncode == 0
|
||||
assert all([ex_re.search(gdb_process.stdout, re.MULTILINE) for ex_re in expected_gdb]), 'No expected GDB output'
|
||||
assert 'Inferior 1 [Remote target] will be killed' in gdb_process.stdout,'Expecting explicit quit from the GDB script and kill QEMU test app.'
|
||||
app_output = '\n'.join(dut.readlines(print_output = False))
|
||||
logger.debug(f"App output:\n{app_output}\n")
|
||||
assert all([ex_re.search(app_output, re.MULTILINE) for ex_re in expected_app]), 'No expected Application output'
|
||||
#
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
set pagination off
|
||||
#symbol-file build/zephyr/zephyr.elf
|
||||
target remote :5678
|
||||
b test
|
||||
b main.c:33
|
||||
c
|
||||
|
||||
s
|
||||
set var a = 2
|
||||
c
|
||||
if ret == 6
|
||||
printf "PASSED\n"
|
||||
quit 0
|
||||
else
|
||||
printf "FAILED\n"
|
||||
quit 1
|
||||
end
|
|
@ -20,19 +20,12 @@ static int test(void)
|
|||
return a + b;
|
||||
}
|
||||
|
||||
static void thread_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
printk("Hello from user thread!\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
printk("%s():enter\n", __func__);
|
||||
ret = test();
|
||||
printk("%d\n", ret);
|
||||
printk("ret=%d\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
K_THREAD_DEFINE(thread, STACKSIZE, thread_entry, NULL, NULL, NULL,
|
||||
7, K_USER, 0);
|
||||
|
|
23
tests/subsys/debug/gdbstub/test_breakpoints.gdbinit
Normal file
23
tests/subsys/debug/gdbstub/test_breakpoints.gdbinit
Normal file
|
@ -0,0 +1,23 @@
|
|||
set pagination off
|
||||
set trace-commands on
|
||||
set logging enabled on
|
||||
|
||||
target remote :5678
|
||||
|
||||
b test
|
||||
b main.c:29
|
||||
c
|
||||
|
||||
# break at test()
|
||||
s
|
||||
set var a = 2
|
||||
c
|
||||
|
||||
# break at main()
|
||||
if ret == 6
|
||||
printf "GDB:PASSED\n"
|
||||
quit 0
|
||||
else
|
||||
printf "GDB:FAILED\n"
|
||||
quit 1
|
||||
end
|
|
@ -1,13 +1,17 @@
|
|||
#
|
||||
# Copyright (c) 2020 intel Corporation.
|
||||
# Copyright (c) 2020, 2023 intel Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
tests:
|
||||
debug.gdbstub.sample:
|
||||
debug.gdbstub.breakpoints:
|
||||
platform_allow: qemu_x86
|
||||
harness: pytest
|
||||
harness_config:
|
||||
pytest_root:
|
||||
- "pytest/test_gdbstub.py"
|
||||
pytest_args: ["--gdb_timeout", "20", "--gdb_script", "test_breakpoints.gdbinit"]
|
||||
tags:
|
||||
- debug
|
||||
- gdbstub
|
||||
|
|
Loading…
Reference in a new issue