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