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