Skip to content

Commit

Permalink
tests: gdbstub: Improve test case
Browse files Browse the repository at this point in the history
Gdbstub test improvements: pytest fixtures, parametrization and
expected pattern matching on outputs from GDB and the test application.

Signed-off-by: Dmitrii Golovanov <dmitrii.golovanov@intel.com>
  • Loading branch information
golowanow committed Oct 8, 2023
1 parent 05d1cfd commit 5151a8c
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 43 deletions.
1 change: 1 addition & 0 deletions tests/subsys/debug/gdbstub/prj.conf
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions tests/subsys/debug/gdbstub/pytest/conftest.py
Original file line number Diff line number Diff line change
@@ -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))
#
66 changes: 51 additions & 15 deletions tests/subsys/debug/gdbstub/pytest/test_gdbstub.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,67 @@

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"))
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'
#
17 changes: 0 additions & 17 deletions tests/subsys/debug/gdbstub/run.gdbinit

This file was deleted.

11 changes: 2 additions & 9 deletions tests/subsys/debug/gdbstub/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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("main():enter\n");

Check warning on line 27 in tests/subsys/debug/gdbstub/src/main.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

EMBEDDED_FUNCTION_NAME

tests/subsys/debug/gdbstub/src/main.c:27 Prefer using '"%s...", __func__' to using 'main', this function's name, in a string
ret = test();
printk("%d\n", ret);
printk("test():ret=%d\n", ret);
return 0;
}

K_THREAD_DEFINE(thread, STACKSIZE, thread_entry, NULL, NULL, NULL,
7, K_USER, 0);
23 changes: 23 additions & 0 deletions tests/subsys/debug/gdbstub/test_breakpoints.gdbinit
Original file line number Diff line number Diff line change
@@ -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
9 changes: 7 additions & 2 deletions tests/subsys/debug/gdbstub/testcase.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#
# 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
- pytest

0 comments on commit 5151a8c

Please sign in to comment.