1#!/usr/bin/env python3 2 3# Copyright 2023 Google LLC 4# SPDX-License-Identifier: Apache-2.0 5""" 6Tests for check_init_priorities 7""" 8 9import mock 10import pathlib 11import unittest 12 13from elftools.elf.relocation import Section 14from elftools.elf.sections import SymbolTableSection 15 16import check_init_priorities 17 18class TestPriority(unittest.TestCase): 19 """Tests for the Priority class.""" 20 21 def test_priority_parsing(self): 22 prio1 = check_init_priorities.Priority("POST_KERNEL", 12) 23 self.assertEqual(prio1._level_priority, (3, 12)) 24 25 prio1 = check_init_priorities.Priority("APPLICATION", 9999) 26 self.assertEqual(prio1._level_priority, (4, 9999)) 27 28 with self.assertRaises(ValueError): 29 check_init_priorities.Priority("i-am-not-a-priority", 0) 30 check_init_priorities.Priority("_DOESNOTEXIST0_", 0) 31 32 def test_priority_levels(self): 33 prios = [ 34 check_init_priorities.Priority("EARLY", 0), 35 check_init_priorities.Priority("EARLY", 1), 36 check_init_priorities.Priority("PRE_KERNEL_1", 0), 37 check_init_priorities.Priority("PRE_KERNEL_1", 1), 38 check_init_priorities.Priority("PRE_KERNEL_2", 0), 39 check_init_priorities.Priority("PRE_KERNEL_2", 1), 40 check_init_priorities.Priority("POST_KERNEL", 0), 41 check_init_priorities.Priority("POST_KERNEL", 1), 42 check_init_priorities.Priority("APPLICATION", 0), 43 check_init_priorities.Priority("APPLICATION", 1), 44 check_init_priorities.Priority("SMP", 0), 45 check_init_priorities.Priority("SMP", 1), 46 ] 47 48 self.assertListEqual(prios, sorted(prios)) 49 50 def test_priority_strings(self): 51 prio = check_init_priorities.Priority("POST_KERNEL", 12) 52 self.assertEqual(str(prio), "POST_KERNEL+12") 53 self.assertEqual(repr(prio), "<Priority POST_KERNEL 12>") 54 55class testZephyrInitLevels(unittest.TestCase): 56 """Tests for the ZephyrInitLevels class.""" 57 58 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 59 def test_load_objects(self, mock_zilinit): 60 mock_elf = mock.Mock() 61 62 sts = mock.Mock(spec=SymbolTableSection) 63 rel = mock.Mock(spec=Section) 64 mock_elf.iter_sections.return_value = [sts, rel] 65 66 s0 = mock.Mock() 67 s0.name = "a" 68 s0.entry.st_info.type = "STT_OBJECT" 69 s0.entry.st_size = 4 70 s0.entry.st_value = 0xaa 71 s0.entry.st_shndx = 1 72 73 s1 = mock.Mock() 74 s1.name = None 75 76 s2 = mock.Mock() 77 s2.name = "b" 78 s2.entry.st_info.type = "STT_FUNC" 79 s2.entry.st_size = 8 80 s2.entry.st_value = 0xbb 81 s2.entry.st_shndx = 2 82 83 sts.iter_symbols.return_value = [s0, s1, s2] 84 85 obj = check_init_priorities.ZephyrInitLevels("") 86 obj._elf = mock_elf 87 obj._load_objects() 88 89 self.assertDictEqual(obj._objects, {0xaa: ("a", 4, 1), 0xbb: ("b", 8, 2)}) 90 91 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 92 def test_load_level_addr(self, mock_zilinit): 93 mock_elf = mock.Mock() 94 95 sts = mock.Mock(spec=SymbolTableSection) 96 rel = mock.Mock(spec=Section) 97 mock_elf.iter_sections.return_value = [sts, rel] 98 99 s0 = mock.Mock() 100 s0.name = "__init_EARLY_start" 101 s0.entry.st_value = 0x00 102 103 s1 = mock.Mock() 104 s1.name = "__init_PRE_KERNEL_1_start" 105 s1.entry.st_value = 0x11 106 107 s2 = mock.Mock() 108 s2.name = "__init_PRE_KERNEL_2_start" 109 s2.entry.st_value = 0x22 110 111 s3 = mock.Mock() 112 s3.name = "__init_POST_KERNEL_start" 113 s3.entry.st_value = 0x33 114 115 s4 = mock.Mock() 116 s4.name = "__init_APPLICATION_start" 117 s4.entry.st_value = 0x44 118 119 s5 = mock.Mock() 120 s5.name = "__init_SMP_start" 121 s5.entry.st_value = 0x55 122 123 s6 = mock.Mock() 124 s6.name = "__init_end" 125 s6.entry.st_value = 0x66 126 127 sts.iter_symbols.return_value = [s0, s1, s2, s3, s4, s5, s6] 128 129 obj = check_init_priorities.ZephyrInitLevels("") 130 obj._elf = mock_elf 131 obj._load_level_addr() 132 133 self.assertDictEqual(obj._init_level_addr, { 134 "EARLY": 0x00, 135 "PRE_KERNEL_1": 0x11, 136 "PRE_KERNEL_2": 0x22, 137 "POST_KERNEL": 0x33, 138 "APPLICATION": 0x44, 139 "SMP": 0x55, 140 }) 141 self.assertEqual(obj._init_level_end, 0x66) 142 143 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 144 def test_device_ord_from_name(self, mock_zilinit): 145 obj = check_init_priorities.ZephyrInitLevels("") 146 147 self.assertEqual(obj._device_ord_from_name(None), None) 148 self.assertEqual(obj._device_ord_from_name("hey, hi!"), None) 149 self.assertEqual(obj._device_ord_from_name("__device_dts_ord_123"), 123) 150 151 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 152 def test_object_name(self, mock_zilinit): 153 obj = check_init_priorities.ZephyrInitLevels("") 154 obj._objects = {0x123: ("name", 4)} 155 156 self.assertEqual(obj._object_name(0), "NULL") 157 self.assertEqual(obj._object_name(73), "unknown") 158 self.assertEqual(obj._object_name(0x123), "name") 159 160 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 161 def test_initlevel_pointer_32(self, mock_zilinit): 162 obj = check_init_priorities.ZephyrInitLevels("") 163 obj._elf = mock.Mock() 164 obj._elf.elfclass = 32 165 mock_section = mock.Mock() 166 obj._elf.get_section.return_value = mock_section 167 mock_section.header.sh_addr = 0x100 168 mock_section.data.return_value = (b"\x01\x00\x00\x00" 169 b"\x02\x00\x00\x00" 170 b"\x03\x00\x00\x00") 171 172 self.assertEqual(obj._initlevel_pointer(0x100, 0, 0), 1) 173 self.assertEqual(obj._initlevel_pointer(0x100, 1, 0), 2) 174 self.assertEqual(obj._initlevel_pointer(0x104, 0, 0), 2) 175 self.assertEqual(obj._initlevel_pointer(0x104, 1, 0), 3) 176 177 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 178 def test_initlevel_pointer_64(self, mock_zilinit): 179 obj = check_init_priorities.ZephyrInitLevels("") 180 obj._elf = mock.Mock() 181 obj._elf.elfclass = 64 182 mock_section = mock.Mock() 183 obj._elf.get_section.return_value = mock_section 184 mock_section.header.sh_addr = 0x100 185 mock_section.data.return_value = (b"\x01\x00\x00\x00\x00\x00\x00\x00" 186 b"\x02\x00\x00\x00\x00\x00\x00\x00" 187 b"\x03\x00\x00\x00\x00\x00\x00\x00") 188 189 self.assertEqual(obj._initlevel_pointer(0x100, 0, 0), 1) 190 self.assertEqual(obj._initlevel_pointer(0x100, 1, 0), 2) 191 self.assertEqual(obj._initlevel_pointer(0x108, 0, 0), 2) 192 self.assertEqual(obj._initlevel_pointer(0x108, 1, 0), 3) 193 194 @mock.patch("check_init_priorities.ZephyrInitLevels._object_name") 195 @mock.patch("check_init_priorities.ZephyrInitLevels._initlevel_pointer") 196 @mock.patch("check_init_priorities.ZephyrInitLevels.__init__", return_value=None) 197 def test_process_initlevels(self, mock_zilinit, mock_ip, mock_on): 198 obj = check_init_priorities.ZephyrInitLevels("") 199 obj._init_level_addr = { 200 "EARLY": 0x00, 201 "PRE_KERNEL_1": 0x00, 202 "PRE_KERNEL_2": 0x00, 203 "POST_KERNEL": 0x08, 204 "APPLICATION": 0x0c, 205 "SMP": 0x0c, 206 } 207 obj._init_level_end = 0x0c 208 obj._objects = { 209 0x00: ("a", 4, 0), 210 0x04: ("b", 4, 0), 211 0x08: ("c", 4, 0), 212 } 213 214 mock_ip.side_effect = lambda *args: args 215 216 def mock_obj_name(*args): 217 if args[0] == (0, 0, 0): 218 return "i0" 219 elif args[0] == (0, 1, 0): 220 return "__device_dts_ord_11" 221 elif args[0] == (4, 0, 0): 222 return "i1" 223 elif args[0] == (4, 1, 0): 224 return "__device_dts_ord_22" 225 return f"name_{args[0][0]}_{args[0][1]}" 226 mock_on.side_effect = mock_obj_name 227 228 obj._process_initlevels() 229 230 self.assertDictEqual(obj.initlevels, { 231 "EARLY": [], 232 "PRE_KERNEL_1": [], 233 "PRE_KERNEL_2": ["a: i0(__device_dts_ord_11)", "b: i1(__device_dts_ord_22)"], 234 "POST_KERNEL": ["c: name_8_0(name_8_1)"], 235 "APPLICATION": [], 236 "SMP": [], 237 }) 238 self.assertDictEqual(obj.devices, { 239 11: (check_init_priorities.Priority("PRE_KERNEL_2", 0), "i0"), 240 22: (check_init_priorities.Priority("PRE_KERNEL_2", 1), "i1"), 241 }) 242 243class testValidator(unittest.TestCase): 244 """Tests for the Validator class.""" 245 246 @mock.patch("check_init_priorities.ZephyrInitLevels") 247 @mock.patch("pickle.load") 248 def test_initialize(self, mock_pl, mock_zil): 249 mock_log = mock.Mock() 250 mock_prio = mock.Mock() 251 mock_obj = mock.Mock() 252 mock_obj.defined_devices = {123: mock_prio} 253 mock_zil.return_value = mock_obj 254 255 with mock.patch("builtins.open", mock.mock_open()) as mock_open: 256 validator = check_init_priorities.Validator("path", "pickle", mock_log) 257 258 self.assertEqual(validator._obj, mock_obj) 259 mock_zil.assert_called_once_with("path") 260 mock_open.assert_called_once_with(pathlib.Path("pickle"), "rb") 261 262 @mock.patch("check_init_priorities.Validator.__init__", return_value=None) 263 def test_check_dep_same_node(self, mock_vinit): 264 validator = check_init_priorities.Validator("", "", None) 265 validator.log = mock.Mock() 266 267 validator._check_dep(123, 123) 268 269 self.assertFalse(validator.log.info.called) 270 self.assertFalse(validator.log.warning.called) 271 self.assertFalse(validator.log.error.called) 272 273 @mock.patch("check_init_priorities.Validator.__init__", return_value=None) 274 def test_check_dep_no_prio(self, mock_vinit): 275 validator = check_init_priorities.Validator("", "", None) 276 validator.log = mock.Mock() 277 validator._obj = mock.Mock() 278 279 validator._ord2node = {1: mock.Mock(), 2: mock.Mock()} 280 validator._ord2node[1]._binding = None 281 validator._ord2node[2]._binding = None 282 283 validator._obj.devices = {1: (10, "i1")} 284 validator._check_dep(1, 2) 285 286 validator._obj.devices = {2: (20, "i2")} 287 validator._check_dep(1, 2) 288 289 self.assertFalse(validator.log.info.called) 290 self.assertFalse(validator.log.warning.called) 291 self.assertFalse(validator.log.error.called) 292 293 @mock.patch("check_init_priorities.Validator.__init__", return_value=None) 294 def test_check(self, mock_vinit): 295 validator = check_init_priorities.Validator("", "", None) 296 validator.log = mock.Mock() 297 validator._obj = mock.Mock() 298 validator.errors = 0 299 300 validator._ord2node = {1: mock.Mock(), 2: mock.Mock()} 301 validator._ord2node[1]._binding = None 302 validator._ord2node[1].path = "/1" 303 validator._ord2node[2]._binding = None 304 validator._ord2node[2].path = "/2" 305 306 validator._obj.devices = {1: (10, "i1"), 2: (20, "i2")} 307 308 validator._check_dep(2, 1) 309 validator._check_dep(1, 2) 310 311 validator.log.info.assert_called_once_with("/2 <i2> 20 > /1 <i1> 10") 312 validator.log.error.assert_has_calls([ 313 mock.call("/1 <i1> is initialized before its dependency /2 <i2> (10 < 20)") 314 ]) 315 self.assertEqual(validator.errors, 1) 316 317 @mock.patch("check_init_priorities.Validator.__init__", return_value=None) 318 def test_check_same_prio_assert(self, mock_vinit): 319 validator = check_init_priorities.Validator("", "", None) 320 validator.log = mock.Mock() 321 validator._obj = mock.Mock() 322 validator.errors = 0 323 324 validator._ord2node = {1: mock.Mock(), 2: mock.Mock()} 325 validator._ord2node[1]._binding = None 326 validator._ord2node[1].path = "/1" 327 validator._ord2node[2]._binding = None 328 validator._ord2node[2].path = "/2" 329 330 validator._obj.devices = {1: (10, "i1"), 2: (10, "i2")} 331 332 with self.assertRaises(ValueError): 333 validator._check_dep(1, 2) 334 335 @mock.patch("check_init_priorities.Validator.__init__", return_value=None) 336 def test_check_ignored(self, mock_vinit): 337 validator = check_init_priorities.Validator("", "", None) 338 validator.log = mock.Mock() 339 validator._obj = mock.Mock() 340 validator.errors = 0 341 342 save_ignore_compatibles = check_init_priorities._IGNORE_COMPATIBLES 343 344 check_init_priorities._IGNORE_COMPATIBLES = set(["compat-3"]) 345 346 validator._ord2node = {1: mock.Mock(), 3: mock.Mock()} 347 validator._ord2node[1]._binding.compatible = "compat-1" 348 validator._ord2node[1].path = "/1" 349 validator._ord2node[3]._binding.compatible = "compat-3" 350 validator._ord2node[3].path = "/3" 351 352 validator._obj.devices = {1: 20, 3: 10} 353 354 validator._check_dep(3, 1) 355 356 self.assertListEqual(validator.log.info.call_args_list, [ 357 mock.call("Ignoring priority: compat-3"), 358 ]) 359 self.assertEqual(validator.errors, 0) 360 361 check_init_priorities._IGNORE_COMPATIBLES = save_ignore_compatibles 362 363 @mock.patch("check_init_priorities.Validator._check_dep") 364 @mock.patch("check_init_priorities.Validator.__init__", return_value=None) 365 def test_check_edt(self, mock_vinit, mock_cd): 366 d0 = mock.Mock() 367 d0.dep_ordinal = 1 368 d1 = mock.Mock() 369 d1.dep_ordinal = 2 370 d2 = mock.Mock() 371 d2.dep_ordinal = 3 372 373 dev0 = mock.Mock() 374 dev0.depends_on = [d0] 375 dev1 = mock.Mock() 376 dev1.depends_on = [d1] 377 dev2 = mock.Mock() 378 dev2.depends_on = [d2] 379 380 validator = check_init_priorities.Validator("", "", None) 381 validator._ord2node = {1: dev0, 2: dev1, 3: dev2} 382 validator._obj = mock.Mock() 383 validator._obj.devices = {1: 10, 2: 10, 3: 20} 384 385 validator.check_edt() 386 387 self.assertListEqual(mock_cd.call_args_list, [ 388 mock.call(1, 1), 389 mock.call(2, 2), 390 mock.call(3, 3), 391 ]) 392 393if __name__ == "__main__": 394 unittest.main() 395