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