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