blob: bbf5e85d2742ebe8d53367a6251b7aba5907bc83 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Mike Frysinger6cb624a2012-05-24 18:17:38 -04002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Sosadad0d322011-01-31 16:37:33 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Unit tests for cros_mark_as_stable.py."""
7
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Mike Frysingerea838d12014-12-08 11:55:32 -050010import mock
Ningning Xia783efc02018-01-24 13:39:51 -080011import os
Chris Sosadad0d322011-01-31 16:37:33 -080012
Ningning Xia783efc02018-01-24 13:39:51 -080013from chromite.lib import constants
J. Richard Barnetted422f622011-11-17 09:39:46 -080014from chromite.lib import cros_build_lib
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040015from chromite.lib import cros_build_lib_unittest
Brian Harringc92788f2012-09-21 18:07:15 -070016from chromite.lib import cros_test_lib
David James97d95872012-11-16 15:09:56 -080017from chromite.lib import git
David James59a0a2b2013-03-22 14:04:44 -070018from chromite.lib import osutils
Ningning Xia783efc02018-01-24 13:39:51 -080019from chromite.lib import parallel
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040020from chromite.lib import parallel_unittest
21from chromite.lib import partial_mock
Ningning Xia783efc02018-01-24 13:39:51 -080022from chromite.lib import portage_util
Mike Frysinger6cb624a2012-05-24 18:17:38 -040023from chromite.scripts import cros_mark_as_stable
Chris Sosadad0d322011-01-31 16:37:33 -080024
Mike Frysingeref6ccb22014-11-07 14:59:48 -050025
Mike Frysingerc9785342014-12-08 00:47:08 -050026class RunGitMock(partial_mock.PartialCmdMock):
27 """Partial mock for git.RunMock."""
28 TARGET = 'chromite.lib.git'
29 ATTRS = ('RunGit',)
30 DEFAULT_ATTR = 'RunGit'
31
32 def RunGit(self, _git_repo, cmd, _retry=True, **kwargs):
33 return self._results['RunGit'].LookupResult(
34 (cmd,), hook_args=(cmd,), hook_kwargs=kwargs)
Mike Frysingeref6ccb22014-11-07 14:59:48 -050035
36
Mike Frysingerc9785342014-12-08 00:47:08 -050037class NonClassTests(cros_test_lib.MockTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -070038 """Test the flow for pushing a change."""
Mike Frysingerc9785342014-12-08 00:47:08 -050039
Chris Sosadad0d322011-01-31 16:37:33 -080040 def setUp(self):
Chris Sosadad0d322011-01-31 16:37:33 -080041 self._branch = 'test_branch'
Brian Harringeb237932012-05-07 02:08:06 -070042 self._target_manifest_branch = 'cros/master'
Chris Sosadad0d322011-01-31 16:37:33 -080043
Matt Tennantcb522052013-11-25 14:23:43 -080044 def _TestPushChange(self, bad_cls):
Mike Frysingerc9785342014-12-08 00:47:08 -050045 side_effect = Exception('unittest says this should not be called')
46
Chris Sosadad0d322011-01-31 16:37:33 -080047 git_log = 'Marking test_one as stable\nMarking test_two as stable\n'
48 fake_description = 'Marking set of ebuilds as stable\n\n%s' % git_log
David James47959632015-10-23 07:56:01 -070049 self.PatchObject(git, 'DoesCommitExistInRepo', return_value=True)
Mike Frysingerc9785342014-12-08 00:47:08 -050050 self.PatchObject(cros_mark_as_stable, '_DoWeHaveLocalCommits',
51 return_value=True)
52 self.PatchObject(cros_mark_as_stable.GitBranch, 'CreateBranch',
53 side_effect=side_effect)
54 self.PatchObject(cros_mark_as_stable.GitBranch, 'Exists',
55 side_effect=side_effect)
Chris Sosadad0d322011-01-31 16:37:33 -080056
Mike Frysingerc9785342014-12-08 00:47:08 -050057 push_mock = self.PatchObject(git, 'PushWithRetry')
Don Garrett99449592015-03-25 11:01:30 -070058 self.PatchObject(
59 git, 'GetTrackingBranch',
60 return_value=git.RemoteRef('gerrit', 'refs/remotes/gerrit/master'))
Mike Frysingerc9785342014-12-08 00:47:08 -050061 sync_mock = self.PatchObject(git, 'SyncPushBranch')
62 create_mock = self.PatchObject(git, 'CreatePushBranch')
63 git_mock = self.StartPatcher(RunGitMock())
Matt Tennantcb522052013-11-25 14:23:43 -080064
Paul Hobbsf52ea8f2015-10-21 17:24:23 -070065 git_mock.AddCmdResult(['checkout', self._branch])
66
Matt Tennantcb522052013-11-25 14:23:43 -080067 cmd = ['log', '--format=short', '--perl-regexp', '--author',
68 '^(?!chrome-bot)', 'refs/remotes/gerrit/master..%s' % self._branch]
69
70 if bad_cls:
Mike Frysingerc9785342014-12-08 00:47:08 -050071 push_mock.side_effect = side_effect
72 create_mock.side_effect = side_effect
73 git_mock.AddCmdResult(cmd, output='Found bad stuff')
Matt Tennantcb522052013-11-25 14:23:43 -080074 else:
Mike Frysingerc9785342014-12-08 00:47:08 -050075 git_mock.AddCmdResult(cmd, output='\n')
Matt Tennantcb522052013-11-25 14:23:43 -080076 cmd = ['log', '--format=format:%s%n%n%b',
77 'refs/remotes/gerrit/master..%s' % self._branch]
Mike Frysingerc9785342014-12-08 00:47:08 -050078 git_mock.AddCmdResult(cmd, output=git_log)
79 git_mock.AddCmdResult(['merge', '--squash', self._branch])
80 git_mock.AddCmdResult(['commit', '-m', fake_description])
81 git_mock.AddCmdResult(['config', 'push.default', 'tracking'])
Matt Tennantcb522052013-11-25 14:23:43 -080082
Paul Hobbs72d8e392015-10-21 17:24:23 -070083 cros_mark_as_stable.PushChange(self._branch, self._target_manifest_branch,
84 False, '.')
85 sync_mock.assert_called_with('.', 'gerrit', 'refs/remotes/gerrit/master')
86 if not bad_cls:
Ningning Xia52009062016-05-09 14:33:51 -070087 push_mock.assert_called_with('merge_branch', '.', dryrun=False,
88 staging_branch=None)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -070089 create_mock.assert_called_with('merge_branch', '.',
90 remote_push_branch=mock.ANY)
Chris Sosadad0d322011-01-31 16:37:33 -080091
Matt Tennantcb522052013-11-25 14:23:43 -080092 def testPushChange(self):
Mike Frysingerc9785342014-12-08 00:47:08 -050093 """Verify pushing changes works."""
Matt Tennantcb522052013-11-25 14:23:43 -080094 self._TestPushChange(bad_cls=False)
95
96 def testPushChangeBadCls(self):
Mike Frysingerc9785342014-12-08 00:47:08 -050097 """Verify we do not push bad CLs."""
Matt Tennantcb522052013-11-25 14:23:43 -080098 self.assertRaises(AssertionError, self._TestPushChange, bad_cls=True)
99
Chris Sosadad0d322011-01-31 16:37:33 -0800100
Ningning Xia783efc02018-01-24 13:39:51 -0800101class EbuildMock(object):
102 """Mock portage_util.Ebuild."""
103
104 def __init__(self, path, new_package=True):
105 self.path = path
106 self.package = '%s_package' % path
107 self.cros_workon_vars = 'cros_workon_vars'
108 self._new_package = new_package
109
110 # pylint: disable=unused-argument
111 def RevWorkOnEBuild(self, srcroot, manifest, redirect_file=None):
112 if self._new_package:
113 return ('%s_new_package' % self.path,
114 '%s_new_ebuild' % self.path,
115 '%s_old_ebuild' % self.path)
116
117
118# pylint: disable=protected-access
119class MarkAsStableParallelTest(cros_test_lib.MockTestCase):
120 """Test mark_as_stable in parallel."""
121
122 def setUp(self):
123 self._overlay = 'test-overlay'
124 self._manifest = 'manifest'
125 self._parser = cros_mark_as_stable.GetParser()
126
127 self._manager = parallel.Manager()
128 self.ebuild_paths_to_add = self._manager.list()
129 self.ebuild_paths_to_remove = self._manager.list()
130 self.revved_packages = self._manager.list()
131 self.new_package_atoms = self._manager.list()
132 self.messages = self._manager.list()
133 self._manager.__enter__()
134
135 self.PatchObject(git, 'GetTrackingBranchViaManifest')
136
137 def tearDown(self):
138 # Mimic exiting a 'with' statement.
139 self._manager.__exit__(None, None, None)
140
141 def testWorkOnEbuildWithNewPackage(self):
142 """Test _WorkOnEbuild with new packages."""
143 ebuild = EbuildMock('ebuild')
144 options = self._parser.parse_args(['commit'])
145
146 cros_mark_as_stable._WorkOnEbuild(
147 self._overlay, ebuild, self._manifest, options,
148 self.ebuild_paths_to_add, self.ebuild_paths_to_remove,
149 self.messages, self.revved_packages, self.new_package_atoms)
150 self.assertItemsEqual(self.ebuild_paths_to_add, ['ebuild_new_ebuild'])
151 self.assertItemsEqual(self.ebuild_paths_to_remove, ['ebuild_old_ebuild'])
152 self.assertItemsEqual(self.messages,
153 [cros_mark_as_stable._GIT_COMMIT_MESSAGE %
154 'ebuild_package'])
155 self.assertItemsEqual(self.revved_packages, ['ebuild_package'])
156 self.assertItemsEqual(self.new_package_atoms, ['=ebuild_new_package'])
157
158 def testWorkOnEbuildWithoutNewPackage(self):
159 """Test _WorkOnEbuild without new packages."""
160 ebuild = EbuildMock('ebuild', new_package=False)
161 options = self._parser.parse_args(['commit'])
162
163 cros_mark_as_stable._WorkOnEbuild(
164 self._overlay, ebuild, self._manifest, options,
165 self.ebuild_paths_to_add, self.ebuild_paths_to_remove,
166 self.messages, self.revved_packages, self.new_package_atoms)
167 self.assertEqual(len(self.ebuild_paths_to_add), 0)
168 self.assertEqual(len(self.ebuild_paths_to_remove), 0)
169 self.assertEqual(len(self.messages), 0)
170 self.assertEqual(len(self.revved_packages), 0)
171 self.assertEqual(len(self.new_package_atoms), 0)
172
173 def testWorkOnOverlayWithPushCmd(self):
174 """Test _WorkOnOverlay with Push command."""
175 ebuild_1 = EbuildMock('ebuild_1')
176 ebuild_2 = EbuildMock('ebuild_2')
177 ebuilds = [ebuild_1, ebuild_2]
Ningning Xiadb884322018-01-26 16:27:06 -0800178 overlay_ebuilds = {self._overlay: ebuilds}
Ningning Xia783efc02018-01-24 13:39:51 -0800179 options = self._parser.parse_args(['push'])
180
181 push_change_mock = self.PatchObject(cros_mark_as_stable, 'PushChange')
182 self.PatchObject(os.path, 'isdir', return_value=True)
183
184 cros_mark_as_stable._WorkOnOverlay(
Ningning Xiadb884322018-01-26 16:27:06 -0800185 self._overlay, overlay_ebuilds, self._manifest, options,
Ningning Xia783efc02018-01-24 13:39:51 -0800186 self.ebuild_paths_to_add, self.ebuild_paths_to_remove,
187 self.messages, self.revved_packages, self.new_package_atoms)
188
189 push_change_mock.assert_called_once_with(
190 constants.STABLE_EBUILD_BRANCH, mock.ANY,
191 options.dryrun, cwd=self._overlay,
192 staging_branch=options.staging_branch)
193
194 def testWorkOnOverlayWithCommitCmd(self):
195 """Test _WorkOnOverlay with Commit command."""
196 ebuild_1 = EbuildMock('ebuild_1')
197 ebuild_2 = EbuildMock('ebuild_2')
198 ebuilds = [ebuild_1, ebuild_2]
Ningning Xiadb884322018-01-26 16:27:06 -0800199 overlay_ebuilds = {self._overlay: ebuilds}
Ningning Xia783efc02018-01-24 13:39:51 -0800200 options = self._parser.parse_args(['commit'])
201
202 self.PatchObject(git, 'GetGitRepoRevision')
203 self.PatchObject(git, 'RunGit')
204 self.PatchObject(cros_mark_as_stable.GitBranch, 'CreateBranch')
205 self.PatchObject(cros_mark_as_stable.GitBranch, 'Exists', return_value=True)
206 self.PatchObject(portage_util.EBuild, 'CommitChange')
207 self.PatchObject(os.path, 'isdir', return_value=True)
208
209 cros_mark_as_stable._WorkOnOverlay(
Ningning Xiadb884322018-01-26 16:27:06 -0800210 self._overlay, overlay_ebuilds, self._manifest, options,
Ningning Xia783efc02018-01-24 13:39:51 -0800211 self.ebuild_paths_to_add, self.ebuild_paths_to_remove,
212 self.messages, self.revved_packages, self.new_package_atoms)
213
214 self.assertItemsEqual(
215 self.ebuild_paths_to_add,
216 ['ebuild_1_new_ebuild', 'ebuild_2_new_ebuild'])
217 self.assertItemsEqual(
218 self.ebuild_paths_to_remove,
219 ['ebuild_1_old_ebuild', 'ebuild_2_old_ebuild'])
220 self.assertItemsEqual(
221 self.messages,
222 [cros_mark_as_stable._GIT_COMMIT_MESSAGE % 'ebuild_1_package',
223 cros_mark_as_stable._GIT_COMMIT_MESSAGE % 'ebuild_2_package'])
224 self.assertItemsEqual(
225 self.revved_packages,
226 ['ebuild_1_package', 'ebuild_2_package'])
227 self.assertItemsEqual(
228 self.new_package_atoms,
229 ['=ebuild_1_new_package', '=ebuild_2_new_package'])
230
231 def testWorkOnOverlayNoEbuildsWithCommitCmd(self):
232 """Test _WorkOnOverlay without ebuilds with Commit command."""
Ningning Xiadb884322018-01-26 16:27:06 -0800233 overlay_ebuilds = {self._overlay: []}
Ningning Xia783efc02018-01-24 13:39:51 -0800234 options = self._parser.parse_args(['commit'])
235
236 self.PatchObject(git, 'GetGitRepoRevision')
237 self.PatchObject(git, 'RunGit')
238 self.PatchObject(cros_mark_as_stable.GitBranch, 'CreateBranch')
239 self.PatchObject(cros_mark_as_stable.GitBranch, 'Exists', return_value=True)
240 self.PatchObject(os.path, 'isdir', return_value=True)
241
242 cros_mark_as_stable._WorkOnOverlay(
Ningning Xiadb884322018-01-26 16:27:06 -0800243 self._overlay, overlay_ebuilds, self._manifest, options,
Ningning Xia783efc02018-01-24 13:39:51 -0800244 self.ebuild_paths_to_add, self.ebuild_paths_to_remove,
245 self.messages, self.revved_packages, self.new_package_atoms)
246 self.assertItemsEqual(self.ebuild_paths_to_add, [])
247 self.assertItemsEqual(self.ebuild_paths_to_remove, [])
248 self.assertItemsEqual(self.messages, [])
249 self.assertItemsEqual(self.revved_packages, [])
250 self.assertItemsEqual(self.new_package_atoms, [])
251
252
Ningning Xiadb884322018-01-26 16:27:06 -0800253class MainTests(cros_build_lib_unittest.RunCommandTestCase,
254 cros_test_lib.MockTempDirTestCase):
255 """Tests for cros_mark_as_stable.main()."""
256
257 def setUp(self):
258 self.PatchObject(git.ManifestCheckout, 'Cached', return_value='manifest')
259 self.PatchObject(cros_mark_as_stable, 'CleanStalePackages')
260 self.mock_work_on_overlay = self.PatchObject(
261 cros_mark_as_stable, '_WorkOnOverlay')
262
263 def testMainWithProvidedOverlays(self):
264 """Test Main with overlays provided in options."""
265 overlays = []
266 for i in range(0, 3):
267 overlay = os.path.join(self.tempdir, 'overlay_%s' % i)
268 osutils.SafeMakedirs(overlay)
269 overlays.append(overlay)
270
271 self.PatchObject(portage_util, 'GetOverlayEBuilds', return_value=['ebuild'])
272
273 cros_mark_as_stable.main(
274 ['commit', '--all', '--overlays', ':'.join(overlays)])
275 self.assertEqual(self.mock_work_on_overlay.call_count, 3)
276
277
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400278class CleanStalePackagesTest(cros_build_lib_unittest.RunCommandTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700279 """Tests for cros_mark_as_stable.CleanStalePackages."""
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400280
David James59a0a2b2013-03-22 14:04:44 -0700281 def setUp(self):
282 self.PatchObject(osutils, 'FindMissingBinaries', return_value=[])
283
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400284 def testNormalClean(self):
285 """Clean up boards/packages with normal success"""
David James41124af2015-06-04 21:13:25 -0700286 cros_mark_as_stable.CleanStalePackages('.', ('board1', 'board2'),
287 ['cow', 'car'])
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400288
289 def testNothingToUnmerge(self):
290 """Clean up packages that don't exist (portage will exit 1)"""
291 self.rc.AddCmdResult(partial_mock.In('emerge'), returncode=1)
David James41124af2015-06-04 21:13:25 -0700292 cros_mark_as_stable.CleanStalePackages('.', (), ['no/pkg'])
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400293
294 def testUnmergeError(self):
295 """Make sure random exit errors are not ignored"""
296 self.rc.AddCmdResult(partial_mock.In('emerge'), returncode=123)
297 with parallel_unittest.ParallelMock():
Dean Liao6eddc8d2018-01-25 17:13:39 +0800298 with self.assertRaises(cros_build_lib.RunCommandError):
299 cros_mark_as_stable.CleanStalePackages('.', (), ['no/pkg'])
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400300
301
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500302class GitBranchTest(cros_test_lib.MockTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700303 """Tests for cros_mark_as_stable.GitBranch."""
Chris Sosadad0d322011-01-31 16:37:33 -0800304
305 def setUp(self):
Chris Sosadad0d322011-01-31 16:37:33 -0800306 # Always stub RunCommmand out as we use it in every method.
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500307 self.rc_mock = self.PatchObject(cros_build_lib, 'RunCommand')
308
Chris Sosadad0d322011-01-31 16:37:33 -0800309 self._branch_name = 'test_branch'
Brian Harringeb237932012-05-07 02:08:06 -0700310 self._target_manifest_branch = 'cros/test'
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500311 self._branch = cros_mark_as_stable.GitBranch(
312 branch_name=self._branch_name,
313 tracking_branch=self._target_manifest_branch,
314 cwd='.')
Chris Sosadad0d322011-01-31 16:37:33 -0800315
316 def testCheckoutCreate(self):
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500317 """Test init with no previous branch existing."""
318 self.PatchObject(self._branch, 'Exists', return_value=False)
Chris Sosadad0d322011-01-31 16:37:33 -0800319 cros_mark_as_stable.GitBranch.Checkout(self._branch)
Dean Liao6eddc8d2018-01-25 17:13:39 +0800320 self.rc_mock.assert_called_with(
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500321 ['repo', 'start', self._branch_name, '.'],
Dean Liao6eddc8d2018-01-25 17:13:39 +0800322 print_cmd=False, cwd='.', capture_output=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800323
324 def testCheckoutNoCreate(self):
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500325 """Test init with previous branch existing."""
326 self.PatchObject(self._branch, 'Exists', return_value=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800327 cros_mark_as_stable.GitBranch.Checkout(self._branch)
Dean Liao6eddc8d2018-01-25 17:13:39 +0800328 self.rc_mock.assert_called_with(
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500329 ['git', 'checkout', '-f', self._branch_name],
Dean Liao6eddc8d2018-01-25 17:13:39 +0800330 print_cmd=False, cwd='.', capture_output=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800331
Chris Sosadad0d322011-01-31 16:37:33 -0800332 def testExists(self):
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500333 """Test if branch exists that is created."""
Mike Frysinger7dafd0e2012-05-08 15:47:16 -0400334 result = cros_build_lib.CommandResult(output=self._branch_name + '\n')
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500335 self.PatchObject(git, 'RunGit', return_value=result)
336 self.assertTrue(self._branch.Exists())