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 <caleb@postmarketos.org>
This commit is contained in:
Caleb Connolly 2024-10-24 00:17:00 +02:00
parent 511d490015
commit b9354d3ccd
No known key found for this signature in database
GPG key ID: 0583312B195F64B6
3 changed files with 217 additions and 0 deletions

View file

@ -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])

View file

@ -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)

View file

@ -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)