1*760c253cSXin Li#!/usr/bin/env python3 2*760c253cSXin Li# -*- coding: utf-8 -*- 3*760c253cSXin Li# 4*760c253cSXin Li# Copyright 2014 The ChromiumOS Authors 5*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be 6*760c253cSXin Li# found in the LICENSE file. 7*760c253cSXin Li 8*760c253cSXin Li"""Tests for the experiment runner module.""" 9*760c253cSXin Li 10*760c253cSXin Li 11*760c253cSXin Liimport getpass 12*760c253cSXin Liimport io 13*760c253cSXin Liimport os 14*760c253cSXin Liimport time 15*760c253cSXin Liimport unittest 16*760c253cSXin Liimport unittest.mock as mock 17*760c253cSXin Li 18*760c253cSXin Lifrom cros_utils import command_executer 19*760c253cSXin Lifrom cros_utils.email_sender import EmailSender 20*760c253cSXin Lifrom cros_utils.file_utils import FileUtils 21*760c253cSXin Lifrom experiment_factory import ExperimentFactory 22*760c253cSXin Lifrom experiment_file import ExperimentFile 23*760c253cSXin Liimport experiment_runner 24*760c253cSXin Liimport experiment_status 25*760c253cSXin Liimport machine_manager 26*760c253cSXin Lifrom results_cache import Result 27*760c253cSXin Lifrom results_report import HTMLResultsReport 28*760c253cSXin Lifrom results_report import TextResultsReport 29*760c253cSXin Liimport test_flag 30*760c253cSXin Li 31*760c253cSXin Liimport config 32*760c253cSXin Li 33*760c253cSXin Li 34*760c253cSXin LiEXPERIMENT_FILE_1 = """ 35*760c253cSXin Li board: parrot 36*760c253cSXin Li remote: chromeos-parrot1.cros chromreos-parrot2.cros 37*760c253cSXin Li locks_dir: /tmp 38*760c253cSXin Li 39*760c253cSXin Li benchmark: kraken { 40*760c253cSXin Li suite: telemetry_Crosperf 41*760c253cSXin Li iterations: 3 42*760c253cSXin Li } 43*760c253cSXin Li 44*760c253cSXin Li image1 { 45*760c253cSXin Li chromeos_root: /usr/local/google/chromeos 46*760c253cSXin Li chromeos_image: /usr/local/google/chromeos/src/build/images/parrot/latest/cros_image1.bin 47*760c253cSXin Li } 48*760c253cSXin Li 49*760c253cSXin Li image2 { 50*760c253cSXin Li chromeos_image: /usr/local/google/chromeos/src/build/imaages/parrot/latest/cros_image2.bin 51*760c253cSXin Li } 52*760c253cSXin Li """ 53*760c253cSXin Li 54*760c253cSXin Li# pylint: disable=protected-access 55*760c253cSXin Li 56*760c253cSXin Li 57*760c253cSXin Liclass FakeLogger(object): 58*760c253cSXin Li """Fake logger for tests.""" 59*760c253cSXin Li 60*760c253cSXin Li def __init__(self): 61*760c253cSXin Li self.LogOutputCount = 0 62*760c253cSXin Li self.LogErrorCount = 0 63*760c253cSXin Li self.output_msgs = [] 64*760c253cSXin Li self.error_msgs = [] 65*760c253cSXin Li self.dot_count = 0 66*760c253cSXin Li self.LogStartDotsCount = 0 67*760c253cSXin Li self.LogEndDotsCount = 0 68*760c253cSXin Li self.LogAppendDotCount = 0 69*760c253cSXin Li 70*760c253cSXin Li def LogOutput(self, msg): 71*760c253cSXin Li self.LogOutputCount += 1 72*760c253cSXin Li self.output_msgs.append(msg) 73*760c253cSXin Li 74*760c253cSXin Li def LogError(self, msg): 75*760c253cSXin Li self.LogErrorCount += 1 76*760c253cSXin Li self.error_msgs.append(msg) 77*760c253cSXin Li 78*760c253cSXin Li def LogStartDots(self): 79*760c253cSXin Li self.LogStartDotsCount += 1 80*760c253cSXin Li self.dot_count += 1 81*760c253cSXin Li 82*760c253cSXin Li def LogAppendDot(self): 83*760c253cSXin Li self.LogAppendDotCount += 1 84*760c253cSXin Li self.dot_count += 1 85*760c253cSXin Li 86*760c253cSXin Li def LogEndDots(self): 87*760c253cSXin Li self.LogEndDotsCount += 1 88*760c253cSXin Li 89*760c253cSXin Li def Reset(self): 90*760c253cSXin Li self.LogOutputCount = 0 91*760c253cSXin Li self.LogErrorCount = 0 92*760c253cSXin Li self.output_msgs = [] 93*760c253cSXin Li self.error_msgs = [] 94*760c253cSXin Li self.dot_count = 0 95*760c253cSXin Li self.LogStartDotsCount = 0 96*760c253cSXin Li self.LogEndDotsCount = 0 97*760c253cSXin Li self.LogAppendDotCount = 0 98*760c253cSXin Li 99*760c253cSXin Li 100*760c253cSXin Liclass ExperimentRunnerTest(unittest.TestCase): 101*760c253cSXin Li """Test for experiment runner class.""" 102*760c253cSXin Li 103*760c253cSXin Li run_count = 0 104*760c253cSXin Li is_complete_count = 0 105*760c253cSXin Li mock_logger = FakeLogger() 106*760c253cSXin Li mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter) 107*760c253cSXin Li 108*760c253cSXin Li def make_fake_experiment(self): 109*760c253cSXin Li test_flag.SetTestMode(True) 110*760c253cSXin Li experiment_file = ExperimentFile(io.StringIO(EXPERIMENT_FILE_1)) 111*760c253cSXin Li experiment = ExperimentFactory().GetExperiment( 112*760c253cSXin Li experiment_file, working_directory="", log_dir="" 113*760c253cSXin Li ) 114*760c253cSXin Li return experiment 115*760c253cSXin Li 116*760c253cSXin Li @mock.patch.object(machine_manager.MachineManager, "AddMachine") 117*760c253cSXin Li @mock.patch.object(os.path, "isfile") 118*760c253cSXin Li 119*760c253cSXin Li # pylint: disable=arguments-differ 120*760c253cSXin Li def setUp(self, mock_isfile, _mock_addmachine): 121*760c253cSXin Li mock_isfile.return_value = True 122*760c253cSXin Li self.exp = self.make_fake_experiment() 123*760c253cSXin Li 124*760c253cSXin Li def test_init(self): 125*760c253cSXin Li er = experiment_runner.ExperimentRunner( 126*760c253cSXin Li self.exp, 127*760c253cSXin Li json_report=False, 128*760c253cSXin Li using_schedv2=False, 129*760c253cSXin Li log=self.mock_logger, 130*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 131*760c253cSXin Li ) 132*760c253cSXin Li self.assertFalse(er._terminated) 133*760c253cSXin Li self.assertEqual(er.STATUS_TIME_DELAY, 10) 134*760c253cSXin Li 135*760c253cSXin Li self.exp.log_level = "verbose" 136*760c253cSXin Li er = experiment_runner.ExperimentRunner( 137*760c253cSXin Li self.exp, 138*760c253cSXin Li json_report=False, 139*760c253cSXin Li using_schedv2=False, 140*760c253cSXin Li log=self.mock_logger, 141*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 142*760c253cSXin Li ) 143*760c253cSXin Li self.assertEqual(er.STATUS_TIME_DELAY, 30) 144*760c253cSXin Li 145*760c253cSXin Li @mock.patch.object(time, "time") 146*760c253cSXin Li @mock.patch.object(time, "sleep") 147*760c253cSXin Li @mock.patch.object(experiment_status.ExperimentStatus, "GetStatusString") 148*760c253cSXin Li @mock.patch.object(experiment_status.ExperimentStatus, "GetProgressString") 149*760c253cSXin Li def test_run( 150*760c253cSXin Li self, mock_progress_string, mock_status_string, mock_sleep, mock_time 151*760c253cSXin Li ): 152*760c253cSXin Li 153*760c253cSXin Li self.run_count = 0 154*760c253cSXin Li self.is_complete_count = 0 155*760c253cSXin Li mock_sleep.return_value = None 156*760c253cSXin Li # pylint: disable=range-builtin-not-iterating 157*760c253cSXin Li mock_time.side_effect = range(1, 50, 1) 158*760c253cSXin Li 159*760c253cSXin Li def reset(): 160*760c253cSXin Li self.run_count = 0 161*760c253cSXin Li self.is_complete_count = 0 162*760c253cSXin Li 163*760c253cSXin Li def FakeRun(): 164*760c253cSXin Li self.run_count += 1 165*760c253cSXin Li return 0 166*760c253cSXin Li 167*760c253cSXin Li def FakeIsComplete(): 168*760c253cSXin Li self.is_complete_count += 1 169*760c253cSXin Li if self.is_complete_count < 6: 170*760c253cSXin Li return False 171*760c253cSXin Li else: 172*760c253cSXin Li return True 173*760c253cSXin Li 174*760c253cSXin Li self.mock_logger.Reset() 175*760c253cSXin Li self.exp.Run = FakeRun 176*760c253cSXin Li self.exp.IsComplete = FakeIsComplete 177*760c253cSXin Li 178*760c253cSXin Li # Test 1: log_level == "quiet" 179*760c253cSXin Li self.exp.log_level = "quiet" 180*760c253cSXin Li er = experiment_runner.ExperimentRunner( 181*760c253cSXin Li self.exp, 182*760c253cSXin Li json_report=False, 183*760c253cSXin Li using_schedv2=False, 184*760c253cSXin Li log=self.mock_logger, 185*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 186*760c253cSXin Li ) 187*760c253cSXin Li er.STATUS_TIME_DELAY = 2 188*760c253cSXin Li mock_status_string.return_value = "Fake status string" 189*760c253cSXin Li er._Run(self.exp) 190*760c253cSXin Li self.assertEqual(self.run_count, 1) 191*760c253cSXin Li self.assertTrue(self.is_complete_count > 0) 192*760c253cSXin Li self.assertEqual(self.mock_logger.LogStartDotsCount, 1) 193*760c253cSXin Li self.assertEqual(self.mock_logger.LogAppendDotCount, 1) 194*760c253cSXin Li self.assertEqual(self.mock_logger.LogEndDotsCount, 1) 195*760c253cSXin Li self.assertEqual(self.mock_logger.dot_count, 2) 196*760c253cSXin Li self.assertEqual(mock_progress_string.call_count, 0) 197*760c253cSXin Li self.assertEqual(mock_status_string.call_count, 2) 198*760c253cSXin Li self.assertEqual( 199*760c253cSXin Li self.mock_logger.output_msgs, 200*760c253cSXin Li [ 201*760c253cSXin Li "==============================", 202*760c253cSXin Li "Fake status string", 203*760c253cSXin Li "==============================", 204*760c253cSXin Li ], 205*760c253cSXin Li ) 206*760c253cSXin Li self.assertEqual(len(self.mock_logger.error_msgs), 0) 207*760c253cSXin Li 208*760c253cSXin Li # Test 2: log_level == "average" 209*760c253cSXin Li self.mock_logger.Reset() 210*760c253cSXin Li reset() 211*760c253cSXin Li self.exp.log_level = "average" 212*760c253cSXin Li mock_status_string.call_count = 0 213*760c253cSXin Li er = experiment_runner.ExperimentRunner( 214*760c253cSXin Li self.exp, 215*760c253cSXin Li json_report=False, 216*760c253cSXin Li using_schedv2=False, 217*760c253cSXin Li log=self.mock_logger, 218*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 219*760c253cSXin Li ) 220*760c253cSXin Li er.STATUS_TIME_DELAY = 2 221*760c253cSXin Li mock_status_string.return_value = "Fake status string" 222*760c253cSXin Li er._Run(self.exp) 223*760c253cSXin Li self.assertEqual(self.run_count, 1) 224*760c253cSXin Li self.assertTrue(self.is_complete_count > 0) 225*760c253cSXin Li self.assertEqual(self.mock_logger.LogStartDotsCount, 1) 226*760c253cSXin Li self.assertEqual(self.mock_logger.LogAppendDotCount, 1) 227*760c253cSXin Li self.assertEqual(self.mock_logger.LogEndDotsCount, 1) 228*760c253cSXin Li self.assertEqual(self.mock_logger.dot_count, 2) 229*760c253cSXin Li self.assertEqual(mock_progress_string.call_count, 0) 230*760c253cSXin Li self.assertEqual(mock_status_string.call_count, 2) 231*760c253cSXin Li self.assertEqual( 232*760c253cSXin Li self.mock_logger.output_msgs, 233*760c253cSXin Li [ 234*760c253cSXin Li "==============================", 235*760c253cSXin Li "Fake status string", 236*760c253cSXin Li "==============================", 237*760c253cSXin Li ], 238*760c253cSXin Li ) 239*760c253cSXin Li self.assertEqual(len(self.mock_logger.error_msgs), 0) 240*760c253cSXin Li 241*760c253cSXin Li # Test 3: log_level == "verbose" 242*760c253cSXin Li self.mock_logger.Reset() 243*760c253cSXin Li reset() 244*760c253cSXin Li self.exp.log_level = "verbose" 245*760c253cSXin Li mock_status_string.call_count = 0 246*760c253cSXin Li er = experiment_runner.ExperimentRunner( 247*760c253cSXin Li self.exp, 248*760c253cSXin Li json_report=False, 249*760c253cSXin Li using_schedv2=False, 250*760c253cSXin Li log=self.mock_logger, 251*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 252*760c253cSXin Li ) 253*760c253cSXin Li er.STATUS_TIME_DELAY = 2 254*760c253cSXin Li mock_status_string.return_value = "Fake status string" 255*760c253cSXin Li mock_progress_string.return_value = "Fake progress string" 256*760c253cSXin Li er._Run(self.exp) 257*760c253cSXin Li self.assertEqual(self.run_count, 1) 258*760c253cSXin Li self.assertTrue(self.is_complete_count > 0) 259*760c253cSXin Li self.assertEqual(self.mock_logger.LogStartDotsCount, 0) 260*760c253cSXin Li self.assertEqual(self.mock_logger.LogAppendDotCount, 0) 261*760c253cSXin Li self.assertEqual(self.mock_logger.LogEndDotsCount, 0) 262*760c253cSXin Li self.assertEqual(self.mock_logger.dot_count, 0) 263*760c253cSXin Li self.assertEqual(mock_progress_string.call_count, 2) 264*760c253cSXin Li self.assertEqual(mock_status_string.call_count, 2) 265*760c253cSXin Li self.assertEqual( 266*760c253cSXin Li self.mock_logger.output_msgs, 267*760c253cSXin Li [ 268*760c253cSXin Li "==============================", 269*760c253cSXin Li "Fake progress string", 270*760c253cSXin Li "Fake status string", 271*760c253cSXin Li "==============================", 272*760c253cSXin Li "==============================", 273*760c253cSXin Li "Fake progress string", 274*760c253cSXin Li "Fake status string", 275*760c253cSXin Li "==============================", 276*760c253cSXin Li ], 277*760c253cSXin Li ) 278*760c253cSXin Li self.assertEqual(len(self.mock_logger.error_msgs), 0) 279*760c253cSXin Li 280*760c253cSXin Li @mock.patch.object(TextResultsReport, "GetReport") 281*760c253cSXin Li def test_print_table(self, mock_report): 282*760c253cSXin Li self.mock_logger.Reset() 283*760c253cSXin Li mock_report.return_value = "This is a fake experiment report." 284*760c253cSXin Li er = experiment_runner.ExperimentRunner( 285*760c253cSXin Li self.exp, 286*760c253cSXin Li json_report=False, 287*760c253cSXin Li using_schedv2=False, 288*760c253cSXin Li log=self.mock_logger, 289*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 290*760c253cSXin Li ) 291*760c253cSXin Li er._PrintTable(self.exp) 292*760c253cSXin Li self.assertEqual(mock_report.call_count, 1) 293*760c253cSXin Li self.assertEqual( 294*760c253cSXin Li self.mock_logger.output_msgs, ["This is a fake experiment report."] 295*760c253cSXin Li ) 296*760c253cSXin Li 297*760c253cSXin Li @mock.patch.object(HTMLResultsReport, "GetReport") 298*760c253cSXin Li @mock.patch.object(TextResultsReport, "GetReport") 299*760c253cSXin Li @mock.patch.object(EmailSender, "Attachment") 300*760c253cSXin Li @mock.patch.object(EmailSender, "SendEmail") 301*760c253cSXin Li @mock.patch.object(getpass, "getuser") 302*760c253cSXin Li def test_email( 303*760c253cSXin Li self, 304*760c253cSXin Li mock_getuser, 305*760c253cSXin Li mock_emailer, 306*760c253cSXin Li mock_attachment, 307*760c253cSXin Li mock_text_report, 308*760c253cSXin Li mock_html_report, 309*760c253cSXin Li ): 310*760c253cSXin Li 311*760c253cSXin Li mock_getuser.return_value = "[email protected]" 312*760c253cSXin Li mock_text_report.return_value = "This is a fake text report." 313*760c253cSXin Li mock_html_report.return_value = "This is a fake html report." 314*760c253cSXin Li 315*760c253cSXin Li self.mock_logger.Reset() 316*760c253cSXin Li config.AddConfig("no_email", True) 317*760c253cSXin Li self.exp.email_to = ["[email protected]"] 318*760c253cSXin Li er = experiment_runner.ExperimentRunner( 319*760c253cSXin Li self.exp, 320*760c253cSXin Li json_report=False, 321*760c253cSXin Li using_schedv2=False, 322*760c253cSXin Li log=self.mock_logger, 323*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 324*760c253cSXin Li ) 325*760c253cSXin Li # Test 1. Config:no_email; exp.email_to set ==> no email sent 326*760c253cSXin Li er._Email(self.exp) 327*760c253cSXin Li self.assertEqual(mock_getuser.call_count, 0) 328*760c253cSXin Li self.assertEqual(mock_emailer.call_count, 0) 329*760c253cSXin Li self.assertEqual(mock_attachment.call_count, 0) 330*760c253cSXin Li self.assertEqual(mock_text_report.call_count, 0) 331*760c253cSXin Li self.assertEqual(mock_html_report.call_count, 0) 332*760c253cSXin Li 333*760c253cSXin Li # Test 2. Config: email. exp.email_to set; cache hit. => send email 334*760c253cSXin Li self.mock_logger.Reset() 335*760c253cSXin Li config.AddConfig("no_email", False) 336*760c253cSXin Li for r in self.exp.benchmark_runs: 337*760c253cSXin Li r.cache_hit = True 338*760c253cSXin Li er._Email(self.exp) 339*760c253cSXin Li self.assertEqual(mock_getuser.call_count, 1) 340*760c253cSXin Li self.assertEqual(mock_emailer.call_count, 1) 341*760c253cSXin Li self.assertEqual(mock_attachment.call_count, 1) 342*760c253cSXin Li self.assertEqual(mock_text_report.call_count, 1) 343*760c253cSXin Li self.assertEqual(mock_html_report.call_count, 1) 344*760c253cSXin Li self.assertEqual(len(mock_emailer.call_args), 2) 345*760c253cSXin Li self.assertEqual( 346*760c253cSXin Li mock_emailer.call_args[0], 347*760c253cSXin Li ( 348*760c253cSXin Li ["[email protected]", "[email protected]"], 349*760c253cSXin Li ": image1 vs. image2", 350*760c253cSXin Li "<pre style='font-size: 13px'>This is a fake text " 351*760c253cSXin Li "report.\nResults are stored in _results.\n</pre>", 352*760c253cSXin Li ), 353*760c253cSXin Li ) 354*760c253cSXin Li self.assertTrue(isinstance(mock_emailer.call_args[1], dict)) 355*760c253cSXin Li self.assertEqual(len(mock_emailer.call_args[1]), 2) 356*760c253cSXin Li self.assertTrue("attachments" in mock_emailer.call_args[1].keys()) 357*760c253cSXin Li self.assertEqual(mock_emailer.call_args[1]["msg_type"], "html") 358*760c253cSXin Li 359*760c253cSXin Li mock_attachment.assert_called_with( 360*760c253cSXin Li "report.html", "This is a fake html report." 361*760c253cSXin Li ) 362*760c253cSXin Li 363*760c253cSXin Li # Test 3. Config: email; exp.mail_to set; no cache hit. => send email 364*760c253cSXin Li self.mock_logger.Reset() 365*760c253cSXin Li mock_getuser.reset_mock() 366*760c253cSXin Li mock_emailer.reset_mock() 367*760c253cSXin Li mock_attachment.reset_mock() 368*760c253cSXin Li mock_text_report.reset_mock() 369*760c253cSXin Li mock_html_report.reset_mock() 370*760c253cSXin Li config.AddConfig("no_email", False) 371*760c253cSXin Li for r in self.exp.benchmark_runs: 372*760c253cSXin Li r.cache_hit = False 373*760c253cSXin Li er._Email(self.exp) 374*760c253cSXin Li self.assertEqual(mock_getuser.call_count, 1) 375*760c253cSXin Li self.assertEqual(mock_emailer.call_count, 1) 376*760c253cSXin Li self.assertEqual(mock_attachment.call_count, 1) 377*760c253cSXin Li self.assertEqual(mock_text_report.call_count, 1) 378*760c253cSXin Li self.assertEqual(mock_html_report.call_count, 1) 379*760c253cSXin Li self.assertEqual(len(mock_emailer.call_args), 2) 380*760c253cSXin Li self.assertEqual( 381*760c253cSXin Li mock_emailer.call_args[0], 382*760c253cSXin Li ( 383*760c253cSXin Li [ 384*760c253cSXin Li "[email protected]", 385*760c253cSXin Li "[email protected]", 386*760c253cSXin Li "[email protected]", 387*760c253cSXin Li ], 388*760c253cSXin Li ": image1 vs. image2", 389*760c253cSXin Li "<pre style='font-size: 13px'>This is a fake text " 390*760c253cSXin Li "report.\nResults are stored in _results.\n</pre>", 391*760c253cSXin Li ), 392*760c253cSXin Li ) 393*760c253cSXin Li self.assertTrue(isinstance(mock_emailer.call_args[1], dict)) 394*760c253cSXin Li self.assertEqual(len(mock_emailer.call_args[1]), 2) 395*760c253cSXin Li self.assertTrue("attachments" in mock_emailer.call_args[1].keys()) 396*760c253cSXin Li self.assertEqual(mock_emailer.call_args[1]["msg_type"], "html") 397*760c253cSXin Li 398*760c253cSXin Li mock_attachment.assert_called_with( 399*760c253cSXin Li "report.html", "This is a fake html report." 400*760c253cSXin Li ) 401*760c253cSXin Li 402*760c253cSXin Li # Test 4. Config: email; exp.mail_to = None; no cache hit. => send email 403*760c253cSXin Li self.mock_logger.Reset() 404*760c253cSXin Li mock_getuser.reset_mock() 405*760c253cSXin Li mock_emailer.reset_mock() 406*760c253cSXin Li mock_attachment.reset_mock() 407*760c253cSXin Li mock_text_report.reset_mock() 408*760c253cSXin Li mock_html_report.reset_mock() 409*760c253cSXin Li self.exp.email_to = [] 410*760c253cSXin Li er._Email(self.exp) 411*760c253cSXin Li self.assertEqual(mock_getuser.call_count, 1) 412*760c253cSXin Li self.assertEqual(mock_emailer.call_count, 1) 413*760c253cSXin Li self.assertEqual(mock_attachment.call_count, 1) 414*760c253cSXin Li self.assertEqual(mock_text_report.call_count, 1) 415*760c253cSXin Li self.assertEqual(mock_html_report.call_count, 1) 416*760c253cSXin Li self.assertEqual(len(mock_emailer.call_args), 2) 417*760c253cSXin Li self.assertEqual( 418*760c253cSXin Li mock_emailer.call_args[0], 419*760c253cSXin Li ( 420*760c253cSXin Li ["[email protected]"], 421*760c253cSXin Li ": image1 vs. image2", 422*760c253cSXin Li "<pre style='font-size: 13px'>This is a fake text " 423*760c253cSXin Li "report.\nResults are stored in _results.\n</pre>", 424*760c253cSXin Li ), 425*760c253cSXin Li ) 426*760c253cSXin Li self.assertTrue(isinstance(mock_emailer.call_args[1], dict)) 427*760c253cSXin Li self.assertEqual(len(mock_emailer.call_args[1]), 2) 428*760c253cSXin Li self.assertTrue("attachments" in mock_emailer.call_args[1].keys()) 429*760c253cSXin Li self.assertEqual(mock_emailer.call_args[1]["msg_type"], "html") 430*760c253cSXin Li 431*760c253cSXin Li mock_attachment.assert_called_with( 432*760c253cSXin Li "report.html", "This is a fake html report." 433*760c253cSXin Li ) 434*760c253cSXin Li 435*760c253cSXin Li # Test 5. Config: email; exp.mail_to = None; cache hit => no email sent 436*760c253cSXin Li self.mock_logger.Reset() 437*760c253cSXin Li mock_getuser.reset_mock() 438*760c253cSXin Li mock_emailer.reset_mock() 439*760c253cSXin Li mock_attachment.reset_mock() 440*760c253cSXin Li mock_text_report.reset_mock() 441*760c253cSXin Li mock_html_report.reset_mock() 442*760c253cSXin Li for r in self.exp.benchmark_runs: 443*760c253cSXin Li r.cache_hit = True 444*760c253cSXin Li er._Email(self.exp) 445*760c253cSXin Li self.assertEqual(mock_getuser.call_count, 0) 446*760c253cSXin Li self.assertEqual(mock_emailer.call_count, 0) 447*760c253cSXin Li self.assertEqual(mock_attachment.call_count, 0) 448*760c253cSXin Li self.assertEqual(mock_text_report.call_count, 0) 449*760c253cSXin Li self.assertEqual(mock_html_report.call_count, 0) 450*760c253cSXin Li 451*760c253cSXin Li @mock.patch.object(FileUtils, "RmDir") 452*760c253cSXin Li @mock.patch.object(FileUtils, "MkDirP") 453*760c253cSXin Li @mock.patch.object(FileUtils, "WriteFile") 454*760c253cSXin Li @mock.patch.object(HTMLResultsReport, "FromExperiment") 455*760c253cSXin Li @mock.patch.object(TextResultsReport, "FromExperiment") 456*760c253cSXin Li @mock.patch.object(Result, "CompressResultsTo") 457*760c253cSXin Li @mock.patch.object(Result, "CopyResultsTo") 458*760c253cSXin Li @mock.patch.object(Result, "CleanUp") 459*760c253cSXin Li @mock.patch.object(Result, "FormatStringTopCommands") 460*760c253cSXin Li @mock.patch("builtins.open", new_callable=mock.mock_open) 461*760c253cSXin Li def test_store_results( 462*760c253cSXin Li self, 463*760c253cSXin Li mock_open, 464*760c253cSXin Li mock_top_commands, 465*760c253cSXin Li mock_cleanup, 466*760c253cSXin Li mock_copy, 467*760c253cSXin Li mock_compress, 468*760c253cSXin Li _mock_text_report, 469*760c253cSXin Li mock_report, 470*760c253cSXin Li mock_writefile, 471*760c253cSXin Li mock_mkdir, 472*760c253cSXin Li mock_rmdir, 473*760c253cSXin Li ): 474*760c253cSXin Li 475*760c253cSXin Li self.mock_logger.Reset() 476*760c253cSXin Li self.exp.results_directory = "/usr/local/crosperf-results" 477*760c253cSXin Li bench_run = self.exp.benchmark_runs[5] 478*760c253cSXin Li bench_path = "/usr/local/crosperf-results/" + "".join( 479*760c253cSXin Li ch for ch in bench_run.name if ch.isalnum() 480*760c253cSXin Li ) 481*760c253cSXin Li self.assertEqual(len(self.exp.benchmark_runs), 6) 482*760c253cSXin Li 483*760c253cSXin Li er = experiment_runner.ExperimentRunner( 484*760c253cSXin Li self.exp, 485*760c253cSXin Li json_report=False, 486*760c253cSXin Li using_schedv2=False, 487*760c253cSXin Li log=self.mock_logger, 488*760c253cSXin Li cmd_exec=self.mock_cmd_exec, 489*760c253cSXin Li ) 490*760c253cSXin Li 491*760c253cSXin Li # Test 1. Make sure nothing is done if _terminated is true. 492*760c253cSXin Li er._terminated = True 493*760c253cSXin Li er._StoreResults(self.exp) 494*760c253cSXin Li self.assertEqual(mock_cleanup.call_count, 0) 495*760c253cSXin Li self.assertEqual(mock_copy.call_count, 0) 496*760c253cSXin Li self.assertEqual(mock_compress.call_count, 0) 497*760c253cSXin Li self.assertEqual(mock_report.call_count, 0) 498*760c253cSXin Li self.assertEqual(mock_writefile.call_count, 0) 499*760c253cSXin Li self.assertEqual(mock_mkdir.call_count, 0) 500*760c253cSXin Li self.assertEqual(mock_rmdir.call_count, 0) 501*760c253cSXin Li self.assertEqual(self.mock_logger.LogOutputCount, 0) 502*760c253cSXin Li self.assertEqual(mock_open.call_count, 0) 503*760c253cSXin Li self.assertEqual(mock_top_commands.call_count, 0) 504*760c253cSXin Li 505*760c253cSXin Li # Test 2. _terminated is false; everything works properly. 506*760c253cSXin Li fake_result = Result( 507*760c253cSXin Li self.mock_logger, self.exp.labels[0], "average", "daisy1" 508*760c253cSXin Li ) 509*760c253cSXin Li for r in self.exp.benchmark_runs: 510*760c253cSXin Li r.result = fake_result 511*760c253cSXin Li er._terminated = False 512*760c253cSXin Li self.exp.compress_results = False 513*760c253cSXin Li er._StoreResults(self.exp) 514*760c253cSXin Li self.assertEqual(mock_cleanup.call_count, 6) 515*760c253cSXin Li mock_cleanup.assert_called_with(bench_run.benchmark.rm_chroot_tmp) 516*760c253cSXin Li self.assertEqual(mock_copy.call_count, 6) 517*760c253cSXin Li mock_copy.assert_called_with(bench_path) 518*760c253cSXin Li self.assertEqual(mock_writefile.call_count, 3) 519*760c253cSXin Li self.assertEqual(len(mock_writefile.call_args_list), 3) 520*760c253cSXin Li first_args = mock_writefile.call_args_list[0] 521*760c253cSXin Li second_args = mock_writefile.call_args_list[1] 522*760c253cSXin Li self.assertEqual( 523*760c253cSXin Li first_args[0][0], "/usr/local/crosperf-results/experiment.exp" 524*760c253cSXin Li ) 525*760c253cSXin Li self.assertEqual( 526*760c253cSXin Li second_args[0][0], "/usr/local/crosperf-results/results.html" 527*760c253cSXin Li ) 528*760c253cSXin Li self.assertEqual(mock_mkdir.call_count, 1) 529*760c253cSXin Li mock_mkdir.assert_called_with("/usr/local/crosperf-results") 530*760c253cSXin Li self.assertEqual(mock_rmdir.call_count, 1) 531*760c253cSXin Li mock_rmdir.assert_called_with("/usr/local/crosperf-results") 532*760c253cSXin Li self.assertEqual(self.mock_logger.LogOutputCount, 5) 533*760c253cSXin Li self.assertEqual( 534*760c253cSXin Li self.mock_logger.output_msgs, 535*760c253cSXin Li [ 536*760c253cSXin Li "Storing experiment file in /usr/local/crosperf-results.", 537*760c253cSXin Li "Storing top statistics of each benchmark run into" 538*760c253cSXin Li " /usr/local/crosperf-results/topstats.log.", 539*760c253cSXin Li "Storing results of each benchmark run.", 540*760c253cSXin Li "Storing results report in /usr/local/crosperf-results.", 541*760c253cSXin Li "Storing email message body in /usr/local/crosperf-results.", 542*760c253cSXin Li ], 543*760c253cSXin Li ) 544*760c253cSXin Li self.assertEqual(mock_open.call_count, 1) 545*760c253cSXin Li # Check write to a topstats.log file. 546*760c253cSXin Li mock_open.assert_called_with( 547*760c253cSXin Li "/usr/local/crosperf-results/topstats.log", "w" 548*760c253cSXin Li ) 549*760c253cSXin Li mock_open().write.assert_called() 550*760c253cSXin Li 551*760c253cSXin Li # Check top calls with no arguments. 552*760c253cSXin Li topcalls = [mock.call()] * 6 553*760c253cSXin Li self.assertEqual(mock_top_commands.call_args_list, topcalls) 554*760c253cSXin Li 555*760c253cSXin Li # Test 3. Test compress_results. 556*760c253cSXin Li self.exp.compress_results = True 557*760c253cSXin Li mock_copy.call_count = 0 558*760c253cSXin Li mock_compress.call_count = 0 559*760c253cSXin Li er._StoreResults(self.exp) 560*760c253cSXin Li self.assertEqual(mock_copy.call_count, 0) 561*760c253cSXin Li mock_copy.assert_called_with(bench_path) 562*760c253cSXin Li self.assertEqual(mock_compress.call_count, 6) 563*760c253cSXin Li mock_compress.assert_called_with(bench_path) 564*760c253cSXin Li 565*760c253cSXin Li 566*760c253cSXin Liif __name__ == "__main__": 567*760c253cSXin Li unittest.main() 568