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