mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 11:17:20 +02:00
ci: use shared OpenOCD class for GDB test app
This commit is contained in:
@@ -47,9 +47,12 @@ tools/test_apps/system/g1_components:
|
|||||||
|
|
||||||
tools/test_apps/system/gdb:
|
tools/test_apps/system/gdb:
|
||||||
disable_test:
|
disable_test:
|
||||||
- if: IDF_TARGET in ["esp32s3", "esp32c2", "esp32c3", "esp32c5", "esp32c61", "esp32p4"]
|
- if: IDF_TARGET == "esp32p4"
|
||||||
temporary: true
|
temporary: true
|
||||||
reason: lack of runners
|
reason: lack of runners
|
||||||
|
- if: IDF_TARGET in ["esp32c5", "esp32c61"]
|
||||||
|
temporary: true
|
||||||
|
reason: not supported yet # TODO: IDF-13142
|
||||||
|
|
||||||
tools/test_apps/system/gdb_loadable_elf:
|
tools/test_apps/system/gdb_loadable_elf:
|
||||||
disable_test:
|
disable_test:
|
||||||
|
@@ -1,72 +1,19 @@
|
|||||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import typing
|
||||||
import time
|
|
||||||
from subprocess import Popen
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import pexpect
|
import pexpect
|
||||||
import pytest
|
import pytest
|
||||||
from pytest_embedded_idf import IdfDut
|
from pytest_embedded_idf import IdfDut
|
||||||
from pytest_embedded_idf.utils import idf_parametrize
|
from pytest_embedded_idf.utils import idf_parametrize
|
||||||
|
|
||||||
MAX_RETRIES = 3
|
if typing.TYPE_CHECKING:
|
||||||
RETRY_DELAY = 3 # seconds
|
from conftest import OpenOCD
|
||||||
|
|
||||||
|
|
||||||
def run_openocd(dut: IdfDut) -> Optional[Popen]:
|
def _test_idf_gdb(openocd: 'OpenOCD', dut: IdfDut) -> None:
|
||||||
desc_path = os.path.join(dut.app.binary_path, 'project_description.json')
|
|
||||||
try:
|
|
||||||
with open(desc_path, 'r') as f:
|
|
||||||
project_desc = json.load(f)
|
|
||||||
except FileNotFoundError:
|
|
||||||
logging.error('Project description file not found at %s', desc_path)
|
|
||||||
return None
|
|
||||||
|
|
||||||
openocd_scripts = os.getenv('OPENOCD_SCRIPTS')
|
|
||||||
if not openocd_scripts:
|
|
||||||
logging.error('OPENOCD_SCRIPTS environment variable is not set.')
|
|
||||||
return None
|
|
||||||
|
|
||||||
debug_args = project_desc.get('debug_arguments_openocd')
|
|
||||||
if not debug_args:
|
|
||||||
logging.error("'debug_arguments_openocd' key is missing in project_description.json")
|
|
||||||
return None
|
|
||||||
|
|
||||||
cmd = ['openocd'] + ['-s', openocd_scripts] + debug_args.split()
|
|
||||||
|
|
||||||
# For debug purpose, make the value '4'
|
|
||||||
ocd_env = os.environ.copy()
|
|
||||||
ocd_env['LIBUSB_DEBUG'] = '1'
|
|
||||||
|
|
||||||
for attempt in range(1, MAX_RETRIES + 1):
|
|
||||||
logging.info('Attempt %d: Running %s', attempt, cmd)
|
|
||||||
with open(os.path.join(dut.logdir, 'ocd.txt'), 'w') as ocd_log:
|
|
||||||
try:
|
|
||||||
ocd = subprocess.Popen(cmd, stdout=ocd_log, stderr=ocd_log, env=ocd_env)
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# Check if the process is running successfully
|
|
||||||
if ocd.poll() is None:
|
|
||||||
return ocd
|
|
||||||
else:
|
|
||||||
logging.error('OpenOCD exited with error code %d', ocd.returncode)
|
|
||||||
except subprocess.SubprocessError as e:
|
|
||||||
logging.error('Error running OpenOCD: %s', e)
|
|
||||||
|
|
||||||
logging.warning("OpenOCD couldn't be run. Retrying in %d seconds...", RETRY_DELAY)
|
|
||||||
time.sleep(RETRY_DELAY)
|
|
||||||
|
|
||||||
logging.error('Failed to run OpenOCD after %d attempts.', MAX_RETRIES)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _test_idf_gdb(dut: IdfDut) -> None:
|
|
||||||
# Need to wait a moment to connect via OpenOCD after the hard reset happened.
|
# Need to wait a moment to connect via OpenOCD after the hard reset happened.
|
||||||
# Along with this check that app runs ok
|
# Along with this check that app runs ok
|
||||||
dut.expect('Hello world!')
|
dut.expect('Hello world!')
|
||||||
@@ -74,36 +21,27 @@ def _test_idf_gdb(dut: IdfDut) -> None:
|
|||||||
# Don't need to have output from UART anymore
|
# Don't need to have output from UART anymore
|
||||||
dut.serial.stop_redirect_thread()
|
dut.serial.stop_redirect_thread()
|
||||||
|
|
||||||
ocd = run_openocd(dut)
|
with openocd.run(), open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, pexpect.spawn(
|
||||||
assert ocd
|
f'idf.py -B {dut.app.binary_path} gdb --batch',
|
||||||
|
timeout=60,
|
||||||
try:
|
logfile=gdb_log,
|
||||||
with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, pexpect.spawn(
|
encoding='utf-8',
|
||||||
f'idf.py -B {dut.app.binary_path} gdb --batch',
|
codec_errors='ignore',
|
||||||
timeout=60,
|
) as p:
|
||||||
logfile=gdb_log,
|
p.expect(re.compile(r'add symbol table from file.*bootloader.elf'))
|
||||||
encoding='utf-8',
|
p.expect(
|
||||||
codec_errors='ignore',
|
re.compile(r'add symbol table from file.*rom.elf')
|
||||||
) as p:
|
) # if fail here: add target support here https://github.com/espressif/esp-rom-elfs
|
||||||
p.expect(re.compile(r'add symbol table from file.*bootloader.elf'))
|
p.expect_exact('hit Temporary breakpoint 1, app_main ()')
|
||||||
p.expect(
|
|
||||||
re.compile(r'add symbol table from file.*rom.elf')
|
|
||||||
) # if fail here: add target support here https://github.com/espressif/esp-rom-elfs
|
|
||||||
p.expect_exact('hit Temporary breakpoint 1, app_main ()')
|
|
||||||
finally:
|
|
||||||
# Check if the process is still running
|
|
||||||
if ocd.poll() is None:
|
|
||||||
ocd.terminate()
|
|
||||||
ocd.kill()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.jtag
|
@pytest.mark.jtag
|
||||||
@idf_parametrize('target', ['esp32', 'esp32s2'], indirect=['target'])
|
@idf_parametrize('target', ['esp32', 'esp32c2', 'esp32s2'], indirect=['target'])
|
||||||
def test_idf_gdb(dut: IdfDut) -> None:
|
def test_idf_gdb(openocd: 'OpenOCD', dut: IdfDut) -> None:
|
||||||
_test_idf_gdb(dut)
|
_test_idf_gdb(openocd, dut)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usb_serial_jtag
|
@pytest.mark.usb_serial_jtag
|
||||||
@idf_parametrize('target', ['esp32c6', 'esp32h2'], indirect=['target'])
|
@idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
|
||||||
def test_idf_gdb_usj(dut: IdfDut) -> None:
|
def test_idf_gdb_usj(openocd: 'OpenOCD', dut: IdfDut) -> None:
|
||||||
_test_idf_gdb(dut)
|
_test_idf_gdb(openocd, dut)
|
||||||
|
Reference in New Issue
Block a user