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