soc/intel/xeon_sp/util: Enhance lock_pam0123
[coreboot2.git] / util / cbfstool / tests / elogtool_test.py
bloba798a4c16cd84ec8dd87cec154bee4913c1fa9a9
1 #!/usr/bin/python3
2 # SPDX-License-Identifier: BSD-3-Clause
4 import os
5 import pytest
6 import struct
7 import subprocess
8 from datetime import datetime
9 from datetime import timedelta
11 # Defined in include/commonlib/bsd/elog.h
12 ELOG_TYPE_SYSTEM_BOOT = 0x17
13 ELOG_TYPE_EOL = 0xff
14 ELOG_EVENT_HEADER_SIZE = 8
15 ELOG_EVENT_CHECKSUM_SIZE = 1
18 def convert_to_event(s: str) -> dict:
19 fields = s.split("|")
20 assert len(fields) == 3 or len(fields) == 4
22 return {
23 "index": int(fields[0]),
24 "timestamp": datetime.strptime(fields[1].strip(), "%Y-%m-%d %H:%M:%S"),
25 "desc": fields[2].strip(),
26 "data": fields[3].strip() if len(fields) == 4 else None,
30 def compare_event(expected: dict, got: dict) -> None:
31 # Ignore the keys that might be in "got", but not in "expected".
32 # In particular "timestamp" might not want to be tested.
33 for key in expected:
34 assert key in got.keys()
35 assert expected[key] == got[key]
38 @pytest.fixture(scope="session")
39 def elogtool_path(request):
40 exe = request.config.option.elogtool_path
41 assert os.path.exists(exe)
42 return exe
45 @pytest.fixture(scope="function")
46 def elogfile(tmp_path):
47 header_size = 8
48 tail_size = 512 - header_size
50 # Elog header:
51 # Magic (4 bytes) = "ELOG"
52 # Version (1 byte) = 1
53 # Size (1 byte) = 8
54 # Reserved (2 bytes) = 0xffff
55 header = struct.pack("4sBBH", bytes("ELOG", "utf-8"), 1, 8, 0xffff)
57 # Fill the tail with EOL events.
58 tail = bytes([ELOG_TYPE_EOL] * tail_size)
59 buf = header + tail
61 buf_path = tmp_path / "elog_empty.bin"
62 with buf_path.open("wb") as fd:
63 fd.write(buf)
64 fd.flush()
65 return str(buf_path)
66 assert False
69 def elog_list(elogtool_path: str, path: str) -> list:
70 output = subprocess.run([elogtool_path, 'list', '-f', path],
71 capture_output=True, check=True)
72 log = output.stdout.decode("utf-8").strip()
74 lines = log.splitlines()
75 lines = [convert_to_event(s.strip()) for s in lines]
76 return lines
79 def elog_clear(elogtool_path: str, path: str) -> None:
80 subprocess.run([elogtool_path, 'clear', '-f', path], check=True)
83 def elog_add(elogtool_path: str, path: str, typ: int, data: bytearray) -> None:
84 subprocess.run([elogtool_path, 'add', '-f', path,
85 hex(typ), data.hex()], check=True)
88 def test_list_empty(elogtool_path, elogfile):
89 events = elog_list(elogtool_path, elogfile)
90 assert len(events) == 0
93 def test_clear_empty(elogtool_path, elogfile):
94 elog_clear(elogtool_path, elogfile)
95 events = elog_list(elogtool_path, elogfile)
97 # Must have one event, the "Log area cleared" event.
98 assert len(events) == 1
100 expected = {"index": 0,
101 "desc": "Log area cleared",
102 # "0", since it was an empty elog buffer. No bytes were cleared.
103 "data": "0"}
104 compare_event(expected, events[0])
107 def test_clear_not_empty(elogtool_path, elogfile):
108 tot_events = 10
109 data_size = 4
110 event_size = ELOG_EVENT_HEADER_SIZE + data_size + ELOG_EVENT_CHECKSUM_SIZE
111 written_bytes = tot_events * event_size
113 for i in range(tot_events):
114 # Adding boot_count for completeness. But it is ignored in this test.
115 boot_count = i.to_bytes(data_size, "little")
116 elog_add(elogtool_path, elogfile, ELOG_TYPE_SYSTEM_BOOT, boot_count)
117 elog_clear(elogtool_path, elogfile)
118 events = elog_list(elogtool_path, elogfile)
120 # Must have one event, the "Log area cleared" event.
121 assert len(events) == 1
123 expected = {"index": 0,
124 "desc": "Log area cleared",
125 "data": str(written_bytes)
127 compare_event(expected, events[0])
130 def test_add_single_event(elogtool_path, elogfile):
131 # "before - one second" is needed because datetime.now() fills the
132 # microsecond variable. But eventlog doesn't use it, and has it hardcoded to
133 # zero.
134 before = datetime.now() - timedelta(seconds=1)
135 boot_count = 128
136 elog_add(elogtool_path, elogfile, ELOG_TYPE_SYSTEM_BOOT,
137 boot_count.to_bytes(4, "little"))
138 after = datetime.now()
140 events = elog_list(elogtool_path, elogfile)
141 assert len(events) == 1
143 ev = events[0]
144 expected = {"index": 0,
145 "desc": "System boot",
146 "data": str(boot_count)
148 compare_event(expected, ev)
150 assert before < ev["timestamp"] < after