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