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