Skip to content

Commit 86363a0

Browse files
Refactor bios error test script with python and add unit tests (New) (#2207)
* migrate acpi bios error script to Python with unit tests (New) * change: Update mock data logs * fix black error. Remove original test script. * fix: Fix duplicate section when next error within 20 lines. Inline bios info check. Update UT * change: Print bios info in separate function.
1 parent ff26eea commit 86363a0

File tree

4 files changed

+128
-19
lines changed

4 files changed

+128
-19
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
3+
import subprocess
4+
5+
6+
def print_bios_info():
7+
"""Print BIOS information from DMI fields."""
8+
dmi_fields = {
9+
"date": "/sys/class/dmi/id/bios_date",
10+
"release": "/sys/class/dmi/id/bios_release",
11+
"vendor": "/sys/class/dmi/id/bios_vendor",
12+
"version": "/sys/class/dmi/id/bios_version",
13+
}
14+
15+
for field, path in dmi_fields.items():
16+
try:
17+
with open(path, "r") as f:
18+
value = f.read().strip()
19+
except (OSError, IOError) as e:
20+
value = f"Unable to read {path}: {e}"
21+
22+
print(f"BIOS {field}: {value}")
23+
24+
25+
def check_acpi_bios_errors():
26+
"""
27+
Check for ACPI BIOS errors in the current boot's kernel messages.
28+
Raises SystemExit if errors are found.
29+
"""
30+
journal = subprocess.check_output(
31+
["journalctl", "-b", "-k"],
32+
universal_newlines=True,
33+
stderr=subprocess.STDOUT,
34+
)
35+
36+
lines = journal.splitlines()
37+
acpi_error_lines = []
38+
for i, line in enumerate(lines):
39+
if "ACPI BIOS Error" in line:
40+
acpi_error_lines.append(i)
41+
42+
if acpi_error_lines:
43+
# Mimic grep -A 20: error line + 20 lines after it
44+
picked_lines = set()
45+
output_lines = []
46+
last_added = -1
47+
48+
for error_line in acpi_error_lines:
49+
# Add separator when next error outside of 20 lines context
50+
if output_lines and error_line > last_added + 1:
51+
output_lines.append("------")
52+
53+
for j in range(error_line, min(error_line + 21, len(lines))):
54+
# Track picked lines to avoid duplicates if next error
55+
# within 20 lines context
56+
if j not in picked_lines:
57+
picked_lines.add(j)
58+
output_lines.append(lines[j])
59+
last_added = j
60+
print("!!! ACPI BIOS Error detected !!!")
61+
print_bios_info()
62+
for error_line in output_lines:
63+
print(error_line)
64+
65+
raise SystemExit("ACPI BIOS Error detected in kernel messages")
66+
67+
68+
def main():
69+
check_acpi_bios_errors()
70+
print("No ACPI BIOS errors detected in current boot")
71+
72+
73+
if __name__ == "__main__":
74+
main()

contrib/pc-sanity/bin/bios-error.sh

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import unittest
2+
from unittest.mock import patch, mock_open
3+
import subprocess
4+
5+
from acpi_bios_error import check_acpi_bios_errors, main
6+
7+
8+
class TestAcpiBiosError(unittest.TestCase):
9+
10+
@patch("subprocess.check_output")
11+
def test_check_acpi_bios_errors_no_errors(self, mock_subprocess):
12+
"""Test when no ACPI BIOS errors are found."""
13+
mock_subprocess.return_value = """Sep 18 17:17:37 test-host kernel: ACPI: 28 ACPI AML tables successfully acquired and loaded
14+
Sep 18 17:17:37 test-host kernel: ACPI Error: No pointer back to namespace node in package (___ptrval___) (20240827/dsargs-301)
15+
Sep 18 17:17:37 test-host kernel: ACPI Error: No pointer back to namespace node in package (___ptrval___) (20240827/dsargs-301)
16+
Sep 18 17:17:37 test-host kernel: ACPI: EC: EC started
17+
Sep 18 17:17:37 test-host kernel: ACPI: EC: interrupt blocked
18+
Sep 18 17:17:37 test-host kernel: ACPI: EC: EC_CMD/EC_SC=0x66, EC_DATA=0x62
19+
Sep 18 17:17:37 test-host kernel: ACPI: EC: Boot ECDT EC used to handle transactions
20+
Sep 18 17:17:37 test-host kernel: ACPI: [Firmware Bug]: BIOS _OSI(Linux) query ignored
21+
Sep 18 17:17:37 test-host kernel: ACPI: USB4 _OSC: OS supports USB3+ DisplayPort+ PCIe+ XDomain+
22+
Sep 18 17:17:37 test-host kernel: ACPI: USB4 _OSC: OS controls USB3+ DisplayPort+ PCIe+ XDomain+"""
23+
24+
check_acpi_bios_errors()
25+
mock_subprocess.assert_called_once_with(
26+
["journalctl", "-b", "-k"],
27+
universal_newlines=True,
28+
stderr=subprocess.STDOUT,
29+
)
30+
31+
@patch("acpi_bios_error.print_bios_info")
32+
@patch("subprocess.check_output")
33+
def test_check_acpi_bios_errors_found(
34+
self, mock_subprocess, mock_print_bios
35+
):
36+
"""Test when ACPI BIOS errors are detected."""
37+
mock_subprocess.return_value = """Sep 18 17:17:37 test-host kernel: ACPI BIOS Error (bug): Failure creating named object [_SB.PC00.TXHC.RHUB.SS01._UPC], AE_ALREADY_EXISTS (20240827/dswload2-326)
38+
Sep 18 17:17:37 test-host kernel: ACPI Error: AE_ALREADY_EXISTS, During name lookup/catalog (20240827/psobject-220)
39+
Sep 18 17:17:37 test-host kernel: ACPI: Skipping parse of AML opcode: Method (0x0014)
40+
Sep 18 17:17:37 test-host kernel: ACPI BIOS Error (bug): Failure creating named object [_SB.PC00.TXHC.RHUB.SS01._PLD], AE_ALREADY_EXISTS (20240827/dswload2-326)
41+
Sep 18 17:17:37 test-host kernel: ACPI Error: AE_ALREADY_EXISTS, During name lookup/catalog (20240827/psobject-220)
42+
Sep 18 17:17:37 test-host kernel: ACPI: Skipping parse of AML opcode: Method (0x0014)
43+
Sep 18 17:17:37 test-host kernel: ACPI BIOS Error (bug): Could not resolve symbol [_SB.PC02.RP21.PXSX.TBDU.XHCI.RHUB.SS01], AE_NOT_FOUND (20240827/dswload2-162)
44+
Sep 18 17:17:37 test-host kernel: ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20240827/psobject-220)
45+
Sep 18 17:17:37 test-host kernel: ACPI: Skipping parse of AML opcode: Scope (0x0010)
46+
Sep 18 17:17:37 test-host kernel: ACPI: 28 ACPI AML tables successfully acquired and loaded"""
47+
48+
with self.assertRaises(SystemExit):
49+
check_acpi_bios_errors()
50+
51+
52+
if __name__ == "__main__":
53+
unittest.main()

contrib/pc-sanity/units/pc-sanity/pc-sanity-check-devices.pxu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ template-unit: job
219219
plugin: shell
220220
category_id: com.canonical.plainbox::miscellanea
221221
id: miscellanea/acpi-bios-error_{type}
222-
command: bios-error.sh
222+
command: acpi_bios_error.py
223223
_summary: Check if kernel reports ACPI BIOS Error
224224
_description:
225225
Check if the kernel reports ACPI BIOS Error

0 commit comments

Comments
 (0)