From b9354d3ccdf624c9ea9f82d3f2e436357c6f0fa2 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Thu, 24 Oct 2024 00:17:00 +0200 Subject: [PATCH] test: parse: add test_deviceinfo (MR 2453) Write some basic parser tests for deviceinfo. The parser is quite basic so there isn't much to test yet. Expecting this to gain features as we look at e.g. making the parser the "source of truth" for the deviceinfo format. Signed-off-by: Caleb Connolly --- pmb/conftest.py | 6 ++ pmb/parse/deviceinfo.py | 7 ++ pmb/parse/test_deviceinfo.py | 204 +++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 pmb/parse/test_deviceinfo.py diff --git a/pmb/conftest.py b/pmb/conftest.py index c15d5837..1ac1f739 100644 --- a/pmb/conftest.py +++ b/pmb/conftest.py @@ -2,6 +2,7 @@ import os from pathlib import Path import pytest import shutil +import tempfile import pmb.core from pmb.core.context import get_context @@ -165,3 +166,8 @@ def pmaports(pmb_args, monkeypatch): pmb.helpers.git.clone("pmaports") assert pmb.helpers.run.user(["git", "checkout", "master"], working_dir=config.aports[0]) == 0 + + +@pytest.fixture +def tmp_file(tmp_path): + return Path(tempfile.mkstemp(dir=tmp_path)[1]) diff --git a/pmb/parse/deviceinfo.py b/pmb/parse/deviceinfo.py index 5598dc85..0d091b2e 100644 --- a/pmb/parse/deviceinfo.py +++ b/pmb/parse/deviceinfo.py @@ -35,6 +35,13 @@ def _parse_kernel_suffix(info, device, kernel): "b": "second", "b_downstream": "third"} """ + # We don't support parsing the kernel variants in tests yet, since this code + # depends on pmaports being available and calls into a whole lot of other code. + if os.environ.get("PYTEST_CURRENT_TEST", "").startswith("pmb/parse/test_deviceinfo.py"): + # If you hit this, you're probably trying to add a test for kernel variants. + # You'll need to figure out how to mock the APKBUILD parsing below. + assert kernel is None + return info # Do nothing if the configured kernel isn't available in the kernel (e.g. # after switching from device with multiple kernels to device with only one # kernel) diff --git a/pmb/parse/test_deviceinfo.py b/pmb/parse/test_deviceinfo.py new file mode 100644 index 00000000..4b3a9deb --- /dev/null +++ b/pmb/parse/test_deviceinfo.py @@ -0,0 +1,204 @@ +from pathlib import Path +from .deviceinfo import Deviceinfo +from pmb.config import deviceinfo_chassis_types + +import pytest +import tempfile +import random + +# Exported from the wiki using https://www.convertcsv.com/html-table-to-csv.htm +# on 2024/10/23 +deviceinfo_keys = [ + "format_version", + "name", + "manufacturer", + "codename", + "uboot_boardname", + "year", + "chassis", + "dtb", + "append_dtb", + "external_storage", + "flash_method", + "arch", + "dev_internal_storage", + "dev_internal_storage_repartition", + "dev_touchscreen", + "dev_touchscreen_calibration", + "keymaps", + "swap_size_recommended", + "zram_swap_pct", + "tmp_as_tmpfs_size", + "disable_dhcpd", + "no_framebuffer", + "initfs_compression", + "create_initfs_extra", + "getty", + "gpu_accelerated", + "super_partitions", + "Variable", + "flash_offset_base", + "flash_offset_dtb", + "flash_offset_kernel", + "flash_offset_ramdisk", + "flash_offset_second", + "flash_offset_tags", + "flash_pagesize", + "flash_sparse", + "flash_sparse_samsung_format", + "flash_kernel_on_update", + "kernel_cmdline", + "kernel_cmdline_append", + "bootimg_amazon_omap_header_size", + "bootimg_blobpack", + "bootimg_qcdt", + "bootimg_qcdt_type", + "bootimg_mtk_label_kernel", + "bootimg_mtk_label_ramdisk", + "bootimg_override_payload", + "bootimg_override_initramfs", + "bootimg_override_payload_compression", + "deviceinfo_bootimg_prepend_dhtb", + "bootimg_override_payload_append_dtb", + "bootimg_dtb_second", + "bootimg_append_seandroidenforce", + "bootimg_pxa", + "bootimg_custom_args", + "header_version", + "generate_bootimg", + "generate_extlinux_config", + "generate_grub_config", + "generate_systemd_boot", + "generate_uboot_fit_images", + "generate_legacy_uboot_initfs", + "legacy_uboot_load_address", + "legacy_uboot_image_name", + "flash_fastboot_partition_kernel", + "flash_fastboot_partition_system", + "flash_fastboot_partition_vbmeta", + "flash_fastboot_partition_dtbo", + "flash_fastboot_max_size", + "flash_heimdall_partition_kernel", + "flash_heimdall_partition_initfs", + "flash_heimdall_partition_system", + "flash_heimdall_partition_vbmeta", + "flash_rk_partition_kernel", + "flash_rk_partition_system", + "flash_mtkclient_partition_kernel", + "flash_mtkclient_partition_rootfs", + "flash_mtkclient_partition_vbmeta", + "flash_mtkclient_partition_dtbo", + "boot_filesystem", + "root_filesystem", + "rootfs_image_sector_size", + "sd_embed_firmware", + "sd_embed_firmware_step_size", + "partition_blacklist", + "boot_part_start", + "partition_type", + "mkinitfs_postprocess", + "Variable", + "bootimg_vendor_dependent", + "bootimg_vendor_android_boot_image", + "bootimg_vendor_device_tree_identifiers", + "Variable", + "screen_width", + "screen_height", + "Variable", + "usb_idVendor", + "usb_idProduct", + "usb_serialnumber", + "usb_network_function", + "usb_network_udc", + "Variable", + "cgpt_kpart", + "cgpt_kpart_start", + "cgpt_kpart_size", + "depthcharge_board", + "generate_depthcharge_image", +] + +deprecated_keys = [ + "flash_methods", + "external_disk", + "external_disk_install", + "msm_refresher", + "flash_fastboot_vendor_id", + "nonfree", + "dev_keyboard", + "date", +] + +required_keys = [ + "codename", + "chassis", + "arch", +] + +# Guaranteed by fair dice roll +random_values = [ + "", + "test", + "True", + "false", + "2020", + "0xf100f", + "843772384", + "0", + "1", + "///@@", + "/34u3294£$*R", +] + + +def random_deviceinfo_props(nprops=10): + props = {} + for _ in range(nprops): + key = random.choice(deviceinfo_keys) + value = random.choice(random_values) + props[key] = value + + return props + + +def random_valid_deviceinfo(tmp_path): + _, name = tempfile.mkstemp(dir=tmp_path) + path = Path(name) + + info = random_deviceinfo_props(random.randint(1, len(deviceinfo_keys))) + + # Set the required properties + # This would be the device package dir... + info["codename"] = tmp_path.name[7:] + info["chassis"] = random.choice(deviceinfo_chassis_types) + info["arch"] = random.choice(["armhf", "aarch64", "x86_64"]) + + # Now write it all out to a file + with open(path, "w") as f: + for key, value in info.items(): + f.write(f'deviceinfo_{key}="{value}"\n') + + return path + + +# Test deviceinfo files that are technically valid but have bogus data +# These are expected to get more strict as the parser is improved +def test_random_valid_deviceinfos(tmp_path): + for _ in range(1000): + info_path = random_valid_deviceinfo(tmp_path) + print(f"Testing randomly generate deviceinfo file {info_path}") + info = Deviceinfo(info_path) + print(info.codename) + + +# Check that lines starting with deviceinfo_ but don't have an +# "=" raise a syntax error +def test_syntax_error(tmp_file): + with open(tmp_file, "w") as f: + f.write('deviceinfo_codename="test"\n') + f.write('deviceinfo_chassis="test"\n') + f.write('deviceinfo_arch="test"\n') + f.write("deviceinfo_nothing??\n\n\n") + + with pytest.raises(SyntaxError): + Deviceinfo(tmp_file)