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