1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright 2012 The ChromiumOS Authors 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7 8"""Unittest for machine_manager.""" 9 10 11import hashlib 12import os.path 13import time 14import unittest 15import unittest.mock as mock 16 17from benchmark import Benchmark 18from benchmark_run import MockBenchmarkRun 19from cros_utils import command_executer 20from cros_utils import logger 21import image_checksummer 22import label 23import machine_manager 24import test_flag 25 26 27# pylint: disable=protected-access 28 29 30class MyMachineManager(machine_manager.MachineManager): 31 """Machine manager for test.""" 32 33 def __init__(self, chromeos_root): 34 super(MyMachineManager, self).__init__(chromeos_root, 0, "average", "") 35 36 def _TryToLockMachine(self, cros_machine): 37 self._machines.append(cros_machine) 38 cros_machine.checksum = "" 39 40 def AddMachine(self, machine_name): 41 with self._lock: 42 for m in self._all_machines: 43 assert m.name != machine_name, ( 44 "Tried to double-add %s" % machine_name 45 ) 46 cm = machine_manager.MockCrosMachine( 47 machine_name, self.chromeos_root, "average" 48 ) 49 assert cm.machine_checksum, ( 50 "Could not find checksum for machine %s" % machine_name 51 ) 52 self._all_machines.append(cm) 53 54 55CHROMEOS_ROOT = "/tmp/chromeos-root" 56MACHINE_NAMES = ["lumpy1", "lumpy2", "lumpy3", "daisy1", "daisy2"] 57LABEL_LUMPY = label.MockLabel( 58 "lumpy", 59 "build", 60 "lumpy_chromeos_image", 61 "autotest_dir", 62 "debug_dir", 63 CHROMEOS_ROOT, 64 "lumpy", 65 ["lumpy1", "lumpy2", "lumpy3", "lumpy4"], 66 "", 67 "", 68 False, 69 "average", 70 "gcc", 71 False, 72 None, 73) 74LABEL_MIX = label.MockLabel( 75 "mix", 76 "build", 77 "chromeos_image", 78 "autotest_dir", 79 "debug_dir", 80 CHROMEOS_ROOT, 81 "mix", 82 ["daisy1", "daisy2", "lumpy3", "lumpy4"], 83 "", 84 "", 85 False, 86 "average", 87 "gcc", 88 False, 89 None, 90) 91 92 93class MachineManagerTest(unittest.TestCase): 94 """Test for machine manager class.""" 95 96 msgs = [] 97 image_log = [] 98 log_fatal_msgs = [] 99 fake_logger_count = 0 100 fake_logger_msgs = [] 101 102 mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter) 103 104 mock_logger = mock.Mock(spec=logger.Logger) 105 106 mock_lumpy1 = mock.Mock(spec=machine_manager.CrosMachine) 107 mock_lumpy2 = mock.Mock(spec=machine_manager.CrosMachine) 108 mock_lumpy3 = mock.Mock(spec=machine_manager.CrosMachine) 109 mock_lumpy4 = mock.Mock(spec=machine_manager.CrosMachine) 110 mock_daisy1 = mock.Mock(spec=machine_manager.CrosMachine) 111 mock_daisy2 = mock.Mock(spec=machine_manager.CrosMachine) 112 113 @mock.patch.object(os.path, "isdir") 114 115 # pylint: disable=arguments-differ 116 def setUp(self, mock_isdir): 117 118 mock_isdir.return_value = True 119 self.mm = machine_manager.MachineManager( 120 "/usr/local/chromeos", 121 0, 122 "average", 123 None, 124 self.mock_cmd_exec, 125 self.mock_logger, 126 ) 127 128 self.mock_lumpy1.name = "lumpy1" 129 self.mock_lumpy2.name = "lumpy2" 130 self.mock_lumpy3.name = "lumpy3" 131 self.mock_lumpy4.name = "lumpy4" 132 self.mock_daisy1.name = "daisy1" 133 self.mock_daisy2.name = "daisy2" 134 self.mock_lumpy1.machine_checksum = "lumpy123" 135 self.mock_lumpy2.machine_checksum = "lumpy123" 136 self.mock_lumpy3.machine_checksum = "lumpy123" 137 self.mock_lumpy4.machine_checksum = "lumpy123" 138 self.mock_daisy1.machine_checksum = "daisy12" 139 self.mock_daisy2.machine_checksum = "daisy12" 140 self.mock_lumpy1.checksum_string = "lumpy_checksum_str" 141 self.mock_lumpy2.checksum_string = "lumpy_checksum_str" 142 self.mock_lumpy3.checksum_string = "lumpy_checksum_str" 143 self.mock_lumpy4.checksum_string = "lumpy_checksum_str" 144 self.mock_daisy1.checksum_string = "daisy_checksum_str" 145 self.mock_daisy2.checksum_string = "daisy_checksum_str" 146 self.mock_lumpy1.cpuinfo = "lumpy_cpu_info" 147 self.mock_lumpy2.cpuinfo = "lumpy_cpu_info" 148 self.mock_lumpy3.cpuinfo = "lumpy_cpu_info" 149 self.mock_lumpy4.cpuinfo = "lumpy_cpu_info" 150 self.mock_daisy1.cpuinfo = "daisy_cpu_info" 151 self.mock_daisy2.cpuinfo = "daisy_cpu_info" 152 self.mm._all_machines.append(self.mock_daisy1) 153 self.mm._all_machines.append(self.mock_daisy2) 154 self.mm._all_machines.append(self.mock_lumpy1) 155 self.mm._all_machines.append(self.mock_lumpy2) 156 self.mm._all_machines.append(self.mock_lumpy3) 157 158 def testGetMachines(self): 159 manager = MyMachineManager(CHROMEOS_ROOT) 160 for m in MACHINE_NAMES: 161 manager.AddMachine(m) 162 names = [m.name for m in manager.GetMachines(LABEL_LUMPY)] 163 self.assertEqual(names, ["lumpy1", "lumpy2", "lumpy3"]) 164 165 def testGetAvailableMachines(self): 166 manager = MyMachineManager(CHROMEOS_ROOT) 167 for m in MACHINE_NAMES: 168 manager.AddMachine(m) 169 for m in manager._all_machines: 170 if int(m.name[-1]) % 2: 171 manager._TryToLockMachine(m) 172 names = [m.name for m in manager.GetAvailableMachines(LABEL_LUMPY)] 173 self.assertEqual(names, ["lumpy1", "lumpy3"]) 174 175 @mock.patch.object(time, "sleep") 176 @mock.patch.object(command_executer.CommandExecuter, "RunCommand") 177 @mock.patch.object(command_executer.CommandExecuter, "CrosRunCommand") 178 @mock.patch.object(image_checksummer.ImageChecksummer, "Checksum") 179 def test_image_machine( 180 self, mock_checksummer, mock_run_croscmd, mock_run_cmd, mock_sleep 181 ): 182 def FakeMD5Checksum(_input_str): 183 return "machine_fake_md5_checksum" 184 185 self.fake_logger_count = 0 186 self.fake_logger_msgs = [] 187 188 def FakeLogOutput(msg): 189 self.fake_logger_count += 1 190 self.fake_logger_msgs.append(msg) 191 192 def ResetValues(): 193 self.fake_logger_count = 0 194 self.fake_logger_msgs = [] 195 mock_run_cmd.reset_mock() 196 mock_run_croscmd.reset_mock() 197 mock_checksummer.reset_mock() 198 mock_sleep.reset_mock() 199 machine.checksum = "fake_md5_checksum" 200 self.mm.checksum = None 201 self.mm.num_reimages = 0 202 203 self.mock_cmd_exec.CrosRunCommand = mock_run_croscmd 204 self.mock_cmd_exec.RunCommand = mock_run_cmd 205 206 self.mm.logger.LogOutput = FakeLogOutput 207 machine = self.mock_lumpy1 208 machine._GetMD5Checksum = FakeMD5Checksum 209 machine.checksum = "fake_md5_checksum" 210 mock_checksummer.return_value = "fake_md5_checksum" 211 self.mock_cmd_exec.log_level = "verbose" 212 213 test_flag.SetTestMode(True) 214 # Test 1: label.image_type == "local" 215 LABEL_LUMPY.image_type = "local" 216 self.mm.ImageMachine(machine, LABEL_LUMPY) 217 self.assertEqual(mock_run_cmd.call_count, 0) 218 self.assertEqual(mock_run_croscmd.call_count, 0) 219 220 # Test 2: label.image_type == "trybot" 221 ResetValues() 222 LABEL_LUMPY.image_type = "trybot" 223 mock_run_cmd.return_value = 0 224 self.mm.ImageMachine(machine, LABEL_LUMPY) 225 self.assertEqual(mock_run_croscmd.call_count, 0) 226 self.assertEqual(mock_checksummer.call_count, 0) 227 228 # Test 3: label.image_type is neither local nor trybot; retval from 229 # RunCommand is 1, i.e. image_chromeos fails... 230 ResetValues() 231 LABEL_LUMPY.image_type = "other" 232 mock_run_cmd.return_value = 1 233 try: 234 self.mm.ImageMachine(machine, LABEL_LUMPY) 235 except RuntimeError: 236 self.assertEqual(mock_checksummer.call_count, 0) 237 self.assertEqual(mock_run_cmd.call_count, 2) 238 self.assertEqual(mock_run_croscmd.call_count, 1) 239 self.assertEqual(mock_sleep.call_count, 1) 240 image_call_args_str = mock_run_cmd.call_args[0][0] 241 image_call_args = image_call_args_str.split(" ") 242 self.assertEqual(image_call_args[0], "python") 243 self.assertEqual( 244 image_call_args[1].split("/")[-1], "image_chromeos.pyc" 245 ) 246 image_call_args = image_call_args[2:] 247 self.assertEqual( 248 image_call_args, 249 [ 250 "--chromeos_root=/tmp/chromeos-root", 251 "--image=lumpy_chromeos_image", 252 "--image_args=", 253 "--remote=lumpy1", 254 "--logging_level=average", 255 "--board=lumpy", 256 ], 257 ) 258 self.assertEqual(mock_run_croscmd.call_args[0][0], "reboot && exit") 259 260 # Test 4: Everything works properly. Trybot image type. 261 ResetValues() 262 LABEL_LUMPY.image_type = "trybot" 263 mock_run_cmd.return_value = 0 264 self.mm.ImageMachine(machine, LABEL_LUMPY) 265 self.assertEqual(mock_checksummer.call_count, 0) 266 self.assertEqual(mock_run_croscmd.call_count, 0) 267 self.assertEqual(mock_sleep.call_count, 0) 268 269 def test_compute_common_checksum(self): 270 self.mm.machine_checksum = {} 271 self.mm.ComputeCommonCheckSum(LABEL_LUMPY) 272 self.assertEqual(self.mm.machine_checksum["lumpy"], "lumpy123") 273 self.assertEqual(len(self.mm.machine_checksum), 1) 274 275 self.mm.machine_checksum = {} 276 self.assertRaisesRegex( 277 machine_manager.BadChecksum, 278 r"daisy.*\n.*lumpy", 279 self.mm.ComputeCommonCheckSum, 280 LABEL_MIX, 281 ) 282 283 def test_compute_common_checksum_string(self): 284 self.mm.machine_checksum_string = {} 285 self.mm.ComputeCommonCheckSumString(LABEL_LUMPY) 286 self.assertEqual(len(self.mm.machine_checksum_string), 1) 287 self.assertEqual( 288 self.mm.machine_checksum_string["lumpy"], "lumpy_checksum_str" 289 ) 290 291 self.mm.machine_checksum_string = {} 292 self.mm.ComputeCommonCheckSumString(LABEL_MIX) 293 self.assertEqual(len(self.mm.machine_checksum_string), 1) 294 self.assertEqual( 295 self.mm.machine_checksum_string["mix"], "daisy_checksum_str" 296 ) 297 298 @mock.patch.object( 299 command_executer.CommandExecuter, "CrosRunCommandWOutput" 300 ) 301 def test_try_to_lock_machine(self, mock_cros_runcmd): 302 mock_cros_runcmd.return_value = [0, "false_lock_checksum", ""] 303 self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd 304 self.mm._machines = [] 305 self.mm._TryToLockMachine(self.mock_lumpy1) 306 self.assertEqual(len(self.mm._machines), 1) 307 self.assertEqual(self.mm._machines[0], self.mock_lumpy1) 308 self.assertEqual(self.mock_lumpy1.checksum, "false_lock_checksum") 309 self.assertEqual(mock_cros_runcmd.call_count, 1) 310 cmd_str = mock_cros_runcmd.call_args[0][0] 311 self.assertEqual(cmd_str, "cat /usr/local/osimage_checksum_file") 312 args_dict = mock_cros_runcmd.call_args[1] 313 self.assertEqual(len(args_dict), 2) 314 self.assertEqual(args_dict["machine"], self.mock_lumpy1.name) 315 self.assertEqual(args_dict["chromeos_root"], "/usr/local/chromeos") 316 317 @mock.patch.object(machine_manager, "CrosMachine") 318 def test_add_machine(self, mock_machine): 319 320 mock_machine.machine_checksum = "daisy123" 321 self.assertEqual(len(self.mm._all_machines), 5) 322 self.mm.AddMachine("daisy3") 323 self.assertEqual(len(self.mm._all_machines), 6) 324 325 self.assertRaises(Exception, self.mm.AddMachine, "lumpy1") 326 327 def test_remove_machine(self): 328 self.mm._machines = self.mm._all_machines 329 self.assertTrue(self.mock_lumpy2 in self.mm._machines) 330 self.mm.RemoveMachine(self.mock_lumpy2.name) 331 self.assertFalse(self.mock_lumpy2 in self.mm._machines) 332 333 def test_force_same_image_to_all_machines(self): 334 self.image_log = [] 335 336 def FakeImageMachine(machine, label_arg): 337 image = label_arg.chromeos_image 338 self.image_log.append("Pushed %s onto %s" % (image, machine.name)) 339 340 def FakeSetUpChecksumInfo(): 341 pass 342 343 self.mm.ImageMachine = FakeImageMachine 344 self.mock_lumpy1.SetUpChecksumInfo = FakeSetUpChecksumInfo 345 self.mock_lumpy2.SetUpChecksumInfo = FakeSetUpChecksumInfo 346 self.mock_lumpy3.SetUpChecksumInfo = FakeSetUpChecksumInfo 347 348 self.mm.ForceSameImageToAllMachines(LABEL_LUMPY) 349 self.assertEqual(len(self.image_log), 3) 350 self.assertEqual( 351 self.image_log[0], "Pushed lumpy_chromeos_image onto lumpy1" 352 ) 353 self.assertEqual( 354 self.image_log[1], "Pushed lumpy_chromeos_image onto lumpy2" 355 ) 356 self.assertEqual( 357 self.image_log[2], "Pushed lumpy_chromeos_image onto lumpy3" 358 ) 359 360 @mock.patch.object(image_checksummer.ImageChecksummer, "Checksum") 361 @mock.patch.object(hashlib, "md5") 362 def test_acquire_machine(self, mock_md5, mock_checksum): 363 364 self.msgs = [] 365 self.log_fatal_msgs = [] 366 367 def FakeLock(machine): 368 self.msgs.append("Tried to lock %s" % machine.name) 369 370 def FakeLogFatal(msg): 371 self.log_fatal_msgs.append(msg) 372 373 self.mm._TryToLockMachine = FakeLock 374 self.mm.logger.LogFatal = FakeLogFatal 375 376 mock_md5.return_value = "123456" 377 mock_checksum.return_value = "fake_md5_checksum" 378 379 self.mm._machines = self.mm._all_machines 380 self.mock_lumpy1.locked = True 381 self.mock_lumpy2.locked = True 382 self.mock_lumpy3.locked = False 383 self.mock_lumpy3.checksum = "fake_md5_checksum" 384 self.mock_daisy1.locked = True 385 self.mock_daisy2.locked = False 386 self.mock_daisy2.checksum = "fake_md5_checksum" 387 388 self.mock_lumpy1.released_time = time.time() 389 self.mock_lumpy2.released_time = time.time() 390 self.mock_lumpy3.released_time = time.time() 391 self.mock_daisy1.released_time = time.time() 392 self.mock_daisy2.released_time = time.time() 393 394 # Test 1. Basic test. Acquire lumpy3. 395 self.mm.AcquireMachine(LABEL_LUMPY) 396 m = self.mock_lumpy1 397 self.assertEqual(m, self.mock_lumpy1) 398 self.assertTrue(self.mock_lumpy1.locked) 399 self.assertEqual(mock_md5.call_count, 0) 400 self.assertEqual( 401 self.msgs, 402 [ 403 "Tried to lock lumpy1", 404 "Tried to lock lumpy2", 405 "Tried to lock lumpy3", 406 ], 407 ) 408 409 # Test the second return statment (machine is unlocked, has no checksum) 410 save_locked = self.mock_lumpy1.locked 411 self.mock_lumpy1.locked = False 412 self.mock_lumpy1.checksum = None 413 m = self.mm.AcquireMachine(LABEL_LUMPY) 414 self.assertEqual(m, self.mock_lumpy1) 415 self.assertTrue(self.mock_lumpy1.locked) 416 417 # Test the third return statement: 418 # - machine is unlocked 419 # - checksums don't match 420 # - current time minus release time is > 20. 421 self.mock_lumpy1.locked = False 422 self.mock_lumpy1.checksum = "123" 423 self.mock_lumpy1.released_time = time.time() - 8 424 m = self.mm.AcquireMachine(LABEL_LUMPY) 425 self.assertEqual(m, self.mock_lumpy1) 426 self.assertTrue(self.mock_lumpy1.locked) 427 428 # Test all machines are already locked. 429 m = self.mm.AcquireMachine(LABEL_LUMPY) 430 self.assertIsNone(m) 431 432 # Restore values of mock_lumpy1, so other tests succeed. 433 self.mock_lumpy1.locked = save_locked 434 self.mock_lumpy1.checksum = "123" 435 436 def test_get_available_machines(self): 437 self.mm._machines = self.mm._all_machines 438 439 machine_list = self.mm.GetAvailableMachines() 440 self.assertEqual(machine_list, self.mm._all_machines) 441 442 machine_list = self.mm.GetAvailableMachines(LABEL_MIX) 443 self.assertEqual( 444 machine_list, [self.mock_daisy1, self.mock_daisy2, self.mock_lumpy3] 445 ) 446 447 machine_list = self.mm.GetAvailableMachines(LABEL_LUMPY) 448 self.assertEqual( 449 machine_list, [self.mock_lumpy1, self.mock_lumpy2, self.mock_lumpy3] 450 ) 451 452 def test_get_machines(self): 453 machine_list = self.mm.GetMachines() 454 self.assertEqual(machine_list, self.mm._all_machines) 455 456 machine_list = self.mm.GetMachines(LABEL_MIX) 457 self.assertEqual( 458 machine_list, [self.mock_daisy1, self.mock_daisy2, self.mock_lumpy3] 459 ) 460 461 machine_list = self.mm.GetMachines(LABEL_LUMPY) 462 self.assertEqual( 463 machine_list, [self.mock_lumpy1, self.mock_lumpy2, self.mock_lumpy3] 464 ) 465 466 def test_release_machines(self): 467 468 self.mm._machines = [self.mock_lumpy1, self.mock_daisy2] 469 470 self.mock_lumpy1.locked = True 471 self.mock_daisy2.locked = True 472 473 self.assertTrue(self.mock_lumpy1.locked) 474 self.mm.ReleaseMachine(self.mock_lumpy1) 475 self.assertFalse(self.mock_lumpy1.locked) 476 self.assertEqual(self.mock_lumpy1.status, "Available") 477 478 self.assertTrue(self.mock_daisy2.locked) 479 self.mm.ReleaseMachine(self.mock_daisy2) 480 self.assertFalse(self.mock_daisy2.locked) 481 self.assertEqual(self.mock_daisy2.status, "Available") 482 483 # Test double-relase... 484 self.assertRaises( 485 AssertionError, self.mm.ReleaseMachine, self.mock_lumpy1 486 ) 487 488 def test_cleanup(self): 489 self.mock_logger.reset_mock() 490 self.mm.Cleanup() 491 self.assertEqual(self.mock_logger.call_count, 0) 492 493 OUTPUT_STR = ( 494 "Machine Status:\nMachine Thread " 495 "Lock Status Checksum" 496 " \nlumpy1 test " 497 "run True PENDING 123" 498 " \nlumpy2 " 499 "test run False PENDING 123" 500 " \nlumpy3 " 501 "test run False PENDING 123" 502 " \ndaisy1 " 503 "test run False PENDING 678" 504 " \ndaisy2 " 505 "test run True PENDING 678" 506 " " 507 ) 508 509 def test_as_string(self): 510 511 mock_logger = mock.Mock(spec=logger.Logger) 512 513 bench = Benchmark( 514 "page_cycler_v2.netsim.top_10", # name 515 "page_cycler_v2.netsim.top_10", # test_name 516 "", # test_args 517 1, # iteratins 518 False, # rm_chroot_tmp 519 "", # perf_args 520 suite="telemetry_Crosperf", 521 ) # suite 522 523 test_run = MockBenchmarkRun( 524 "test run", 525 bench, 526 LABEL_LUMPY, 527 1, 528 [], 529 self.mm, 530 mock_logger, 531 "verbose", 532 "", 533 {}, 534 ) 535 536 self.mm._machines = [ 537 self.mock_lumpy1, 538 self.mock_lumpy2, 539 self.mock_lumpy3, 540 self.mock_daisy1, 541 self.mock_daisy2, 542 ] 543 544 self.mock_lumpy1.test_run = test_run 545 self.mock_lumpy2.test_run = test_run 546 self.mock_lumpy3.test_run = test_run 547 self.mock_daisy1.test_run = test_run 548 self.mock_daisy2.test_run = test_run 549 550 self.mock_lumpy1.locked = True 551 self.mock_lumpy2.locked = False 552 self.mock_lumpy3.locked = False 553 self.mock_daisy1.locked = False 554 self.mock_daisy2.locked = True 555 556 self.mock_lumpy1.checksum = "123" 557 self.mock_lumpy2.checksum = "123" 558 self.mock_lumpy3.checksum = "123" 559 self.mock_daisy1.checksum = "678" 560 self.mock_daisy2.checksum = "678" 561 562 output = self.mm.AsString() 563 self.assertEqual(output, self.OUTPUT_STR) 564 565 def test_get_all_cpu_info(self): 566 info = self.mm.GetAllCPUInfo([LABEL_LUMPY, LABEL_MIX]) 567 self.assertEqual( 568 info, 569 "lumpy\n-------------------\nlumpy_cpu_info\n\n\nmix\n-" 570 "------------------\ndaisy_cpu_info\n\n\n", 571 ) 572 573 574MEMINFO_STRING = """MemTotal: 3990332 kB 575MemFree: 2608396 kB 576Buffers: 147168 kB 577Cached: 811560 kB 578SwapCached: 0 kB 579Active: 503480 kB 580Inactive: 628572 kB 581Active(anon): 174532 kB 582Inactive(anon): 88576 kB 583Active(file): 328948 kB 584Inactive(file): 539996 kB 585Unevictable: 0 kB 586Mlocked: 0 kB 587SwapTotal: 5845212 kB 588SwapFree: 5845212 kB 589Dirty: 9384 kB 590Writeback: 0 kB 591AnonPages: 173408 kB 592Mapped: 146268 kB 593Shmem: 89676 kB 594Slab: 188260 kB 595SReclaimable: 169208 kB 596SUnreclaim: 19052 kB 597KernelStack: 2032 kB 598PageTables: 7120 kB 599NFS_Unstable: 0 kB 600Bounce: 0 kB 601WritebackTmp: 0 kB 602CommitLimit: 7840376 kB 603Committed_AS: 1082032 kB 604VmallocTotal: 34359738367 kB 605VmallocUsed: 364980 kB 606VmallocChunk: 34359369407 kB 607DirectMap4k: 45824 kB 608DirectMap2M: 4096000 kB 609""" 610 611CPUINFO_STRING = """processor: 0 612vendor_id: GenuineIntel 613cpu family: 6 614model: 42 615model name: Intel(R) Celeron(R) CPU 867 @ 1.30GHz 616stepping: 7 617microcode: 0x25 618cpu MHz: 1300.000 619cache size: 2048 KB 620physical id: 0 621siblings: 2 622core id: 0 623cpu cores: 2 624apicid: 0 625initial apicid: 0 626fpu: yes 627fpu_exception: yes 628cpuid level: 13 629wp: yes 630flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer xsave lahf_lm arat epb xsaveopt pln pts dts tpr_shadow vnmi flexpriority ept vpid 631bogomips: 2594.17 632clflush size: 64 633cache_alignment: 64 634address sizes: 36 bits physical, 48 bits virtual 635power management: 636 637processor: 1 638vendor_id: GenuineIntel 639cpu family: 6 640model: 42 641model name: Intel(R) Celeron(R) CPU 867 @ 1.30GHz 642stepping: 7 643microcode: 0x25 644cpu MHz: 1300.000 645cache size: 2048 KB 646physical id: 0 647siblings: 2 648core id: 1 649cpu cores: 2 650apicid: 2 651initial apicid: 2 652fpu: yes 653fpu_exception: yes 654cpuid level: 13 655wp: yes 656flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer xsave lahf_lm arat epb xsaveopt pln pts dts tpr_shadow vnmi flexpriority ept vpid 657bogomips: 2594.17 658clflush size: 64 659cache_alignment: 64 660address sizes: 36 bits physical, 48 bits virtual 661power management: 662""" 663 664CHECKSUM_STRING = ( 665 "processor: 0vendor_id: GenuineIntelcpu family: 6model: " 666 "42model name: Intel(R) Celeron(R) CPU 867 @ " 667 "1.30GHzstepping: 7microcode: 0x25cache size: 2048 " 668 "KBphysical id: 0siblings: 2cpu cores: 2" 669 "fpu: yesfpu_exception: yescpuid level: " 670 "13wp: yesflags: fpu vme de pse tsc msr pae mce cx8 apic sep" 671 " mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse " 672 "sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc " 673 "arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc " 674 "aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 " 675 "ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt " 676 "tsc_deadline_timer xsave lahf_lm arat epb xsaveopt pln pts " 677 "dts tpr_shadow vnmi flexpriority ept vpidclflush size: " 678 "64cache_alignment: 64address sizes: 36 bits physical, 48 " 679 "bits virtualpower management:processor: 1vendor_id: " 680 "GenuineIntelcpu family: 6model: 42model name: Intel(R) " 681 "Celeron(R) CPU 867 @ 1.30GHzstepping: 7microcode: 0x25cache" 682 " size: 2048 KBphysical id: 0siblings: 2cpu cores:" 683 " 2fpu: yesfpu_exception: yescpuid" 684 " level: 13wp: yesflags: fpu vme de pse tsc msr pae mce cx8 " 685 "apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx " 686 "fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm " 687 "constant_tsc arch_perfmon pebs bts rep_good nopl xtopology " 688 "nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl " 689 "vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic " 690 "popcnt tsc_deadline_timer xsave lahf_lm arat epb xsaveopt " 691 "pln pts dts tpr_shadow vnmi flexpriority ept vpidclflush " 692 "size: 64cache_alignment: 64address sizes: 36 bits physical," 693 " 48 bits virtualpower management: 4194304" 694) 695 696DUMP_VPD_STRING = """ 697"PBA_SN"="Pba.txt" 698"Product_S/N"="HT4L91SC300208" 699"serial_number"="HT4L91SC300208Z" 700"System_UUID"="12153006-1755-4f66-b410-c43758a71127" 701"shipping_country"="US" 702"initial_locale"="en-US" 703"keyboard_layout"="xkb:us::eng" 704"initial_timezone"="America/Los_Angeles" 705"MACAddress"="" 706"System_UUID"="29dd9c61-7fa1-4c83-b89a-502e7eb08afe" 707"ubind_attribute"="0c433ce7585f486730b682bb05626a12ce2d896e9b57665387f8ce2ccfdcc56d2e2f1483" 708"gbind_attribute"="7e9a851324088e269319347c6abb8d1572ec31022fa07e28998229afe8acb45c35a89b9d" 709"ActivateDate"="2013-38" 710""" 711 712IFCONFIG_STRING = """ 713eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 714 inet 172.17.129.247 netmask 255.255.254.0 broadcast 172.17.129.255 715 inet6 2620:0:1000:3002:143:fed4:3ff6:279d prefixlen 64 scopeid 0x0<global> 716 inet6 2620:0:1000:3002:4459:1399:1f02:9e4c prefixlen 64 scopeid 0x0<global> 717 inet6 2620:0:1000:3002:d9e4:87b:d4ec:9a0e prefixlen 64 scopeid 0x0<global> 718 inet6 2620:0:1000:3002:7d45:23f1:ea8a:9604 prefixlen 64 scopeid 0x0<global> 719 inet6 2620:0:1000:3002:250:b6ff:fe63:db65 prefixlen 64 scopeid 0x0<global> 720 inet6 fe80::250:b6ff:fe63:db65 prefixlen 64 scopeid 0x20<link> 721 ether 00:50:b6:63:db:65 txqueuelen 1000 (Ethernet) 722 RX packets 9817166 bytes 10865181708 (10.1 GiB) 723 RX errors 194 dropped 0 overruns 0 frame 194 724 TX packets 0 bytes 2265811903 (2.1 GiB) 725 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 726 727eth1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 728 ether e8:03:9a:9c:50:3d txqueuelen 1000 (Ethernet) 729 RX packets 0 bytes 0 (0.0 B) 730 RX errors 0 dropped 0 overruns 0 frame 0 731 TX packets 0 bytes 0 (0.0 B) 732 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 733 734lo: flags=73<UP,LOOPBACK,RUNNING> mtu 16436 735 inet 127.0.0.1 netmask 255.0.0.0 736 inet6 ::1 prefixlen 128 scopeid 0x10<host> 737 loop txqueuelen 0 (Local Loopback) 738 RX packets 981004 bytes 1127468524 (1.0 GiB) 739 RX errors 0 dropped 0 overruns 0 frame 0 740 TX packets 981004 bytes 1127468524 (1.0 GiB) 741 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 742 743wlan0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 744 ether 44:6d:57:20:4a:c5 txqueuelen 1000 (Ethernet) 745 RX packets 0 bytes 0 (0.0 B) 746 RX errors 0 dropped 0 overruns 0 frame 0 747 TX packets 0 bytes 0 (0.0 B) 748 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 749""" 750 751 752class CrosMachineTest(unittest.TestCase): 753 """Test for CrosMachine class.""" 754 755 mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter) 756 757 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 758 def test_init(self, mock_setup): 759 760 cm = machine_manager.CrosMachine( 761 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 762 ) 763 self.assertEqual(mock_setup.call_count, 1) 764 self.assertEqual(cm.chromeos_root, "/usr/local/chromeos") 765 self.assertEqual(cm.log_level, "average") 766 767 @mock.patch.object(machine_manager.CrosMachine, "IsReachable") 768 @mock.patch.object(machine_manager.CrosMachine, "_GetMemoryInfo") 769 @mock.patch.object(machine_manager.CrosMachine, "_GetCPUInfo") 770 @mock.patch.object( 771 machine_manager.CrosMachine, "_ComputeMachineChecksumString" 772 ) 773 @mock.patch.object(machine_manager.CrosMachine, "_GetMachineID") 774 @mock.patch.object(machine_manager.CrosMachine, "_GetMD5Checksum") 775 def test_setup_checksum_info( 776 self, 777 mock_md5sum, 778 mock_machineid, 779 mock_checkstring, 780 mock_cpuinfo, 781 mock_meminfo, 782 mock_isreachable, 783 ): 784 785 # Test 1. Machine is not reachable; SetUpChecksumInfo is called via 786 # __init__. 787 mock_isreachable.return_value = False 788 mock_md5sum.return_value = "md5_checksum" 789 cm = machine_manager.CrosMachine( 790 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 791 ) 792 cm.checksum_string = "This is a checksum string." 793 cm.machine_id = "machine_id1" 794 self.assertEqual(mock_isreachable.call_count, 1) 795 self.assertIsNone(cm.machine_checksum) 796 self.assertEqual(mock_meminfo.call_count, 0) 797 798 # Test 2. Machine is reachable. Call explicitly. 799 mock_isreachable.return_value = True 800 cm.checksum_string = "This is a checksum string." 801 cm.machine_id = "machine_id1" 802 cm.SetUpChecksumInfo() 803 self.assertEqual(mock_isreachable.call_count, 2) 804 self.assertEqual(mock_meminfo.call_count, 1) 805 self.assertEqual(mock_cpuinfo.call_count, 1) 806 self.assertEqual(mock_checkstring.call_count, 1) 807 self.assertEqual(mock_machineid.call_count, 1) 808 self.assertEqual(mock_md5sum.call_count, 2) 809 self.assertEqual(cm.machine_checksum, "md5_checksum") 810 self.assertEqual(cm.machine_id_checksum, "md5_checksum") 811 self.assertEqual( 812 mock_md5sum.call_args_list[0][0][0], "This is a checksum string." 813 ) 814 self.assertEqual(mock_md5sum.call_args_list[1][0][0], "machine_id1") 815 816 @mock.patch.object(command_executer.CommandExecuter, "CrosRunCommand") 817 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 818 def test_is_reachable(self, mock_setup, mock_run_cmd): 819 820 cm = machine_manager.CrosMachine( 821 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 822 ) 823 self.mock_cmd_exec.CrosRunCommand = mock_run_cmd 824 825 # Test 1. CrosRunCommand returns 1 (fail) 826 mock_run_cmd.return_value = 1 827 result = cm.IsReachable() 828 self.assertFalse(result) 829 self.assertEqual(mock_setup.call_count, 1) 830 self.assertEqual(mock_run_cmd.call_count, 1) 831 832 # Test 2. CrosRunCommand returns 0 (success) 833 mock_run_cmd.return_value = 0 834 result = cm.IsReachable() 835 self.assertTrue(result) 836 self.assertEqual(mock_run_cmd.call_count, 2) 837 first_args = mock_run_cmd.call_args_list[0] 838 second_args = mock_run_cmd.call_args_list[1] 839 self.assertEqual(first_args[0], second_args[0]) 840 self.assertEqual(first_args[1], second_args[1]) 841 self.assertEqual(len(first_args[0]), 1) 842 self.assertEqual(len(first_args[1]), 2) 843 self.assertEqual(first_args[0][0], "ls") 844 args_dict = first_args[1] 845 self.assertEqual(args_dict["machine"], "daisy.cros") 846 self.assertEqual(args_dict["chromeos_root"], "/usr/local/chromeos") 847 848 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 849 def test_parse_memory_info(self, _mock_setup): 850 cm = machine_manager.CrosMachine( 851 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 852 ) 853 cm.meminfo = MEMINFO_STRING 854 cm._ParseMemoryInfo() 855 self.assertEqual(cm.phys_kbytes, 4194304) 856 857 @mock.patch.object( 858 command_executer.CommandExecuter, "CrosRunCommandWOutput" 859 ) 860 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 861 def test_get_memory_info(self, _mock_setup, mock_run_cmd): 862 cm = machine_manager.CrosMachine( 863 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 864 ) 865 self.mock_cmd_exec.CrosRunCommandWOutput = mock_run_cmd 866 mock_run_cmd.return_value = [0, MEMINFO_STRING, ""] 867 cm._GetMemoryInfo() 868 self.assertEqual(mock_run_cmd.call_count, 1) 869 call_args = mock_run_cmd.call_args_list[0] 870 self.assertEqual(call_args[0][0], "cat /proc/meminfo") 871 args_dict = call_args[1] 872 self.assertEqual(args_dict["machine"], "daisy.cros") 873 self.assertEqual(args_dict["chromeos_root"], "/usr/local/chromeos") 874 self.assertEqual(cm.meminfo, MEMINFO_STRING) 875 self.assertEqual(cm.phys_kbytes, 4194304) 876 877 mock_run_cmd.return_value = [1, MEMINFO_STRING, ""] 878 self.assertRaises(Exception, cm._GetMemoryInfo) 879 880 @mock.patch.object( 881 command_executer.CommandExecuter, "CrosRunCommandWOutput" 882 ) 883 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 884 def test_get_cpu_info(self, _mock_setup, mock_run_cmd): 885 cm = machine_manager.CrosMachine( 886 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 887 ) 888 self.mock_cmd_exec.CrosRunCommandWOutput = mock_run_cmd 889 mock_run_cmd.return_value = [0, CPUINFO_STRING, ""] 890 cm._GetCPUInfo() 891 self.assertEqual(mock_run_cmd.call_count, 1) 892 call_args = mock_run_cmd.call_args_list[0] 893 self.assertEqual(call_args[0][0], "cat /proc/cpuinfo") 894 args_dict = call_args[1] 895 self.assertEqual(args_dict["machine"], "daisy.cros") 896 self.assertEqual(args_dict["chromeos_root"], "/usr/local/chromeos") 897 self.assertEqual(cm.cpuinfo, CPUINFO_STRING) 898 899 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 900 def test_compute_machine_checksum_string(self, _mock_setup): 901 cm = machine_manager.CrosMachine( 902 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 903 ) 904 cm.cpuinfo = CPUINFO_STRING 905 cm.meminfo = MEMINFO_STRING 906 cm._ParseMemoryInfo() 907 cm._ComputeMachineChecksumString() 908 self.assertEqual(cm.checksum_string, CHECKSUM_STRING) 909 910 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 911 def test_get_md5_checksum(self, _mock_setup): 912 cm = machine_manager.CrosMachine( 913 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 914 ) 915 temp_str = "abcde" 916 checksum_str = cm._GetMD5Checksum(temp_str) 917 self.assertEqual(checksum_str, "ab56b4d92b40713acc5af89985d4b786") 918 919 temp_str = "" 920 checksum_str = cm._GetMD5Checksum(temp_str) 921 self.assertEqual(checksum_str, "") 922 923 @mock.patch.object( 924 command_executer.CommandExecuter, "CrosRunCommandWOutput" 925 ) 926 @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo") 927 def test_get_machine_id(self, _mock_setup, mock_run_cmd): 928 cm = machine_manager.CrosMachine( 929 "daisy.cros", "/usr/local/chromeos", "average", self.mock_cmd_exec 930 ) 931 self.mock_cmd_exec.CrosRunCommandWOutput = mock_run_cmd 932 mock_run_cmd.return_value = [0, DUMP_VPD_STRING, ""] 933 934 cm._GetMachineID() 935 self.assertEqual(cm.machine_id, '"Product_S/N"="HT4L91SC300208"') 936 937 mock_run_cmd.return_value = [0, IFCONFIG_STRING, ""] 938 cm._GetMachineID() 939 self.assertEqual( 940 cm.machine_id, 941 " ether 00:50:b6:63:db:65 txqueuelen 1000 (Ethernet)_ " 942 "ether e8:03:9a:9c:50:3d txqueuelen 1000 (Ethernet)_ ether " 943 "44:6d:57:20:4a:c5 txqueuelen 1000 (Ethernet)", 944 ) 945 946 mock_run_cmd.return_value = [0, "invalid hardware config", ""] 947 self.assertRaises(Exception, cm._GetMachineID) 948 949 def test_add_cooldown_waittime(self): 950 cm = machine_manager.CrosMachine( 951 "1.2.3.4.cros", "/usr/local/chromeos", "average" 952 ) 953 self.assertEqual(cm.GetCooldownWaitTime(), 0) 954 cm.AddCooldownWaitTime(250) 955 self.assertEqual(cm.GetCooldownWaitTime(), 250) 956 cm.AddCooldownWaitTime(1) 957 self.assertEqual(cm.GetCooldownWaitTime(), 251) 958 959 960if __name__ == "__main__": 961 unittest.main() 962