#!/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), "") 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), "i0"), 22: (check_init_priorities.Priority("PRE_KERNEL_2", 1), "i1"), }) 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, "i1")} validator._check_dep(1, 2) validator._obj.devices = {2: (20, "i2")} 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, "i1"), 2: (20, "i2")} 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_has_calls([ mock.call("/1 is initialized before its dependency /2 (10 < 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, "i1"), 2: (10, "i2")} with self.assertRaises(ValueError): validator._check_dep(1, 2) @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()