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