mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-28 19:24:04 +08:00
docs: add generated tutorial compatibility matrix (#212)
* docs: declare tutorial compatibility requirements * docs: generate tutorial compatibility matrix * fix: correct BPF Arena minimum kernel * refactor: simplify compatibility validation --------- Co-authored-by: LinuxDev9002 <i@littlefisher.me>
This commit is contained in:
129
scripts/test_generate_compatibility.py
Normal file
129
scripts/test_generate_compatibility.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from scripts.generate_compatibility import (
|
||||
REQUIRED_FIELDS,
|
||||
collect_tutorials,
|
||||
parse_config,
|
||||
render,
|
||||
validate_metadata,
|
||||
)
|
||||
|
||||
|
||||
class CompatibilityMetadataTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.project_root = Path(__file__).resolve().parent.parent
|
||||
cls.tutorials = collect_tutorials(cls.project_root / "src")
|
||||
|
||||
def test_every_tutorial_has_valid_metadata(self):
|
||||
config_paths = list((self.project_root / "src").rglob(".config"))
|
||||
self.assertTrue(config_paths)
|
||||
self.assertEqual(len(config_paths), len(self.tutorials))
|
||||
for path in config_paths:
|
||||
metadata = parse_config(path)
|
||||
self.assertTrue(set(REQUIRED_FIELDS) <= set(metadata), path)
|
||||
|
||||
def test_bilingual_tables_contain_every_tutorial(self):
|
||||
for chinese in (False, True):
|
||||
table = render(self.tutorials, chinese=chinese)
|
||||
self.assertEqual(len(self.tutorials), table.count("| ["))
|
||||
for tutorial in self.tutorials:
|
||||
readme = "README.zh.md" if chinese else "README.md"
|
||||
expected = f"{tutorial['relative'].as_posix()}/{readme}"
|
||||
self.assertIn(expected, table)
|
||||
|
||||
def test_missing_field_is_rejected(self):
|
||||
metadata = {
|
||||
"kernel_min": "5.15",
|
||||
"kernel_min_basis": "required-feature",
|
||||
"architectures": "x86_64",
|
||||
"btf": "optional",
|
||||
"kernel_config": "CONFIG_BPF=y",
|
||||
"hardware": "none",
|
||||
"root": "required",
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "test_status"):
|
||||
validate_metadata(Path("example/.config"), metadata)
|
||||
|
||||
def test_required_btf_config_is_enforced(self):
|
||||
metadata = {
|
||||
"kernel_min": "5.15",
|
||||
"kernel_min_basis": "required-feature",
|
||||
"architectures": "x86_64",
|
||||
"btf": "required",
|
||||
"kernel_config": "CONFIG_BPF=y",
|
||||
"hardware": "none",
|
||||
"root": "required",
|
||||
"test_status": "not-in-ci",
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "CONFIG_DEBUG_INFO_BTF"):
|
||||
validate_metadata(Path("example/.config"), metadata)
|
||||
|
||||
def test_duplicate_config_field_is_rejected(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = Path(directory) / ".config"
|
||||
path.write_text("level=Basic\nlevel=Depth\n", encoding="utf-8")
|
||||
with self.assertRaisesRegex(ValueError, "duplicate field level"):
|
||||
parse_config(path)
|
||||
|
||||
def test_empty_csv_item_is_rejected(self):
|
||||
metadata = {
|
||||
"kernel_min": "5.15",
|
||||
"kernel_min_basis": "repository-baseline",
|
||||
"architectures": "x86_64,,arm64",
|
||||
"btf": "optional",
|
||||
"kernel_config": "CONFIG_BPF=y",
|
||||
"hardware": "none",
|
||||
"root": "required",
|
||||
"test_status": "not-in-ci",
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "architectures"):
|
||||
validate_metadata(Path("example/.config"), metadata)
|
||||
|
||||
def test_per_arch_kernel_min_covers_all_architectures(self):
|
||||
metadata = {
|
||||
"kernel_min": "x86_64:5.5",
|
||||
"kernel_min_basis": "documented",
|
||||
"architectures": "x86_64,arm64",
|
||||
"btf": "optional",
|
||||
"kernel_config": "CONFIG_BPF=y",
|
||||
"hardware": "none",
|
||||
"root": "required",
|
||||
"test_status": "not-in-ci",
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "kernel_min"):
|
||||
validate_metadata(Path("example/.config"), metadata)
|
||||
|
||||
def test_not_applicable_basis_requires_not_applicable_kernel(self):
|
||||
metadata = {
|
||||
"kernel_min": "5.15",
|
||||
"kernel_min_basis": "not-applicable",
|
||||
"architectures": "x86_64",
|
||||
"btf": "optional",
|
||||
"kernel_config": "CONFIG_BPF=y",
|
||||
"hardware": "none",
|
||||
"root": "required",
|
||||
"test_status": "not-in-ci",
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "disagree"):
|
||||
validate_metadata(Path("example/.config"), metadata)
|
||||
|
||||
def test_repository_baseline_is_consistent(self):
|
||||
metadata = {
|
||||
"kernel_min": "5.15",
|
||||
"kernel_min_basis": "repository-baseline",
|
||||
"architectures": "x86_64",
|
||||
"btf": "optional",
|
||||
"kernel_config": "CONFIG_BPF=y,CONFIG_BPF_SYSCALL=y",
|
||||
"hardware": "none",
|
||||
"root": "required",
|
||||
"test_status": "not-in-ci",
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "repository-baseline must be 4.8"):
|
||||
validate_metadata(Path("example/.config"), metadata)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user