diff options
author | Salud Lemus <saludlemus@google.com> | 2019-09-09 13:26:50 -0700 |
---|---|---|
committer | Salud Lemus <saludlemus@google.com> | 2019-09-12 00:05:14 +0000 |
commit | 4344157210d5729631a3c299ab23315710a7772b (patch) | |
tree | 0ad6fc82ae56a8fab99e8743703b3ae453420343 /llvm_tools | |
parent | d4475f88f851d42cac195c42beafdbfecf284c9e (diff) | |
download | toolchain-utils-4344157210d5729631a3c299ab23315710a7772b.tar.gz |
LLVM tools: Unittests for update_packages_and_run_tryjobs_unittest.py
BUG=None
TEST='./update_packages_and_run_tryjobs_unittest.py' passes
Change-Id: I46768d5e0b85135ecf26eb2a7dad6ce7521051ba
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1793261
Reviewed-by: George Burgess <gbiv@chromium.org>
Reviewed-by: Manoj Gupta <manojgupta@chromium.org>
Tested-by: Salud Lemus <saludlemus@google.com>
Diffstat (limited to 'llvm_tools')
-rw-r--r-- | llvm_tools/test_helpers.py | 42 | ||||
-rwxr-xr-x | llvm_tools/update_packages_and_run_tryjobs.py | 7 | ||||
-rwxr-xr-x | llvm_tools/update_packages_and_run_tryjobs_unittest.py | 292 |
3 files changed, 328 insertions, 13 deletions
diff --git a/llvm_tools/test_helpers.py b/llvm_tools/test_helpers.py index 7f1beafb..99448181 100644 --- a/llvm_tools/test_helpers.py +++ b/llvm_tools/test_helpers.py @@ -13,6 +13,19 @@ import json import os +class ArgsOutputTest(object): + """Testing class to simulate a argument parser object.""" + + def __init__(self, svn_option='google3'): + self.chroot_path = '/abs/path/to/chroot' + self.last_tested = '/abs/path/to/last_tested_file.json' + self.llvm_version = svn_option + self.verbose = False + self.extra_change_lists = None + self.options = ['latest-toolchain'] + self.builders = ['some-builder'] + + # FIXME: Migrate modules with similar helper to use this module. def CallCountsToMockFunctions(mock_function): """A decorator that passes a call count to the function it decorates. @@ -25,15 +38,19 @@ def CallCountsToMockFunctions(mock_function): ... [foo(), foo(), foo()] [0, 1, 2] - - NOTE: This decorator will not handle recursive functions properly. """ counter = [0] def Result(*args, **kwargs): - ret_value = mock_function(counter[0], *args, **kwargs) + # For some values of `counter`, the mock function would simulate raising + # an exception, so let the test case catch the exception via + # `unittest.TestCase.assertRaises()` and to also handle recursive functions. + prev_counter = counter[0] counter[0] += 1 + + ret_value = mock_function(prev_counter, *args, **kwargs) + return ret_value return Result @@ -50,22 +67,23 @@ def WritePrettyJsonFile(file_name, json_object): json.dump(file_name, json_object, indent=4, separators=(',', ': ')) -@contextmanager def CreateTemporaryJsonFile(): """Makes a temporary .json file.""" - # Create a temporary file to simulate a .json file. - fd, temp_file_path = mkstemp() + return CreateTemporaryFile(suffix='.json') + + +@contextmanager +def CreateTemporaryFile(suffix=''): + """Makes a temporary file.""" - temp_json_file = '%s.json' % temp_file_path + fd, temp_file_path = mkstemp(suffix=suffix) os.close(fd) - os.remove(temp_file_path) try: - yield temp_json_file + yield temp_file_path finally: - # Make sure that the file was created. - if os.path.isfile(temp_json_file): - os.remove(temp_json_file) + if os.path.isfile(temp_file_path): + os.remove(temp_file_path) diff --git a/llvm_tools/update_packages_and_run_tryjobs.py b/llvm_tools/update_packages_and_run_tryjobs.py index f4fc234f..fac93db3 100755 --- a/llvm_tools/update_packages_and_run_tryjobs.py +++ b/llvm_tools/update_packages_and_run_tryjobs.py @@ -167,6 +167,11 @@ def GetTryJobCommand(change_list, extra_change_lists, options, builder): return tryjob_cmd +def GetCurrentTimeInUTC(): + """Returns the current time via `datetime.datetime.utcnow()`.""" + return datetime.datetime.utcnow() + + def RunTryJobs(cl_number, extra_change_lists, options, builders, chroot_path, verbose): """Runs a tryjob/tryjobs. @@ -204,7 +209,7 @@ def RunTryJobs(cl_number, extra_change_lists, options, builders, chroot_path, out = ChrootRunCommand(chroot_path, tryjob_cmd, verbose=verbose) - tryjob_launch_time = datetime.datetime.utcnow() + tryjob_launch_time = GetCurrentTimeInUTC() tryjob_contents = json.loads(out) diff --git a/llvm_tools/update_packages_and_run_tryjobs_unittest.py b/llvm_tools/update_packages_and_run_tryjobs_unittest.py new file mode 100755 index 00000000..55e344bb --- /dev/null +++ b/llvm_tools/update_packages_and_run_tryjobs_unittest.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright 2019 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Unittests for running tryjobs after updating packages.""" + +from __future__ import print_function + +import json +import unittest +import unittest.mock as mock + +from test_helpers import ArgsOutputTest +from test_helpers import CreateTemporaryFile +from update_chromeos_llvm_next_hash import CommitContents +import update_chromeos_llvm_next_hash +import update_packages_and_run_tryjobs + + +class UpdatePackagesAndRunTryjobsTest(unittest.TestCase): + """Unittests when running tryjobs after updating packages.""" + + def testNoLastTestedFile(self): + self.assertEqual( + update_packages_and_run_tryjobs.GetLastTestedSVNVersion(None), None) + + def testFailedToGetIntegerFromLastTestedFile(self): + # Create a temporary file to simulate the behavior of the last tested file + # when the file does not have a SVN version (i.e. int() failed). + with CreateTemporaryFile() as temp_file: + self.assertEqual( + update_packages_and_run_tryjobs.GetLastTestedSVNVersion(temp_file), + None) + + def testLastTestFileDoesNotExist(self): + # Simulate 'open()' on a lasted tested file that does not exist. + mock_open = mock.mock_open(read_data='') + + self.assertEqual( + update_packages_and_run_tryjobs.GetLastTestedSVNVersion( + '/some/file/that/does/not/exist.txt'), None) + + def testSuccessfullyRetrievedLastTestedSVNVersion(self): + with CreateTemporaryFile() as temp_file: + # Simulate behavior when the last tested file contains a SVN version. + with open(temp_file, 'w') as svn_file: + svn_file.write('1234') + + self.assertEqual( + update_packages_and_run_tryjobs.GetLastTestedSVNVersion(temp_file), + 1234) + + def testGetTryJobCommandWithNoExtraInformation(self): + test_change_list = 1234 + + test_builder = 'nocturne' + + expected_tryjob_cmd_list = [ + 'cros', 'tryjob', '--yes', '--json', '-g', + '%d' % test_change_list, test_builder + ] + + self.assertEqual( + update_packages_and_run_tryjobs.GetTryJobCommand( + test_change_list, None, None, test_builder), + expected_tryjob_cmd_list) + + def testGetTryJobCommandWithExtraInformation(self): + test_change_list = 4321 + test_extra_cls = [1000, 10] + test_options = ['report_error', 'delete_tryjob'] + test_builder = 'kevin' + + expected_tryjob_cmd_list = [ + 'cros', + 'tryjob', + '--yes', + '--json', + '-g', + '%d' % test_change_list, + '-g', + '%d' % test_extra_cls[0], + '-g', + '%d' % test_extra_cls[1], + test_builder, + '--%s' % test_options[0], + '--%s' % test_options[1], + ] + + self.assertEqual( + update_packages_and_run_tryjobs.GetTryJobCommand( + test_change_list, test_extra_cls, test_options, test_builder), + expected_tryjob_cmd_list) + + # Simulate `datetime.datetime.utcnow()` when retrieving the current time when + # submitted a tryjob. + @mock.patch.object( + update_packages_and_run_tryjobs, + 'GetCurrentTimeInUTC', + return_value='2019-09-09') + # Simulate the behavior of `AddTryjobLinkToCL()` when successfully added the + # tryjob url to the CL that was uploaded to Gerrit for review. + @mock.patch.object(update_packages_and_run_tryjobs, 'AddTryjobLinkToCL') + # Simulate behavior of `ChrootRunCommand()` when successfully submitted a + # tryjob via `cros tryjob`. + @mock.patch.object(update_packages_and_run_tryjobs, 'ChrootRunCommand') + def testSuccessfullySubmittedTryJob( + self, mock_chroot_cmd, mock_add_tryjob_link_to_cl, mock_launch_time): + + expected_tryjob_cmd_list = [ + 'cros', 'tryjob', '--yes', '--json', '-g', + '%d' % 900, '-g', + '%d' % 1200, 'builder1', '--some_option' + ] + + buildbucket_id = '1234' + url = 'https://some_tryjob_url.com' + + tryjob_launch_contents = [{'buildbucket_id': buildbucket_id, 'url': url}] + + mock_chroot_cmd.return_value = json.dumps(tryjob_launch_contents) + + extra_cls = [1200] + tryjob_options = ['some_option'] + builder_list = ['builder1'] + chroot_path = '/some/path/to/chroot' + cl_to_launch_tryjob = 900 + verbose = False + + tryjob_results_list = update_packages_and_run_tryjobs.RunTryJobs( + cl_to_launch_tryjob, extra_cls, tryjob_options, builder_list, + chroot_path, verbose) + + expected_tryjob_dict = { + 'launch_time': '2019-09-09', + 'link': url, + 'buildbucket_id': int(buildbucket_id), + 'extra_cls': extra_cls, + 'options': tryjob_options, + 'builder': builder_list + } + + self.assertEqual(tryjob_results_list, [expected_tryjob_dict]) + + mock_chroot_cmd.assert_called_once_with( + chroot_path, expected_tryjob_cmd_list, verbose=False) + + mock_add_tryjob_link_to_cl.assert_called_once() + + mock_launch_time.assert_called_once() + + # Simulate behavior of `ExecCommandAndCaptureOutput()` when successfully added + # the tryjob link to the CL via `gerrit message <CL> <message>`. + @mock.patch.object( + update_packages_and_run_tryjobs, + 'ExecCommandAndCaptureOutput', + return_value=None) + def testSuccessfullyAddedTryjobLinkToCL(self, mock_exec_cmd): + chroot_path = '/abs/path/to/chroot' + + test_cl_number = 1000 + + tryjob_result = [{'link': 'https://some_tryjob_link.com'}] + + update_packages_and_run_tryjobs.AddTryjobLinkToCL( + tryjob_result, test_cl_number, chroot_path) + + expected_gerrit_message = [ + '%s/chromite/bin/gerrit' % chroot_path, 'message', + str(test_cl_number), + 'Started the following tryjobs:\n%s' % tryjob_result[0]['link'] + ] + + mock_exec_cmd.assert_called_once_with(expected_gerrit_message) + + # Simulate behavior of `GetCommandLineArgs()` when successfully parsed the + # command line for the optional/required arguments for the script. + @mock.patch.object(update_packages_and_run_tryjobs, 'GetCommandLineArgs') + # Simulate behavior of `GetLLVMHashAndVersionFromSVNOption()` when + # successfully retrieved the LLVM hash and version for google3. + @mock.patch.object(update_packages_and_run_tryjobs, + 'GetLLVMHashAndVersionFromSVNOption') + # Simulate behavior of `GetLastTestedSVNVersion()` when successfully retrieved + # the last tested revision from the last tested file. + @mock.patch.object( + update_packages_and_run_tryjobs, + 'GetLastTestedSVNVersion', + return_value=100) + # Simulate behavior of `VerifyOutsideChroot()` when successfully invoked the + # script outside of the chroot. + @mock.patch.object( + update_packages_and_run_tryjobs, 'VerifyOutsideChroot', return_value=True) + def testLastTestSVNVersionMatchesSVNVersion( + self, mock_outside_chroot, mock_get_last_tested_version, + mock_get_hash_and_version, mock_get_commandline_args): + + args_output_obj = ArgsOutputTest() + + mock_get_commandline_args.return_value = args_output_obj + + mock_get_hash_and_version.return_value = ('a123testhash1', 100) + + update_packages_and_run_tryjobs.main() + + mock_outside_chroot.assert_called_once() + + mock_get_commandline_args.assert_called_once() + + mock_get_last_tested_version.assert_called_once_with( + args_output_obj.last_tested) + + mock_get_hash_and_version.assert_called_once_with( + args_output_obj.llvm_version) + + # Simulate the behavior of `RunTryJobs()` when successfully submitted a + # tryjob. + @mock.patch.object(update_packages_and_run_tryjobs, 'RunTryJobs') + # Simulate behavior of `UpdatePackages()` when successfully updated the + # packages and uploaded a CL for review. + @mock.patch.object(update_chromeos_llvm_next_hash, 'UpdatePackages') + # Simulate behavior of `GetCommandLineArgs()` when successfully parsed the + # command line for the optional/required arguments for the script. + @mock.patch.object(update_packages_and_run_tryjobs, 'GetCommandLineArgs') + # Simulate behavior of `GetLLVMHashAndVersionFromSVNOption()` when + # successfully retrieved the LLVM hash and version for google3. + @mock.patch.object(update_packages_and_run_tryjobs, + 'GetLLVMHashAndVersionFromSVNOption') + # Simulate behavior of `GetLastTestedSVNVersion()` when successfully retrieved + # the last tested revision from the last tested file. + @mock.patch.object( + update_packages_and_run_tryjobs, + 'GetLastTestedSVNVersion', + return_value=100) + # Simulate behavior of `VerifyOutsideChroot()` when successfully invoked the + # script outside of the chroot. + @mock.patch.object( + update_packages_and_run_tryjobs, 'VerifyOutsideChroot', return_value=True) + def testUpdatedLastTestedFileWithNewTestedRevision( + self, mock_outside_chroot, mock_get_last_tested_version, + mock_get_hash_and_version, mock_get_commandline_args, + mock_update_packages, mock_run_tryjobs): + + mock_get_hash_and_version.return_value = ('a123testhash2', 200) + + test_cl_url = 'https://some_cl_url.com' + + test_cl_number = 12345 + + mock_update_packages.return_value = CommitContents( + url=test_cl_url, cl_number=test_cl_number) + + tryjob_test_results = [{ + 'link': 'https://some_tryjob_url.com', + 'buildbucket_id': 1234 + }] + + mock_run_tryjobs.return_value = tryjob_test_results + + # Create a temporary file to simulate the last tested file that contains a + # revision. + with CreateTemporaryFile() as last_tested_file: + args_output_obj = ArgsOutputTest(svn_option=200) + args_output_obj.last_tested = last_tested_file + + mock_get_commandline_args.return_value = args_output_obj + + update_packages_and_run_tryjobs.main() + + # Verify that the lasted tested file has been updated to the new LLVM + # revision. + with open(last_tested_file) as update_revision: + new_revision = update_revision.readline() + + self.assertEqual(int(new_revision.rstrip()), 200) + + mock_outside_chroot.assert_called_once() + + mock_get_commandline_args.assert_called_once() + + mock_get_last_tested_version.assert_called_once() + + mock_get_hash_and_version.assert_called_once() + + mock_run_tryjobs.assert_called_once() + + mock_update_packages.assert_called_once() + + +if __name__ == '__main__': + unittest.main() |