diff options
Diffstat (limited to 'deps/v8/tools/release/test_scripts.py')
-rw-r--r-- | deps/v8/tools/release/test_scripts.py | 1558 |
1 files changed, 1558 insertions, 0 deletions
diff --git a/deps/v8/tools/release/test_scripts.py b/deps/v8/tools/release/test_scripts.py new file mode 100644 index 0000000000..3beddfd936 --- /dev/null +++ b/deps/v8/tools/release/test_scripts.py @@ -0,0 +1,1558 @@ +#!/usr/bin/env python +# Copyright 2013 the V8 project authors. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os +import shutil +import tempfile +import traceback +import unittest + +import auto_push +from auto_push import LastReleaseBailout +import auto_roll +import common_includes +from common_includes import * +import create_release +from create_release import CreateRelease +import merge_to_branch +from merge_to_branch import * +import push_to_candidates +from push_to_candidates import * +import chromium_roll +from chromium_roll import ChromiumRoll +import releases +from releases import Releases +from auto_tag import AutoTag + + +TEST_CONFIG = { + "DEFAULT_CWD": None, + "BRANCHNAME": "test-prepare-push", + "CANDIDATESBRANCH": "test-candidates-push", + "PERSISTFILE_BASENAME": "/tmp/test-v8-push-to-candidates-tempfile", + "CHANGELOG_ENTRY_FILE": + "/tmp/test-v8-push-to-candidates-tempfile-changelog-entry", + "PATCH_FILE": "/tmp/test-v8-push-to-candidates-tempfile-patch", + "COMMITMSG_FILE": "/tmp/test-v8-push-to-candidates-tempfile-commitmsg", + "CHROMIUM": "/tmp/test-v8-push-to-candidates-tempfile-chromium", + "SETTINGS_LOCATION": None, + "ALREADY_MERGING_SENTINEL_FILE": + "/tmp/test-merge-to-branch-tempfile-already-merging", + "TEMPORARY_PATCH_FILE": "/tmp/test-merge-to-branch-tempfile-temporary-patch", + "CLUSTERFUZZ_API_KEY_FILE": "/tmp/test-fake-cf-api-key", +} + + +AUTO_PUSH_ARGS = [ + "-a", "author@chromium.org", + "-r", "reviewer@chromium.org", +] + + +class ToplevelTest(unittest.TestCase): + def testSortBranches(self): + S = releases.SortBranches + self.assertEquals(["3.1", "2.25"], S(["2.25", "3.1"])[0:2]) + self.assertEquals(["3.0", "2.25"], S(["2.25", "3.0", "2.24"])[0:2]) + self.assertEquals(["3.11", "3.2"], S(["3.11", "3.2", "2.24"])[0:2]) + + def testFilterDuplicatesAndReverse(self): + F = releases.FilterDuplicatesAndReverse + self.assertEquals([], F([])) + self.assertEquals([["100", "10"]], F([["100", "10"]])) + self.assertEquals([["99", "9"], ["100", "10"]], + F([["100", "10"], ["99", "9"]])) + self.assertEquals([["98", "9"], ["100", "10"]], + F([["100", "10"], ["99", "9"], ["98", "9"]])) + self.assertEquals([["98", "9"], ["99", "10"]], + F([["100", "10"], ["99", "10"], ["98", "9"]])) + + def testBuildRevisionRanges(self): + B = releases.BuildRevisionRanges + self.assertEquals({}, B([])) + self.assertEquals({"10": "100"}, B([["100", "10"]])) + self.assertEquals({"10": "100", "9": "99:99"}, + B([["100", "10"], ["99", "9"]])) + self.assertEquals({"10": "100", "9": "97:99"}, + B([["100", "10"], ["98", "9"], ["97", "9"]])) + self.assertEquals({"10": "100", "9": "99:99", "3": "91:98"}, + B([["100", "10"], ["99", "9"], ["91", "3"]])) + self.assertEquals({"13": "101", "12": "100:100", "9": "94:97", + "3": "91:93, 98:99"}, + B([["101", "13"], ["100", "12"], ["98", "3"], + ["94", "9"], ["91", "3"]])) + + def testMakeComment(self): + self.assertEquals("# Line 1\n# Line 2\n#", + MakeComment(" Line 1\n Line 2\n")) + self.assertEquals("#Line 1\n#Line 2", + MakeComment("Line 1\n Line 2")) + + def testStripComments(self): + self.assertEquals(" Line 1\n Line 3\n", + StripComments(" Line 1\n# Line 2\n Line 3\n#\n")) + self.assertEquals("\nLine 2 ### Test\n #", + StripComments("###\n# \n\n# Line 1\nLine 2 ### Test\n #")) + + def testMakeChangeLogBodySimple(self): + commits = [ + ["Title text 1", + "Title text 1\n\nBUG=\n", + "author1@chromium.org"], + ["Title text 2.", + "Title text 2\n\nBUG=1234\n", + "author2@chromium.org"], + ] + self.assertEquals(" Title text 1.\n" + " (author1@chromium.org)\n\n" + " Title text 2 (Chromium issue 1234).\n" + " (author2@chromium.org)\n\n", + MakeChangeLogBody(commits)) + + def testMakeChangeLogBodyEmpty(self): + self.assertEquals("", MakeChangeLogBody([])) + + def testMakeChangeLogBodyAutoFormat(self): + commits = [ + ["Title text 1!", + "Title text 1\nLOG=y\nBUG=\n", + "author1@chromium.org"], + ["Title text 2", + "Title text 2\n\nBUG=1234\n", + "author2@chromium.org"], + ["Title text 3", + "Title text 3\n\nBUG=1234\nLOG = Yes\n", + "author3@chromium.org"], + ["Title text 3", + "Title text 4\n\nBUG=1234\nLOG=\n", + "author4@chromium.org"], + ] + self.assertEquals(" Title text 1.\n\n" + " Title text 3 (Chromium issue 1234).\n\n", + MakeChangeLogBody(commits, True)) + + def testRegressWrongLogEntryOnTrue(self): + body = """ +Check elimination: Learn from if(CompareMap(x)) on true branch. + +BUG= +R=verwaest@chromium.org + +Committed: https://code.google.com/p/v8/source/detail?r=18210 +""" + self.assertEquals("", MakeChangeLogBody([["title", body, "author"]], True)) + + def testMakeChangeLogBugReferenceEmpty(self): + self.assertEquals("", MakeChangeLogBugReference("")) + self.assertEquals("", MakeChangeLogBugReference("LOG=")) + self.assertEquals("", MakeChangeLogBugReference(" BUG =")) + self.assertEquals("", MakeChangeLogBugReference("BUG=none\t")) + + def testMakeChangeLogBugReferenceSimple(self): + self.assertEquals("(issue 987654)", + MakeChangeLogBugReference("BUG = v8:987654")) + self.assertEquals("(Chromium issue 987654)", + MakeChangeLogBugReference("BUG=987654 ")) + + def testMakeChangeLogBugReferenceFromBody(self): + self.assertEquals("(Chromium issue 1234567)", + MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n" + " BUG=\tchromium:1234567\t\n" + "R=somebody\n")) + + def testMakeChangeLogBugReferenceMultiple(self): + # All issues should be sorted and grouped. Multiple references to the same + # issue should be filtered. + self.assertEquals("(issues 123, 234, Chromium issue 345)", + MakeChangeLogBugReference("Title\n\n" + "BUG=v8:234\n" + " BUG\t= 345, \tv8:234,\n" + "BUG=v8:123\n" + "R=somebody\n")) + self.assertEquals("(Chromium issues 123, 234)", + MakeChangeLogBugReference("Title\n\n" + "BUG=234,,chromium:123 \n" + "R=somebody\n")) + self.assertEquals("(Chromium issues 123, 234)", + MakeChangeLogBugReference("Title\n\n" + "BUG=chromium:234, , 123\n" + "R=somebody\n")) + self.assertEquals("(issues 345, 456)", + MakeChangeLogBugReference("Title\n\n" + "\t\tBUG=v8:345,v8:456\n" + "R=somebody\n")) + self.assertEquals("(issue 123, Chromium issues 345, 456)", + MakeChangeLogBugReference("Title\n\n" + "BUG=chromium:456\n" + "BUG = none\n" + "R=somebody\n" + "BUG=456,v8:123, 345")) + + # TODO(machenbach): These test don't make much sense when the formatting is + # done later. + def testMakeChangeLogBugReferenceLong(self): + # -----------------00--------10--------20--------30-------- + self.assertEquals("(issues 234, 1234567890, 1234567" + "8901234567890, Chromium issues 12345678," + " 123456789)", + MakeChangeLogBugReference("BUG=v8:234\n" + "BUG=v8:1234567890\n" + "BUG=v8:12345678901234567890\n" + "BUG=123456789\n" + "BUG=12345678\n")) + # -----------------00--------10--------20--------30-------- + self.assertEquals("(issues 234, 1234567890, 1234567" + "8901234567890, Chromium issues" + " 123456789, 1234567890)", + MakeChangeLogBugReference("BUG=v8:234\n" + "BUG=v8:12345678901234567890\n" + "BUG=v8:1234567890\n" + "BUG=123456789\n" + "BUG=1234567890\n")) + # -----------------00--------10--------20--------30-------- + self.assertEquals("(Chromium issues 234, 1234567890" + ", 12345678901234567, " + "1234567890123456789)", + MakeChangeLogBugReference("BUG=234\n" + "BUG=12345678901234567\n" + "BUG=1234567890123456789\n" + "BUG=1234567890\n")) + + +def Cmd(*args, **kwargs): + """Convenience function returning a shell command test expectation.""" + return { + "name": "command", + "args": args, + "ret": args[-1], + "cb": kwargs.get("cb"), + "cwd": kwargs.get("cwd", TEST_CONFIG["DEFAULT_CWD"]), + } + + +def RL(text, cb=None): + """Convenience function returning a readline test expectation.""" + return { + "name": "readline", + "args": [], + "ret": text, + "cb": cb, + "cwd": None, + } + + +def URL(*args, **kwargs): + """Convenience function returning a readurl test expectation.""" + return { + "name": "readurl", + "args": args[:-1], + "ret": args[-1], + "cb": kwargs.get("cb"), + "cwd": None, + } + + +class SimpleMock(object): + def __init__(self): + self._recipe = [] + self._index = -1 + + def Expect(self, recipe): + self._recipe = recipe + + def Call(self, name, *args, **kwargs): # pragma: no cover + self._index += 1 + try: + expected_call = self._recipe[self._index] + except IndexError: + raise NoRetryException("Calling %s %s" % (name, " ".join(args))) + + if not isinstance(expected_call, dict): + raise NoRetryException("Found wrong expectation type for %s %s" % + (name, " ".join(args))) + + if expected_call["name"] != name: + raise NoRetryException("Expected action: %s %s - Actual: %s" % + (expected_call["name"], expected_call["args"], name)) + + # Check if the given working directory matches the expected one. + if expected_call["cwd"] != kwargs.get("cwd"): + raise NoRetryException("Expected cwd: %s in %s %s - Actual: %s" % + (expected_call["cwd"], + expected_call["name"], + expected_call["args"], + kwargs.get("cwd"))) + + # The number of arguments in the expectation must match the actual + # arguments. + if len(args) > len(expected_call['args']): + raise NoRetryException("When calling %s with arguments, the " + "expectations must consist of at least as many arguments." % + name) + + # Compare expected and actual arguments. + for (expected_arg, actual_arg) in zip(expected_call['args'], args): + if expected_arg != actual_arg: + raise NoRetryException("Expected: %s - Actual: %s" % + (expected_arg, actual_arg)) + + # The expected call contains an optional callback for checking the context + # at the time of the call. + if expected_call['cb']: + try: + expected_call['cb']() + except: + tb = traceback.format_exc() + raise NoRetryException("Caught exception from callback: %s" % tb) + + # If the return value is an exception, raise it instead of returning. + if isinstance(expected_call['ret'], Exception): + raise expected_call['ret'] + return expected_call['ret'] + + def AssertFinished(self): # pragma: no cover + if self._index < len(self._recipe) -1: + raise NoRetryException("Called mock too seldom: %d vs. %d" % + (self._index, len(self._recipe))) + + +class ScriptTest(unittest.TestCase): + def MakeEmptyTempFile(self): + handle, name = tempfile.mkstemp() + os.close(handle) + self._tmp_files.append(name) + return name + + def MakeEmptyTempDirectory(self): + name = tempfile.mkdtemp() + self._tmp_files.append(name) + return name + + + def WriteFakeVersionFile(self, major=3, minor=22, build=4, patch=0): + version_file = os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE) + if not os.path.exists(os.path.dirname(version_file)): + os.makedirs(os.path.dirname(version_file)) + with open(version_file, "w") as f: + f.write(" // Some line...\n") + f.write("\n") + f.write("#define MAJOR_VERSION %s\n" % major) + f.write("#define MINOR_VERSION %s\n" % minor) + f.write("#define BUILD_NUMBER %s\n" % build) + f.write("#define PATCH_LEVEL %s\n" % patch) + f.write(" // Some line...\n") + f.write("#define IS_CANDIDATE_VERSION 0\n") + + def MakeStep(self): + """Convenience wrapper.""" + options = ScriptsBase(TEST_CONFIG, self, self._state).MakeOptions([]) + return MakeStep(step_class=Step, state=self._state, + config=TEST_CONFIG, side_effect_handler=self, + options=options) + + def RunStep(self, script=PushToCandidates, step_class=Step, args=None): + """Convenience wrapper.""" + args = args if args is not None else ["-m"] + return script(TEST_CONFIG, self, self._state).RunSteps([step_class], args) + + def Call(self, fun, *args, **kwargs): + print "Calling %s with %s and %s" % (str(fun), str(args), str(kwargs)) + + def Command(self, cmd, args="", prefix="", pipe=True, cwd=None): + print "%s %s" % (cmd, args) + print "in %s" % cwd + return self._mock.Call("command", cmd + " " + args, cwd=cwd) + + def ReadLine(self): + return self._mock.Call("readline") + + def ReadURL(self, url, params): + if params is not None: + return self._mock.Call("readurl", url, params) + else: + return self._mock.Call("readurl", url) + + def ReadClusterFuzzAPI(self, api_key, **params): + # TODO(machenbach): Use a mock for this and add a test that stops rolling + # due to clustefuzz results. + return [] + + def Sleep(self, seconds): + pass + + def GetDate(self): + return "1999-07-31" + + def GetUTCStamp(self): + return "1000000" + + def Expect(self, *args): + """Convenience wrapper.""" + self._mock.Expect(*args) + + def setUp(self): + self._mock = SimpleMock() + self._tmp_files = [] + self._state = {} + TEST_CONFIG["DEFAULT_CWD"] = self.MakeEmptyTempDirectory() + + def tearDown(self): + if os.path.exists(TEST_CONFIG["PERSISTFILE_BASENAME"]): + shutil.rmtree(TEST_CONFIG["PERSISTFILE_BASENAME"]) + + # Clean up temps. Doesn't work automatically. + for name in self._tmp_files: + if os.path.isfile(name): + os.remove(name) + if os.path.isdir(name): + shutil.rmtree(name) + + self._mock.AssertFinished() + + def testGitMock(self): + self.Expect([Cmd("git --version", "git version 1.2.3"), + Cmd("git dummy", "")]) + self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version")) + self.assertEquals("", self.MakeStep().Git("dummy")) + + def testCommonPrepareDefault(self): + self.Expect([ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch"), + Cmd("git fetch", ""), + Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]), + RL("Y"), + Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""), + ]) + self.MakeStep().CommonPrepare() + self.MakeStep().PrepareBranch() + self.assertEquals("some_branch", self._state["current_branch"]) + + def testCommonPrepareNoConfirm(self): + self.Expect([ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch"), + Cmd("git fetch", ""), + Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]), + RL("n"), + ]) + self.MakeStep().CommonPrepare() + self.assertRaises(Exception, self.MakeStep().PrepareBranch) + self.assertEquals("some_branch", self._state["current_branch"]) + + def testCommonPrepareDeleteBranchFailure(self): + self.Expect([ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch"), + Cmd("git fetch", ""), + Cmd("git branch", " branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]), + RL("Y"), + Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], None), + ]) + self.MakeStep().CommonPrepare() + self.assertRaises(Exception, self.MakeStep().PrepareBranch) + self.assertEquals("some_branch", self._state["current_branch"]) + + def testInitialEnvironmentChecks(self): + TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git")) + os.environ["EDITOR"] = "vi" + self.Expect([ + Cmd("which vi", "/usr/bin/vi"), + ]) + self.MakeStep().InitialEnvironmentChecks(TEST_CONFIG["DEFAULT_CWD"]) + + def testTagTimeout(self): + self.Expect([ + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=\"Title\" origin/candidates", ""), + ]) + args = ["--branch", "candidates", "ab12345"] + self._state["version"] = "tag_name" + self._state["commit_title"] = "Title" + self.assertRaises(Exception, + lambda: self.RunStep(MergeToBranch, TagRevision, args)) + + def testReadAndPersistVersion(self): + self.WriteFakeVersionFile(build=5) + step = self.MakeStep() + step.ReadAndPersistVersion() + self.assertEquals("3", step["major"]) + self.assertEquals("22", step["minor"]) + self.assertEquals("5", step["build"]) + self.assertEquals("0", step["patch"]) + + def testRegex(self): + self.assertEqual("(issue 321)", + re.sub(r"BUG=v8:(.*)$", r"(issue \1)", "BUG=v8:321")) + self.assertEqual("(Chromium issue 321)", + re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", "BUG=321")) + + cl = " too little\n\ttab\ttab\n too much\n trailing " + cl = MSub(r"\t", r" ", cl) + cl = MSub(r"^ {1,7}([^ ])", r" \1", cl) + cl = MSub(r"^ {9,80}([^ ])", r" \1", cl) + cl = MSub(r" +$", r"", cl) + self.assertEqual(" too little\n" + " tab tab\n" + " too much\n" + " trailing", cl) + + self.assertEqual("//\n#define BUILD_NUMBER 3\n", + MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$", + r"\g<space>3", + "//\n#define BUILD_NUMBER 321\n")) + + def testPreparePushRevision(self): + # Tests the default push hash used when the --revision option is not set. + self.Expect([ + Cmd("git log -1 --format=%H HEAD", "push_hash") + ]) + + self.RunStep(PushToCandidates, PreparePushRevision) + self.assertEquals("push_hash", self._state["push_hash"]) + + def testPrepareChangeLog(self): + self.WriteFakeVersionFile() + TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile() + + self.Expect([ + Cmd("git log --format=%H 1234..push_hash", "rev1\nrev2\nrev3\nrev4"), + Cmd("git log -1 --format=%s rev1", "Title text 1"), + Cmd("git log -1 --format=%B rev1", "Title\n\nBUG=\nLOG=y\n"), + Cmd("git log -1 --format=%an rev1", "author1@chromium.org"), + Cmd("git log -1 --format=%s rev2", "Title text 2."), + Cmd("git log -1 --format=%B rev2", "Title\n\nBUG=123\nLOG= \n"), + Cmd("git log -1 --format=%an rev2", "author2@chromium.org"), + Cmd("git log -1 --format=%s rev3", "Title text 3"), + Cmd("git log -1 --format=%B rev3", "Title\n\nBUG=321\nLOG=true\n"), + Cmd("git log -1 --format=%an rev3", "author3@chromium.org"), + Cmd("git log -1 --format=%s rev4", "Title text 4"), + Cmd("git log -1 --format=%B rev4", + ("Title\n\nBUG=456\nLOG=Y\n\n" + "Review URL: https://codereview.chromium.org/9876543210\n")), + URL("https://codereview.chromium.org/9876543210/description", + "Title\n\nBUG=456\nLOG=N\n\n"), + Cmd("git log -1 --format=%an rev4", "author4@chromium.org"), + ]) + + self._state["last_push_master"] = "1234" + self._state["push_hash"] = "push_hash" + self._state["version"] = "3.22.5" + self.RunStep(PushToCandidates, PrepareChangeLog) + + actual_cl = FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"]) + + expected_cl = """1999-07-31: Version 3.22.5 + + Title text 1. + + Title text 3 (Chromium issue 321). + + Performance and stability improvements on all platforms. +# +# The change log above is auto-generated. Please review if all relevant +# commit messages from the list below are included. +# All lines starting with # will be stripped. +# +# Title text 1. +# (author1@chromium.org) +# +# Title text 2 (Chromium issue 123). +# (author2@chromium.org) +# +# Title text 3 (Chromium issue 321). +# (author3@chromium.org) +# +# Title text 4 (Chromium issue 456). +# (author4@chromium.org) +# +#""" + + self.assertEquals(expected_cl, actual_cl) + + def testEditChangeLog(self): + TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile() + TextToFile(" New \n\tLines \n", TEST_CONFIG["CHANGELOG_ENTRY_FILE"]) + os.environ["EDITOR"] = "vi" + self.Expect([ + RL(""), # Open editor. + Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""), + ]) + + self.RunStep(PushToCandidates, EditChangeLog) + + self.assertEquals("New\n Lines", + FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"])) + + TAGS = """ +4425.0 +0.0.0.0 +3.9.6 +3.22.4 +test_tag +""" + + # Version as tag: 3.22.4.0. Version on master: 3.22.6. + # Make sure that the latest version is 3.22.6.0. + def testIncrementVersion(self): + self.Expect([ + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git checkout -f origin/master -- src/version.cc", + "", cb=lambda: self.WriteFakeVersionFile(3, 22, 6)), + ]) + + self.RunStep(PushToCandidates, IncrementVersion) + + self.assertEquals("3", self._state["new_major"]) + self.assertEquals("22", self._state["new_minor"]) + self.assertEquals("7", self._state["new_build"]) + self.assertEquals("0", self._state["new_patch"]) + + def _TestSquashCommits(self, change_log, expected_msg): + TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile() + with open(TEST_CONFIG["CHANGELOG_ENTRY_FILE"], "w") as f: + f.write(change_log) + + self.Expect([ + Cmd("git diff origin/candidates hash1", "patch content"), + ]) + + self._state["push_hash"] = "hash1" + self._state["date"] = "1999-11-11" + + self.RunStep(PushToCandidates, SquashCommits) + self.assertEquals(FileToText(TEST_CONFIG["COMMITMSG_FILE"]), expected_msg) + + patch = FileToText(TEST_CONFIG["PATCH_FILE"]) + self.assertTrue(re.search(r"patch content", patch)) + + def testSquashCommitsUnformatted(self): + change_log = """1999-11-11: Version 3.22.5 + + Log text 1. + Chromium issue 12345 + + Performance and stability improvements on all platforms.\n""" + commit_msg = """Version 3.22.5 (based on hash1) + +Log text 1. Chromium issue 12345 + +Performance and stability improvements on all platforms.""" + self._TestSquashCommits(change_log, commit_msg) + + def testSquashCommitsFormatted(self): + change_log = """1999-11-11: Version 3.22.5 + + Long commit message that fills more than 80 characters (Chromium issue + 12345). + + Performance and stability improvements on all platforms.\n""" + commit_msg = """Version 3.22.5 (based on hash1) + +Long commit message that fills more than 80 characters (Chromium issue 12345). + +Performance and stability improvements on all platforms.""" + self._TestSquashCommits(change_log, commit_msg) + + def testSquashCommitsQuotationMarks(self): + change_log = """Line with "quotation marks".\n""" + commit_msg = """Line with "quotation marks".""" + self._TestSquashCommits(change_log, commit_msg) + + def testBootstrapper(self): + work_dir = self.MakeEmptyTempDirectory() + class FakeScript(ScriptsBase): + def _Steps(self): + return [] + + # Use the test configuration without the fake testing default work dir. + fake_config = dict(TEST_CONFIG) + del(fake_config["DEFAULT_CWD"]) + + self.Expect([ + Cmd("fetch v8", "", cwd=work_dir), + ]) + FakeScript(fake_config, self).Run(["--work-dir", work_dir]) + + def _PushToCandidates(self, force=False, manual=False): + TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git")) + + # The version file on master has build level 5, while the version + # file from candidates has build level 4. + self.WriteFakeVersionFile(build=5) + + TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile() + master_change_log = "2014-03-17: Sentinel\n" + TextToFile(master_change_log, + os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + os.environ["EDITOR"] = "vi" + + commit_msg_squashed = """Version 3.22.5 (squashed - based on push_hash) + +Log text 1 (issue 321). + +Performance and stability improvements on all platforms.""" + + commit_msg = """Version 3.22.5 (based on push_hash) + +Log text 1 (issue 321). + +Performance and stability improvements on all platforms.""" + + def ResetChangeLog(): + """On 'git co -b new_branch origin/candidates', + and 'git checkout -- ChangeLog', + the ChangLog will be reset to its content on candidates.""" + candidates_change_log = """1999-04-05: Version 3.22.4 + + Performance and stability improvements on all platforms.\n""" + TextToFile(candidates_change_log, + os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + + def ResetToCandidates(): + ResetChangeLog() + self.WriteFakeVersionFile() + + def CheckVersionCommit(): + commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"]) + self.assertEquals(commit_msg, commit) + version = FileToText( + os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE)) + self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version)) + self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version)) + self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version)) + self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version)) + self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version)) + + # Check that the change log on the candidates branch got correctly + # modified. + change_log = FileToText( + os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + self.assertEquals( +"""1999-07-31: Version 3.22.5 + + Log text 1 (issue 321). + + Performance and stability improvements on all platforms. + + +1999-04-05: Version 3.22.4 + + Performance and stability improvements on all platforms.\n""", + change_log) + + force_flag = " -f" if not manual else "" + expectations = [] + if not force: + expectations.append(Cmd("which vi", "/usr/bin/vi")) + expectations += [ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch\n"), + Cmd("git fetch", ""), + Cmd("git branch", " branch1\n* branch2\n"), + Cmd("git branch", " branch1\n* branch2\n"), + Cmd(("git new-branch %s --upstream origin/master" % + TEST_CONFIG["BRANCHNAME"]), ""), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git checkout -f origin/master -- src/version.cc", + "", cb=self.WriteFakeVersionFile), + Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"), + Cmd("git log -1 --format=%s release_hash", + "Version 3.22.4 (based on abc3)\n"), + Cmd("git log --format=%H abc3..push_hash", "rev1\n"), + Cmd("git log -1 --format=%s rev1", "Log text 1.\n"), + Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"), + Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"), + ] + if manual: + expectations.append(RL("")) # Open editor. + if not force: + expectations.append( + Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], "")) + expectations += [ + Cmd("git fetch", ""), + Cmd("git checkout -f origin/master", ""), + Cmd("git diff origin/candidates push_hash", "patch content\n"), + Cmd(("git new-branch %s --upstream origin/candidates" % + TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates), + Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""), + Cmd("git checkout -f origin/candidates -- ChangeLog", "", + cb=ResetChangeLog), + Cmd("git checkout -f origin/candidates -- src/version.cc", "", + cb=self.WriteFakeVersionFile), + Cmd("git commit -am \"%s\"" % commit_msg_squashed, ""), + ] + if manual: + expectations.append(RL("Y")) # Sanity check. + expectations += [ + Cmd("git cl land -f --bypass-hooks", ""), + Cmd("git checkout -f master", ""), + Cmd("git fetch", ""), + Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""), + Cmd(("git new-branch %s --upstream origin/candidates" % + TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates), + Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "", + cb=CheckVersionCommit), + Cmd("git cl land -f --bypass-hooks", ""), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=" + "\"Version 3.22.5 (based on push_hash)\"" + " origin/candidates", "hsh_to_tag"), + Cmd("git tag 3.22.5 hsh_to_tag", ""), + Cmd("git push origin 3.22.5", ""), + Cmd("git checkout -f some_branch", ""), + Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""), + Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""), + ] + self.Expect(expectations) + + args = ["-a", "author@chromium.org", "--revision", "push_hash"] + if force: args.append("-f") + if manual: args.append("-m") + else: args += ["-r", "reviewer@chromium.org"] + PushToCandidates(TEST_CONFIG, self).Run(args) + + cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl)) + self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl)) + self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl)) + + # Note: The version file is on build number 5 again in the end of this test + # since the git command that merges to master is mocked out. + + def testPushToCandidatesManual(self): + self._PushToCandidates(manual=True) + + def testPushToCandidatesSemiAutomatic(self): + self._PushToCandidates() + + def testPushToCandidatesForced(self): + self._PushToCandidates(force=True) + + def testCreateRelease(self): + TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git")) + + # The version file on master has build level 5. + self.WriteFakeVersionFile(build=5) + + master_change_log = "2014-03-17: Sentinel\n" + TextToFile(master_change_log, + os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + + commit_msg = """Version 3.22.5 + +Log text 1 (issue 321). + +Performance and stability improvements on all platforms.""" + + def ResetChangeLog(): + last_change_log = """1999-04-05: Version 3.22.4 + + Performance and stability improvements on all platforms.\n""" + TextToFile(last_change_log, + os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + + + def CheckVersionCommit(): + commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"]) + self.assertEquals(commit_msg, commit) + version = FileToText( + os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE)) + self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version)) + self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version)) + self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version)) + self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version)) + self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version)) + + # Check that the change log on the candidates branch got correctly + # modified. + change_log = FileToText( + os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + self.assertEquals( +"""1999-07-31: Version 3.22.5 + + Log text 1 (issue 321). + + Performance and stability improvements on all platforms. + + +1999-04-05: Version 3.22.4 + + Performance and stability improvements on all platforms.\n""", + change_log) + + expectations = [ + Cmd("git fetch origin " + "+refs/heads/*:refs/heads/* " + "+refs/pending/*:refs/pending/* " + "+refs/pending-tags/*:refs/pending-tags/*", ""), + Cmd("git checkout -f origin/master", ""), + Cmd("git branch", ""), + Cmd("git log -1 --format=\"%H %T\" push_hash", "push_hash tree_hash"), + Cmd("git log -200 --format=\"%H %T\" refs/pending/heads/master", + "not_right wrong\npending_hash tree_hash\nsome other\n"), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git checkout -f origin/master -- src/version.cc", + "", cb=self.WriteFakeVersionFile), + Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"), + Cmd("git log -1 --format=%s release_hash", "Version 3.22.4\n"), + Cmd("git log -1 --format=%H release_hash^", "abc3\n"), + Cmd("git log --format=%H abc3..push_hash", "rev1\n"), + Cmd("git log -1 --format=%s rev1", "Log text 1.\n"), + Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"), + Cmd("git log -1 --format=%an rev1", "author1@chromium.org\n"), + Cmd("git reset --hard origin/master", ""), + Cmd("git checkout -b work-branch pending_hash", ""), + Cmd("git checkout -f 3.22.4 -- ChangeLog", "", cb=ResetChangeLog), + Cmd("git checkout -f 3.22.4 -- src/version.cc", "", + cb=self.WriteFakeVersionFile), + Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "", + cb=CheckVersionCommit), + Cmd("git push origin " + "refs/heads/work-branch:refs/pending/heads/3.22.5 " + "pending_hash:refs/pending-tags/heads/3.22.5 " + "push_hash:refs/heads/3.22.5", ""), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=" + "\"Version 3.22.5\" origin/3.22.5", "hsh_to_tag"), + Cmd("git tag 3.22.5 hsh_to_tag", ""), + Cmd("git push origin 3.22.5", ""), + Cmd("git checkout -f origin/master", ""), + Cmd("git branch", "* master\n work-branch\n"), + Cmd("git branch -D work-branch", ""), + Cmd("git gc", ""), + ] + self.Expect(expectations) + + args = ["-a", "author@chromium.org", + "-r", "reviewer@chromium.org", + "--revision", "push_hash"] + CreateRelease(TEST_CONFIG, self).Run(args) + + cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE)) + self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl)) + self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl)) + self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl)) + + # Note: The version file is on build number 5 again in the end of this test + # since the git command that merges to master is mocked out. + + C_V8_22624_LOG = """V8 CL. + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22624 123 + +""" + + C_V8_123455_LOG = """V8 CL. + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123455 123 + +""" + + C_V8_123456_LOG = """V8 CL. + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123456 123 + +""" + + def testChromiumRoll(self): + googlers_mapping_py = "%s-mapping.py" % TEST_CONFIG["PERSISTFILE_BASENAME"] + with open(googlers_mapping_py, "w") as f: + f.write(""" +def list_to_dict(entries): + return {"g_name@google.com": "c_name@chromium.org"} +def get_list(): + pass""") + + # Setup fake directory structures. + TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory() + TextToFile("", os.path.join(TEST_CONFIG["CHROMIUM"], ".git")) + chrome_dir = TEST_CONFIG["CHROMIUM"] + os.makedirs(os.path.join(chrome_dir, "v8")) + + # Write fake deps file. + TextToFile("Some line\n \"v8_revision\": \"123444\",\n some line", + os.path.join(chrome_dir, "DEPS")) + def WriteDeps(): + TextToFile("Some line\n \"v8_revision\": \"22624\",\n some line", + os.path.join(chrome_dir, "DEPS")) + + expectations = [ + Cmd("git fetch origin", ""), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"), + Cmd("git log -1 --format=%s push_hash", + "Version 3.22.4 (based on abc)\n"), + Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"), + Cmd("git log -1 --format=%s push_hash", + "Version 3.22.4 (based on abc)"), + Cmd("git describe --tags last_roll_hsh", "3.22.2.1"), + Cmd("git log -1 --format=%H 3.22.2", "last_roll_base_hash"), + Cmd("git log -1 --format=%s last_roll_base_hash", "Version 3.22.2"), + Cmd("git log -1 --format=%H last_roll_base_hash^", + "last_roll_master_hash"), + URL("https://chromium-build.appspot.com/p/chromium/sheriff_v8.js", + "document.write('g_name')"), + Cmd("git status -s -uno", "", cwd=chrome_dir), + Cmd("git checkout -f master", "", cwd=chrome_dir), + Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir), + Cmd("git pull", "", cwd=chrome_dir), + Cmd("git fetch origin", ""), + Cmd("git new-branch v8-roll-push_hash", "", cwd=chrome_dir), + Cmd("roll-dep v8 push_hash", "rolled", cb=WriteDeps, cwd=chrome_dir), + Cmd(("git commit -am \"Update V8 to version 3.22.4 " + "(based on abc).\n\n" + "Summary of changes available at:\n" + "https://chromium.googlesource.com/v8/v8/+log/last_rol..abc\n\n" + "Please reply to the V8 sheriff c_name@chromium.org in " + "case of problems.\n\nTBR=c_name@chromium.org\" " + "--author \"author@chromium.org <author@chromium.org>\""), + "", cwd=chrome_dir), + Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f", "", + cwd=chrome_dir), + ] + self.Expect(expectations) + + args = ["-a", "author@chromium.org", "-c", chrome_dir, + "--sheriff", "--googlers-mapping", googlers_mapping_py, + "-r", "reviewer@chromium.org", + "--last-roll", "last_roll_hsh"] + ChromiumRoll(TEST_CONFIG, self).Run(args) + + deps = FileToText(os.path.join(chrome_dir, "DEPS")) + self.assertTrue(re.search("\"v8_revision\": \"22624\"", deps)) + + def testCheckLastPushRecently(self): + self.Expect([ + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"), + Cmd("git log -1 --format=%s release_hash", + "Version 3.22.4 (based on abc3)\n"), + Cmd("git log --format=%H abc3..abc123", "\n"), + ]) + + self._state["candidate"] = "abc123" + self.assertEquals(0, self.RunStep( + auto_push.AutoPush, LastReleaseBailout, AUTO_PUSH_ARGS)) + + def testAutoPush(self): + TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git")) + + self.Expect([ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch\n"), + Cmd("git fetch", ""), + Cmd("git fetch origin +refs/heads/roll:refs/heads/roll", ""), + Cmd("git show-ref -s refs/heads/roll", "abc123\n"), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"), + Cmd("git log -1 --format=%s release_hash", + "Version 3.22.4 (based on abc3)\n"), + Cmd("git log --format=%H abc3..abc123", "some_stuff\n"), + ]) + + auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"]) + + state = json.loads(FileToText("%s-state.json" + % TEST_CONFIG["PERSISTFILE_BASENAME"])) + + self.assertEquals("abc123", state["candidate"]) + + def testAutoRollExistingRoll(self): + self.Expect([ + URL("https://codereview.chromium.org/search", + "owner=author%40chromium.org&limit=30&closed=3&format=json", + ("{\"results\": [{\"subject\": \"different\"}," + "{\"subject\": \"Update V8 to Version...\"}]}")), + ]) + + result = auto_roll.AutoRoll(TEST_CONFIG, self).Run( + AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]]) + self.assertEquals(0, result) + + # Snippet from the original DEPS file. + FAKE_DEPS = """ +vars = { + "v8_revision": "abcd123455", +} +deps = { + "src/v8": + (Var("googlecode_url") % "v8") + "/" + Var("v8_branch") + "@" + + Var("v8_revision"), +} +""" + + def testAutoRollUpToDate(self): + TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory() + TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS")) + self.Expect([ + URL("https://codereview.chromium.org/search", + "owner=author%40chromium.org&limit=30&closed=3&format=json", + ("{\"results\": [{\"subject\": \"different\"}]}")), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"), + ]) + + result = auto_roll.AutoRoll(TEST_CONFIG, self).Run( + AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]]) + self.assertEquals(0, result) + + def testAutoRoll(self): + TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory() + TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS")) + TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"] = self.MakeEmptyTempFile() + TextToFile("fake key", TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"]) + + self.Expect([ + URL("https://codereview.chromium.org/search", + "owner=author%40chromium.org&limit=30&closed=3&format=json", + ("{\"results\": [{\"subject\": \"different\"}]}")), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git tag", self.TAGS), + Cmd("git log -1 --format=%H 3.22.4", "push_hash\n"), + ]) + + result = auto_roll.AutoRoll(TEST_CONFIG, self).Run( + AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"], "--roll"]) + self.assertEquals(0, result) + + def testMergeToBranch(self): + TEST_CONFIG["ALREADY_MERGING_SENTINEL_FILE"] = self.MakeEmptyTempFile() + TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git")) + self.WriteFakeVersionFile(build=5) + os.environ["EDITOR"] = "vi" + extra_patch = self.MakeEmptyTempFile() + + def VerifyPatch(patch): + return lambda: self.assertEquals(patch, + FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"])) + + msg = """Version 3.22.5.1 (cherry-pick) + +Merged ab12345 +Merged ab23456 +Merged ab34567 +Merged ab45678 +Merged ab56789 + +Title4 + +Title2 + +Title3 + +Title1 + +Revert "Something" + +BUG=123,234,345,456,567,v8:123 +LOG=N +""" + + def VerifyLand(): + commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"]) + self.assertEquals(msg, commit) + version = FileToText( + os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE)) + self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version)) + self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version)) + self.assertTrue(re.search(r"#define PATCH_LEVEL\s+1", version)) + self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version)) + + self.Expect([ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch\n"), + Cmd("git fetch", ""), + Cmd("git branch", " branch1\n* branch2\n"), + Cmd("git new-branch %s --upstream refs/remotes/origin/candidates" % + TEST_CONFIG["BRANCHNAME"], ""), + Cmd(("git log --format=%H --grep=\"Port ab12345\" " + "--reverse origin/master"), + "ab45678\nab23456"), + Cmd("git log -1 --format=%s ab45678", "Title1"), + Cmd("git log -1 --format=%s ab23456", "Title2"), + Cmd(("git log --format=%H --grep=\"Port ab23456\" " + "--reverse origin/master"), + ""), + Cmd(("git log --format=%H --grep=\"Port ab34567\" " + "--reverse origin/master"), + "ab56789"), + Cmd("git log -1 --format=%s ab56789", "Title3"), + RL("Y"), # Automatically add corresponding ports (ab34567, ab56789)? + # Simulate git being down which stops the script. + Cmd("git log -1 --format=%s ab12345", None), + # Restart script in the failing step. + Cmd("git log -1 --format=%s ab12345", "Title4"), + Cmd("git log -1 --format=%s ab23456", "Title2"), + Cmd("git log -1 --format=%s ab34567", "Title3"), + Cmd("git log -1 --format=%s ab45678", "Title1"), + Cmd("git log -1 --format=%s ab56789", "Revert \"Something\""), + Cmd("git log -1 ab12345", "Title4\nBUG=123\nBUG=234"), + Cmd("git log -1 ab23456", "Title2\n BUG = v8:123,345"), + Cmd("git log -1 ab34567", "Title3\nLOG=n\nBUG=567, 456"), + Cmd("git log -1 ab45678", "Title1\nBUG="), + Cmd("git log -1 ab56789", "Revert \"Something\"\nBUG=none"), + Cmd("git log -1 -p ab12345", "patch4"), + Cmd(("git apply --index --reject \"%s\"" % + TEST_CONFIG["TEMPORARY_PATCH_FILE"]), + "", cb=VerifyPatch("patch4")), + Cmd("git log -1 -p ab23456", "patch2"), + Cmd(("git apply --index --reject \"%s\"" % + TEST_CONFIG["TEMPORARY_PATCH_FILE"]), + "", cb=VerifyPatch("patch2")), + Cmd("git log -1 -p ab34567", "patch3"), + Cmd(("git apply --index --reject \"%s\"" % + TEST_CONFIG["TEMPORARY_PATCH_FILE"]), + "", cb=VerifyPatch("patch3")), + Cmd("git log -1 -p ab45678", "patch1"), + Cmd(("git apply --index --reject \"%s\"" % + TEST_CONFIG["TEMPORARY_PATCH_FILE"]), + "", cb=VerifyPatch("patch1")), + Cmd("git log -1 -p ab56789", "patch5\n"), + Cmd(("git apply --index --reject \"%s\"" % + TEST_CONFIG["TEMPORARY_PATCH_FILE"]), + "", cb=VerifyPatch("patch5\n")), + Cmd("git apply --index --reject \"%s\"" % extra_patch, ""), + RL("Y"), # Automatically increment patch level? + Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], ""), + RL("reviewer@chromium.org"), # V8 reviewer. + Cmd("git cl upload --send-mail -r \"reviewer@chromium.org\" " + "--bypass-hooks --cc \"ulan@chromium.org\"", ""), + Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""), + RL("LGTM"), # Enter LGTM for V8 CL. + Cmd("git cl presubmit", "Presubmit successfull\n"), + Cmd("git cl land -f --bypass-hooks", "Closing issue\n", + cb=VerifyLand), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=\"" + "Version 3.22.5.1 (cherry-pick)" + "\" refs/remotes/origin/candidates", + ""), + Cmd("git fetch", ""), + Cmd("git log -1 --format=%H --grep=\"" + "Version 3.22.5.1 (cherry-pick)" + "\" refs/remotes/origin/candidates", + "hsh_to_tag"), + Cmd("git tag 3.22.5.1 hsh_to_tag", ""), + Cmd("git push origin 3.22.5.1", ""), + Cmd("git checkout -f some_branch", ""), + Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""), + ]) + + # ab12345 and ab34567 are patches. ab23456 (included) and ab45678 are the + # MIPS ports of ab12345. ab56789 is the MIPS port of ab34567. + args = ["-f", "-p", extra_patch, "--branch", "candidates", + "ab12345", "ab23456", "ab34567"] + + # The first run of the script stops because of git being down. + self.assertRaises(GitFailedException, + lambda: MergeToBranch(TEST_CONFIG, self).Run(args)) + + # Test that state recovery after restarting the script works. + args += ["-s", "4"] + MergeToBranch(TEST_CONFIG, self).Run(args) + + def testReleases(self): + c_hash1_commit_log = """Update V8 to Version 4.2.71. + +Cr-Commit-Position: refs/heads/master@{#5678} +""" + c_hash2_commit_log = """Revert something. + +BUG=12345 + +Reason: +> Some reason. +> Cr-Commit-Position: refs/heads/master@{#12345} +> git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12345 003-1c4 + +Review URL: https://codereview.chromium.org/12345 + +Cr-Commit-Position: refs/heads/master@{#4567} +git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4567 0039-1c4b + +""" + c_hash3_commit_log = """Simple. + +git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b + +""" + c_hash_234_commit_log = """Version 3.3.1.1 (cherry-pick). + +Merged abc12. + +Review URL: fake.com + +Cr-Commit-Position: refs/heads/candidates@{#234} +""" + c_hash_123_commit_log = """Version 3.3.1.0 + +git-svn-id: googlecode@123 0039-1c4b +""" + c_hash_345_commit_log = """Version 3.4.0. + +Cr-Commit-Position: refs/heads/candidates@{#345} +""" + c_hash_456_commit_log = """Version 4.2.71. + +Cr-Commit-Position: refs/heads/4.2.71@{#1} +""" + + json_output = self.MakeEmptyTempFile() + csv_output = self.MakeEmptyTempFile() + self.WriteFakeVersionFile() + + TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory() + chrome_dir = TEST_CONFIG["CHROMIUM"] + chrome_v8_dir = os.path.join(chrome_dir, "v8") + os.makedirs(chrome_v8_dir) + def WriteDEPS(revision): + TextToFile("Line\n \"v8_revision\": \"%s\",\n line\n" % revision, + os.path.join(chrome_dir, "DEPS")) + WriteDEPS(567) + + def ResetVersion(major, minor, build, patch=0): + return lambda: self.WriteFakeVersionFile(major=major, + minor=minor, + build=build, + patch=patch) + + def ResetDEPS(revision): + return lambda: WriteDEPS(revision) + + self.Expect([ + Cmd("git status -s -uno", ""), + Cmd("git status -s -b -uno", "## some_branch\n"), + Cmd("git fetch", ""), + Cmd("git branch", " branch1\n* branch2\n"), + Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], ""), + Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""), + Cmd("git rev-list --max-age=395200 --tags", + "bad_tag\nhash_234\nhash_123\nhash_345\nhash_456\n"), + Cmd("git describe --tags bad_tag", "3.23.42-1-deadbeef"), + Cmd("git describe --tags hash_234", "3.3.1.1"), + Cmd("git describe --tags hash_123", "3.21.2"), + Cmd("git describe --tags hash_345", "3.22.3"), + Cmd("git describe --tags hash_456", "4.2.71"), + Cmd("git diff --name-only hash_234 hash_234^", VERSION_FILE), + Cmd("git checkout -f hash_234 -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 3, 1, 1)), + Cmd("git branch -r --contains hash_234", " branch-heads/3.3\n"), + Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log), + Cmd("git log -1 --format=%s hash_234", ""), + Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log), + Cmd("git log -1 --format=%ci hash_234", "18:15"), + Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 22, 5)), + Cmd("git diff --name-only hash_123 hash_123^", VERSION_FILE), + Cmd("git checkout -f hash_123 -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 21, 2)), + Cmd("git branch -r --contains hash_123", " branch-heads/3.21\n"), + Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log), + Cmd("git log -1 --format=%s hash_123", ""), + Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log), + Cmd("git log -1 --format=%ci hash_123", "03:15"), + Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 22, 5)), + Cmd("git diff --name-only hash_345 hash_345^", VERSION_FILE), + Cmd("git checkout -f hash_345 -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 22, 3)), + Cmd("git branch -r --contains hash_345", " origin/candidates\n"), + Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log), + Cmd("git log -1 --format=%s hash_345", ""), + Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log), + Cmd("git log -1 --format=%ci hash_345", ""), + Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 22, 5)), + Cmd("git diff --name-only hash_456 hash_456^", VERSION_FILE), + Cmd("git checkout -f hash_456 -- %s" % VERSION_FILE, "", + cb=ResetVersion(4, 2, 71)), + Cmd("git branch -r --contains hash_456", " origin/4.2.71\n"), + Cmd("git log -1 --format=%B hash_456", c_hash_456_commit_log), + Cmd("git log -1 --format=%H 4.2.71", "hash_456"), + Cmd("git log -1 --format=%s hash_456", "Version 4.2.71"), + Cmd("git log -1 --format=%H hash_456^", "master_456"), + Cmd("git log -1 --format=%B master_456", + "Cr-Commit-Position: refs/heads/master@{#456}"), + Cmd("git log -1 --format=%B hash_456", c_hash_456_commit_log), + Cmd("git log -1 --format=%ci hash_456", "02:15"), + Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "", + cb=ResetVersion(3, 22, 5)), + Cmd("git status -s -uno", "", cwd=chrome_dir), + Cmd("git checkout -f master", "", cwd=chrome_dir), + Cmd("git pull", "", cwd=chrome_dir), + Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], "", + cwd=chrome_dir), + Cmd("git fetch origin", "", cwd=chrome_v8_dir), + Cmd("git log --format=%H --grep=\"V8\"", + "c_hash0\nc_hash1\nc_hash2\nc_hash3\n", + cwd=chrome_dir), + Cmd("git diff --name-only c_hash0 c_hash0^", "", cwd=chrome_dir), + Cmd("git diff --name-only c_hash1 c_hash1^", "DEPS", cwd=chrome_dir), + Cmd("git checkout -f c_hash1 -- DEPS", "", + cb=ResetDEPS("hash_456"), + cwd=chrome_dir), + Cmd("git log -1 --format=%B c_hash1", c_hash1_commit_log, + cwd=chrome_dir), + Cmd("git diff --name-only c_hash2 c_hash2^", "DEPS", cwd=chrome_dir), + Cmd("git checkout -f c_hash2 -- DEPS", "", + cb=ResetDEPS("hash_345"), + cwd=chrome_dir), + Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log, + cwd=chrome_dir), + Cmd("git diff --name-only c_hash3 c_hash3^", "DEPS", cwd=chrome_dir), + Cmd("git checkout -f c_hash3 -- DEPS", "", cb=ResetDEPS("deadbeef"), + cwd=chrome_dir), + Cmd("git log -1 --format=%B c_hash3", c_hash3_commit_log, + cwd=chrome_dir), + Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS("hash_567"), + cwd=chrome_dir), + Cmd("git branch -r", " weird/123\n branch-heads/7\n", cwd=chrome_dir), + Cmd("git checkout -f branch-heads/7 -- DEPS", "", + cb=ResetDEPS("hash_345"), + cwd=chrome_dir), + Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS("hash_567"), + cwd=chrome_dir), + Cmd("git checkout -f master", "", cwd=chrome_dir), + Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], "", cwd=chrome_dir), + Cmd("git checkout -f some_branch", ""), + Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""), + ]) + + args = ["-c", TEST_CONFIG["CHROMIUM"], + "--json", json_output, + "--csv", csv_output, + "--max-releases", "1"] + Releases(TEST_CONFIG, self).Run(args) + + # Check expected output. + csv = ("4.2.71,4.2.71,1,5678,\r\n" + "3.22.3,candidates,345,4567:5677,\r\n" + "3.21.2,3.21,123,,\r\n" + "3.3.1.1,3.3,234,,abc12\r\n") + self.assertEquals(csv, FileToText(csv_output)) + + expected_json = [ + { + "revision": "1", + "revision_git": "hash_456", + "master_position": "456", + "master_hash": "master_456", + "patches_merged": "", + "version": "4.2.71", + "chromium_revision": "5678", + "branch": "4.2.71", + "review_link": "", + "date": "02:15", + "chromium_branch": "", + # FIXME(machenbach): Fix revisions link for git. + "revision_link": "https://code.google.com/p/v8/source/detail?r=1", + }, + { + "revision": "345", + "revision_git": "hash_345", + "master_position": "", + "master_hash": "", + "patches_merged": "", + "version": "3.22.3", + "chromium_revision": "4567:5677", + "branch": "candidates", + "review_link": "", + "date": "", + "chromium_branch": "7", + "revision_link": "https://code.google.com/p/v8/source/detail?r=345", + }, + { + "revision": "123", + "revision_git": "hash_123", + "patches_merged": "", + "master_position": "", + "master_hash": "", + "version": "3.21.2", + "chromium_revision": "", + "branch": "3.21", + "review_link": "", + "date": "03:15", + "chromium_branch": "", + "revision_link": "https://code.google.com/p/v8/source/detail?r=123", + }, + { + "revision": "234", + "revision_git": "hash_234", + "patches_merged": "abc12", + "master_position": "", + "master_hash": "", + "version": "3.3.1.1", + "chromium_revision": "", + "branch": "3.3", + "review_link": "fake.com", + "date": "18:15", + "chromium_branch": "", + "revision_link": "https://code.google.com/p/v8/source/detail?r=234", + }, + ] + self.assertEquals(expected_json, json.loads(FileToText(json_output))) + + +class SystemTest(unittest.TestCase): + def testReload(self): + options = ScriptsBase( + TEST_CONFIG, DEFAULT_SIDE_EFFECT_HANDLER, {}).MakeOptions([]) + step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={}, + options=options, + side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER) + body = step.Reload( +"""------------------------------------------------------------------------ +r17997 | machenbach@chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines + +Prepare push to trunk. Now working on version 3.23.11. + +R=danno@chromium.org + +Review URL: https://codereview.chromium.org/83173002 + +------------------------------------------------------------------------""") + self.assertEquals( +"""Prepare push to trunk. Now working on version 3.23.11. + +R=danno@chromium.org + +Committed: https://code.google.com/p/v8/source/detail?r=17997""", body) |