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