schedv2_unittest.py revision f2a3ef46f75d2196a93d3ed27f4d1fcf22b54fbe
1#!/usr/bin/python
2
3# Copyright 2015 Google Inc. All Rights Reserved.
4
5import mock
6import unittest
7import StringIO
8
9import benchmark_run
10import machine_manager
11import schedv2
12import test_flag
13from benchmark_run import MockBenchmarkRun
14from experiment_factory import ExperimentFactory
15from experiment_file import ExperimentFile
16from experiment_runner import ExperimentRunner
17from machine_manager import MockCrosMachine
18from cros_utils import command_executer
19from cros_utils.command_executer import CommandExecuter
20from experiment_runner_unittest import FakeLogger
21from schedv2 import Schedv2
22
23EXPERIMENT_FILE_1 = """\
24board: daisy
25remote: chromeos-daisy1.cros chromeos-daisy2.cros
26
27benchmark: kraken {
28  suite: telemetry_Crosperf
29  iterations: 3
30}
31
32image1 {
33  chromeos_image: /chromeos/src/build/images/daisy/latest/cros_image1.bin
34  remote: chromeos-daisy3.cros
35}
36
37image2 {
38  chromeos_image: /chromeos/src/build/imaages/daisy/latest/cros_image2.bin
39  remote: chromeos-daisy4.cros chromeos-daisy5.cros
40}
41"""
42
43EXPERIMENT_FILE_WITH_FORMAT = """\
44board: daisy
45remote: chromeos-daisy1.cros chromeos-daisy2.cros
46
47benchmark: kraken {{
48  suite: telemetry_Crosperf
49  iterations: {kraken_iterations}
50}}
51
52image1 {{
53  chromeos_image: /chromeos/src/build/images/daisy/latest/cros_image1.bin
54  remote: chromeos-daisy3.cros
55}}
56
57image2 {{
58  chromeos_image: /chromeos/src/build/imaages/daisy/latest/cros_image2.bin
59  remote: chromeos-daisy4.cros chromeos-daisy5.cros
60}}
61"""
62
63
64class Schedv2Test(unittest.TestCase):
65
66  mock_logger = FakeLogger()
67  mock_cmd_exec = mock.Mock(spec=CommandExecuter)
68
69  @mock.patch('benchmark_run.BenchmarkRun', new=benchmark_run.MockBenchmarkRun)
70  def _make_fake_experiment(self, expstr):
71    """Create fake experiment from string.
72
73        Note - we mock out BenchmarkRun in this step.
74        """
75    experiment_file = ExperimentFile(StringIO.StringIO(expstr))
76    experiment = ExperimentFactory().GetExperiment(experiment_file,
77                                                   working_directory='',
78                                                   log_dir='')
79    return experiment
80
81  def test_remote(self):
82    """Test that remotes in labels are aggregated into experiment.remote."""
83
84    self.exp = self._make_fake_experiment(EXPERIMENT_FILE_1)
85    self.exp.log_level = 'verbose'
86    schedv2 = Schedv2(self.exp)
87    self.assertIn('chromeos-daisy1.cros', self.exp.remote)
88    self.assertIn('chromeos-daisy2.cros', self.exp.remote)
89    self.assertIn('chromeos-daisy3.cros', self.exp.remote)
90    self.assertIn('chromeos-daisy4.cros', self.exp.remote)
91    self.assertIn('chromeos-daisy5.cros', self.exp.remote)
92
93  def test_unreachable_remote(self):
94    """Test unreachable remotes are removed from experiment remote and
95        label.remote."""
96
97    def MockIsReachable(cm):
98      return (cm.name != 'chromeos-daisy3.cros' and
99              cm.name != 'chromeos-daisy5.cros')
100
101    with mock.patch('machine_manager.MockCrosMachine.IsReachable',
102                    new=MockIsReachable) as f:
103      self.exp = self._make_fake_experiment(EXPERIMENT_FILE_1)
104      self.assertIn('chromeos-daisy1.cros', self.exp.remote)
105      self.assertIn('chromeos-daisy2.cros', self.exp.remote)
106      self.assertNotIn('chromeos-daisy3.cros', self.exp.remote)
107      self.assertIn('chromeos-daisy4.cros', self.exp.remote)
108      self.assertNotIn('chromeos-daisy5.cros', self.exp.remote)
109
110      for l in self.exp.labels:
111        if l.name == 'image2':
112          self.assertNotIn('chromeos-daisy5.cros', l.remote)
113          self.assertIn('chromeos-daisy4.cros', l.remote)
114        elif l.name == 'image1':
115          self.assertNotIn('chromeos-daisy3.cros', l.remote)
116
117  @mock.patch('schedv2.BenchmarkRunCacheReader')
118  def test_BenchmarkRunCacheReader_1(self, reader):
119    """Test benchmarkrun set is split into 5 segments."""
120
121    self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format(
122        kraken_iterations=9))
123    schedv2 = Schedv2(self.exp)
124    # We have 9 * 2 == 18 brs, we use 5 threads, each reading 4, 4, 4,
125    # 4, 2 brs respectively.
126    # Assert that BenchmarkRunCacheReader() is called 5 times.
127    self.assertEquals(reader.call_count, 5)
128    # reader.call_args_list[n] - nth call.
129    # reader.call_args_list[n][0] - positioned args in nth call.
130    # reader.call_args_list[n][0][1] - the 2nd arg in nth call,
131    # that is 'br_list' in 'schedv2.BenchmarkRunCacheReader'.
132    self.assertEquals(len(reader.call_args_list[0][0][1]), 4)
133    self.assertEquals(len(reader.call_args_list[1][0][1]), 4)
134    self.assertEquals(len(reader.call_args_list[2][0][1]), 4)
135    self.assertEquals(len(reader.call_args_list[3][0][1]), 4)
136    self.assertEquals(len(reader.call_args_list[4][0][1]), 2)
137
138  @mock.patch('schedv2.BenchmarkRunCacheReader')
139  def test_BenchmarkRunCacheReader_2(self, reader):
140    """Test benchmarkrun set is split into 4 segments."""
141
142    self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format(
143        kraken_iterations=8))
144    schedv2 = Schedv2(self.exp)
145    # We have 8 * 2 == 16 brs, we use 4 threads, each reading 4 brs.
146    self.assertEquals(reader.call_count, 4)
147    self.assertEquals(len(reader.call_args_list[0][0][1]), 4)
148    self.assertEquals(len(reader.call_args_list[1][0][1]), 4)
149    self.assertEquals(len(reader.call_args_list[2][0][1]), 4)
150    self.assertEquals(len(reader.call_args_list[3][0][1]), 4)
151
152  @mock.patch('schedv2.BenchmarkRunCacheReader')
153  def test_BenchmarkRunCacheReader_3(self, reader):
154    """Test benchmarkrun set is split into 2 segments."""
155
156    self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format(
157        kraken_iterations=3))
158    schedv2 = Schedv2(self.exp)
159    # We have 3 * 2 == 6 brs, we use 2 threads.
160    self.assertEquals(reader.call_count, 2)
161    self.assertEquals(len(reader.call_args_list[0][0][1]), 3)
162    self.assertEquals(len(reader.call_args_list[1][0][1]), 3)
163
164  @mock.patch('schedv2.BenchmarkRunCacheReader')
165  def test_BenchmarkRunCacheReader_4(self, reader):
166    """Test benchmarkrun set is not splitted."""
167
168    self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format(
169        kraken_iterations=1))
170    schedv2 = Schedv2(self.exp)
171    # We have 1 * 2 == 2 br, so only 1 instance.
172    self.assertEquals(reader.call_count, 1)
173    self.assertEquals(len(reader.call_args_list[0][0][1]), 2)
174
175  def test_cachehit(self):
176    """Test cache-hit and none-cache-hit brs are properly organized."""
177
178    def MockReadCache(br):
179      br.cache_hit = (br.label.name == 'image2')
180
181    with mock.patch('benchmark_run.MockBenchmarkRun.ReadCache',
182                    new=MockReadCache) as f:
183      # We have 2 * 30 brs, half of which are put into _cached_br_list.
184      self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format(
185          kraken_iterations=30))
186      schedv2 = Schedv2(self.exp)
187      self.assertEquals(len(schedv2._cached_br_list), 30)
188      # The non-cache-hit brs are put into Schedv2._label_brl_map.
189      self.assertEquals(
190          reduce(lambda a, x: a + len(x[1]), schedv2._label_brl_map.iteritems(),
191                 0), 30)
192
193  def test_nocachehit(self):
194    """Test no cache-hit."""
195
196    def MockReadCache(br):
197      br.cache_hit = False
198
199    with mock.patch('benchmark_run.MockBenchmarkRun.ReadCache',
200                    new=MockReadCache) as f:
201      # We have 2 * 30 brs, none of which are put into _cached_br_list.
202      self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format(
203          kraken_iterations=30))
204      schedv2 = Schedv2(self.exp)
205      self.assertEquals(len(schedv2._cached_br_list), 0)
206      # The non-cache-hit brs are put into Schedv2._label_brl_map.
207      self.assertEquals(
208          reduce(lambda a, x: a + len(x[1]), schedv2._label_brl_map.iteritems(),
209                 0), 60)
210
211
212if __name__ == '__main__':
213  test_flag.SetTestMode(True)
214  unittest.main()
215