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