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