machine_manager_unittest.py revision 036c9233742004aa773a374df381b1cf137484f5
1#!/usr/bin/python
2
3# Copyright 2012 Google Inc. All Rights Reserved.
4
5"""Unittest for machine_manager."""
6import os.path
7import time
8import hashlib
9
10import mock
11import unittest
12
13import image_chromeos
14import label
15import file_lock_machine
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
25class MyMachineManager(machine_manager.MachineManager):
26
27  def __init__(self, chromeos_root):
28    super(MyMachineManager, self).__init__(chromeos_root, 0, "average",
29                                           file_lock_machine.Machine.LOCKS_DIR)
30
31  def _TryToLockMachine(self, cros_machine):
32    self._machines.append(cros_machine)
33    cros_machine.checksum = ""
34
35  def AddMachine(self, machine_name):
36    with self._lock:
37      for m in self._all_machines:
38        assert m.name != machine_name, "Tried to double-add %s" % machine_name
39      cm = machine_manager.MockCrosMachine(machine_name, self.chromeos_root,
40                                           "average")
41      assert cm.machine_checksum, ("Could not find checksum for machine %s" %
42                                   machine_name)
43      self._all_machines.append(cm)
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",
49                              ["lumpy1", "lumpy2", "lumpy3", "lumpy4"],
50                              "", "", False, "average," "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("/usr/local/chromeos", 0,
74                                             "average",
75                                             file_lock_machine.Machine.LOCKS_DIR,
76                                             self.mock_cmd_exec,
77                                             self.mock_logger)
78
79    self.mock_lumpy1.name = 'lumpy1'
80    self.mock_lumpy2.name = 'lumpy2'
81    self.mock_lumpy3.name = 'lumpy3'
82    self.mock_lumpy4.name = 'lumpy4'
83    self.mock_daisy1.name = 'daisy1'
84    self.mock_daisy2.name = 'daisy2'
85    self.mock_lumpy1.machine_checksum = 'lumpy123'
86    self.mock_lumpy2.machine_checksum = 'lumpy123'
87    self.mock_lumpy3.machine_checksum = 'lumpy123'
88    self.mock_lumpy4.machine_checksum = 'lumpy123'
89    self.mock_daisy1.machine_checksum = 'daisy12'
90    self.mock_daisy2.machine_checksum = 'daisy12'
91    self.mock_lumpy1.checksum_string = 'lumpy_checksum_str'
92    self.mock_lumpy2.checksum_string = 'lumpy_checksum_str'
93    self.mock_lumpy3.checksum_string = 'lumpy_checksum_str'
94    self.mock_lumpy4.checksum_string = 'lumpy_checksum_str'
95    self.mock_daisy1.checksum_string = 'daisy_checksum_str'
96    self.mock_daisy2.checksum_string = 'daisy_checksum_str'
97    self.mock_lumpy1.cpuinfo = "lumpy_cpu_info"
98    self.mock_lumpy2.cpuinfo = "lumpy_cpu_info"
99    self.mock_lumpy3.cpuinfo = "lumpy_cpu_info"
100    self.mock_lumpy4.cpuinfo = "lumpy_cpu_info"
101    self.mock_daisy1.cpuinfo = "daisy_cpu_info"
102    self.mock_daisy2.cpuinfo = "daisy_cpu_info"
103    self.mm._all_machines.append(self.mock_daisy1)
104    self.mm._all_machines.append(self.mock_daisy2)
105    self.mm._all_machines.append(self.mock_lumpy1)
106    self.mm._all_machines.append(self.mock_lumpy2)
107    self.mm._all_machines.append(self.mock_lumpy3)
108
109
110  def testGetMachines(self):
111    manager = MyMachineManager(CHROMEOS_ROOT)
112    for m in MACHINE_NAMES:
113      manager.AddMachine(m)
114    names = [m.name for m in manager.GetMachines(LABEL_LUMPY)]
115    self.assertEqual(names, ["lumpy1", "lumpy2", "lumpy3"])
116
117  def testGetAvailableMachines(self):
118    manager = MyMachineManager(CHROMEOS_ROOT)
119    for m in MACHINE_NAMES:
120      manager.AddMachine(m)
121    for m in manager._all_machines:
122      if int(m.name[-1]) % 2:
123        manager._TryToLockMachine(m)
124    names = [m.name for m in manager.GetAvailableMachines(LABEL_LUMPY)]
125    self.assertEqual(names, ["lumpy1", "lumpy3"])
126
127  @mock.patch.object(time, 'sleep')
128  @mock.patch.object(command_executer.CommandExecuter, 'RunCommand')
129  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
130  @mock.patch.object(image_checksummer.ImageChecksummer, 'Checksum')
131  def test_image_machine(self, mock_checksummer, mock_run_croscmd,
132                         mock_run_cmd, mock_sleep):
133
134    def FakeMD5Checksum(input_str):
135      return "machine_fake_md5_checksum"
136
137    self.fake_logger_count = 0
138    self.fake_logger_msgs = []
139
140    def FakeLogOutput(msg):
141      self.fake_logger_count += 1
142      self.fake_logger_msgs.append(msg)
143
144    def ResetValues():
145      self.fake_logger_count = 0
146      self.fake_logger_msgs = []
147      mock_run_cmd.reset_mock()
148      mock_run_croscmd.reset_mock()
149      mock_checksummer.reset_mock()
150      mock_sleep.reset_mock()
151      machine.checksum = "fake_md5_checksum"
152      self.mm.checksum = None
153      self.mm.num_reimages = 0
154
155    self.mock_cmd_exec.CrosRunCommand = mock_run_croscmd
156    self.mock_cmd_exec.RunCommand = mock_run_cmd
157
158    self.mm.logger.LogOutput = FakeLogOutput
159    machine = self.mock_lumpy1
160    machine._GetMD5Checksum = FakeMD5Checksum
161    machine.checksum = "fake_md5_checksum"
162    mock_checksummer.return_value = "fake_md5_checksum"
163    self.mock_cmd_exec.log_level = "verbose"
164
165    test_flag.SetTestMode(True)
166    # Test 1: label.image_type == "local"
167    LABEL_LUMPY.image_type = "local"
168    self.mm.ImageMachine(machine, LABEL_LUMPY)
169    self.assertEqual(mock_run_cmd.call_count, 0)
170    self.assertEqual(mock_run_croscmd.call_count, 0)
171
172    #Test 2: label.image_type == "trybot"
173    ResetValues()
174    LABEL_LUMPY.image_type = "trybot"
175    mock_run_cmd.return_value = 0
176    self.mm.ImageMachine(machine, LABEL_LUMPY)
177    self.assertEqual(mock_run_croscmd.call_count, 0)
178    self.assertEqual(mock_checksummer.call_count, 0)
179
180    # Test 3: label.image_type is neither local nor trybot; retval from
181    # RunCommand is 1, i.e. image_chromeos fails...
182    ResetValues()
183    LABEL_LUMPY.image_type = "other"
184    mock_run_cmd.return_value = 1
185    try:
186      self.mm.ImageMachine(machine, LABEL_LUMPY)
187    except:
188      self.assertEqual(mock_checksummer.call_count, 0)
189      self.assertEqual(mock_run_cmd.call_count, 2)
190      self.assertEqual(mock_run_croscmd.call_count, 1)
191      self.assertEqual(mock_sleep.call_count, 1)
192      image_call_args_str = mock_run_cmd.call_args[0][0]
193      image_call_args = image_call_args_str.split(' ')
194      self.assertEqual(image_call_args[0], 'python')
195      self.assertEqual(image_call_args[1].split('/')[-1], 'image_chromeos.pyc')
196      image_call_args = image_call_args[2:]
197      self.assertEqual(image_call_args,
198                       [ '--chromeos_root=/tmp/chromeos-root',
199                         '--image=lumpy_chromeos_image',
200                         '--image_args=', '--remote=lumpy1',
201                         '--logging_level=average', '--board=lumpy'])
202      self.assertEqual(mock_run_croscmd.call_args[0][0], 'reboot && exit')
203
204    # Test 4: Everything works properly. Trybot image type.
205    ResetValues()
206    LABEL_LUMPY.image_type = 'trybot'
207    mock_run_cmd.return_value = 0
208    self.mm.ImageMachine(machine, LABEL_LUMPY)
209    self.assertEqual(mock_checksummer.call_count, 0)
210    self.assertEqual(mock_run_croscmd.call_count, 0)
211    self.assertEqual(mock_sleep.call_count, 0)
212
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, self.mm.ComputeCommonCheckSum, LABEL_MIX)
223
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
239  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput')
240  def test_try_to_lock_machine(self, mock_cros_runcmd):
241
242    self.assertRaises(self.mm._TryToLockMachine, None)
243
244    mock_cros_runcmd.return_value = [0, "false_lock_checksum", ""]
245    self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd
246    self.mm._machines = []
247    self.mm._TryToLockMachine(self.mock_lumpy1)
248    self.assertEqual(len(self.mm._machines), 1)
249    self.assertEqual(self.mm._machines[0], self.mock_lumpy1)
250    self.assertEqual(self.mock_lumpy1.checksum, "false_lock_checksum")
251    self.assertEqual(mock_cros_runcmd.call_count, 1)
252    cmd_str = mock_cros_runcmd.call_args[0][0]
253    self.assertEqual(cmd_str, 'cat /usr/local/osimage_checksum_file')
254    args_dict = mock_cros_runcmd.call_args[1]
255    self.assertEqual(len(args_dict), 2)
256    self.assertEqual(args_dict['machine'], self.mock_lumpy1.name)
257    self.assertEqual(args_dict['chromeos_root'], '/usr/local/chromeos')
258
259
260  @mock.patch.object(machine_manager, 'CrosMachine')
261  def test_add_machine(self, mock_machine):
262
263    mock_machine.machine_checksum = 'daisy123'
264    self.assertEqual (len(self.mm._all_machines), 5)
265    self.mm.AddMachine('daisy3')
266    self.assertEqual (len(self.mm._all_machines), 6)
267
268    self.assertRaises(Exception, self.mm.AddMachine, 'lumpy1')
269
270
271  def test_remove_machine(self):
272    self.mm._machines = self.mm._all_machines
273    self.assertTrue(self.mock_lumpy2 in self.mm._machines)
274    self.mm.RemoveMachine(self.mock_lumpy2.name)
275    self.assertFalse(self.mock_lumpy2 in self.mm._machines)
276
277
278  def test_force_same_image_to_all_machines(self):
279    self.image_log = []
280
281    def FakeImageMachine(machine, label_arg):
282      image = label_arg.chromeos_image
283      self.image_log.append("Pushed %s onto %s" % (image, machine.name))
284
285    def FakeSetUpChecksumInfo():
286      pass
287
288    self.mm.ImageMachine = FakeImageMachine
289    self.mock_lumpy1.SetUpChecksumInfo = FakeSetUpChecksumInfo
290    self.mock_lumpy2.SetUpChecksumInfo = FakeSetUpChecksumInfo
291    self.mock_lumpy3.SetUpChecksumInfo = FakeSetUpChecksumInfo
292
293    self.mm.ForceSameImageToAllMachines(LABEL_LUMPY)
294    self.assertEqual(len(self.image_log), 3)
295    self.assertEqual(self.image_log[0],
296                     'Pushed lumpy_chromeos_image onto lumpy1')
297    self.assertEqual(self.image_log[1],
298                     'Pushed lumpy_chromeos_image onto lumpy2')
299    self.assertEqual(self.image_log[2],
300                     'Pushed lumpy_chromeos_image onto lumpy3')
301
302
303
304  @mock.patch.object(image_checksummer.ImageChecksummer, 'Checksum')
305  @mock.patch.object(hashlib,'md5')
306  def test_acquire_machine(self, mock_md5, mock_checksum):
307
308    self.msgs = []
309    self.log_fatal_msgs = []
310
311    def FakeLock(machine):
312      self.msgs.append("Tried to lock %s" % machine.name)
313
314    def FakeLogFatal(msg):
315      self.log_fatal_msgs.append(msg)
316
317    self.mm._TryToLockMachine = FakeLock
318    self.mm.logger.LogFatal = FakeLogFatal
319
320    mock_md5.return_value = "123456"
321    mock_checksum.return_value = "fake_md5_checksum"
322
323    self.mm._machines = self.mm._all_machines
324    self.mock_lumpy1.locked = True
325    self.mock_lumpy2.locked = True
326    self.mock_lumpy3.locked = False
327    self.mock_lumpy3.checksum = "fake_md5_checksum"
328    self.mock_daisy1.locked = True
329    self.mock_daisy2.locked = False
330    self.mock_daisy2.checksum = "fake_md5_checksum"
331
332    self.mock_lumpy1.released_time = time.time()
333    self.mock_lumpy2.released_time = time.time()
334    self.mock_lumpy3.released_time = time.time()
335    self.mock_daisy1.released_time = time.time()
336    self.mock_daisy2.released_time = time.time()
337
338    # Test 1. Basic test. Acquire lumpy3.
339    self.mm.AcquireMachine(LABEL_LUMPY)
340    m = self.mock_lumpy1
341    self.assertEqual(m, self.mock_lumpy1)
342    self.assertTrue(self.mock_lumpy1.locked)
343    self.assertEqual(mock_md5.call_count, 0)
344    self.assertEqual(self.msgs, ['Tried to lock lumpy1',
345                                 'Tried to lock lumpy2',
346                                 'Tried to lock lumpy3'])
347
348    # Test the second return statment (machine is unlocked, has no checksum)
349    save_locked = self.mock_lumpy1.locked
350    self.mock_lumpy1.locked = False
351    self.mock_lumpy1.checksum = None
352    m = self.mm.AcquireMachine(LABEL_LUMPY)
353    self.assertEqual(m, self.mock_lumpy1)
354    self.assertTrue(self.mock_lumpy1.locked)
355
356    # Test the third return statement:
357    #   - machine is unlocked
358    #   - checksums don't match
359    #   - current time minus release time is > 20.
360    self.mock_lumpy1.locked = False
361    self.mock_lumpy1.checksum = "123"
362    self.mock_lumpy1.released_time = time.time() - 8
363    m = self.mm.AcquireMachine(LABEL_LUMPY)
364    self.assertEqual(m, self.mock_lumpy1)
365    self.assertTrue(self.mock_lumpy1.locked)
366
367    # Test all machines are already locked.
368    m = self.mm.AcquireMachine(LABEL_LUMPY)
369    self.assertIsNone(m)
370
371    # Restore values of mock_lumpy1, so other tests succeed.
372    self.mock_lumpy1.locked = save_locked
373    self.mock_lumpy1.checksum = "123"
374
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
391  def test_get_machines(self):
392    machine_list = self.mm.GetMachines()
393    self.assertEqual(machine_list, self.mm._all_machines)
394
395    machine_list = self.mm.GetMachines(LABEL_MIX)
396    self.assertEqual(machine_list, [self.mock_daisy1, self.mock_daisy2,
397                                    self.mock_lumpy3])
398
399    machine_list = self.mm.GetMachines(LABEL_LUMPY)
400    self.assertEqual(machine_list, [self.mock_lumpy1, self.mock_lumpy2,
401                                    self.mock_lumpy3])
402
403
404  def test_release_machines(self):
405
406    self.mm._machines = [self.mock_lumpy1, self.mock_daisy2]
407
408    self.mock_lumpy1.locked = True
409    self.mock_daisy2.locked = True
410
411    self.assertTrue(self.mock_lumpy1.locked)
412    self.mm.ReleaseMachine(self.mock_lumpy1)
413    self.assertFalse(self.mock_lumpy1.locked)
414    self.assertEqual(self.mock_lumpy1.status, "Available")
415
416    self.assertTrue(self.mock_daisy2.locked)
417    self.mm.ReleaseMachine(self.mock_daisy2)
418    self.assertFalse(self.mock_daisy2.locked)
419    self.assertEqual(self.mock_daisy2.status, "Available")
420
421    # Test double-relase...
422    self.assertRaises(AssertionError, self.mm.ReleaseMachine, self.mock_lumpy1)
423
424
425  def test_cleanup(self):
426    self.mock_logger.reset_mock()
427    self.mm.Cleanup()
428    self.assertEqual(self.mock_logger.call_count, 0)
429
430  OUTPUT_STR = 'Machine Status:\nMachine                        Thread     Lock Status                    Checksum                        \nlumpy1                         test run   True PENDING                   123                             \nlumpy2                         test run   False PENDING                   123                             \nlumpy3                         test run   False PENDING                   123                             \ndaisy1                         test run   False PENDING                   678                             \ndaisy2                         test run   True PENDING                   678                             '
431
432  def test_as_string(self):
433
434    mock_logger = mock.Mock(spec=logger.Logger)
435
436    bench = Benchmark("page_cycler.netsim.top_10",    # name
437                      "page_cycler.netsim.top_10",    # test_name
438                      "",             # test_args
439                      1,              # iteratins
440                      False,          # rm_chroot_tmp
441                      "",             # perf_args
442                      suite="telemetry_Crosperf")     # suite
443
444    test_run = MockBenchmarkRun("test run",
445                         bench,
446                         LABEL_LUMPY,
447                         1,
448                         [],
449                         self.mm,
450                         mock_logger,
451                         "verbose",
452                         "")
453
454    self.mm._machines = [self.mock_lumpy1, self.mock_lumpy2, self.mock_lumpy3,
455                         self.mock_daisy1, self.mock_daisy2]
456
457    self.mock_lumpy1.test_run = test_run
458    self.mock_lumpy2.test_run = test_run
459    self.mock_lumpy3.test_run = test_run
460    self.mock_daisy1.test_run = test_run
461    self.mock_daisy2.test_run = test_run
462
463    self.mock_lumpy1.locked = True
464    self.mock_lumpy2.locked = False
465    self.mock_lumpy3.locked = False
466    self.mock_daisy1.locked = False
467    self.mock_daisy2.locked = True
468
469    self.mock_lumpy1.checksum = "123"
470    self.mock_lumpy2.checksum = "123"
471    self.mock_lumpy3.checksum = "123"
472    self.mock_daisy1.checksum = "678"
473    self.mock_daisy2.checksum = "678"
474
475    output = self.mm.AsString()
476    self.assertEqual(output, self.OUTPUT_STR)
477
478
479  def test_get_all_cpu_info(self):
480    info = self.mm.GetAllCPUInfo([LABEL_LUMPY, LABEL_MIX])
481    self.assertEqual(info,
482                     'lumpy\n-------------------\nlumpy_cpu_info\n\n\nmix\n-'
483                     '------------------\ndaisy_cpu_info\n\n\n')
484
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: 42model name: Intel(R) Celeron(R) CPU 867 @ 1.30GHzstepping: 7microcode: 0x25cache size: 2048 KBphysical id: 0siblings: 2core id: 0cpu cores: 2apicid: 0initial apicid: 0fpu: yesfpu_exception: yescpuid level: 13wp: yesflags: 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 vpidclflush size: 64cache_alignment: 64address sizes: 36 bits physical, 48 bits virtualpower management:processor: 1vendor_id: GenuineIntelcpu family: 6model: 42model name: Intel(R) Celeron(R) CPU 867 @ 1.30GHzstepping: 7microcode: 0x25cache size: 2048 KBphysical id: 0siblings: 2core id: 1cpu cores: 2apicid: 2initial apicid: 2fpu: yesfpu_exception: yescpuid level: 13wp: yesflags: 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 vpidclflush size: 64cache_alignment: 64address sizes: 36 bits physical, 48 bits virtualpower management: 4194304"
578
579DUMP_VPD_STRING = """
580"PBA_SN"="Pba.txt"
581"Product_S/N"="HT4L91SC300208"
582"serial_number"="HT4L91SC300208Z"
583"System_UUID"="12153006-1755-4f66-b410-c43758a71127"
584"shipping_country"="US"
585"initial_locale"="en-US"
586"keyboard_layout"="xkb:us::eng"
587"initial_timezone"="America/Los_Angeles"
588"MACAddress"=""
589"System_UUID"="29dd9c61-7fa1-4c83-b89a-502e7eb08afe"
590"ubind_attribute"="0c433ce7585f486730b682bb05626a12ce2d896e9b57665387f8ce2ccfdcc56d2e2f1483"
591"gbind_attribute"="7e9a851324088e269319347c6abb8d1572ec31022fa07e28998229afe8acb45c35a89b9d"
592"ActivateDate"="2013-38"
593"""
594
595
596IFCONFIG_STRING = """
597eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
598        inet 172.17.129.247  netmask 255.255.254.0  broadcast 172.17.129.255
599        inet6 2620:0:1000:3002:143:fed4:3ff6:279d  prefixlen 64  scopeid 0x0<global>
600        inet6 2620:0:1000:3002:4459:1399:1f02:9e4c  prefixlen 64  scopeid 0x0<global>
601        inet6 2620:0:1000:3002:d9e4:87b:d4ec:9a0e  prefixlen 64  scopeid 0x0<global>
602        inet6 2620:0:1000:3002:7d45:23f1:ea8a:9604  prefixlen 64  scopeid 0x0<global>
603        inet6 2620:0:1000:3002:250:b6ff:fe63:db65  prefixlen 64  scopeid 0x0<global>
604        inet6 fe80::250:b6ff:fe63:db65  prefixlen 64  scopeid 0x20<link>
605        ether 00:50:b6:63:db:65  txqueuelen 1000  (Ethernet)
606        RX packets 9817166  bytes 10865181708 (10.1 GiB)
607        RX errors 194  dropped 0  overruns 0  frame 194
608        TX packets 0  bytes 2265811903 (2.1 GiB)
609        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
610
611eth1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
612        ether e8:03:9a:9c:50:3d  txqueuelen 1000  (Ethernet)
613        RX packets 0  bytes 0 (0.0 B)
614        RX errors 0  dropped 0  overruns 0  frame 0
615        TX packets 0  bytes 0 (0.0 B)
616        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
617
618lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 16436
619        inet 127.0.0.1  netmask 255.0.0.0
620        inet6 ::1  prefixlen 128  scopeid 0x10<host>
621        loop  txqueuelen 0  (Local Loopback)
622        RX packets 981004  bytes 1127468524 (1.0 GiB)
623        RX errors 0  dropped 0  overruns 0  frame 0
624        TX packets 981004  bytes 1127468524 (1.0 GiB)
625        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
626
627wlan0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
628        ether 44:6d:57:20:4a:c5  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"""
634
635
636class CrosMachineTest(unittest.TestCase):
637
638  mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter)
639
640  @mock.patch.object(machine_manager.CrosMachine, 'SetUpChecksumInfo')
641  def test_init(self, mock_setup):
642
643    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
644                                     "average", self.mock_cmd_exec)
645    self.assertEqual(mock_setup.call_count, 1)
646    self.assertEqual(cm.chromeos_root, "/usr/local/chromeos")
647    self.assertEqual(cm.log_level, "average")
648
649
650  @mock.patch.object(machine_manager.CrosMachine, 'IsReachable')
651  @mock.patch.object(machine_manager.CrosMachine, '_GetMemoryInfo')
652  @mock.patch.object(machine_manager.CrosMachine, '_GetCPUInfo')
653  @mock.patch.object(machine_manager.CrosMachine,
654                     '_ComputeMachineChecksumString')
655  @mock.patch.object(machine_manager.CrosMachine, '_GetMachineID')
656  @mock.patch.object(machine_manager.CrosMachine, '_GetMD5Checksum')
657  def test_setup_checksum_info(self, mock_md5sum, mock_machineid,
658                               mock_checkstring, mock_cpuinfo, mock_meminfo,
659                               mock_isreachable):
660
661    # Test 1. Machine is not reachable; SetUpChecksumInfo is called via
662    # __init__.
663    mock_isreachable.return_value = False
664    mock_md5sum.return_value = "md5_checksum"
665    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
666                                     "average", self.mock_cmd_exec)
667    cm.checksum_string = "This is a checksum string."
668    cm.machine_id = "machine_id1"
669    self.assertEqual(mock_isreachable.call_count, 1)
670    self.assertIsNone(cm.machine_checksum)
671    self.assertEqual(mock_meminfo.call_count, 0)
672
673    # Test 2. Machine is reachable. Call explicitly.
674    mock_isreachable.return_value = True
675    cm.checksum_string = "This is a checksum string."
676    cm.machine_id = "machine_id1"
677    cm.SetUpChecksumInfo()
678    self.assertEqual(mock_isreachable.call_count, 2)
679    self.assertEqual(mock_meminfo.call_count, 1)
680    self.assertEqual(mock_cpuinfo.call_count, 1)
681    self.assertEqual(mock_checkstring.call_count, 1)
682    self.assertEqual(mock_machineid.call_count, 1)
683    self.assertEqual(mock_md5sum.call_count, 2)
684    self.assertEqual(cm.machine_checksum, "md5_checksum")
685    self.assertEqual(cm.machine_id_checksum, "md5_checksum")
686    self.assertEqual(mock_md5sum.call_args_list[0][0][0],
687                     "This is a checksum string.")
688    self.assertEqual(mock_md5sum.call_args_list[1][0][0],
689                     "machine_id1")
690
691  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
692  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
693  def test_is_reachable(self, mock_setup, mock_run_cmd):
694
695    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
696                                     "average", self.mock_cmd_exec)
697    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
698
699    # Test 1. CrosRunCommand returns 1 (fail)
700    mock_run_cmd.return_value = 1
701    result = cm.IsReachable()
702    self.assertFalse(result)
703    self.assertEqual(mock_setup.call_count, 1)
704    self.assertEqual(mock_run_cmd.call_count, 1)
705
706    # Test 2. CrosRunCommand returns 0 (success)
707    mock_run_cmd.return_value = 0
708    result = cm.IsReachable()
709    self.assertTrue(result)
710    self.assertEqual(mock_run_cmd.call_count, 2)
711    first_args = mock_run_cmd.call_args_list[0]
712    second_args = mock_run_cmd.call_args_list[1]
713    self.assertEqual (first_args[0], second_args[0])
714    self.assertEqual (first_args[1], second_args[1])
715    self.assertEqual (len(first_args[0]), 1)
716    self.assertEqual (len(first_args[1]), 2)
717    self.assertEqual (first_args[0][0], 'ls')
718    args_dict = first_args[1]
719    self.assertEqual (args_dict['machine'], 'daisy.cros')
720    self.assertEqual (args_dict['chromeos_root'], '/usr/local/chromeos')
721
722
723  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
724  def test_parse_memory_info(self, mock_setup):
725    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
726                                     "average", self.mock_cmd_exec)
727    cm.meminfo = MEMINFO_STRING
728    cm._ParseMemoryInfo()
729    self.assertEqual(cm.phys_kbytes, 4194304)
730
731
732  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput')
733  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
734  def test_get_memory_info(self, mock_setup, mock_run_cmd):
735    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
736                                     "average", self.mock_cmd_exec)
737    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
738    mock_run_cmd.return_value = [0, MEMINFO_STRING, ""]
739    cm._GetMemoryInfo()
740    self.assertEqual(mock_run_cmd.call_count, 1)
741    call_args = mock_run_cmd.call_args_list[0]
742    self.assertEqual(call_args[0][0], "cat /proc/meminfo")
743    args_dict = call_args[1]
744    self.assertEqual(args_dict['machine'], 'daisy.cros')
745    self.assertEqual(args_dict['chromeos_root'], '/usr/local/chromeos')
746    self.assertEqual(cm.meminfo, MEMINFO_STRING)
747    self.assertEqual(cm.phys_kbytes, 4194304)
748
749    mock_run_cmd.return_value = [1, MEMINFO_STRING, ""]
750    self.assertRaises (cm._GetMemoryInfo)
751
752
753  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput')
754  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
755  def test_get_cpu_info(self, mock_setup, mock_run_cmd):
756    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
757                                     "average", self.mock_cmd_exec)
758    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
759    mock_run_cmd.return_value = [0, CPUINFO_STRING, ""]
760    cm._GetCPUInfo()
761    self.assertEqual(mock_run_cmd.call_count, 1)
762    call_args = mock_run_cmd.call_args_list[0]
763    self.assertEqual(call_args[0][0], "cat /proc/cpuinfo")
764    args_dict = call_args[1]
765    self.assertEqual(args_dict['machine'], 'daisy.cros')
766    self.assertEqual(args_dict['chromeos_root'], '/usr/local/chromeos')
767    self.assertEqual(cm.cpuinfo, CPUINFO_STRING)
768
769
770  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
771  def test_compute_machine_checksum_string(self, mock_setup):
772    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
773                                     "average", self.mock_cmd_exec)
774    cm.cpuinfo = CPUINFO_STRING
775    cm.meminfo = MEMINFO_STRING
776    cm._ParseMemoryInfo()
777    cm._ComputeMachineChecksumString()
778    self.assertEqual(cm.checksum_string, CHECKSUM_STRING)
779
780
781  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
782  def test_get_md5_checksum(self, mock_setup):
783    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
784                                     "average", self.mock_cmd_exec)
785    temp_str = "abcde"
786    checksum_str = cm._GetMD5Checksum(temp_str)
787    self.assertEqual(checksum_str, "ab56b4d92b40713acc5af89985d4b786")
788
789    temp_str = ""
790    checksum_str = cm._GetMD5Checksum(temp_str)
791    self.assertEqual(checksum_str, "")
792
793
794  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
795  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
796  def test_get_machine_id(self, mock_setup, mock_run_cmd):
797    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
798                                     "average", self.mock_cmd_exec)
799    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
800    mock_run_cmd.return_value = [0, DUMP_VPD_STRING, ""]
801
802    cm._GetMachineID()
803    self.assertEqual(cm.machine_id, '"Product_S/N"="HT4L91SC300208"')
804
805    mock_run_cmd.return_value = [0, IFCONFIG_STRING, ""]
806    cm._GetMachineID()
807    self.assertEqual(cm.machine_id, "        ether 00:50:b6:63:db:65  txqueuelen 1000  (Ethernet)_        ether e8:03:9a:9c:50:3d  txqueuelen 1000  (Ethernet)_        ether 44:6d:57:20:4a:c5  txqueuelen 1000  (Ethernet)")
808
809    mock_run_cmd.return_value = [0, "invalid hardware config", ""]
810    self.assertRaises(cm._GetMachineID)
811
812
813
814if __name__ == "__main__":
815  unittest.main()
816