mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
ci: move more openocd scripts into pytest-embedded
This commit is contained in:
parent
09a32437b3
commit
dc3c630919
@ -77,6 +77,17 @@ example_test_pytest_esp32_twai_network:
|
||||
- build_pytest_examples_esp32
|
||||
tags: [ esp32, twai_network ]
|
||||
|
||||
example_test_pytest_esp32_jtag:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
- .rules:test:example_test-esp32
|
||||
needs:
|
||||
- build_pytest_examples_esp32
|
||||
tags: [ esp32, jtag ]
|
||||
variables:
|
||||
SETUP_TOOLS: "1" # need gdb openocd
|
||||
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
|
||||
|
||||
example_test_pytest_esp32s2_generic:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
@ -670,7 +681,7 @@ test_app_test_pytest_esp32_jtag:
|
||||
- .rules:test:custom_test-esp32
|
||||
needs:
|
||||
- build_pytest_test_apps_esp32
|
||||
tags: [ esp32, test_jtag_arm]
|
||||
tags: [ esp32, jtag]
|
||||
variables:
|
||||
SETUP_TOOLS: "1" # need gdb
|
||||
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
|
||||
@ -902,15 +913,6 @@ example_test_007:
|
||||
- ESP32
|
||||
- Example_I2C_CCS811_SENSOR
|
||||
|
||||
example_test_009:
|
||||
extends: .example_test_esp32_template
|
||||
tags:
|
||||
- ESP32
|
||||
- test_jtag_arm
|
||||
variables:
|
||||
SETUP_TOOLS: "1"
|
||||
PYTHON_VER: 3
|
||||
|
||||
example_test_011:
|
||||
extends: .example_test_esp32_template
|
||||
tags:
|
||||
@ -986,14 +988,6 @@ example_test_C6_GENERIC:
|
||||
- .test_app_template
|
||||
- .rules:test:custom_test-esp32s3
|
||||
|
||||
test_app_test_001:
|
||||
extends: .test_app_esp32_template
|
||||
tags:
|
||||
- ESP32
|
||||
- test_jtag_arm
|
||||
variables:
|
||||
SETUP_TOOLS: "1"
|
||||
|
||||
test_app_test_eth:
|
||||
extends: .test_app_esp32_template
|
||||
tags:
|
||||
|
@ -109,7 +109,7 @@ ENV_MARKERS = {
|
||||
'MSPI_F8R8': 'runner with Octal Flash and Octal PSRAM',
|
||||
'MSPI_F4R8': 'runner with Quad Flash and Octal PSRAM',
|
||||
'MSPI_F4R4': 'runner with Quad Flash and Quad PSRAM',
|
||||
'test_jtag_arm': 'runner where the chip is accessible through JTAG as well',
|
||||
'jtag': 'runner where the chip is accessible through JTAG as well',
|
||||
'adc': 'ADC related tests should run on adc runners',
|
||||
'xtal32k': 'Runner with external 32k crystal connected',
|
||||
'no32kXtal': 'Runner with no external 32k crystal connected',
|
||||
@ -203,6 +203,11 @@ def get_target_marker_from_expr(markexpr: str) -> str:
|
||||
############
|
||||
# Fixtures #
|
||||
############
|
||||
@pytest.fixture(scope='session')
|
||||
def idf_path() -> str:
|
||||
return os.path.dirname(__file__)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', autouse=True)
|
||||
def session_tempdir() -> str:
|
||||
_tmpdir = os.path.join(
|
||||
|
65
examples/storage/semihost_vfs/pytest_semihost_vfs.py
Normal file
65
examples/storage/semihost_vfs/pytest_semihost_vfs.py
Normal file
@ -0,0 +1,65 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import typing as t
|
||||
from itertools import zip_longest
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
|
||||
TEMP_DIR = tempfile.mkdtemp()
|
||||
HOST_FILE_NAME = 'host_file.txt'
|
||||
HOST_FILE_PATH = os.path.join(os.path.dirname(__file__), 'data', HOST_FILE_NAME)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def prepare() -> t.Generator[None, None, None]:
|
||||
shutil.copyfile(HOST_FILE_PATH, os.path.join(TEMP_DIR, HOST_FILE_NAME))
|
||||
|
||||
yield
|
||||
|
||||
shutil.rmtree(TEMP_DIR, ignore_errors=True)
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.jtag
|
||||
@pytest.mark.parametrize(
|
||||
'embedded_services, no_gdb, openocd_cli_args',
|
||||
[
|
||||
pytest.param(
|
||||
'esp,idf,jtag',
|
||||
'y',
|
||||
f'-c \'set ESP_SEMIHOST_BASEDIR "{TEMP_DIR}"\' -f board/esp32-wrover-kit-3.3v.cfg',
|
||||
marks=[pytest.mark.esp32],
|
||||
),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_semihost_vfs(dut: IdfDut) -> None:
|
||||
dut.expect_exact('example: Switch to semihosted stdout')
|
||||
dut.expect_exact('example: Switched back to UART stdout')
|
||||
dut.expect_exact('example: Wrote 2798 bytes')
|
||||
dut.expect_exact('====================== HOST DATA START =========================')
|
||||
|
||||
with open(HOST_FILE_PATH) as f:
|
||||
for line in f:
|
||||
if line.strip():
|
||||
dut.expect_exact(line.strip())
|
||||
|
||||
dut.expect_exact('====================== HOST DATA END =========================')
|
||||
dut.expect_exact('example: Read 6121 bytes')
|
||||
|
||||
with open(os.path.join(TEMP_DIR, 'esp32_stdout.txt')) as f:
|
||||
|
||||
def expected_content() -> t.Iterator[str]:
|
||||
yield 'example: Switched to semihosted stdout'
|
||||
for i in range(100):
|
||||
yield 'Semihosted stdout write {}'.format(i)
|
||||
yield 'example: Switch to UART stdout'
|
||||
|
||||
for actual, expected in zip_longest(f, expected_content(), fillvalue='-'):
|
||||
if expected not in actual: # "in" used because of the printed ASCII color codes
|
||||
raise RuntimeError('"{}" != "{}"'.format(expected, actual.strip()))
|
@ -1,59 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from io import open
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
try:
|
||||
from itertools import izip_longest as zip_longest
|
||||
except ImportError:
|
||||
# Python 3
|
||||
from itertools import zip_longest
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='test_jtag_arm')
|
||||
def test_examples_semihost_vfs(env, extra_data):
|
||||
|
||||
rel_project_path = os.path.join('examples', 'storage', 'semihost_vfs')
|
||||
dut = env.get_dut('semihost_vfs', rel_project_path)
|
||||
idf_path = dut.app.get_sdk_path()
|
||||
proj_path = os.path.join(idf_path, rel_project_path)
|
||||
host_file_name = 'host_file.txt'
|
||||
|
||||
try:
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
host_file_path = os.path.join(proj_path, 'data', host_file_name)
|
||||
shutil.copyfile(host_file_path, os.path.join(temp_dir, host_file_name))
|
||||
cfg_cmds = ['set ESP_SEMIHOST_BASEDIR "{}"'.format(temp_dir)]
|
||||
|
||||
with ttfw_idf.OCDBackend(os.path.join(proj_path, 'openocd.log'), dut.app.target, cfg_cmds=cfg_cmds):
|
||||
dut.start_app()
|
||||
dut.expect_all('example: Switch to semihosted stdout',
|
||||
'example: Switched back to UART stdout',
|
||||
'example: Wrote 2798 bytes',
|
||||
'====================== HOST DATA START =========================',
|
||||
timeout=20)
|
||||
with open(host_file_path) as f:
|
||||
file_content = [line.strip() for line in f]
|
||||
dut.expect_all(*file_content, timeout=20)
|
||||
dut.expect_all('====================== HOST DATA END =========================',
|
||||
'example: Read 6121 bytes',
|
||||
timeout=5)
|
||||
|
||||
with open(os.path.join(temp_dir, 'esp32_stdout.txt')) as f:
|
||||
def expected_content():
|
||||
yield 'example: Switched to semihosted stdout'
|
||||
for i in range(100):
|
||||
yield 'Semihosted stdout write {}'.format(i)
|
||||
yield 'example: Switch to UART stdout'
|
||||
|
||||
for actual, expected in zip_longest(f, expected_content(), fillvalue='-'):
|
||||
if expected not in actual: # "in" used because of the printed ASCII color codes
|
||||
raise RuntimeError('"{}" != "{}"'.format(expected, actual.strip()))
|
||||
finally:
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_semihost_vfs()
|
@ -1,53 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='test_jtag_arm')
|
||||
def test_examples_app_trace_to_host(env, extra_data):
|
||||
rel_project_path = os.path.join('examples', 'system', 'app_trace_to_host')
|
||||
dut = env.get_dut('app_trace_to_host', rel_project_path)
|
||||
idf_path = dut.app.get_sdk_path()
|
||||
proj_path = os.path.join(idf_path, rel_project_path)
|
||||
oocd_log_path = os.path.join(proj_path, 'openocd.log')
|
||||
|
||||
with ttfw_idf.OCDBackend(oocd_log_path, dut.app.target) as ocd:
|
||||
dut.start_app()
|
||||
dut.expect_all('example: Enabling ADC1 on channel 6 / GPIO34.',
|
||||
'example: Enabling CW generator on DAC channel 0 / GPIO25',
|
||||
'example: Sampling ADC and sending data to the host...',
|
||||
re.compile(r'example: Collected \d+ samples in 20 ms.'),
|
||||
'example: Sampling ADC and sending data to the UART...',
|
||||
re.compile(r'example: Sample:\d, Value:\d+'),
|
||||
re.compile(r'example: Collected \d+ samples in 20 ms.'),
|
||||
timeout=20)
|
||||
|
||||
ocd.apptrace_start('file://adc.log 0 9000 5 0 0')
|
||||
ocd.apptrace_wait_stop(tmo=30)
|
||||
|
||||
with open(oocd_log_path) as oocd_log:
|
||||
cores = 1 if dut.app.get_sdkconfig().get('CONFIG_FREERTOS_UNICORE', '').replace('"','') == 'y' else 2
|
||||
params_str = 'App trace params: from {} cores'.format(cores)
|
||||
for line in oocd_log:
|
||||
if params_str in line:
|
||||
break
|
||||
else:
|
||||
raise RuntimeError('"{}" could not be found in {}'.format(params_str, oocd_log_path))
|
||||
|
||||
with ttfw_idf.CustomProcess(' '.join([os.path.join(idf_path, 'tools/esp_app_trace/logtrace_proc.py'),
|
||||
'adc.log',
|
||||
os.path.join(dut.app.binary_path, 'app_trace_to_host.elf')]),
|
||||
logfile='logtrace_proc.log') as logtrace:
|
||||
logtrace.pexpect_proc.expect_exact('Parse trace file')
|
||||
logtrace.pexpect_proc.expect_exact('Parsing completed.')
|
||||
logtrace.pexpect_proc.expect_exact('====================================================================')
|
||||
logtrace.pexpect_proc.expect(re.compile(r'example: Sample:\d+, Value:\d+'))
|
||||
logtrace.pexpect_proc.expect_exact('====================================================================')
|
||||
logtrace.pexpect_proc.expect(re.compile(r'Log records count: \d+'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_app_trace_to_host()
|
@ -0,0 +1,75 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from pytest_embedded.log import DuplicateStdoutPopen, MessageQueue
|
||||
from pytest_embedded_idf import IdfDut
|
||||
from pytest_embedded_jtag import OpenOcd
|
||||
|
||||
|
||||
def apptrace_wait_stop(openocd: OpenOcd, timeout: int = 30) -> None:
|
||||
stopped = False
|
||||
end_before = time.time() + timeout
|
||||
while not stopped:
|
||||
cmd_out = openocd.write('esp apptrace status')
|
||||
for line in cmd_out.splitlines():
|
||||
if line.startswith('Tracing is STOPPED.'):
|
||||
stopped = True
|
||||
break
|
||||
if not stopped and time.time() > end_before:
|
||||
raise pexpect.TIMEOUT('Failed to wait for apptrace stop!')
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.jtag
|
||||
@pytest.mark.parametrize(
|
||||
'embedded_services, no_gdb',
|
||||
[
|
||||
('esp,idf,jtag', 'y'),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_examples_app_trace_to_host(msg_queue: MessageQueue, dut: IdfDut, openocd: OpenOcd, idf_path: str) -> None:
|
||||
dut.expect_exact('example: Enabling ADC1 on channel 6 / GPIO34.')
|
||||
dut.expect_exact('example: Enabling CW generator on DAC channel 0 / GPIO25')
|
||||
dut.expect_exact('example: Sampling ADC and sending data to the host...')
|
||||
dut.expect(r'example: Collected \d+ samples in 20 ms.')
|
||||
dut.expect_exact('example: Sampling ADC and sending data to the UART...')
|
||||
dut.expect(r'example: Sample:\d, Value:\d+')
|
||||
dut.expect(r'example: Collected \d+ samples in 20 ms.')
|
||||
|
||||
assert 'Targets connected.' in dut.openocd.write('esp apptrace start file://adc.log 0 9000 5 0 0')
|
||||
apptrace_wait_stop(dut.openocd)
|
||||
|
||||
with open(openocd._logfile) as oocd_log: # pylint: disable=protected-access
|
||||
cores = 1 if dut.app.sdkconfig.get('CONFIG_FREERTOS_UNICORE') == 'y' else 2
|
||||
params_str = 'App trace params: from {} cores'.format(cores)
|
||||
for line in oocd_log:
|
||||
if params_str in line:
|
||||
break
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'"{}" could not be found in {}'.format(params_str, openocd._logfile) # pylint: disable=protected-access
|
||||
)
|
||||
|
||||
DuplicateStdoutPopen(
|
||||
msg_queue,
|
||||
[
|
||||
os.path.join(idf_path, 'tools', 'esp_app_trace', 'logtrace_proc.py'),
|
||||
'adc.log',
|
||||
os.path.join(dut.app.elf_file),
|
||||
],
|
||||
)
|
||||
|
||||
dut.expect_exact('Parse trace file')
|
||||
dut.expect_exact('Parsing completed.')
|
||||
dut.expect_exact('====================================================================')
|
||||
dut.expect(re.compile(rb'example: Sample:\d+, Value:\d+'))
|
||||
dut.expect_exact('====================================================================')
|
||||
dut.expect(re.compile(rb'Log records count: \d+'))
|
@ -1,66 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
import ttfw_idf
|
||||
from ttfw_idf import Utility
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='test_jtag_arm')
|
||||
def test_examples_gcov(env, extra_data):
|
||||
|
||||
rel_project_path = os.path.join('examples', 'system', 'gcov')
|
||||
dut = env.get_dut('gcov', rel_project_path)
|
||||
idf_path = dut.app.get_sdk_path()
|
||||
proj_path = os.path.join(idf_path, rel_project_path)
|
||||
openocd_cmd_log = os.path.join(proj_path, 'openocd_cmd.log')
|
||||
|
||||
with ttfw_idf.OCDBackend(os.path.join(proj_path, 'openocd.log'), dut.app.target) as oocd:
|
||||
dut.start_app()
|
||||
|
||||
def expect_counter_output(loop, timeout=10):
|
||||
dut.expect_all('blink_dummy_func: Counter = {}'.format(loop),
|
||||
'some_dummy_func: Counter = {}'.format(loop * 2),
|
||||
timeout=timeout)
|
||||
|
||||
expect_counter_output(0, timeout=20)
|
||||
dut.expect('Ready to dump GCOV data...', timeout=5)
|
||||
|
||||
def dump_coverage(cmd):
|
||||
try:
|
||||
response = oocd.cmd_exec(cmd)
|
||||
with open(openocd_cmd_log, 'a') as f:
|
||||
f.write(response)
|
||||
|
||||
assert all(x in response for x in ['Targets connected.',
|
||||
'gcov_example_main.c.gcda',
|
||||
'gcov_example_func.c.gcda',
|
||||
'some_funcs.c.gcda',
|
||||
'Targets disconnected.',
|
||||
])
|
||||
|
||||
except AssertionError:
|
||||
# Print what is happening with DUT. Limit the size if it is in loop and generating output.
|
||||
Utility.console_log(dut.read(size=1000))
|
||||
raise
|
||||
|
||||
# Test two hard-coded dumps
|
||||
dump_coverage('esp gcov dump')
|
||||
dut.expect('GCOV data have been dumped.', timeout=5)
|
||||
expect_counter_output(1)
|
||||
dut.expect('Ready to dump GCOV data...', timeout=5)
|
||||
dump_coverage('esp gcov dump')
|
||||
dut.expect('GCOV data have been dumped.', timeout=5)
|
||||
|
||||
for i in range(2, 6):
|
||||
expect_counter_output(i)
|
||||
|
||||
for _ in range(3):
|
||||
time.sleep(1)
|
||||
# Test instant run-time dump
|
||||
dump_coverage('esp gcov')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_gcov()
|
72
examples/system/gcov/pytest_gcov.py
Normal file
72
examples/system/gcov/pytest_gcov.py
Normal file
@ -0,0 +1,72 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
from pytest_embedded_jtag import OpenOcd
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.jtag
|
||||
@pytest.mark.parametrize(
|
||||
'embedded_services, no_gdb',
|
||||
[
|
||||
('esp,idf,jtag', 'y'),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_gcov(dut: IdfDut, openocd: OpenOcd) -> None:
|
||||
# create the generated .gcda folder, otherwise would have error: failed to open file.
|
||||
# normally this folder would be created via `idf.py build`. but in CI the non-related files would not be preserved
|
||||
os.makedirs(os.path.join(dut.app.binary_path, 'esp-idf', 'main', 'CMakeFiles', '__idf_main.dir'), exist_ok=True)
|
||||
os.makedirs(os.path.join(dut.app.binary_path, 'esp-idf', 'sample', 'CMakeFiles', '__idf_sample.dir'), exist_ok=True)
|
||||
|
||||
def expect_counter_output(loop: int, timeout: int = 10) -> None:
|
||||
dut.expect_exact(
|
||||
[f'blink_dummy_func: Counter = {loop}', f'some_dummy_func: Counter = {loop * 2}'],
|
||||
expect_all=True,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
expect_counter_output(0)
|
||||
dut.expect('Ready to dump GCOV data...', timeout=5)
|
||||
|
||||
def dump_coverage(cmd: str) -> None:
|
||||
response = openocd.write(cmd)
|
||||
|
||||
expect_lines = [
|
||||
'Targets connected.',
|
||||
'gcov_example_main.c.gcda',
|
||||
'gcov_example_func.c.gcda',
|
||||
'some_funcs.c.gcda',
|
||||
'Targets disconnected.',
|
||||
]
|
||||
|
||||
for line in response.splitlines():
|
||||
for expect in expect_lines[:]:
|
||||
if expect in line:
|
||||
if expect.endswith('.gcda'): # check file exists
|
||||
file_path = line.split()[-1].strip("'")
|
||||
assert os.path.isfile(file_path)
|
||||
|
||||
expect_lines.remove(expect)
|
||||
|
||||
assert len(expect_lines) == 0
|
||||
|
||||
# Test two hard-coded dumps
|
||||
dump_coverage('esp gcov dump')
|
||||
dut.expect('GCOV data have been dumped.', timeout=5)
|
||||
expect_counter_output(1)
|
||||
dut.expect('Ready to dump GCOV data...', timeout=5)
|
||||
dump_coverage('esp gcov dump')
|
||||
dut.expect('GCOV data have been dumped.', timeout=5)
|
||||
|
||||
for i in range(2, 6):
|
||||
expect_counter_output(i)
|
||||
|
||||
for _ in range(3):
|
||||
time.sleep(1)
|
||||
# Test instant run-time dump
|
||||
dump_coverage('esp gcov')
|
@ -1,66 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import time
|
||||
from io import open
|
||||
|
||||
import debug_backend
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='test_jtag_arm')
|
||||
def test_examples_sysview_tracing(env, extra_data):
|
||||
|
||||
rel_project_path = os.path.join('examples', 'system', 'sysview_tracing')
|
||||
dut = env.get_dut('sysview_tracing', rel_project_path)
|
||||
proj_path = os.path.join(dut.app.idf_path, rel_project_path)
|
||||
elf_path = os.path.join(dut.app.binary_path, 'sysview_tracing.elf')
|
||||
|
||||
def get_temp_file():
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
return f.name
|
||||
|
||||
try:
|
||||
tempfiles = [get_temp_file(), get_temp_file()]
|
||||
|
||||
with open(os.path.join(proj_path, 'gdbinit')) as f_in, open(tempfiles[0], 'w') as f_out:
|
||||
new_content = f_in.read()
|
||||
# localhost connection issue occurs in docker unless:
|
||||
new_content = new_content.replace(':3333', '127.0.0.1:3333', 1)
|
||||
new_content = new_content.replace('file:///tmp/sysview_example.svdat', 'file://{}'.format(tempfiles[1]), 1)
|
||||
f_out.write(new_content)
|
||||
|
||||
with ttfw_idf.OCDBackend(os.path.join(proj_path, 'openocd.log'), dut.app.target) as oocd:
|
||||
dut.start_app()
|
||||
|
||||
def dut_expect_task_event():
|
||||
dut.expect(re.compile(r'example: Task\[0x3[0-9A-Fa-f]+\]: received event \d+'), timeout=30)
|
||||
|
||||
dut_expect_task_event()
|
||||
|
||||
gdb_log = os.path.join(proj_path, 'gdb.log')
|
||||
gdb_workdir = os.path.join(proj_path, 'main')
|
||||
with ttfw_idf.GDBBackend(gdb_log, elf_path, dut.app.target, tempfiles[0], gdb_workdir) as p:
|
||||
p.gdb.wait_target_state(debug_backend.TARGET_STATE_RUNNING)
|
||||
stop_reason = p.gdb.wait_target_state(debug_backend.TARGET_STATE_STOPPED)
|
||||
assert stop_reason == debug_backend.TARGET_STOP_REASON_BP, 'STOP reason: {}'.format(stop_reason)
|
||||
|
||||
dut.expect('example: Created task') # dut has been restarted by gdb since the last dut.expect()
|
||||
dut_expect_task_event()
|
||||
|
||||
# Do a sleep while sysview samples are captured.
|
||||
time.sleep(3)
|
||||
# GDBMI isn't responding now to any commands, therefore, the following command is issued to openocd
|
||||
oocd.cmd_exec('esp sysview stop')
|
||||
finally:
|
||||
for x in tempfiles:
|
||||
try:
|
||||
os.unlink(x)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_sysview_tracing()
|
47
examples/system/sysview_tracing/pytest_sysview_tracing.py
Normal file
47
examples/system/sysview_tracing/pytest_sysview_tracing.py
Normal file
@ -0,0 +1,47 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import re
|
||||
import time
|
||||
|
||||
import pexpect.fdpexpect
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.jtag
|
||||
@pytest.mark.parametrize(
|
||||
'embedded_services',
|
||||
[
|
||||
'esp,idf,jtag',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_examples_sysview_tracing(dut: IdfDut) -> None:
|
||||
def dut_expect_task_event() -> None:
|
||||
dut.expect(re.compile(rb'example: Task\[0x3[0-9A-Fa-f]+\]: received event \d+'), timeout=30)
|
||||
|
||||
dut.gdb.write('mon reset halt')
|
||||
dut.gdb.write('flushregs')
|
||||
dut.gdb.write('b app_main')
|
||||
|
||||
dut.gdb.write('commands', non_blocking=True)
|
||||
dut.gdb.write(
|
||||
'mon esp sysview start file:///tmp/sysview_example0.svdat file:///tmp/sysview_example1.svdat', non_blocking=True
|
||||
)
|
||||
dut.gdb.write('c', non_blocking=True)
|
||||
dut.gdb.write('end')
|
||||
|
||||
dut.gdb.write('c', non_blocking=True)
|
||||
time.sleep(1) # to avoid EOF file error
|
||||
with open(dut.gdb._logfile) as fr: # pylint: disable=protected-access
|
||||
gdb_pexpect_proc = pexpect.fdpexpect.fdspawn(fr.fileno())
|
||||
gdb_pexpect_proc.expect('Thread 2 "main" hit Breakpoint 1, app_main ()')
|
||||
|
||||
dut.expect('example: Created task') # dut has been restarted by gdb since the last dut.expect()
|
||||
dut_expect_task_event()
|
||||
|
||||
# Do a sleep while sysview samples are captured.
|
||||
time.sleep(3)
|
||||
# GDB isn't responding now to any commands, therefore, the following command is issued to openocd
|
||||
dut.openocd.write('esp sysview stop')
|
@ -1,64 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from io import open
|
||||
|
||||
import debug_backend
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='test_jtag_arm')
|
||||
def test_examples_sysview_tracing_heap_log(env, extra_data):
|
||||
|
||||
rel_project_path = os.path.join('examples', 'system', 'sysview_tracing_heap_log')
|
||||
dut = env.get_dut('sysview_tracing_heap_log', rel_project_path)
|
||||
proj_path = os.path.join(dut.app.idf_path, rel_project_path)
|
||||
elf_path = os.path.join(dut.app.binary_path, 'sysview_tracing_heap_log.elf')
|
||||
|
||||
def get_temp_file():
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
return f.name
|
||||
|
||||
try:
|
||||
tempfiles = [get_temp_file(), get_temp_file()]
|
||||
|
||||
with open(os.path.join(proj_path, 'gdbinit')) as f_in, open(tempfiles[0], 'w') as f_out:
|
||||
new_content = f_in.read()
|
||||
# localhost connection issue occurs in docker unless:
|
||||
new_content = new_content.replace(':3333', '127.0.0.1:3333', 1)
|
||||
new_content = new_content.replace('file:///tmp/heap_log.svdat', 'file://{}'.format(tempfiles[1]), 1)
|
||||
f_out.write(new_content)
|
||||
|
||||
with ttfw_idf.OCDBackend(os.path.join(proj_path, 'openocd.log'), dut.app.target):
|
||||
dut.start_app()
|
||||
dut.expect('esp_apptrace: Initialized TRAX on CPU0')
|
||||
|
||||
gdb_log = os.path.join(proj_path, 'gdb.log')
|
||||
gdb_workdir = os.path.join(proj_path, 'main')
|
||||
with ttfw_idf.GDBBackend(gdb_log, elf_path, dut.app.target, tempfiles[0], gdb_workdir) as p:
|
||||
for _ in range(2): # There are two breakpoints
|
||||
p.gdb.wait_target_state(debug_backend.TARGET_STATE_RUNNING)
|
||||
stop_reason = p.gdb.wait_target_state(debug_backend.TARGET_STATE_STOPPED)
|
||||
assert stop_reason == debug_backend.TARGET_STOP_REASON_BP, 'STOP reason: {}'.format(stop_reason)
|
||||
|
||||
# dut has been restarted by gdb since the last dut.expect()
|
||||
dut.expect('esp_apptrace: Initialized TRAX on CPU0')
|
||||
|
||||
with ttfw_idf.CustomProcess(' '.join([os.path.join(dut.app.idf_path, 'tools/esp_app_trace/sysviewtrace_proc.py'),
|
||||
'-p',
|
||||
'-b', elf_path,
|
||||
tempfiles[1]]),
|
||||
logfile='sysviewtrace_proc.log') as sysviewtrace:
|
||||
sysviewtrace.pexpect_proc.expect(re.compile(r'Found \d+ leaked bytes in \d+ blocks.'), timeout=120)
|
||||
finally:
|
||||
for x in tempfiles:
|
||||
try:
|
||||
os.unlink(x)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_sysview_tracing_heap_log()
|
@ -0,0 +1,47 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import os.path
|
||||
import time
|
||||
|
||||
import pexpect.fdpexpect
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
|
||||
TEMP_FILE = os.path.join(os.path.dirname(__file__), 'heap_log.svdat')
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.jtag
|
||||
@pytest.mark.parametrize('embedded_services', [
|
||||
'esp,idf,jtag',
|
||||
], indirect=True)
|
||||
def test_examples_sysview_tracing_heap_log(idf_path: str, dut: IdfDut) -> None:
|
||||
dut.gdb.write('mon reset halt')
|
||||
dut.gdb.write('flushregs')
|
||||
|
||||
dut.gdb.write('tb heap_trace_start')
|
||||
dut.gdb.write('commands', non_blocking=True)
|
||||
dut.gdb.write(f'mon esp sysview start file://{TEMP_FILE}', non_blocking=True)
|
||||
dut.gdb.write('c', non_blocking=True)
|
||||
dut.gdb.write('end')
|
||||
|
||||
dut.gdb.write('tb heap_trace_stop')
|
||||
dut.gdb.write('commands', non_blocking=True)
|
||||
dut.gdb.write('mon esp sysview stop', non_blocking=True)
|
||||
dut.gdb.write('end')
|
||||
|
||||
dut.gdb.write('c', non_blocking=True)
|
||||
dut.expect('esp_apptrace: Initialized TRAX on CPU0')
|
||||
|
||||
time.sleep(1) # make sure that the sysview file has been generated
|
||||
with pexpect.spawn(' '.join([os.path.join(idf_path, 'tools', 'esp_app_trace', 'sysviewtrace_proc.py'),
|
||||
'-p',
|
||||
'-b', dut.app.elf_file,
|
||||
TEMP_FILE])) as sysviewtrace:
|
||||
sysviewtrace.expect(r'Found \d+ leaked bytes in \d+ blocks.', timeout=120)
|
||||
|
||||
with open(dut.gdb._logfile) as fr: # pylint: disable=protected-access
|
||||
gdb_pexpect_proc = pexpect.fdpexpect.fdspawn(fr.fileno())
|
||||
gdb_pexpect_proc.expect_exact(
|
||||
'Thread 2 "main" hit Temporary breakpoint 1, heap_trace_start (mode_param=HEAP_TRACE_ALL)', timeout=10)
|
||||
gdb_pexpect_proc.expect_exact('Thread 2 "main" hit Temporary breakpoint 2, heap_trace_stop ()', timeout=10)
|
@ -18,8 +18,8 @@ except ModuleNotFoundError:
|
||||
|
||||
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.test_jtag_arm
|
||||
def test_idf_gdb(dut: Dut) -> None:
|
||||
@pytest.mark.jtag
|
||||
def test_idf_gdb(dut: IdfDut) -> None:
|
||||
# Need to wait a moment to connect via OpenOCD after the hard reset happened.
|
||||
# Along with this check that app runs ok
|
||||
dut.expect('Hello world!')
|
||||
|
@ -13,7 +13,7 @@ from pytest_embedded_idf import IdfDut
|
||||
@pytest.mark.parametrize('embedded_services, skip_autoflash, erase_all', [
|
||||
('esp,idf,jtag', 'y', 'y'),
|
||||
], indirect=True)
|
||||
@pytest.mark.test_jtag_arm
|
||||
@pytest.mark.jtag
|
||||
def test_loadable_elf(dut: IdfDut, offset: str) -> None:
|
||||
dut.gdb.write('mon reset halt')
|
||||
dut.gdb.write(f'thb *{offset}')
|
||||
|
Loading…
x
Reference in New Issue
Block a user