#!/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()