aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools
diff options
context:
space:
mode:
authorSalud Lemus <saludlemus@google.com>2019-09-09 13:26:50 -0700
committerSalud Lemus <saludlemus@google.com>2019-09-12 00:05:14 +0000
commit4344157210d5729631a3c299ab23315710a7772b (patch)
tree0ad6fc82ae56a8fab99e8743703b3ae453420343 /llvm_tools
parentd4475f88f851d42cac195c42beafdbfecf284c9e (diff)
downloadtoolchain-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.py42
-rwxr-xr-xllvm_tools/update_packages_and_run_tryjobs.py7
-rwxr-xr-xllvm_tools/update_packages_and_run_tryjobs_unittest.py292
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()