diff options
Diffstat (limited to 'crosperf/schedv2_unittest.py')
-rwxr-xr-x | crosperf/schedv2_unittest.py | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/crosperf/schedv2_unittest.py b/crosperf/schedv2_unittest.py new file mode 100755 index 00000000..be0fde4b --- /dev/null +++ b/crosperf/schedv2_unittest.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python2 + +# Copyright 2015 Google Inc. All Rights Reserved. +"""This contains the unit tests for the new Crosperf task scheduler.""" + +from __future__ import print_function + +import mock +import unittest +import StringIO + +import benchmark_run +import test_flag +from experiment_factory import ExperimentFactory +from experiment_file import ExperimentFile +from cros_utils.command_executer import CommandExecuter +from experiment_runner_unittest import FakeLogger +from schedv2 import Schedv2 + +EXPERIMENT_FILE_1 = """\ +board: daisy +remote: chromeos-daisy1.cros chromeos-daisy2.cros + +benchmark: kraken { + suite: telemetry_Crosperf + iterations: 3 +} + +image1 { + chromeos_image: /chromeos/src/build/images/daisy/latest/cros_image1.bin + remote: chromeos-daisy3.cros +} + +image2 { + chromeos_image: /chromeos/src/build/imaages/daisy/latest/cros_image2.bin + remote: chromeos-daisy4.cros chromeos-daisy5.cros +} +""" + +EXPERIMENT_FILE_WITH_FORMAT = """\ +board: daisy +remote: chromeos-daisy1.cros chromeos-daisy2.cros + +benchmark: kraken {{ + suite: telemetry_Crosperf + iterations: {kraken_iterations} +}} + +image1 {{ + chromeos_image: /chromeos/src/build/images/daisy/latest/cros_image1.bin + remote: chromeos-daisy3.cros +}} + +image2 {{ + chromeos_image: /chromeos/src/build/imaages/daisy/latest/cros_image2.bin + remote: chromeos-daisy4.cros chromeos-daisy5.cros +}} +""" + + +class Schedv2Test(unittest.TestCase): + """Class for setting up and running the unit tests.""" + + def setUp(self): + self.exp = None + + mock_logger = FakeLogger() + mock_cmd_exec = mock.Mock(spec=CommandExecuter) + + @mock.patch('benchmark_run.BenchmarkRun', new=benchmark_run.MockBenchmarkRun) + def _make_fake_experiment(self, expstr): + """Create fake experiment from string. + + Note - we mock out BenchmarkRun in this step. + """ + experiment_file = ExperimentFile(StringIO.StringIO(expstr)) + experiment = ExperimentFactory().GetExperiment(experiment_file, + working_directory='', + log_dir='') + return experiment + + def test_remote(self): + """Test that remotes in labels are aggregated into experiment.remote.""" + + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_1) + self.exp.log_level = 'verbose' + my_schedv2 = Schedv2(self.exp) + self.assertFalse(my_schedv2.is_complete()) + self.assertIn('chromeos-daisy1.cros', self.exp.remote) + self.assertIn('chromeos-daisy2.cros', self.exp.remote) + self.assertIn('chromeos-daisy3.cros', self.exp.remote) + self.assertIn('chromeos-daisy4.cros', self.exp.remote) + self.assertIn('chromeos-daisy5.cros', self.exp.remote) + + def test_unreachable_remote(self): + """Test unreachable remotes are removed from experiment and label.""" + + def MockIsReachable(cm): + return (cm.name != 'chromeos-daisy3.cros' and + cm.name != 'chromeos-daisy5.cros') + + with mock.patch('machine_manager.MockCrosMachine.IsReachable', + new=MockIsReachable): + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_1) + self.assertIn('chromeos-daisy1.cros', self.exp.remote) + self.assertIn('chromeos-daisy2.cros', self.exp.remote) + self.assertNotIn('chromeos-daisy3.cros', self.exp.remote) + self.assertIn('chromeos-daisy4.cros', self.exp.remote) + self.assertNotIn('chromeos-daisy5.cros', self.exp.remote) + + for l in self.exp.labels: + if l.name == 'image2': + self.assertNotIn('chromeos-daisy5.cros', l.remote) + self.assertIn('chromeos-daisy4.cros', l.remote) + elif l.name == 'image1': + self.assertNotIn('chromeos-daisy3.cros', l.remote) + + @mock.patch('schedv2.BenchmarkRunCacheReader') + def test_BenchmarkRunCacheReader_1(self, reader): + """Test benchmarkrun set is split into 5 segments.""" + + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format( + kraken_iterations=9)) + my_schedv2 = Schedv2(self.exp) + self.assertFalse(my_schedv2.is_complete()) + # We have 9 * 2 == 18 brs, we use 5 threads, each reading 4, 4, 4, + # 4, 2 brs respectively. + # Assert that BenchmarkRunCacheReader() is called 5 times. + self.assertEquals(reader.call_count, 5) + # reader.call_args_list[n] - nth call. + # reader.call_args_list[n][0] - positioned args in nth call. + # reader.call_args_list[n][0][1] - the 2nd arg in nth call, + # that is 'br_list' in 'schedv2.BenchmarkRunCacheReader'. + self.assertEquals(len(reader.call_args_list[0][0][1]), 4) + self.assertEquals(len(reader.call_args_list[1][0][1]), 4) + self.assertEquals(len(reader.call_args_list[2][0][1]), 4) + self.assertEquals(len(reader.call_args_list[3][0][1]), 4) + self.assertEquals(len(reader.call_args_list[4][0][1]), 2) + + @mock.patch('schedv2.BenchmarkRunCacheReader') + def test_BenchmarkRunCacheReader_2(self, reader): + """Test benchmarkrun set is split into 4 segments.""" + + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format( + kraken_iterations=8)) + my_schedv2 = Schedv2(self.exp) + self.assertFalse(my_schedv2.is_complete()) + # We have 8 * 2 == 16 brs, we use 4 threads, each reading 4 brs. + self.assertEquals(reader.call_count, 4) + self.assertEquals(len(reader.call_args_list[0][0][1]), 4) + self.assertEquals(len(reader.call_args_list[1][0][1]), 4) + self.assertEquals(len(reader.call_args_list[2][0][1]), 4) + self.assertEquals(len(reader.call_args_list[3][0][1]), 4) + + @mock.patch('schedv2.BenchmarkRunCacheReader') + def test_BenchmarkRunCacheReader_3(self, reader): + """Test benchmarkrun set is split into 2 segments.""" + + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format( + kraken_iterations=3)) + my_schedv2 = Schedv2(self.exp) + self.assertFalse(my_schedv2.is_complete()) + # We have 3 * 2 == 6 brs, we use 2 threads. + self.assertEquals(reader.call_count, 2) + self.assertEquals(len(reader.call_args_list[0][0][1]), 3) + self.assertEquals(len(reader.call_args_list[1][0][1]), 3) + + @mock.patch('schedv2.BenchmarkRunCacheReader') + def test_BenchmarkRunCacheReader_4(self, reader): + """Test benchmarkrun set is not splitted.""" + + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format( + kraken_iterations=1)) + my_schedv2 = Schedv2(self.exp) + self.assertFalse(my_schedv2.is_complete()) + # We have 1 * 2 == 2 br, so only 1 instance. + self.assertEquals(reader.call_count, 1) + self.assertEquals(len(reader.call_args_list[0][0][1]), 2) + + def test_cachehit(self): + """Test cache-hit and none-cache-hit brs are properly organized.""" + + def MockReadCache(br): + br.cache_hit = (br.label.name == 'image2') + + with mock.patch('benchmark_run.MockBenchmarkRun.ReadCache', + new=MockReadCache): + # We have 2 * 30 brs, half of which are put into _cached_br_list. + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format( + kraken_iterations=30)) + my_schedv2 = Schedv2(self.exp) + self.assertEquals(len(my_schedv2.get_cached_run_list()), 30) + # The non-cache-hit brs are put into Schedv2._label_brl_map. + self.assertEquals( + reduce(lambda a, x: a + len(x[1]), + my_schedv2.get_label_map().iteritems(), + 0), 30) + + def test_nocachehit(self): + """Test no cache-hit.""" + + def MockReadCache(br): + br.cache_hit = False + + with mock.patch('benchmark_run.MockBenchmarkRun.ReadCache', + new=MockReadCache): + # We have 2 * 30 brs, none of which are put into _cached_br_list. + self.exp = self._make_fake_experiment(EXPERIMENT_FILE_WITH_FORMAT.format( + kraken_iterations=30)) + my_schedv2 = Schedv2(self.exp) + self.assertEquals(len(my_schedv2.get_cached_run_list()), 0) + # The non-cache-hit brs are put into Schedv2._label_brl_map. + self.assertEquals( + reduce(lambda a, x: a + len(x[1]), + my_schedv2.get_label_map().iteritems(), + 0), 60) + + +if __name__ == '__main__': + test_flag.SetTestMode(True) + unittest.main() |