zephyr/tests/misc/llext-edk/pytest/test_edk.py
Luca Burelli ddd795a028 tests: llext-edk: get the Zephyr SDK path from build_info.yml
The LLEXT EDK test works by packaging an EDK and then testing its
functionality to build the extension in an external CMake build step.
That CMakelists.txt file currently references the required tools using
the ZEPHYR_SDK_INSTALL_DIR environment variable, which must be manually
set by the user.

This change modifies the test to read the newly added 'build_info.yml'
file, generated by Zephyr during the first build step. This allows to
set the ZEPHYR_SDK_INSTALL_DIR environment variable automatically based
on the (possibly auto-discovered) SDK path.

A few minor compliance cleanups are also included.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2025-01-10 09:51:54 +01:00

120 lines
4.7 KiB
Python

# Copyright (c) 2024 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
import logging
import os
import shutil
import tempfile
from pathlib import Path
from subprocess import check_output
import pytest
import yaml
from twister_harness import DeviceAdapter
logger = logging.getLogger(__name__)
def test_edk(unlaunched_dut: DeviceAdapter):
# Get the SDK path from build_info.yml
build_dir = str(unlaunched_dut.device_config.build_dir)
with open(Path(build_dir) / "build_info.yml") as f:
build_info = yaml.safe_load(f)
if build_info["cmake"]["toolchain"]["name"] != "zephyr":
logger.warning("This test requires the Zephyr SDK to be used, skipping")
pytest.skip("The Zephyr SDK must be used")
sdk_dir = build_info["cmake"]["toolchain"]["path"]
# Can we build the edk?
command = [
"west",
"build",
"-b",
unlaunched_dut.device_config.platform,
"-t",
"llext-edk",
"--build-dir",
unlaunched_dut.device_config.build_dir,
]
output = check_output(command, text=True)
logger.info(output)
# Install the edk to a temporary location
with tempfile.TemporaryDirectory() as tempdir:
# Copy the edk to the temporary directory using python methods
logger.debug(f"Copying llext-edk.tar.xz to {tempdir}")
edk_path = Path(unlaunched_dut.device_config.build_dir) / "zephyr/llext-edk.tar.xz"
shutil.copy(edk_path, tempdir)
# Extract the edk using tar
logger.debug(f"Extracting llext-edk.tar.xz to {tempdir}")
command = ["tar", "-xf", "llext-edk.tar.xz"]
output = check_output(command, text=True, cwd=tempdir)
logger.info(output)
# Copy the extension to another temporary directory to test out of tree builds
with tempfile.TemporaryDirectory() as tempdir_extension:
logger.debug(f"Copying extension to {tempdir_extension}")
ext_dir = Path(os.environ["ZEPHYR_BASE"]) / "tests/misc/llext-edk/extension"
shutil.copytree(ext_dir, tempdir_extension, dirs_exist_ok=True)
# Also copy file2hex.py to the extension directory, so that it's possible
# to generate a hex file from the extension binary
logger.debug(f"Copying file2hex.py to {tempdir_extension}")
file2hex = Path(os.environ["ZEPHYR_BASE"]) / "scripts/build/file2hex.py"
shutil.copy(file2hex, tempdir_extension)
# Set the LLEXT_EDK_INSTALL_DIR environment variable so that the extension
# knows where the EDK is installed
edk_dir = Path(tempdir) / "llext-edk"
env = os.environ.copy()
env.update({"ZEPHYR_SDK_INSTALL_DIR": sdk_dir})
env.update({"LLEXT_EDK_INSTALL_DIR": edk_dir})
# Build the extension using the edk
logger.debug(f"Building extension in {tempdir_extension} - cmake")
command = ["cmake", "-B", "build"]
output = check_output(command, text=True, cwd=tempdir_extension, env=env)
logger.info(output)
logger.debug(f"Building extension in {tempdir_extension} - make")
command = ["make", "-C", "build"]
output = check_output(command, text=True, cwd=tempdir_extension, env=env)
logger.info(output)
# Check if the extension was built
assert os.path.exists(Path(tempdir_extension) / "build/extension.llext")
# Can we run it? First, rebuild the application, now including the extension
# build directory in the include path, so that the application can find the
# extension code.
logger.debug(f"Running application with extension in {tempdir_extension} - west build")
command = [
"west",
"build",
"-b",
unlaunched_dut.device_config.platform,
"--build-dir",
unlaunched_dut.device_config.build_dir,
"--",
f"-DEXTENSION_DIR={tempdir_extension}/build/",
]
logger.debug(f"west command: {command}")
output = check_output(command, text=True)
logger.info(output)
# Now that the application is built, run it
logger.debug(f"Running application with extension in {tempdir_extension}")
try:
unlaunched_dut.launch()
lines = unlaunched_dut.readlines_until("Done")
assert "Calling extension from kernel" in lines
assert "Calling extension from user" in lines
assert "foo(42) is 1764" in lines
assert "foo(43) is 1849" in lines
finally:
unlaunched_dut.close()