blob: 7e84187b4f8eb01ae8adc9fc3583024b3ed2273a [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
J. Richard Barnetted422f622011-11-17 09:39:46 -080013from chromite.lib import cros_build_lib
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040014from chromite.lib import cros_build_lib_unittest
Brian Harringc92788f2012-09-21 18:07:15 -070015from chromite.lib import cros_test_lib
David James97d95872012-11-16 15:09:56 -080016from chromite.lib import git
David James59a0a2b2013-03-22 14:04:44 -070017from chromite.lib import osutils
Ningning Xia783efc02018-01-24 13:39:51 -080018from chromite.lib import parallel
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040019from chromite.lib import parallel_unittest
20from chromite.lib import partial_mock
Ningning Xia783efc02018-01-24 13:39:51 -080021from chromite.lib import portage_util
Mike Frysinger6cb624a2012-05-24 18:17:38 -040022from chromite.scripts import cros_mark_as_stable
Chris Sosadad0d322011-01-31 16:37:33 -080023
Mike Frysingeref6ccb22014-11-07 14:59:48 -050024
Mike Frysingerc9785342014-12-08 00:47:08 -050025class RunGitMock(partial_mock.PartialCmdMock):
26 """Partial mock for git.RunMock."""
27 TARGET = 'chromite.lib.git'
28 ATTRS = ('RunGit',)
29 DEFAULT_ATTR = 'RunGit'
30
31 def RunGit(self, _git_repo, cmd, _retry=True, **kwargs):
32 return self._results['RunGit'].LookupResult(
33 (cmd,), hook_args=(cmd,), hook_kwargs=kwargs)
Mike Frysingeref6ccb22014-11-07 14:59:48 -050034
35
Mike Frysingerc9785342014-12-08 00:47:08 -050036class NonClassTests(cros_test_lib.MockTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -070037 """Test the flow for pushing a change."""
Mike Frysingerc9785342014-12-08 00:47:08 -050038
Chris Sosadad0d322011-01-31 16:37:33 -080039 def setUp(self):
Chris Sosadad0d322011-01-31 16:37:33 -080040 self._branch = 'test_branch'
Brian Harringeb237932012-05-07 02:08:06 -070041 self._target_manifest_branch = 'cros/master'
Chris Sosadad0d322011-01-31 16:37:33 -080042
Matt Tennantcb522052013-11-25 14:23:43 -080043 def _TestPushChange(self, bad_cls):
Mike Frysingerc9785342014-12-08 00:47:08 -050044 side_effect = Exception('unittest says this should not be called')
45
Chris Sosadad0d322011-01-31 16:37:33 -080046 git_log = 'Marking test_one as stable\nMarking test_two as stable\n'
47 fake_description = 'Marking set of ebuilds as stable\n\n%s' % git_log
David James47959632015-10-23 07:56:01 -070048 self.PatchObject(git, 'DoesCommitExistInRepo', return_value=True)
Mike Frysingerc9785342014-12-08 00:47:08 -050049 self.PatchObject(cros_mark_as_stable, '_DoWeHaveLocalCommits',
50 return_value=True)
51 self.PatchObject(cros_mark_as_stable.GitBranch, 'CreateBranch',
52 side_effect=side_effect)
53 self.PatchObject(cros_mark_as_stable.GitBranch, 'Exists',
54 side_effect=side_effect)
Chris Sosadad0d322011-01-31 16:37:33 -080055
Mike Nicholsa6818c52018-04-09 11:05:42 -060056 push_mock = self.PatchObject(git, 'PushBranch')
Don Garrett99449592015-03-25 11:01:30 -070057 self.PatchObject(
58 git, 'GetTrackingBranch',
59 return_value=git.RemoteRef('gerrit', 'refs/remotes/gerrit/master'))
Mike Frysingerc9785342014-12-08 00:47:08 -050060 sync_mock = self.PatchObject(git, 'SyncPushBranch')
61 create_mock = self.PatchObject(git, 'CreatePushBranch')
62 git_mock = self.StartPatcher(RunGitMock())
Matt Tennantcb522052013-11-25 14:23:43 -080063
Paul Hobbsf52ea8f2015-10-21 17:24:23 -070064 git_mock.AddCmdResult(['checkout', self._branch])
65
Matt Tennantcb522052013-11-25 14:23:43 -080066 cmd = ['log', '--format=short', '--perl-regexp', '--author',
67 '^(?!chrome-bot)', 'refs/remotes/gerrit/master..%s' % self._branch]
68
69 if bad_cls:
Mike Frysingerc9785342014-12-08 00:47:08 -050070 push_mock.side_effect = side_effect
71 create_mock.side_effect = side_effect
72 git_mock.AddCmdResult(cmd, output='Found bad stuff')
Matt Tennantcb522052013-11-25 14:23:43 -080073 else:
Mike Frysingerc9785342014-12-08 00:47:08 -050074 git_mock.AddCmdResult(cmd, output='\n')
Matt Tennantcb522052013-11-25 14:23:43 -080075 cmd = ['log', '--format=format:%s%n%n%b',
76 'refs/remotes/gerrit/master..%s' % self._branch]
Mike Frysingerc9785342014-12-08 00:47:08 -050077 git_mock.AddCmdResult(cmd, output=git_log)
78 git_mock.AddCmdResult(['merge', '--squash', self._branch])
79 git_mock.AddCmdResult(['commit', '-m', fake_description])
80 git_mock.AddCmdResult(['config', 'push.default', 'tracking'])
Matt Tennantcb522052013-11-25 14:23:43 -080081
Paul Hobbs72d8e392015-10-21 17:24:23 -070082 cros_mark_as_stable.PushChange(self._branch, self._target_manifest_branch,
83 False, '.')
84 sync_mock.assert_called_with('.', 'gerrit', 'refs/remotes/gerrit/master')
85 if not bad_cls:
Ningning Xia52009062016-05-09 14:33:51 -070086 push_mock.assert_called_with('merge_branch', '.', dryrun=False,
87 staging_branch=None)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -070088 create_mock.assert_called_with('merge_branch', '.',
89 remote_push_branch=mock.ANY)
Chris Sosadad0d322011-01-31 16:37:33 -080090
Matt Tennantcb522052013-11-25 14:23:43 -080091 def testPushChange(self):
Mike Frysingerc9785342014-12-08 00:47:08 -050092 """Verify pushing changes works."""
Matt Tennantcb522052013-11-25 14:23:43 -080093 self._TestPushChange(bad_cls=False)
94
95 def testPushChangeBadCls(self):
Mike Frysingerc9785342014-12-08 00:47:08 -050096 """Verify we do not push bad CLs."""
Matt Tennantcb522052013-11-25 14:23:43 -080097 self.assertRaises(AssertionError, self._TestPushChange, bad_cls=True)
98
Chris Sosadad0d322011-01-31 16:37:33 -080099
Ningning Xia783efc02018-01-24 13:39:51 -0800100class EbuildMock(object):
101 """Mock portage_util.Ebuild."""
102
103 def __init__(self, path, new_package=True):
104 self.path = path
105 self.package = '%s_package' % path
106 self.cros_workon_vars = 'cros_workon_vars'
107 self._new_package = new_package
108
109 # pylint: disable=unused-argument
110 def RevWorkOnEBuild(self, srcroot, manifest, redirect_file=None):
111 if self._new_package:
112 return ('%s_new_package' % self.path,
113 '%s_new_ebuild' % self.path,
114 '%s_old_ebuild' % self.path)
115
116
117# pylint: disable=protected-access
Ningning Xia419e4eb2018-02-05 10:30:36 -0800118class MarkAsStableCMDTest(cros_test_lib.MockTempDirTestCase):
119 """Test cros_mark_as_stable commands."""
Ningning Xia783efc02018-01-24 13:39:51 -0800120
121 def setUp(self):
Ningning Xia783efc02018-01-24 13:39:51 -0800122 self._manifest = 'manifest'
123 self._parser = cros_mark_as_stable.GetParser()
Ningning Xia419e4eb2018-02-05 10:30:36 -0800124 self._package_list = ['pkg1']
Ningning Xia783efc02018-01-24 13:39:51 -0800125
Ningning Xia419e4eb2018-02-05 10:30:36 -0800126 self._overlays = [os.path.join(self.tempdir, 'overlay_%s' % i)
127 for i in range(0, 3)]
128
129 self._overlay_remote_ref = {
130 self._overlays[0]: git.RemoteRef('remote', 'ref', 'project_1'),
131 self._overlays[1]: git.RemoteRef('remote', 'ref', 'project_1'),
132 self._overlays[2]: git.RemoteRef('remote', 'ref', 'project_2'),
133 }
134
135 self._git_project_overlays = {}
136 self._overlay_tracking_branch = {}
137 for overlay in self._overlays:
138 self._git_project_overlays.setdefault(
139 self._overlay_remote_ref[overlay], []).append(overlay)
140 self._overlay_tracking_branch[overlay] = (
141 self._overlay_remote_ref[overlay].ref)
Ningning Xia783efc02018-01-24 13:39:51 -0800142
143 self.PatchObject(git, 'GetTrackingBranchViaManifest')
Ningning Xia419e4eb2018-02-05 10:30:36 -0800144 self._commit_options = self._parser.parse_args(['commit'])
145 self._push_options = self._parser.parse_args(['push'])
Ningning Xia783efc02018-01-24 13:39:51 -0800146
Ningning Xia419e4eb2018-02-05 10:30:36 -0800147 def testWorkOnPush(self):
148 """Test _WorkOnPush."""
149 self.PatchObject(parallel, 'RunTasksInProcessPool')
150
151 cros_mark_as_stable._WorkOnPush(
152 self._push_options, self._overlay_tracking_branch,
153 self._git_project_overlays)
154
155 def testPushOverlays(self):
156 """Test _PushOverlays."""
157 self.PatchObject(os.path, 'isdir', return_value=True)
158 mock_push_change = self.PatchObject(cros_mark_as_stable, 'PushChange')
159
160 cros_mark_as_stable._PushOverlays(
161 self._push_options, self._overlays, self._overlay_tracking_branch)
162 self.assertEqual(mock_push_change.call_count, 3)
163
164 def testWorkOnCommit(self):
165 """Test _WorkOnCommit."""
166 self.PatchObject(parallel, 'RunTasksInProcessPool')
167 self.PatchObject(cros_mark_as_stable, '_CommitOverlays')
168 self.PatchObject(cros_mark_as_stable, '_GetOverlayToEbuildsMap',
169 return_value={})
170
171 cros_mark_as_stable._WorkOnCommit(
172 self._commit_options, self._overlays, self._overlay_tracking_branch,
173 self._git_project_overlays, self._manifest, self._package_list)
174
175 def testGetOverlayToEbuildsMap(self):
176 """Test _GetOverlayToEbuildsMap."""
177 self.PatchObject(portage_util, 'GetOverlayEBuilds', return_value=['ebuild'])
178
179 expected_overlay_dicts = {
180 overlay : ['ebuild'] for overlay in self._overlays}
181 overlay_ebuilds = cros_mark_as_stable._GetOverlayToEbuildsMap(
182 self._commit_options, self._overlays, self._package_list)
183 self.assertItemsEqual(expected_overlay_dicts, overlay_ebuilds)
184
185 def testCommitOverlays(self):
186 """Test _CommitOverlays."""
187 mock_run_process_pool = self.PatchObject(parallel, 'RunTasksInProcessPool')
188 self.PatchObject(os.path, 'isdir', return_value=True)
189 self.PatchObject(git, 'RunGit')
190 self.PatchObject(cros_mark_as_stable, '_WorkOnEbuild', return_value=None)
191 self.PatchObject(git, 'GetGitRepoRevision')
192 self.PatchObject(cros_mark_as_stable.GitBranch, 'CreateBranch')
193 self.PatchObject(cros_mark_as_stable.GitBranch, 'Exists', return_value=True)
194 self.PatchObject(portage_util.EBuild, 'CommitChange')
195
196 overlay_ebuilds = {
197 self._overlays[0]: ['ebuild_1_1', 'ebuild_1_2'],
198 self._overlays[1]: ['ebuild_2_1'],
199 self._overlays[2]: ['ebuild_3_1', 'ebuild_3_2'],
200 }
201
202 cros_mark_as_stable._CommitOverlays(
203 self._commit_options, self._manifest, self._overlays,
204 self._overlay_tracking_branch, overlay_ebuilds, list(), list())
205 self.assertEqual(3, mock_run_process_pool.call_count)
Ningning Xia783efc02018-01-24 13:39:51 -0800206
207 def testWorkOnEbuildWithNewPackage(self):
208 """Test _WorkOnEbuild with new packages."""
Ningning Xia419e4eb2018-02-05 10:30:36 -0800209 overlay = self._overlays[0]
Ningning Xia783efc02018-01-24 13:39:51 -0800210 ebuild = EbuildMock('ebuild')
Ningning Xia783efc02018-01-24 13:39:51 -0800211
Ningning Xia419e4eb2018-02-05 10:30:36 -0800212 with parallel.Manager() as manager:
213 revved_packages = manager.list()
214 new_package_atoms = manager.list()
215
216 messages = manager.list()
217 ebuild_paths_to_add = manager.list()
218 ebuild_paths_to_remove = manager.list()
219
220 cros_mark_as_stable._WorkOnEbuild(
221 overlay, ebuild, self._manifest, self._commit_options,
222 ebuild_paths_to_add, ebuild_paths_to_remove,
223 messages, revved_packages, new_package_atoms)
224 self.assertItemsEqual(ebuild_paths_to_add, ['ebuild_new_ebuild'])
225 self.assertItemsEqual(ebuild_paths_to_remove, ['ebuild_old_ebuild'])
226 self.assertItemsEqual(messages,
227 [cros_mark_as_stable._GIT_COMMIT_MESSAGE %
228 'ebuild_package'])
229 self.assertItemsEqual(revved_packages, ['ebuild_package'])
230 self.assertItemsEqual(new_package_atoms, ['=ebuild_new_package'])
Ningning Xia783efc02018-01-24 13:39:51 -0800231
232 def testWorkOnEbuildWithoutNewPackage(self):
233 """Test _WorkOnEbuild without new packages."""
234 ebuild = EbuildMock('ebuild', new_package=False)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800235 overlay = self._overlays[0]
Ningning Xia783efc02018-01-24 13:39:51 -0800236
Ningning Xia419e4eb2018-02-05 10:30:36 -0800237 with parallel.Manager() as manager:
238 revved_packages = manager.list()
239 new_package_atoms = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800240
Ningning Xia419e4eb2018-02-05 10:30:36 -0800241 messages = manager.list()
242 ebuild_paths_to_add = manager.list()
243 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800244
Ningning Xia419e4eb2018-02-05 10:30:36 -0800245 cros_mark_as_stable._WorkOnEbuild(
246 overlay, ebuild, self._manifest, self._commit_options,
247 ebuild_paths_to_add, ebuild_paths_to_remove, messages,
248 revved_packages, new_package_atoms)
249 self.assertEqual(list(ebuild_paths_to_add), [])
250 self.assertEqual(list(ebuild_paths_to_remove), [])
251 self.assertEqual(list(messages), [])
252 self.assertEqual(list(revved_packages), [])
253 self.assertEqual(list(new_package_atoms), [])
Ningning Xia783efc02018-01-24 13:39:51 -0800254
255
Ningning Xiadb884322018-01-26 16:27:06 -0800256class MainTests(cros_build_lib_unittest.RunCommandTestCase,
257 cros_test_lib.MockTempDirTestCase):
258 """Tests for cros_mark_as_stable.main()."""
259
260 def setUp(self):
261 self.PatchObject(git.ManifestCheckout, 'Cached', return_value='manifest')
Ningning Xia419e4eb2018-02-05 10:30:36 -0800262 self.mock_work_on_push = self.PatchObject(
263 cros_mark_as_stable, '_WorkOnPush')
264 self.mock_work_on_commit = self.PatchObject(
265 cros_mark_as_stable, '_WorkOnCommit')
Ningning Xiadb884322018-01-26 16:27:06 -0800266
Ningning Xia419e4eb2018-02-05 10:30:36 -0800267 self._overlays = []
268 remote_refs = []
269 self._overlay_tracking_branch = {}
270 self._git_project_overlays = {}
Ningning Xiadb884322018-01-26 16:27:06 -0800271 for i in range(0, 3):
272 overlay = os.path.join(self.tempdir, 'overlay_%s' % i)
273 osutils.SafeMakedirs(overlay)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800274 self._overlays.append(overlay)
Ningning Xiadb884322018-01-26 16:27:06 -0800275
Ningning Xia419e4eb2018-02-05 10:30:36 -0800276 remote_ref = git.RemoteRef('remote', 'ref', 'project_%s' % i)
277 remote_refs.append(remote_ref)
Ningning Xiadb884322018-01-26 16:27:06 -0800278
Ningning Xia419e4eb2018-02-05 10:30:36 -0800279 self._overlay_tracking_branch[overlay] = remote_ref.ref
280 self._git_project_overlays[remote_ref.project_name] = [overlay]
281
282 self.PatchObject(git, 'GetTrackingBranchViaManifest',
283 side_effect=remote_refs)
284
285 def testMainWithCommit(self):
286 """Test Main with Commit options."""
Ningning Xiadb884322018-01-26 16:27:06 -0800287 cros_mark_as_stable.main(
Ningning Xia419e4eb2018-02-05 10:30:36 -0800288 ['commit', '--all', '--overlays', ':'.join(self._overlays)])
289 self.mock_work_on_commit.assert_called_once_with(
290 mock.ANY, self._overlays, self._overlay_tracking_branch,
291 self._git_project_overlays, 'manifest', None)
292
293 def testMainWithPush(self):
294 """Test Main with Push options."""
295 cros_mark_as_stable.main(
296 ['push', '--all', '--overlays', ':'.join(self._overlays)])
297 self.mock_work_on_push.assert_called_once_with(
298 mock.ANY, self._overlay_tracking_branch, self._git_project_overlays)
Ningning Xiadb884322018-01-26 16:27:06 -0800299
300
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400301class CleanStalePackagesTest(cros_build_lib_unittest.RunCommandTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700302 """Tests for cros_mark_as_stable.CleanStalePackages."""
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400303
David James59a0a2b2013-03-22 14:04:44 -0700304 def setUp(self):
305 self.PatchObject(osutils, 'FindMissingBinaries', return_value=[])
306
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400307 def testNormalClean(self):
308 """Clean up boards/packages with normal success"""
David James41124af2015-06-04 21:13:25 -0700309 cros_mark_as_stable.CleanStalePackages('.', ('board1', 'board2'),
310 ['cow', 'car'])
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400311
312 def testNothingToUnmerge(self):
313 """Clean up packages that don't exist (portage will exit 1)"""
314 self.rc.AddCmdResult(partial_mock.In('emerge'), returncode=1)
David James41124af2015-06-04 21:13:25 -0700315 cros_mark_as_stable.CleanStalePackages('.', (), ['no/pkg'])
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400316
317 def testUnmergeError(self):
318 """Make sure random exit errors are not ignored"""
319 self.rc.AddCmdResult(partial_mock.In('emerge'), returncode=123)
320 with parallel_unittest.ParallelMock():
Dean Liao6eddc8d2018-01-25 17:13:39 +0800321 with self.assertRaises(cros_build_lib.RunCommandError):
322 cros_mark_as_stable.CleanStalePackages('.', (), ['no/pkg'])
Mike Frysingerde5ab0e2013-03-21 20:48:36 -0400323
324
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500325class GitBranchTest(cros_test_lib.MockTestCase):
Don Garrett25f309a2014-03-19 14:02:12 -0700326 """Tests for cros_mark_as_stable.GitBranch."""
Chris Sosadad0d322011-01-31 16:37:33 -0800327
328 def setUp(self):
Chris Sosadad0d322011-01-31 16:37:33 -0800329 # Always stub RunCommmand out as we use it in every method.
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500330 self.rc_mock = self.PatchObject(cros_build_lib, 'RunCommand')
331
Chris Sosadad0d322011-01-31 16:37:33 -0800332 self._branch_name = 'test_branch'
Brian Harringeb237932012-05-07 02:08:06 -0700333 self._target_manifest_branch = 'cros/test'
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500334 self._branch = cros_mark_as_stable.GitBranch(
335 branch_name=self._branch_name,
336 tracking_branch=self._target_manifest_branch,
337 cwd='.')
Chris Sosadad0d322011-01-31 16:37:33 -0800338
339 def testCheckoutCreate(self):
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500340 """Test init with no previous branch existing."""
341 self.PatchObject(self._branch, 'Exists', return_value=False)
Chris Sosadad0d322011-01-31 16:37:33 -0800342 cros_mark_as_stable.GitBranch.Checkout(self._branch)
Dean Liao6eddc8d2018-01-25 17:13:39 +0800343 self.rc_mock.assert_called_with(
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500344 ['repo', 'start', self._branch_name, '.'],
Dean Liao6eddc8d2018-01-25 17:13:39 +0800345 print_cmd=False, cwd='.', capture_output=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800346
347 def testCheckoutNoCreate(self):
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500348 """Test init with previous branch existing."""
349 self.PatchObject(self._branch, 'Exists', return_value=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800350 cros_mark_as_stable.GitBranch.Checkout(self._branch)
Dean Liao6eddc8d2018-01-25 17:13:39 +0800351 self.rc_mock.assert_called_with(
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500352 ['git', 'checkout', '-f', self._branch_name],
Dean Liao6eddc8d2018-01-25 17:13:39 +0800353 print_cmd=False, cwd='.', capture_output=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800354
Chris Sosadad0d322011-01-31 16:37:33 -0800355 def testExists(self):
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500356 """Test if branch exists that is created."""
Mike Frysinger7dafd0e2012-05-08 15:47:16 -0400357 result = cros_build_lib.CommandResult(output=self._branch_name + '\n')
Mike Frysingeref6ccb22014-11-07 14:59:48 -0500358 self.PatchObject(git, 'RunGit', return_value=result)
359 self.assertTrue(self._branch.Exists())