Skip to content

Commit df79ece

Browse files
committed
feat: Add custom_allowlist to verify_messages function
Signed-off-by: Kacper Tokarzewski <kacper.tokarzewski@intel.com>
1 parent 571d6fd commit df79ece

4 files changed

Lines changed: 108 additions & 4 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ print(dmesg_obj.get_os_package_info())
2424
`get_buffer_size_data(self, driver_name: str, driver_interface_number: str) -> Optional[list]` - responsible to return buffer size for respective drivername and interface number.
2525
`get_os_package_info(self) -> Union[OSPackageInfo, None]` - responsible to return os package installed which is retrived from dmesg output.
2626
`get_messages_additional(self, service_name: str = None, lines: int = 1000, expected_return_codes: Iterable = frozenset({0}), additional_greps: Optional[List[str]] = None) -> str` - responsible to return latest dmesg output based on addtional filters as specified by the user.
27-
`verify_messages(self) -> dict` - responsible to check if there are err level messages in dmesg output.
27+
`verify_messages(self, custom_allowlist: Optional[Iterable[str]] = None) -> dict` - responsible to check if there are err level messages in dmesg output. If `custom_allowlist` is provided, it extends the default `DMESG_WHITELIST` with additional benign error patterns to ignore.
2828
`clear_messages(self, errors_filter: Optional[List[str]] = [], ignore_filter: Optional[List[str]] = [],) -> Tuple[str, List[str]]` - responsible to clear the message buffer of the kernel (dmesg).
2929
`clear_messages_after_error(self, error_msg: str) -> Union[Tuple[str, List[str]], None]` - responsible to clear the message buffer of the kernel (dmesg) after user defined error occurred.
3030
`check_errors(self, error_list: list) -> tuple` - responsible to check for the errors as specified by the user list or user can select from predefined list declared in constant file.

mfd_dmesg/base.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,20 +220,30 @@ def _check_specific_errors(self, error_msg: str) -> bool:
220220
else:
221221
return True
222222

223-
def verify_messages(self) -> dict:
223+
def verify_messages(self, custom_allowlist: Iterable[str] | None = None) -> dict:
224224
"""Verify if there are err level messages in dmesg output.
225225
226+
:param custom_allowlist: list of error messages to ignore in the dmesg output, if any.
227+
By default, it uses DMESG_WHITELIST which contains known benign errors.
228+
If this parameter is provided, it will be combined with DMESG_WHITELIST
229+
to create the final allowlist.
226230
:return: dictionary indicating success or failure and the error messages if present.
227231
"""
232+
if custom_allowlist is None:
233+
allowlist = DMESG_WHITELIST
234+
else:
235+
allowlist = list(DMESG_WHITELIST) + list(custom_allowlist)
228236
logger.log(level=log_levels.MODULE_DEBUG, msg="Verify Dmesg Errors.")
229237
level = DmesgLevelOptions.ERRORS if self._is_linux() else DmesgLevelOptions.NONE
230238
out = self.get_messages(level=level)
231239
dmesg_result = {"successful": True, "error": ""}
232240
if out:
233241
for error in out.splitlines():
242+
if not error.strip():
243+
continue
234244
is_error = True
235245
if self._check_specific_errors(error):
236-
for benign_message in DMESG_WHITELIST:
246+
for benign_message in allowlist:
237247
if benign_message in error:
238248
is_error = False
239249
logger.log(

mfd_dmesg/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from dataclasses import dataclass
66
from typing import Optional
7-
from .enums import DmesgLevelOptions # noqa: F401
7+
from .enums import DmesgLevelOptions # noqa: F401
88

99

1010
@dataclass

tests/unit/test_mfd_dmesg/test_base.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,63 @@ def test_verify_messages_no_errors(self, dmesg):
386386
)
387387
assert dmesg.verify_messages()["successful"]
388388

