machine_manager_unittest.py revision e627fd61c2edba668eb2af8221892286b13f05a3
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, 'CrosRunCommand')
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), 3)
256    self.assertEqual(args_dict['machine'], self.mock_lumpy1.name)
257    self.assertEqual(args_dict['chromeos_root'], '/usr/local/chromeos')
258    self.assertTrue(args_dict['return_output'])
259
260
261  @mock.patch.object(machine_manager, 'CrosMachine')
262  def test_add_machine(self, mock_machine):
263
264    mock_machine.machine_checksum = 'daisy123'
265    self.assertEqual (len(self.mm._all_machines), 5)
266    self.mm.AddMachine('daisy3')
267    self.assertEqual (len(self.mm._all_machines), 6)
268
269    self.assertRaises(Exception, self.mm.AddMachine, 'lumpy1')
270
271
272  def test_remove_machine(self):
273    self.mm._machines = self.mm._all_machines
274    self.assertTrue(self.mock_lumpy2 in self.mm._machines)
275    self.mm.RemoveMachine(self.mock_lumpy2.name)
276    self.assertFalse(self.mock_lumpy2 in self.mm._machines)
277
278
279  def test_force_same_image_to_all_machines(self):
280    self.image_log = []
281
282    def FakeImageMachine(machine, label_arg):
283      image = label_arg.chromeos_image
284      self.image_log.append("Pushed %s onto %s" % (image, machine.name))
285
286    def FakeSetUpChecksumInfo():
287      pass
288
289    self.mm.ImageMachine = FakeImageMachine
290    self.mock_lumpy1.SetUpChecksumInfo = FakeSetUpChecksumInfo
291    self.mock_lumpy2.SetUpChecksumInfo = FakeSetUpChecksumInfo
292    self.mock_lumpy3.SetUpChecksumInfo = FakeSetUpChecksumInfo
293
294    self.mm.ForceSameImageToAllMachines(LABEL_LUMPY)
295    self.assertEqual(len(self.image_log), 3)
296    self.assertEqual(self.image_log[0],
297                     'Pushed lumpy_chromeos_image onto lumpy1')
298    self.assertEqual(self.image_log[1],
299                     'Pushed lumpy_chromeos_image onto lumpy2')
300    self.assertEqual(self.image_log[2],
301                     'Pushed lumpy_chromeos_image onto lumpy3')
302
303
304
305  @mock.patch.object(image_checksummer.ImageChecksummer, 'Checksum')
306  @mock.patch.object(hashlib,'md5')
307  def test_acquire_machine(self, mock_md5, mock_checksum):
308
309    self.msgs = []
310    self.log_fatal_msgs = []
311
312    def FakeLock(machine):
313      self.msgs.append("Tried to lock %s" % machine.name)
314
315    def FakeLogFatal(msg):
316      self.log_fatal_msgs.append(msg)
317
318    self.mm._TryToLockMachine = FakeLock
319    self.mm.logger.LogFatal = FakeLogFatal
320
321    mock_md5.return_value = "123456"
322    mock_checksum.return_value = "fake_md5_checksum"
323
324    self.mm._machines = self.mm._all_machines
325    self.mock_lumpy1.locked = True
326    self.mock_lumpy2.locked = True
327    self.mock_lumpy3.locked = False
328    self.mock_lumpy3.checksum = "fake_md5_checksum"
329    self.mock_daisy1.locked = True
330    self.mock_daisy2.locked = False
331    self.mock_daisy2.checksum = "fake_md5_checksum"
332
333    self.mock_lumpy1.released_time = time.time()
334    self.mock_lumpy2.released_time = time.time()
335    self.mock_lumpy3.released_time = time.time()
336    self.mock_daisy1.released_time = time.time()
337    self.mock_daisy2.released_time = time.time()
338
339    # Test 1. Basic test. Acquire lumpy3.
340    self.mm.AcquireMachine(LABEL_LUMPY)
341    m = self.mock_lumpy1
342    self.assertEqual(m, self.mock_lumpy1)
343    self.assertTrue(self.mock_lumpy1.locked)
344    self.assertEqual(mock_md5.call_count, 0)
345    self.assertEqual(self.msgs, ['Tried to lock lumpy1',
346                                 '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
377  def test_get_available_machines(self):
378    self.mm._machines = self.mm._all_machines
379
380    machine_list = self.mm.GetAvailableMachines()
381    self.assertEqual(machine_list, self.mm._all_machines)
382
383    machine_list = self.mm.GetAvailableMachines(LABEL_MIX)
384    self.assertEqual(machine_list, [self.mock_daisy1, self.mock_daisy2,
385                                    self.mock_lumpy3])
386
387    machine_list = self.mm.GetAvailableMachines(LABEL_LUMPY)
388    self.assertEqual(machine_list, [self.mock_lumpy1, self.mock_lumpy2,
389                                    self.mock_lumpy3])
390
391
392  def test_get_machines(self):
393    machine_list = self.mm.GetMachines()
394    self.assertEqual(machine_list, self.mm._all_machines)
395
396    machine_list = self.mm.GetMachines(LABEL_MIX)
397    self.assertEqual(machine_list, [self.mock_daisy1, self.mock_daisy2,
398                                    self.mock_lumpy3])
399
400    machine_list = self.mm.GetMachines(LABEL_LUMPY)
401    self.assertEqual(machine_list, [self.mock_lumpy1, self.mock_lumpy2,
402                                    self.mock_lumpy3])
403
404
405  def test_release_machines(self):
406
407    self.mm._machines = [self.mock_lumpy1, self.mock_daisy2]
408
409    self.mock_lumpy1.locked = True
410    self.mock_daisy2.locked = True
411
412    self.assertTrue(self.mock_lumpy1.locked)
413    self.mm.ReleaseMachine(self.mock_lumpy1)
414    self.assertFalse(self.mock_lumpy1.locked)
415    self.assertEqual(self.mock_lumpy1.status, "Available")
416
417    self.assertTrue(self.mock_daisy2.locked)
418    self.mm.ReleaseMachine(self.mock_daisy2)
419    self.assertFalse(self.mock_daisy2.locked)
420    self.assertEqual(self.mock_daisy2.status, "Available")
421
422    # Test double-relase...
423    self.assertRaises(AssertionError, self.mm.ReleaseMachine, self.mock_lumpy1)
424
425
426  def test_cleanup(self):
427    self.mock_logger.reset_mock()
428    self.mm.Cleanup()
429    self.assertEqual(self.mock_logger.call_count, 0)
430
431  OUTPUT_STR = 'Machine Status:\nMachine                        Thread     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                             '
432
433  def test_as_string(self):
434
435    mock_logger = mock.Mock(spec=logger.Logger)
436
437    bench = Benchmark("page_cycler.netsim.top_10",    # name
438                      "page_cycler.netsim.top_10",    # test_name
439                      "",             # test_args
440                      1,              # iteratins
441                      False,          # rm_chroot_tmp
442                      "",             # perf_args
443                      suite="telemetry_Crosperf")     # suite
444
445    test_run = MockBenchmarkRun("test run",
446                         bench,
447                         LABEL_LUMPY,
448                         1,
449                         [],
450                         self.mm,
451                         mock_logger,
452                         "verbose",
453                         "")
454
455    self.mm._machines = [self.mock_lumpy1, self.mock_lumpy2, self.mock_lumpy3,
456                         self.mock_daisy1, self.mock_daisy2]
457
458    self.mock_lumpy1.test_run = test_run
459    self.mock_lumpy2.test_run = test_run
460    self.mock_lumpy3.test_run = test_run
461    self.mock_daisy1.test_run = test_run
462    self.mock_daisy2.test_run = test_run
463
464    self.mock_lumpy1.locked = True
465    self.mock_lumpy2.locked = False
466    self.mock_lumpy3.locked = False
467    self.mock_daisy1.locked = False
468    self.mock_daisy2.locked = True
469
470    self.mock_lumpy1.checksum = "123"
471    self.mock_lumpy2.checksum = "123"
472    self.mock_lumpy3.checksum = "123"
473    self.mock_daisy1.checksum = "678"
474    self.mock_daisy2.checksum = "678"
475
476    output = self.mm.AsString()
477    self.assertEqual(output, self.OUTPUT_STR)
478
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
487
488MEMINFO_STRING = """MemTotal:        3990332 kB
489MemFree:         2608396 kB
490Buffers:          147168 kB
491Cached:           811560 kB
492SwapCached:            0 kB
493Active:           503480 kB
494Inactive:         628572 kB
495Active(anon):     174532 kB
496Inactive(anon):    88576 kB
497Active(file):     328948 kB
498Inactive(file):   539996 kB
499Unevictable:           0 kB
500Mlocked:               0 kB
501SwapTotal:       5845212 kB
502SwapFree:        5845212 kB
503Dirty:              9384 kB
504Writeback:             0 kB
505AnonPages:        173408 kB
506Mapped:           146268 kB
507Shmem:             89676 kB
508Slab:             188260 kB
509SReclaimable:     169208 kB
510SUnreclaim:        19052 kB
511KernelStack:        2032 kB
512PageTables:         7120 kB
513NFS_Unstable:          0 kB
514Bounce:                0 kB
515WritebackTmp:          0 kB
516CommitLimit:     7840376 kB
517Committed_AS:    1082032 kB
518VmallocTotal:   34359738367 kB
519VmallocUsed:      364980 kB
520VmallocChunk:   34359369407 kB
521DirectMap4k:       45824 kB
522DirectMap2M:     4096000 kB
523"""
524
525CPUINFO_STRING = """processor: 0
526vendor_id: GenuineIntel
527cpu family: 6
528model: 42
529model name: Intel(R) Celeron(R) CPU 867 @ 1.30GHz
530stepping: 7
531microcode: 0x25
532cpu MHz: 1300.000
533cache size: 2048 KB
534physical id: 0
535siblings: 2
536core id: 0
537cpu cores: 2
538apicid: 0
539initial apicid: 0
540fpu: yes
541fpu_exception: yes
542cpuid level: 13
543wp: yes
544flags: 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
545bogomips: 2594.17
546clflush size: 64
547cache_alignment: 64
548address sizes: 36 bits physical, 48 bits virtual
549power management:
550
551processor: 1
552vendor_id: GenuineIntel
553cpu family: 6
554model: 42
555model name: Intel(R) Celeron(R) CPU 867 @ 1.30GHz
556stepping: 7
557microcode: 0x25
558cpu MHz: 1300.000
559cache size: 2048 KB
560physical id: 0
561siblings: 2
562core id: 1
563cpu cores: 2
564apicid: 2
565initial apicid: 2
566fpu: yes
567fpu_exception: yes
568cpuid level: 13
569wp: yes
570flags: 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
571bogomips: 2594.17
572clflush size: 64
573cache_alignment: 64
574address sizes: 36 bits physical, 48 bits virtual
575power management:
576"""
577
578CHECKSUM_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"
579
580DUMP_VPD_STRING = """
581"PBA_SN"="Pba.txt"
582"Product_S/N"="HT4L91SC300208"
583"serial_number"="HT4L91SC300208Z"
584"System_UUID"="12153006-1755-4f66-b410-c43758a71127"
585"shipping_country"="US"
586"initial_locale"="en-US"
587"keyboard_layout"="xkb:us::eng"
588"initial_timezone"="America/Los_Angeles"
589"MACAddress"=""
590"System_UUID"="29dd9c61-7fa1-4c83-b89a-502e7eb08afe"
591"ubind_attribute"="0c433ce7585f486730b682bb05626a12ce2d896e9b57665387f8ce2ccfdcc56d2e2f1483"
592"gbind_attribute"="7e9a851324088e269319347c6abb8d1572ec31022fa07e28998229afe8acb45c35a89b9d"
593"ActivateDate"="2013-38"
594"""
595
596
597IFCONFIG_STRING = """
598eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
599        inet 172.17.129.247  netmask 255.255.254.0  broadcast 172.17.129.255
600        inet6 2620:0:1000:3002:143:fed4:3ff6:279d  prefixlen 64  scopeid 0x0<global>
601        inet6 2620:0:1000:3002:4459:1399:1f02:9e4c  prefixlen 64  scopeid 0x0<global>
602        inet6 2620:0:1000:3002:d9e4:87b:d4ec:9a0e  prefixlen 64  scopeid 0x0<global>
603        inet6 2620:0:1000:3002:7d45:23f1:ea8a:9604  prefixlen 64  scopeid 0x0<global>
604        inet6 2620:0:1000:3002:250:b6ff:fe63:db65  prefixlen 64  scopeid 0x0<global>
605        inet6 fe80::250:b6ff:fe63:db65  prefixlen 64  scopeid 0x20<link>
606        ether 00:50:b6:63:db:65  txqueuelen 1000  (Ethernet)
607        RX packets 9817166  bytes 10865181708 (10.1 GiB)
608        RX errors 194  dropped 0  overruns 0  frame 194
609        TX packets 0  bytes 2265811903 (2.1 GiB)
610        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
611
612eth1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
613        ether e8:03:9a:9c:50:3d  txqueuelen 1000  (Ethernet)
614        RX packets 0  bytes 0 (0.0 B)
615        RX errors 0  dropped 0  overruns 0  frame 0
616        TX packets 0  bytes 0 (0.0 B)
617        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
618
619lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 16436
620        inet 127.0.0.1  netmask 255.0.0.0
621        inet6 ::1  prefixlen 128  scopeid 0x10<host>
622        loop  txqueuelen 0  (Local Loopback)
623        RX packets 981004  bytes 1127468524 (1.0 GiB)
624        RX errors 0  dropped 0  overruns 0  frame 0
625        TX packets 981004  bytes 1127468524 (1.0 GiB)
626        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
627
628wlan0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
629        ether 44:6d:57:20:4a:c5  txqueuelen 1000  (Ethernet)
630        RX packets 0  bytes 0 (0.0 B)
631        RX errors 0  dropped 0  overruns 0  frame 0
632        TX packets 0  bytes 0 (0.0 B)
633        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
634"""
635
636
637class CrosMachineTest(unittest.TestCase):
638
639  mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter)
640
641  @mock.patch.object(machine_manager.CrosMachine, 'SetUpChecksumInfo')
642  def test_init(self, mock_setup):
643
644    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
645                                     "average", self.mock_cmd_exec)
646    self.assertEqual(mock_setup.call_count, 1)
647    self.assertEqual(cm.chromeos_root, "/usr/local/chromeos")
648    self.assertEqual(cm.log_level, "average")
649
650
651  @mock.patch.object(machine_manager.CrosMachine, 'IsReachable')
652  @mock.patch.object(machine_manager.CrosMachine, '_GetMemoryInfo')
653  @mock.patch.object(machine_manager.CrosMachine, '_GetCPUInfo')
654  @mock.patch.object(machine_manager.CrosMachine,
655                     '_ComputeMachineChecksumString')
656  @mock.patch.object(machine_manager.CrosMachine, '_GetMachineID')
657  @mock.patch.object(machine_manager.CrosMachine, '_GetMD5Checksum')
658  def test_setup_checksum_info(self, mock_md5sum, mock_machineid,
659                               mock_checkstring, mock_cpuinfo, mock_meminfo,
660                               mock_isreachable):
661
662    # Test 1. Machine is not reachable; SetUpChecksumInfo is called via
663    # __init__.
664    mock_isreachable.return_value = False
665    mock_md5sum.return_value = "md5_checksum"
666    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
667                                     "average", self.mock_cmd_exec)
668    cm.checksum_string = "This is a checksum string."
669    cm.machine_id = "machine_id1"
670    self.assertEqual(mock_isreachable.call_count, 1)
671    self.assertIsNone(cm.machine_checksum)
672    self.assertEqual(mock_meminfo.call_count, 0)
673
674    # Test 2. Machine is reachable. Call explicitly.
675    mock_isreachable.return_value = True
676    cm.checksum_string = "This is a checksum string."
677    cm.machine_id = "machine_id1"
678    cm.SetUpChecksumInfo()
679    self.assertEqual(mock_isreachable.call_count, 2)
680    self.assertEqual(mock_meminfo.call_count, 1)
681    self.assertEqual(mock_cpuinfo.call_count, 1)
682    self.assertEqual(mock_checkstring.call_count, 1)
683    self.assertEqual(mock_machineid.call_count, 1)
684    self.assertEqual(mock_md5sum.call_count, 2)
685    self.assertEqual(cm.machine_checksum, "md5_checksum")
686    self.assertEqual(cm.machine_id_checksum, "md5_checksum")
687    self.assertEqual(mock_md5sum.call_args_list[0][0][0],
688                     "This is a checksum string.")
689    self.assertEqual(mock_md5sum.call_args_list[1][0][0],
690                     "machine_id1")
691
692  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
693  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
694  def test_is_reachable(self, mock_setup, mock_run_cmd):
695
696    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
697                                     "average", self.mock_cmd_exec)
698    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
699
700    # Test 1. CrosRunCommand returns 1 (fail)
701    mock_run_cmd.return_value = 1
702    result = cm.IsReachable()
703    self.assertFalse(result)
704    self.assertEqual(mock_setup.call_count, 1)
705    self.assertEqual(mock_run_cmd.call_count, 1)
706
707    # Test 2. CrosRunCommand returns 0 (success)
708    mock_run_cmd.return_value = 0
709    result = cm.IsReachable()
710    self.assertTrue(result)
711    self.assertEqual(mock_run_cmd.call_count, 2)
712    first_args = mock_run_cmd.call_args_list[0]
713    second_args = mock_run_cmd.call_args_list[1]
714    self.assertEqual (first_args[0], second_args[0])
715    self.assertEqual (first_args[1], second_args[1])
716    self.assertEqual (len(first_args[0]), 1)
717    self.assertEqual (len(first_args[1]), 2)
718    self.assertEqual (first_args[0][0], 'ls')
719    args_dict = first_args[1]
720    self.assertEqual (args_dict['machine'], 'daisy.cros')
721    self.assertEqual (args_dict['chromeos_root'], '/usr/local/chromeos')
722
723
724  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
725  def test_parse_memory_info(self, mock_setup):
726    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
727                                     "average", self.mock_cmd_exec)
728    cm.meminfo = MEMINFO_STRING
729    cm._ParseMemoryInfo()
730    self.assertEqual(cm.phys_kbytes, 4194304)
731
732
733  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
734  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
735  def test_get_memory_info(self, mock_setup, mock_run_cmd):
736    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
737                                     "average", self.mock_cmd_exec)
738    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
739    mock_run_cmd.return_value = [0, MEMINFO_STRING, ""]
740    cm._GetMemoryInfo()
741    self.assertEqual(mock_run_cmd.call_count, 1)
742    call_args = mock_run_cmd.call_args_list[0]
743    self.assertEqual(call_args[0][0], "cat /proc/meminfo")
744    args_dict = call_args[1]
745    self.assertEqual(args_dict['machine'], 'daisy.cros')
746    self.assertEqual(args_dict['chromeos_root'], '/usr/local/chromeos')
747    self.assertEqual(args_dict['return_output'], True)
748    self.assertEqual(cm.meminfo, MEMINFO_STRING)
749    self.assertEqual(cm.phys_kbytes, 4194304)
750
751    mock_run_cmd.return_value = [1, MEMINFO_STRING, ""]
752    self.assertRaises (cm._GetMemoryInfo)
753
754
755  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
756  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
757  def test_get_cpu_info(self, mock_setup, mock_run_cmd):
758    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
759                                     "average", self.mock_cmd_exec)
760    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
761    mock_run_cmd.return_value = [0, CPUINFO_STRING, ""]
762    cm._GetCPUInfo()
763    self.assertEqual(mock_run_cmd.call_count, 1)
764    call_args = mock_run_cmd.call_args_list[0]
765    self.assertEqual(call_args[0][0], "cat /proc/cpuinfo")
766    args_dict = call_args[1]
767    self.assertEqual(args_dict['machine'], 'daisy.cros')
768    self.assertEqual(args_dict['chromeos_root'], '/usr/local/chromeos')
769    self.assertEqual(args_dict['return_output'], True)
770    self.assertEqual(cm.cpuinfo, CPUINFO_STRING)
771
772
773  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
774  def test_compute_machine_checksum_string(self, mock_setup):
775    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
776                                     "average", self.mock_cmd_exec)
777    cm.cpuinfo = CPUINFO_STRING
778    cm.meminfo = MEMINFO_STRING
779    cm._ParseMemoryInfo()
780    cm._ComputeMachineChecksumString()
781    self.assertEqual(cm.checksum_string, CHECKSUM_STRING)
782
783
784  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
785  def test_get_md5_checksum(self, mock_setup):
786    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
787                                     "average", self.mock_cmd_exec)
788    temp_str = "abcde"
789    checksum_str = cm._GetMD5Checksum(temp_str)
790    self.assertEqual(checksum_str, "ab56b4d92b40713acc5af89985d4b786")
791
792    temp_str = ""
793    checksum_str = cm._GetMD5Checksum(temp_str)
794    self.assertEqual(checksum_str, "")
795
796
797  @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand')
798  @mock.patch.object(machine_manager.CrosMachine, "SetUpChecksumInfo")
799  def test_get_machine_id(self, mock_setup, mock_run_cmd):
800    cm = machine_manager.CrosMachine("daisy.cros", "/usr/local/chromeos",
801                                     "average", self.mock_cmd_exec)
802    self.mock_cmd_exec.CrosRunCommand = mock_run_cmd
803    mock_run_cmd.return_value = [0, DUMP_VPD_STRING, ""]
804
805    cm._GetMachineID()
806    self.assertEqual(cm.machine_id, '"Product_S/N"="HT4L91SC300208"')
807
808    mock_run_cmd.return_value = [0, IFCONFIG_STRING, ""]
809    cm._GetMachineID()
810    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)")
811
812    mock_run_cmd.return_value = [0, "invalid hardware config", ""]
813    self.assertRaises(cm._GetMachineID)
814
815
816
817if __name__ == "__main__":
818  unittest.main()
819