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