389+
def test_verify_messages_ignores_empty_lines(self, dmesg):
390+
output = (
391+
"[ 4.923735] SELinux: Runtime disable is not supported\n"
392+
"\n"
393+
"[ 321.327775] CIFS: VFS: unaligned rsize, making it a multiple of 4096 bytes"
394+
)
395+
custom_allowlist = ["SELinux", "unaligned rsize"]
396+
dmesg._connection.execute_command.return_value = ConnectionCompletedProcess(
397+
return_code=0, args="command", stdout=output, stderr="stderr"
398+
)
399+
result = dmesg.verify_messages(custom_allowlist=custom_allowlist)
400+
assert result["successful"]
401+
assert result["error"] == ""
402+
403+
@pytest.mark.parametrize(
404+
"custom_allowlist,expected_successful,expected_error_contains",
405+
[
406+
pytest.param(
407+
["Couldn't get size", "MODSIGN", "unexpected notification"],
408+
True,
409+
[],
410+
id="all_errors_allowlisted",
411+
),
412+
pytest.param(
413+
["Couldn't get size"],
414+
False,
415+
["MODSIGN", "unexpected notification"],
416+
id="partial_match",
417+
),
418+
pytest.param(
419+
[],
420+
False,
421+
["Couldn't get size"],
422+
id="empty_allowlist",
423+
),
424+
],
425+
)
426+
def test_verify_messages_with_custom_allowlist(
427+
self, dmesg, custom_allowlist, expected_successful, expected_error_contains
428+
):
429+
output = dedent(
430+
"""
431+
[ 4.660616] Couldn't get size: 0x800000000000000e
432+
[ 4.694322] MODSIGN: Couldn't get UEFI db list
433+
[ 33.580364] cdc_ether 1-1.1.2:1.0 enp0s29u1u1u2: CDC: unexpected notification 20!"""
434+
)
435+
dmesg._connection.execute_command.return_value = ConnectionCompletedProcess(
436+
return_code=0, args="command", stdout=output, stderr="stderr"
437+
)
438+
result = dmesg.verify_messages(custom_allowlist=custom_allowlist)
439+
assert result["successful"] == expected_successful
440+
if expected_successful:
441+
assert result["error"] == ""
442+
else:
443+
for fragment in expected_error_contains:
444+
assert fragment in result["error"]
445+
389446
def test_check_errors(self, dmesg):
390447
output = dedent(
391448
"""
@@ -841,6 +898,43 @@ def test_verify_messages_no_errors(self, dmesg):
841898
)
842899
assert dmesg.verify_messages()["successful"]
843900

901+
@pytest.mark.parametrize(
902+
"custom_allowlist,expected_successful,expected_error_contains",
903+
[
904+
pytest.param(
905+
["Couldn't get size", "MODSIGN"],
906+
True,
907+
[],
908+
id="all_errors_allowlisted",
909+
),
910+
pytest.param(
911+
["Couldn't get size"],
912+
False,
913+
["MODSIGN ERROR"],
914+
id="partial_match",
915+
),
916+
],
917+
)
918+
def test_verify_messages_with_custom_allowlist(
919+
self, dmesg, custom_allowlist, expected_successful, expected_error_contains
920+
):
921+
output = dedent(
922+
"""
923+
[ 4.660616] Couldn't get size error: 0x800000000000000e
924+
[ 4.694322] MODSIGN ERROR: Couldn't get UEFI db list
925+
[ 4.728454] Couldn't get size ERROR: 0x800000000000000e"""
926+
)
927+
dmesg._connection.execute_command.return_value = ConnectionCompletedProcess(
928+
return_code=0, args="command", stdout=output, stderr="stderr"
929+
)
930+
result = dmesg.verify_messages(custom_allowlist=custom_allowlist)
931+
assert result["successful"] == expected_successful
932+
if expected_successful:
933+
assert result["error"] == ""
934+
else:
935+
for fragment in expected_error_contains:
936+
assert fragment in result["error"]
937+
844938
def test_check_errors(self, dmesg):
845939
output = dedent(
846940
"""

0 commit comments

Comments
 (0)