2 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Unittests for manifest_version. Needs to be run inside of chroot."""
8 from __future__ import print_function
16 if __name__ == '__main__':
17 sys.path.insert(0, constants.SOURCE_ROOT)
19 from chromite.cbuildbot import failures_lib
20 from chromite.cbuildbot import manifest_version
21 from chromite.cbuildbot import repository
22 from chromite.lib import cros_build_lib_unittest
23 from chromite.lib import git
24 from chromite.lib import cros_test_lib
25 from chromite.lib import osutils
27 # pylint: disable=W0212,R0904
29 CHROMEOS_BUILD=%(build_number)s
30 CHROMEOS_BRANCH=%(branch_build_number)s
31 CHROMEOS_PATCH=%(patch_number)s
32 CHROME_BRANCH=%(chrome_branch)s
35 FAKE_VERSION_STRING = '1.2.3'
36 FAKE_VERSION_STRING_NEXT = '1.2.4'
39 # Use the chromite repo to actually test git changes.
40 GIT_TEST_PATH = 'chromite'
42 MOCK_BUILD_ID = 162345
44 class HelperMethodsTest(cros_test_lib.TempDirTestCase):
45 """Test methods associated with methods not in a class."""
47 def testCreateSymlink(self):
48 """Tests that we can create symlinks and remove a previous one."""
49 srcfile = os.path.join(self.tempdir, 'src')
50 osutils.Touch(srcfile)
51 other_dir = os.path.join(self.tempdir, 'other_dir')
52 os.makedirs(other_dir)
53 destfile = os.path.join(other_dir, 'dest')
55 manifest_version.CreateSymlink(srcfile, destfile)
56 self.assertTrue(os.path.lexists(destfile),
57 'Unable to create symlink to %s' % destfile)
60 class VersionInfoTest(cros_test_lib.MoxTempDirTestCase):
61 """Test methods testing methods in VersionInfo class."""
64 def WriteFakeVersionFile(cls, version_file, version=None, chrome_branch=None):
65 """Helper method to write a version file from specified version number."""
67 version = FAKE_VERSION_STRING
68 if chrome_branch is None:
69 chrome_branch = CHROME_BRANCH
71 osutils.SafeMakedirs(os.path.split(version_file)[0])
72 info = manifest_version.VersionInfo(version, chrome_branch)
73 osutils.WriteFile(version_file, FAKE_VERSION % info.__dict__)
76 def CreateFakeVersionFile(cls, tmpdir, version=None, chrome_branch=None):
77 """Helper method to create a version file from specified version number."""
78 version_file = tempfile.mktemp(dir=tmpdir)
79 cls.WriteFakeVersionFile(version_file, version=version,
80 chrome_branch=chrome_branch)
83 def testLoadFromFile(self):
84 """Tests whether we can load from a version file."""
85 version_file = self.CreateFakeVersionFile(self.tempdir)
86 info = manifest_version.VersionInfo(version_file=version_file)
87 self.assertEqual(info.VersionString(), FAKE_VERSION_STRING)
89 def testLoadFromRepo(self):
90 """Tests whether we can load from a source repo."""
91 version_file = os.path.join(self.tempdir, constants.VERSION_FILE)
92 self.WriteFakeVersionFile(version_file)
93 info = manifest_version.VersionInfo.from_repo(self.tempdir)
94 self.assertEqual(info.VersionString(), FAKE_VERSION_STRING)
96 def testLoadFromString(self):
97 """Tests whether we can load from a string."""
98 info = manifest_version.VersionInfo(FAKE_VERSION_STRING, CHROME_BRANCH)
99 self.assertEqual(info.VersionString(), FAKE_VERSION_STRING)
101 def CommonTestIncrementVersion(self, incr_type, version, chrome_branch=None):
102 """Common test increment. Returns path to new incremented file."""
103 message = 'Incrementing cuz I sed so'
104 self.mox.StubOutWithMock(git, 'CreateBranch')
105 self.mox.StubOutWithMock(manifest_version, '_PushGitChanges')
106 self.mox.StubOutWithMock(git, 'CleanAndCheckoutUpstream')
108 git.CreateBranch(self.tempdir, manifest_version.PUSH_BRANCH)
110 version_file = self.CreateFakeVersionFile(
111 self.tempdir, version=version, chrome_branch=chrome_branch)
113 manifest_version._PushGitChanges(self.tempdir, message, dry_run=False,
116 git.CleanAndCheckoutUpstream(self.tempdir)
118 info = manifest_version.VersionInfo(version_file=version_file,
120 info.IncrementVersion()
121 info.UpdateVersionFile(message, dry_run=False)
125 def testIncrementVersionPatch(self):
126 """Tests whether we can increment a version file by patch number."""
127 version_file = self.CommonTestIncrementVersion('branch', '1.2.3')
128 new_info = manifest_version.VersionInfo(version_file=version_file,
130 self.assertEqual(new_info.VersionString(), '1.2.4')
132 def testIncrementVersionBranch(self):
133 """Tests whether we can increment a version file by branch number."""
134 version_file = self.CommonTestIncrementVersion('branch', '1.2.0')
135 new_info = manifest_version.VersionInfo(version_file=version_file,
137 self.assertEqual(new_info.VersionString(), '1.3.0')
139 def testIncrementVersionBuild(self):
140 """Tests whether we can increment a version file by build number."""
141 version_file = self.CommonTestIncrementVersion('build', '1.0.0')
142 new_info = manifest_version.VersionInfo(version_file=version_file,
144 self.assertEqual(new_info.VersionString(), '2.0.0')
146 def testIncrementVersionChrome(self):
147 """Tests whether we can increment the chrome version."""
148 version_file = self.CommonTestIncrementVersion(
149 'chrome_branch', version='1.0.0', chrome_branch='29')
150 new_info = manifest_version.VersionInfo(version_file=version_file)
151 self.assertEqual(new_info.VersionString(), '2.0.0')
152 self.assertEqual(new_info.chrome_branch, '30')
155 class BuildSpecsManagerTest(cros_test_lib.MoxTempDirTestCase,
156 cros_test_lib.MockTestCase):
157 """Tests for the BuildSpecs manager."""
160 os.makedirs(os.path.join(self.tempdir, '.repo'))
161 self.source_repo = 'ssh://source/repo'
162 self.manifest_repo = 'ssh://manifest/repo'
163 self.version_file = 'version-file.sh'
164 self.branch = 'master'
165 self.build_names = ['x86-generic-paladin']
166 self.incr_type = 'branch'
168 repo = repository.RepoRepository(
169 self.source_repo, self.tempdir, self.branch)
170 self.manager = manifest_version.BuildSpecsManager(
171 repo, self.manifest_repo, self.build_names, self.incr_type, False,
172 branch=self.branch, dry_run=True)
174 # Change default to something we clean up.
175 self.tmpmandir = os.path.join(self.tempdir, 'man')
176 osutils.SafeMakedirs(self.tmpmandir)
177 self.manager.manifest_dir = self.tmpmandir
178 # Shorten the sleep between attempts.
179 self.manager.SLEEP_TIMEOUT = 1
181 def testPublishManifestCommitMessageWithBuildId(self):
182 """Tests that PublishManifest writes a build id."""
183 expected_message = ('Automatic: Start x86-generic-paladin master 1\n'
184 'CrOS-Build-Id: %s' % MOCK_BUILD_ID)
185 self.mox.StubOutWithMock(self.manager, 'PushSpecChanges')
187 info = manifest_version.VersionInfo(
188 FAKE_VERSION_STRING, CHROME_BRANCH, incr_type='branch')
190 # Create a fake manifest file.
191 m = os.path.join(self.tmpmandir, '1.xml')
193 self.manager.InitializeManifestVariables(info)
195 self.manager.PushSpecChanges(expected_message)
198 self.manager.PublishManifest(m, '1', build_id=MOCK_BUILD_ID)
201 def testPublishManifestCommitMessageWithNegativeBuildId(self):
202 """Tests that PublishManifest doesn't write a negative build_id"""
203 expected_message = 'Automatic: Start x86-generic-paladin master 1'
204 self.mox.StubOutWithMock(self.manager, 'PushSpecChanges')
206 info = manifest_version.VersionInfo(
207 FAKE_VERSION_STRING, CHROME_BRANCH, incr_type='branch')
209 # Create a fake manifest file.
210 m = os.path.join(self.tmpmandir, '1.xml')
212 self.manager.InitializeManifestVariables(info)
214 self.manager.PushSpecChanges(expected_message)
217 self.manager.PublishManifest(m, '1', build_id=-1)
220 def testPublishManifestCommitMessageWithNoneBuildId(self):
221 """Tests that PublishManifest doesn't write a non-existant build_id"""
222 expected_message = 'Automatic: Start x86-generic-paladin master 1'
223 self.mox.StubOutWithMock(self.manager, 'PushSpecChanges')
225 info = manifest_version.VersionInfo(
226 FAKE_VERSION_STRING, CHROME_BRANCH, incr_type='branch')
228 # Create a fake manifest file.
229 m = os.path.join(self.tmpmandir, '1.xml')
231 self.manager.InitializeManifestVariables(info)
233 self.manager.PushSpecChanges(expected_message)
236 self.manager.PublishManifest(m, '1')
239 def testLoadSpecs(self):
240 """Tests whether we can load specs correctly."""
241 info = manifest_version.VersionInfo(
242 FAKE_VERSION_STRING, CHROME_BRANCH, incr_type='branch')
243 mpath = os.path.join(self.manager.manifest_dir, 'buildspecs', CHROME_BRANCH)
244 m1, m2, m3, m4 = [os.path.join(mpath, '1.2.%d.xml' % x)
246 for_build = os.path.join(self.manager.manifest_dir, 'build-name',
249 # Create fake buildspecs.
250 osutils.SafeMakedirs(os.path.join(mpath))
251 for m in [m1, m2, m3, m4]:
254 # Fake BuilderStatus with status MISSING.
255 missing = manifest_version.BuilderStatus(
256 manifest_version.BuilderStatus.STATUS_MISSING, None)
258 # Fail 1, pass 2, leave 3,4 unprocessed.
259 manifest_version.CreateSymlink(m1, os.path.join(
260 for_build, 'fail', CHROME_BRANCH, os.path.basename(m1)))
261 manifest_version.CreateSymlink(m1, os.path.join(
262 for_build, 'pass', CHROME_BRANCH, os.path.basename(m2)))
263 self.mox.StubOutWithMock(self.manager, 'GetBuildStatus')
264 self.manager.GetBuildStatus(self.build_names[0], '1.2.5').AndReturn(missing)
266 self.manager.InitializeManifestVariables(info)
268 self.assertEqual(self.manager.latest_unprocessed, '1.2.5')
270 def testLatestSpecFromDir(self):
271 """Tests whether we can get sorted specs correctly from a directory."""
272 self.mox.StubOutWithMock(repository, 'CloneGitRepo')
273 info = manifest_version.VersionInfo(
274 '99.1.2', CHROME_BRANCH, incr_type='branch')
276 specs_dir = os.path.join(self.manager.manifest_dir, 'buildspecs',
278 m1, m2, m3, m4 = [os.path.join(specs_dir, x)
279 for x in ['100.0.0.xml', '99.3.3.xml', '99.1.10.xml',
282 # Create fake buildspecs.
283 osutils.SafeMakedirs(specs_dir)
284 for m in [m1, m2, m3, m4]:
288 spec = self.manager._LatestSpecFromDir(info, specs_dir)
290 # Should be the latest on the 99.1 branch.
291 self.assertEqual(spec, '99.1.10')
293 def testGetNextVersionNoIncrement(self):
294 """Tests whether we can get the next version to be built correctly.
296 Tests without pre-existing version in manifest dir.
298 info = manifest_version.VersionInfo(
299 FAKE_VERSION_STRING, CHROME_BRANCH, incr_type='branch')
301 self.manager.latest = None
303 version = self.manager.GetNextVersion(info)
305 self.assertEqual(FAKE_VERSION_STRING, version)
307 def testGetNextVersionIncrement(self):
308 """Tests that we create a new version if a previous one exists."""
309 self.mox.StubOutWithMock(manifest_version.VersionInfo, 'UpdateVersionFile')
310 version_file = VersionInfoTest.CreateFakeVersionFile(self.tempdir)
311 info = manifest_version.VersionInfo(version_file=version_file,
313 info.UpdateVersionFile(
314 'Automatic: %s - Updating to a new version number from %s' % (
315 self.build_names[0], FAKE_VERSION_STRING), dry_run=True)
317 self.manager.latest = FAKE_VERSION_STRING
319 version = self.manager.GetNextVersion(info)
321 self.assertEqual(FAKE_VERSION_STRING_NEXT, version)
323 def testGetNextBuildSpec(self):
324 """End-to-end test of updating the manifest."""
325 my_info = manifest_version.VersionInfo('1.2.3', chrome_branch='4')
326 self.PatchObject(manifest_version.BuildSpecsManager,
327 'GetCurrentVersionInfo', return_value=my_info)
328 self.PatchObject(repository.RepoRepository, 'Sync')
329 self.PatchObject(repository.RepoRepository, 'ExportManifest',
330 return_value='<manifest />')
331 rc = self.StartPatcher(cros_build_lib_unittest.RunCommandMock())
332 rc.SetDefaultCmdResult()
335 self.manager.GetNextBuildSpec(retries=0)
336 self.manager.UpdateStatus({self.build_names[0]: True})
339 def testUnpickleBuildStatus(self):
340 """Tests that _UnpickleBuildStatus returns the correct values."""
341 failed_msg = failures_lib.BuildFailureMessage(
342 'you failed', ['traceback'], True, 'taco', 'bot')
343 failed_input_status = manifest_version.BuilderStatus(
344 manifest_version.BuilderStatus.STATUS_FAILED, failed_msg)
345 passed_input_status = manifest_version.BuilderStatus(
346 manifest_version.BuilderStatus.STATUS_PASSED, None)
348 failed_output_status = self.manager._UnpickleBuildStatus(
349 failed_input_status.AsPickledDict())
350 passed_output_status = self.manager._UnpickleBuildStatus(
351 passed_input_status.AsPickledDict())
352 empty_string_status = self.manager._UnpickleBuildStatus('')
354 self.assertEqual(failed_input_status.AsFlatDict(),
355 failed_output_status.AsFlatDict())
356 self.assertEqual(passed_input_status.AsFlatDict(),
357 passed_output_status.AsFlatDict())
358 self.assertTrue(empty_string_status.Failed())
360 def _GetBuildersStatus(self, builders, status_runs):
361 """Test a call to BuildSpecsManager.GetBuildersStatus.
364 builders: List of builders to get status for.
365 status_runs: List of dictionaries of expected build and status.
367 self.mox.StubOutWithMock(manifest_version.BuildSpecsManager,
368 'GetSlaveStatusesFromCIDB')
369 self.mox.StubOutWithMock(manifest_version.BuildSpecsManager,
371 for status_dict in status_runs:
372 manifest_version.BuildSpecsManager.GetSlaveStatusesFromCIDB(
373 mox.IgnoreArg()).AndReturn(status_dict)
375 final_status_dict = status_runs[-1]
376 for builder in builders:
377 status = manifest_version.BuilderStatus(
378 final_status_dict.get(builder), None)
379 manifest_version.BuildSpecsManager.GetBuildStatus(
380 builder, mox.IgnoreArg()).AndReturn(status)
383 statuses = self.manager.GetBuildersStatus(mox.IgnoreArg, builders)
387 def testGetBuildersStatusBothFinished(self):
388 """Tests GetBuilderStatus where both builds have finished."""
389 status_runs = [{'build1': manifest_version.BuilderStatus.STATUS_FAILED,
390 'build2': manifest_version.BuilderStatus.STATUS_PASSED}]
391 statuses = self._GetBuildersStatus(['build1', 'build2'], status_runs)
392 self.assertTrue(statuses['build1'].Failed())
393 self.assertTrue(statuses['build2'].Passed())
395 def testGetBuildersStatusLoop(self):
396 """Tests GetBuilderStatus where builds are inflight."""
397 status_runs = [{'build1': manifest_version.BuilderStatus.STATUS_INFLIGHT,
398 'build2': manifest_version.BuilderStatus.STATUS_MISSING},
399 {'build1': manifest_version.BuilderStatus.STATUS_FAILED,
400 'build2': manifest_version.BuilderStatus.STATUS_INFLIGHT},
401 {'build1': manifest_version.BuilderStatus.STATUS_FAILED,
402 'build2': manifest_version.BuilderStatus.STATUS_PASSED}]
403 statuses = self._GetBuildersStatus(['build1', 'build2'], status_runs)
404 self.assertTrue(statuses['build1'].Failed())
405 self.assertTrue(statuses['build2'].Passed())
408 if __name__ == '__main__':