zephyr/scripts/build/check_init_priorities_test.py
Fabio Baltieri 2a70c31945 scripts: check_init_priorities: drop the same priority check
Since bb590b5b6e introduced ordinals in the priority sequence, the "same
priority" case cannot happen anymore, furthermore the priority value in
the script is now the position of the function in the init sequence, so
if two devices have the same priority there's something real bad going
on.

Drop all the "same priority" handling code and tests, convert the case
into ane exception instead. Drop the init stubs as well from the test,
they are not required anymore.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
2023-11-03 11:45:23 +01:00

421 lines
15 KiB
Python
Executable file

#!/usr/bin/env python3
# Copyright 2023 Google LLC
# SPDX-License-Identifier: Apache-2.0
"""
Tests for check_init_priorities
"""
import mock
import pathlib
import unittest
from elftools.elf.relocation import Section
from elftools.elf.sections import SymbolTableSection
import check_init_priorities
class TestPriority(unittest.TestCase):
"""Tests for the Priority class."""
def test_priority_parsing(self):
prio1 = check_init_priorities.Priority("POST_KERNEL", 12)
self.assertEqual(prio1._level_priority, (3, 12))
prio1 = check_init_priorities.Priority("APPLICATION", 9999)
self.assertEqual(prio1._level_priority, (4, 9999))
with self.assertRaises(ValueError):
check_init_priorities.Priority("i-am-not-a-priority", 0)
check_init_priorities.Priority("_DOESNOTEXIST0_", 0)
def test_priority_levels(self):
prios = [
check_init_priorities.Priority("EARLY", 0),
check_init_priorities.Priority("EARLY", 1),
check_init_priorities.Priority("PRE_KERNEL_1", 0),
check_init_priorities.Priority("PRE_KERNEL_1", 1),
check_init_priorities.Priority("PRE_KERNEL_2", 0),
check_init_priorities.Priority("PRE_KERNEL_2", 1),
check_init_priorities.Priority("POST_KERNEL", 0),
check_init_priorities.Priority("POST_KERNEL", 1),
check_init_priorities.Priority("APPLICATION", 0),
check_init_priorities.Priority("APPLICATION", 1),
check_init_priorities.Priority("SMP", 0),
check_init_priorities.Priority("SMP", 1),
]
self.assertListEqual(prios, sorted(prios))
def test_priority_strings(self):
prio = check_init_priorities.Priority("POST_KERNEL", 12)
self.assertEqual(str(prio), "POST_KERNEL 12")
self.assertEqual(repr(prio), "<Priority POST_KERNEL 12>")
class testZephyrInitLevels(unittest.TestCase):
"""Tests for the ZephyrInitLevels class."""
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_load_objects(self, mock_zilinit):
mock_elf = mock.Mock()
sts = mock.Mock(spec=SymbolTableSection)
rel = mock.Mock(spec=Section)
mock_elf.iter_sections.return_value = [sts, rel]
s0 = mock.Mock()
s0.name = "a"
s0.entry.st_info.type = "STT_OBJECT"
s0.entry.st_size = 4
s0.entry.st_value = 0xaa
s0.entry.st_shndx = 1
s1 = mock.Mock()
s1.name = None
s2 = mock.Mock()
s2.name = "b"
s2.entry.st_info.type = "STT_FUNC"
s2.entry.st_size = 8
s2.entry.st_value = 0xbb
s2.entry.st_shndx = 2
sts.iter_symbols.return_value = [s0, s1, s2]
obj = check_init_priorities.ZephyrInitLevels("")
obj._elf = mock_elf
obj._load_objects()
self.assertDictEqual(obj._objects, {0xaa: ("a", 4, 1), 0xbb: ("b", 8, 2)})
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_load_level_addr(self, mock_zilinit):
mock_elf = mock.Mock()
sts = mock.Mock(spec=SymbolTableSection)
rel = mock.Mock(spec=Section)
mock_elf.iter_sections.return_value = [sts, rel]
s0 = mock.Mock()
s0.name = "__init_EARLY_start"
s0.entry.st_value = 0x00
s1 = mock.Mock()
s1.name = "__init_PRE_KERNEL_1_start"
s1.entry.st_value = 0x11
s2 = mock.Mock()
s2.name = "__init_PRE_KERNEL_2_start"
s2.entry.st_value = 0x22
s3 = mock.Mock()
s3.name = "__init_POST_KERNEL_start"
s3.entry.st_value = 0x33
s4 = mock.Mock()
s4.name = "__init_APPLICATION_start"
s4.entry.st_value = 0x44
s5 = mock.Mock()
s5.name = "__init_SMP_start"
s5.entry.st_value = 0x55
s6 = mock.Mock()
s6.name = "__init_end"
s6.entry.st_value = 0x66
sts.iter_symbols.return_value = [s0, s1, s2, s3, s4, s5, s6]
obj = check_init_priorities.ZephyrInitLevels("")
obj._elf = mock_elf
obj._load_level_addr()
self.assertDictEqual(obj._init_level_addr, {
"EARLY": 0x00,
"PRE_KERNEL_1": 0x11,
"PRE_KERNEL_2": 0x22,
"POST_KERNEL": 0x33,
"APPLICATION": 0x44,
"SMP": 0x55,
})
self.assertEqual(obj._init_level_end, 0x66)
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_device_ord_from_name(self, mock_zilinit):
obj = check_init_priorities.ZephyrInitLevels("")
self.assertEqual(obj._device_ord_from_name(None), None)
self.assertEqual(obj._device_ord_from_name("hey, hi!"), None)
self.assertEqual(obj._device_ord_from_name("__device_dts_ord_123"), 123)
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_object_name(self, mock_zilinit):
obj = check_init_priorities.ZephyrInitLevels("")
obj._objects = {0x123: ("name", 4)}
self.assertEqual(obj._object_name(0), "NULL")
self.assertEqual(obj._object_name(73), "unknown")
self.assertEqual(obj._object_name(0x123), "name")
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_initlevel_pointer_32(self, mock_zilinit):
obj = check_init_priorities.ZephyrInitLevels("")
obj._elf = mock.Mock()
obj._elf.elfclass = 32
mock_section = mock.Mock()
obj._elf.get_section.return_value = mock_section
mock_section.header.sh_addr = 0x100
mock_section.data.return_value = (b"\x01\x00\x00\x00"
b"\x02\x00\x00\x00"
b"\x03\x00\x00\x00")
self.assertEqual(obj._initlevel_pointer(0x100, 0, 0), 1)
self.assertEqual(obj._initlevel_pointer(0x100, 1, 0), 2)
self.assertEqual(obj._initlevel_pointer(0x104, 0, 0), 2)
self.assertEqual(obj._initlevel_pointer(0x104, 1, 0), 3)
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_initlevel_pointer_64(self, mock_zilinit):
obj = check_init_priorities.ZephyrInitLevels("")
obj._elf = mock.Mock()
obj._elf.elfclass = 64
mock_section = mock.Mock()
obj._elf.get_section.return_value = mock_section
mock_section.header.sh_addr = 0x100
mock_section.data.return_value = (b"\x01\x00\x00\x00\x00\x00\x00\x00"
b"\x02\x00\x00\x00\x00\x00\x00\x00"
b"\x03\x00\x00\x00\x00\x00\x00\x00")
self.assertEqual(obj._initlevel_pointer(0x100, 0, 0), 1)
self.assertEqual(obj._initlevel_pointer(0x100, 1, 0), 2)
self.assertEqual(obj._initlevel_pointer(0x108, 0, 0), 2)
self.assertEqual(obj._initlevel_pointer(0x108, 1, 0), 3)
@mock.patch("check_init_priorities.ZephyrInitLevels._object_name")
@mock.patch("check_init_priorities.ZephyrInitLevels._initlevel_pointer")
@mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None)
def test_process_initlevels(self, mock_zilinit, mock_ip, mock_on):
obj = check_init_priorities.ZephyrInitLevels("")
obj._init_level_addr = {
"EARLY": 0x00,
"PRE_KERNEL_1": 0x00,
"PRE_KERNEL_2": 0x00,
"POST_KERNEL": 0x08,
"APPLICATION": 0x0c,
"SMP": 0x0c,
}
obj._init_level_end = 0x0c
obj._objects = {
0x00: ("a", 4, 0),
0x04: ("b", 4, 0),
0x08: ("c", 4, 0),
}
mock_ip.side_effect = lambda *args: args
def mock_obj_name(*args):
if args[0] == (0, 0, 0):
return "i0"
elif args[0] == (0, 1, 0):
return "__device_dts_ord_11"
elif args[0] == (4, 0, 0):
return "i1"
elif args[0] == (4, 1, 0):
return "__device_dts_ord_22"
return f"name_{args[0][0]}_{args[0][1]}"
mock_on.side_effect = mock_obj_name
obj._process_initlevels()
self.assertDictEqual(obj.initlevels, {
"EARLY": [],
"PRE_KERNEL_1": [],
"PRE_KERNEL_2": ["a: i0(__device_dts_ord_11)", "b: i1(__device_dts_ord_22)"],
"POST_KERNEL": ["c: name_8_0(name_8_1)"],
"APPLICATION": [],
"SMP": [],
})
self.assertDictEqual(obj.devices, {
11: check_init_priorities.Priority("PRE_KERNEL_2", 0),
22: check_init_priorities.Priority("PRE_KERNEL_2", 1),
})
class testValidator(unittest.TestCase):
"""Tests for the Validator class."""
@mock.patch("check_init_priorities.ZephyrInitLevels")
@mock.patch("pickle.load")
def test_initialize(self, mock_pl, mock_zil):
mock_log = mock.Mock()
mock_prio = mock.Mock()
mock_obj = mock.Mock()
mock_obj.defined_devices = {123: mock_prio}
mock_zil.return_value = mock_obj
with mock.patch("builtins.open", mock.mock_open()) as mock_open:
validator = check_init_priorities.Validator("path", "pickle", mock_log)
self.assertEqual(validator._obj, mock_obj)
mock_zil.assert_called_once_with("path")
mock_open.assert_called_once_with(pathlib.Path("pickle"), "rb")
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check_dep_same_node(self, mock_vinit):
validator = check_init_priorities.Validator("", "", None)
validator.log = mock.Mock()
validator._check_dep(123, 123)
self.assertFalse(validator.log.info.called)
self.assertFalse(validator.log.warning.called)
self.assertFalse(validator.log.error.called)
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check_dep_no_prio(self, mock_vinit):
validator = check_init_priorities.Validator("", "", None)
validator.log = mock.Mock()
validator._obj = mock.Mock()
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
validator._ord2node[1]._binding = None
validator._ord2node[2]._binding = None
validator._obj.devices = {1: 10}
validator._check_dep(1, 2)
validator._obj.devices = {2: 20}
validator._check_dep(1, 2)
self.assertFalse(validator.log.info.called)
self.assertFalse(validator.log.warning.called)
self.assertFalse(validator.log.error.called)
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check(self, mock_vinit):
validator = check_init_priorities.Validator("", "", None)
validator.log = mock.Mock()
validator._obj = mock.Mock()
validator.errors = 0
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
validator._ord2node[1]._binding = None
validator._ord2node[1].path = "/1"
validator._ord2node[2]._binding = None
validator._ord2node[2].path = "/2"
validator._obj.devices = {1: 10, 2: 20}
validator._check_dep(2, 1)
validator._check_dep(1, 2)
validator.log.info.assert_called_once_with("/2 20 > /1 10")
validator.log.error.assert_called_once_with("/1 10 < /2 20")
self.assertEqual(validator.errors, 1)
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check_same_prio_assert(self, mock_vinit):
validator = check_init_priorities.Validator("", "", None)
validator.log = mock.Mock()
validator._obj = mock.Mock()
validator.errors = 0
validator._ord2node = {1: mock.Mock(), 2: mock.Mock()}
validator._ord2node[1]._binding = None
validator._ord2node[1].path = "/1"
validator._ord2node[2]._binding = None
validator._ord2node[2].path = "/2"
validator._obj.devices = {1: 10, 2: 10}
with self.assertRaises(ValueError):
validator._check_dep(1, 2)
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check_swapped(self, mock_vinit):
validator = check_init_priorities.Validator("", "", None)
validator.log = mock.Mock()
validator._obj = mock.Mock()
validator.errors = 0
save_inverted_priorities = check_init_priorities._INVERTED_PRIORITY_COMPATIBLES
check_init_priorities._INVERTED_PRIORITY_COMPATIBLES = set([("compat-3", "compat-1")])
validator._ord2node = {1: mock.Mock(), 3: mock.Mock()}
validator._ord2node[1]._binding.compatible = "compat-1"
validator._ord2node[1].path = "/1"
validator._ord2node[3]._binding.compatible = "compat-3"
validator._ord2node[3].path = "/3"
validator._obj.devices = {1: 20, 3: 10}
validator._check_dep(3, 1)
self.assertListEqual(validator.log.info.call_args_list, [
mock.call("Swapped priority: compat-3, compat-1"),
mock.call("/3 20 > /1 10"),
])
self.assertEqual(validator.errors, 0)
check_init_priorities._INVERTED_PRIORITY_COMPATIBLES = save_inverted_priorities
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check_ignored(self, mock_vinit):
validator = check_init_priorities.Validator("", "", None)
validator.log = mock.Mock()
validator._obj = mock.Mock()
validator.errors = 0
save_ignore_compatibles = check_init_priorities._IGNORE_COMPATIBLES
check_init_priorities._IGNORE_COMPATIBLES = set(["compat-3"])
validator._ord2node = {1: mock.Mock(), 3: mock.Mock()}
validator._ord2node[1]._binding.compatible = "compat-1"
validator._ord2node[1].path = "/1"
validator._ord2node[3]._binding.compatible = "compat-3"
validator._ord2node[3].path = "/3"
validator._obj.devices = {1: 20, 3: 10}
validator._check_dep(3, 1)
self.assertListEqual(validator.log.info.call_args_list, [
mock.call("Ignoring priority: compat-3"),
])
self.assertEqual(validator.errors, 0)
check_init_priorities._IGNORE_COMPATIBLES = save_ignore_compatibles
@mock.patch("check_init_priorities.Validator._check_dep")
@mock.patch("check_init_priorities.Validator.__init__", return_value=None)
def test_check_edt(self, mock_vinit, mock_cd):
d0 = mock.Mock()
d0.dep_ordinal = 1
d1 = mock.Mock()
d1.dep_ordinal = 2
d2 = mock.Mock()
d2.dep_ordinal = 3
dev0 = mock.Mock()
dev0.depends_on = [d0]
dev1 = mock.Mock()
dev1.depends_on = [d1]
dev2 = mock.Mock()
dev2.depends_on = [d2]
validator = check_init_priorities.Validator("", "", None)
validator._ord2node = {1: dev0, 2: dev1, 3: dev2}
validator._obj = mock.Mock()
validator._obj.devices = {1: 10, 2: 10, 3: 20}
validator.check_edt()
self.assertListEqual(mock_cd.call_args_list, [
mock.call(1, 1),
mock.call(2, 2),
mock.call(3, 3),
])
if __name__ == "__main__":
unittest.main()