1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2019 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Unittests for running tryjobs after updating packages.""" 8 9from __future__ import print_function 10 11import json 12import unittest 13import unittest.mock as mock 14 15from test_helpers import ArgsOutputTest 16from test_helpers import CreateTemporaryFile 17from update_chromeos_llvm_next_hash import CommitContents 18import update_chromeos_llvm_next_hash 19import update_packages_and_run_tryjobs 20 21 22class UpdatePackagesAndRunTryjobsTest(unittest.TestCase): 23 """Unittests when running tryjobs after updating packages.""" 24 25 def testNoLastTestedFile(self): 26 self.assertEqual( 27 update_packages_and_run_tryjobs.GetLastTestedSVNVersion(None), None) 28 29 def testFailedToGetIntegerFromLastTestedFile(self): 30 # Create a temporary file to simulate the behavior of the last tested file 31 # when the file does not have a SVN version (i.e. int() failed). 32 with CreateTemporaryFile() as temp_file: 33 self.assertEqual( 34 update_packages_and_run_tryjobs.GetLastTestedSVNVersion(temp_file), 35 None) 36 37 def testLastTestFileDoesNotExist(self): 38 # Simulate 'open()' on a lasted tested file that does not exist. 39 mock_open = mock.mock_open(read_data='') 40 41 self.assertEqual( 42 update_packages_and_run_tryjobs.GetLastTestedSVNVersion( 43 '/some/file/that/does/not/exist.txt'), None) 44 45 def testSuccessfullyRetrievedLastTestedSVNVersion(self): 46 with CreateTemporaryFile() as temp_file: 47 # Simulate behavior when the last tested file contains a SVN version. 48 with open(temp_file, 'w') as svn_file: 49 svn_file.write('1234') 50 51 self.assertEqual( 52 update_packages_and_run_tryjobs.GetLastTestedSVNVersion(temp_file), 53 1234) 54 55 def testGetTryJobCommandWithNoExtraInformation(self): 56 test_change_list = 1234 57 58 test_builder = 'nocturne' 59 60 expected_tryjob_cmd_list = [ 61 'cros', 'tryjob', '--yes', '--json', '-g', 62 '%d' % test_change_list, test_builder 63 ] 64 65 self.assertEqual( 66 update_packages_and_run_tryjobs.GetTryJobCommand( 67 test_change_list, None, None, test_builder), 68 expected_tryjob_cmd_list) 69 70 def testGetTryJobCommandWithExtraInformation(self): 71 test_change_list = 4321 72 test_extra_cls = [1000, 10] 73 test_options = ['report_error', 'delete_tryjob'] 74 test_builder = 'kevin' 75 76 expected_tryjob_cmd_list = [ 77 'cros', 78 'tryjob', 79 '--yes', 80 '--json', 81 '-g', 82 '%d' % test_change_list, 83 '-g', 84 '%d' % test_extra_cls[0], 85 '-g', 86 '%d' % test_extra_cls[1], 87 test_builder, 88 '--%s' % test_options[0], 89 '--%s' % test_options[1], 90 ] 91 92 self.assertEqual( 93 update_packages_and_run_tryjobs.GetTryJobCommand( 94 test_change_list, test_extra_cls, test_options, test_builder), 95 expected_tryjob_cmd_list) 96 97 # Simulate `datetime.datetime.utcnow()` when retrieving the current time when 98 # submitted a tryjob. 99 @mock.patch.object( 100 update_packages_and_run_tryjobs, 101 'GetCurrentTimeInUTC', 102 return_value='2019-09-09') 103 # Simulate the behavior of `AddTryjobLinkToCL()` when successfully added the 104 # tryjob url to the CL that was uploaded to Gerrit for review. 105 @mock.patch.object(update_packages_and_run_tryjobs, 'AddTryjobLinkToCL') 106 # Simulate behavior of `ChrootRunCommand()` when successfully submitted a 107 # tryjob via `cros tryjob`. 108 @mock.patch.object(update_packages_and_run_tryjobs, 'ChrootRunCommand') 109 def testSuccessfullySubmittedTryJob( 110 self, mock_chroot_cmd, mock_add_tryjob_link_to_cl, mock_launch_time): 111 112 expected_tryjob_cmd_list = [ 113 'cros', 'tryjob', '--yes', '--json', '-g', 114 '%d' % 900, '-g', 115 '%d' % 1200, 'builder1', '--some_option' 116 ] 117 118 buildbucket_id = '1234' 119 url = 'https://some_tryjob_url.com' 120 121 tryjob_launch_contents = [{'buildbucket_id': buildbucket_id, 'url': url}] 122 123 mock_chroot_cmd.return_value = json.dumps(tryjob_launch_contents) 124 125 extra_cls = [1200] 126 tryjob_options = ['some_option'] 127 builder_list = ['builder1'] 128 chroot_path = '/some/path/to/chroot' 129 cl_to_launch_tryjob = 900 130 verbose = False 131 132 tryjob_results_list = update_packages_and_run_tryjobs.RunTryJobs( 133 cl_to_launch_tryjob, extra_cls, tryjob_options, builder_list, 134 chroot_path, verbose) 135 136 expected_tryjob_dict = { 137 'launch_time': '2019-09-09', 138 'link': url, 139 'buildbucket_id': int(buildbucket_id), 140 'extra_cls': extra_cls, 141 'options': tryjob_options, 142 'builder': builder_list 143 } 144 145 self.assertEqual(tryjob_results_list, [expected_tryjob_dict]) 146 147 mock_chroot_cmd.assert_called_once_with( 148 chroot_path, expected_tryjob_cmd_list, verbose=False) 149 150 mock_add_tryjob_link_to_cl.assert_called_once() 151 152 mock_launch_time.assert_called_once() 153 154 # Simulate behavior of `ExecCommandAndCaptureOutput()` when successfully added 155 # the tryjob link to the CL via `gerrit message <CL> <message>`. 156 @mock.patch.object( 157 update_packages_and_run_tryjobs, 158 'ExecCommandAndCaptureOutput', 159 return_value=None) 160 def testSuccessfullyAddedTryjobLinkToCL(self, mock_exec_cmd): 161 chroot_path = '/abs/path/to/chroot' 162 163 test_cl_number = 1000 164 165 tryjob_result = [{'link': 'https://some_tryjob_link.com'}] 166 167 update_packages_and_run_tryjobs.AddTryjobLinkToCL( 168 tryjob_result, test_cl_number, chroot_path) 169 170 expected_gerrit_message = [ 171 '%s/chromite/bin/gerrit' % chroot_path, 'message', 172 str(test_cl_number), 173 'Started the following tryjobs:\n%s' % tryjob_result[0]['link'] 174 ] 175 176 mock_exec_cmd.assert_called_once_with(expected_gerrit_message) 177 178 # Simulate behavior of `GetCommandLineArgs()` when successfully parsed the 179 # command line for the optional/required arguments for the script. 180 @mock.patch.object(update_packages_and_run_tryjobs, 'GetCommandLineArgs') 181 # Simulate behavior of `GetLLVMHashAndVersionFromSVNOption()` when 182 # successfully retrieved the LLVM hash and version for google3. 183 @mock.patch.object(update_packages_and_run_tryjobs, 184 'GetLLVMHashAndVersionFromSVNOption') 185 # Simulate behavior of `GetLastTestedSVNVersion()` when successfully retrieved 186 # the last tested revision from the last tested file. 187 @mock.patch.object( 188 update_packages_and_run_tryjobs, 189 'GetLastTestedSVNVersion', 190 return_value=100) 191 # Simulate behavior of `VerifyOutsideChroot()` when successfully invoked the 192 # script outside of the chroot. 193 @mock.patch.object( 194 update_packages_and_run_tryjobs, 'VerifyOutsideChroot', return_value=True) 195 def testLastTestSVNVersionMatchesSVNVersion( 196 self, mock_outside_chroot, mock_get_last_tested_version, 197 mock_get_hash_and_version, mock_get_commandline_args): 198 199 args_output_obj = ArgsOutputTest() 200 201 mock_get_commandline_args.return_value = args_output_obj 202 203 mock_get_hash_and_version.return_value = ('a123testhash1', 100) 204 205 update_packages_and_run_tryjobs.main() 206 207 mock_outside_chroot.assert_called_once() 208 209 mock_get_commandline_args.assert_called_once() 210 211 mock_get_last_tested_version.assert_called_once_with( 212 args_output_obj.last_tested) 213 214 mock_get_hash_and_version.assert_called_once_with( 215 args_output_obj.llvm_version) 216 217 # Simulate the behavior of `RunTryJobs()` when successfully submitted a 218 # tryjob. 219 @mock.patch.object(update_packages_and_run_tryjobs, 'RunTryJobs') 220 # Simulate behavior of `UpdatePackages()` when successfully updated the 221 # packages and uploaded a CL for review. 222 @mock.patch.object(update_chromeos_llvm_next_hash, 'UpdatePackages') 223 # Simulate behavior of `GetCommandLineArgs()` when successfully parsed the 224 # command line for the optional/required arguments for the script. 225 @mock.patch.object(update_packages_and_run_tryjobs, 'GetCommandLineArgs') 226 # Simulate behavior of `GetLLVMHashAndVersionFromSVNOption()` when 227 # successfully retrieved the LLVM hash and version for google3. 228 @mock.patch.object(update_packages_and_run_tryjobs, 229 'GetLLVMHashAndVersionFromSVNOption') 230 # Simulate behavior of `GetLastTestedSVNVersion()` when successfully retrieved 231 # the last tested revision from the last tested file. 232 @mock.patch.object( 233 update_packages_and_run_tryjobs, 234 'GetLastTestedSVNVersion', 235 return_value=100) 236 # Simulate behavior of `VerifyOutsideChroot()` when successfully invoked the 237 # script outside of the chroot. 238 @mock.patch.object( 239 update_packages_and_run_tryjobs, 'VerifyOutsideChroot', return_value=True) 240 def testUpdatedLastTestedFileWithNewTestedRevision( 241 self, mock_outside_chroot, mock_get_last_tested_version, 242 mock_get_hash_and_version, mock_get_commandline_args, 243 mock_update_packages, mock_run_tryjobs): 244 245 mock_get_hash_and_version.return_value = ('a123testhash2', 200) 246 247 test_cl_url = 'https://some_cl_url.com' 248 249 test_cl_number = 12345 250 251 mock_update_packages.return_value = CommitContents( 252 url=test_cl_url, cl_number=test_cl_number) 253 254 tryjob_test_results = [{ 255 'link': 'https://some_tryjob_url.com', 256 'buildbucket_id': 1234 257 }] 258 259 mock_run_tryjobs.return_value = tryjob_test_results 260 261 # Create a temporary file to simulate the last tested file that contains a 262 # revision. 263 with CreateTemporaryFile() as last_tested_file: 264 args_output_obj = ArgsOutputTest(svn_option=200) 265 args_output_obj.last_tested = last_tested_file 266 267 mock_get_commandline_args.return_value = args_output_obj 268 269 update_packages_and_run_tryjobs.main() 270 271 # Verify that the lasted tested file has been updated to the new LLVM 272 # revision. 273 with open(last_tested_file) as update_revision: 274 new_revision = update_revision.readline() 275 276 self.assertEqual(int(new_revision.rstrip()), 200) 277 278 mock_outside_chroot.assert_called_once() 279 280 mock_get_commandline_args.assert_called_once() 281 282 mock_get_last_tested_version.assert_called_once() 283 284 mock_get_hash_and_version.assert_called_once() 285 286 mock_run_tryjobs.assert_called_once() 287 288 mock_update_packages.assert_called_once() 289 290 291if __name__ == '__main__': 292 unittest.main() 293