• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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