Home | History | Annotate | Download | only in push-to-trunk
      1 #!/usr/bin/env python
      2 # Copyright 2013 the V8 project authors. All rights reserved.
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #     * Redistributions of source code must retain the above copyright
      8 #       notice, this list of conditions and the following disclaimer.
      9 #     * Redistributions in binary form must reproduce the above
     10 #       copyright notice, this list of conditions and the following
     11 #       disclaimer in the documentation and/or other materials provided
     12 #       with the distribution.
     13 #     * Neither the name of Google Inc. nor the names of its
     14 #       contributors may be used to endorse or promote products derived
     15 #       from this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 import os
     30 import shutil
     31 import tempfile
     32 import traceback
     33 import unittest
     34 
     35 import auto_push
     36 from auto_push import CheckLastPush
     37 import auto_roll
     38 import common_includes
     39 from common_includes import *
     40 import merge_to_branch
     41 from merge_to_branch import *
     42 import push_to_trunk
     43 from push_to_trunk import *
     44 import chromium_roll
     45 from chromium_roll import ChromiumRoll
     46 import releases
     47 from releases import Releases
     48 import bump_up_version
     49 from bump_up_version import BumpUpVersion
     50 from bump_up_version import LastChangeBailout
     51 from bump_up_version import LKGRVersionUpToDateBailout
     52 from auto_tag import AutoTag
     53 
     54 
     55 TEST_CONFIG = {
     56   "DEFAULT_CWD": None,
     57   "BRANCHNAME": "test-prepare-push",
     58   "TRUNKBRANCH": "test-trunk-push",
     59   "PERSISTFILE_BASENAME": "/tmp/test-v8-push-to-trunk-tempfile",
     60   "CHANGELOG_FILE": None,
     61   "CHANGELOG_ENTRY_FILE": "/tmp/test-v8-push-to-trunk-tempfile-changelog-entry",
     62   "PATCH_FILE": "/tmp/test-v8-push-to-trunk-tempfile-patch",
     63   "COMMITMSG_FILE": "/tmp/test-v8-push-to-trunk-tempfile-commitmsg",
     64   "CHROMIUM": "/tmp/test-v8-push-to-trunk-tempfile-chromium",
     65   "SETTINGS_LOCATION": None,
     66   "ALREADY_MERGING_SENTINEL_FILE":
     67       "/tmp/test-merge-to-branch-tempfile-already-merging",
     68   "TEMPORARY_PATCH_FILE": "/tmp/test-merge-to-branch-tempfile-temporary-patch",
     69   "CLUSTERFUZZ_API_KEY_FILE": "/tmp/test-fake-cf-api-key",
     70 }
     71 
     72 
     73 AUTO_PUSH_ARGS = [
     74   "-a", "author (at] chromium.org",
     75   "-r", "reviewer (at] chromium.org",
     76 ]
     77 
     78 
     79 class ToplevelTest(unittest.TestCase):
     80   def testSortBranches(self):
     81     S = releases.SortBranches
     82     self.assertEquals(["3.1", "2.25"], S(["2.25", "3.1"])[0:2])
     83     self.assertEquals(["3.0", "2.25"], S(["2.25", "3.0", "2.24"])[0:2])
     84     self.assertEquals(["3.11", "3.2"], S(["3.11", "3.2", "2.24"])[0:2])
     85 
     86   def testFilterDuplicatesAndReverse(self):
     87     F = releases.FilterDuplicatesAndReverse
     88     self.assertEquals([], F([]))
     89     self.assertEquals([["100", "10"]], F([["100", "10"]]))
     90     self.assertEquals([["99", "9"], ["100", "10"]],
     91                       F([["100", "10"], ["99", "9"]]))
     92     self.assertEquals([["98", "9"], ["100", "10"]],
     93                       F([["100", "10"], ["99", "9"], ["98", "9"]]))
     94     self.assertEquals([["98", "9"], ["99", "10"]],
     95                       F([["100", "10"], ["99", "10"], ["98", "9"]]))
     96 
     97   def testBuildRevisionRanges(self):
     98     B = releases.BuildRevisionRanges
     99     self.assertEquals({}, B([]))
    100     self.assertEquals({"10": "100"}, B([["100", "10"]]))
    101     self.assertEquals({"10": "100", "9": "99:99"},
    102                       B([["100", "10"], ["99", "9"]]))
    103     self.assertEquals({"10": "100", "9": "97:99"},
    104                       B([["100", "10"], ["98", "9"], ["97", "9"]]))
    105     self.assertEquals({"10": "100", "9": "99:99", "3": "91:98"},
    106                       B([["100", "10"], ["99", "9"], ["91", "3"]]))
    107     self.assertEquals({"13": "101", "12": "100:100", "9": "94:97",
    108                        "3": "91:93, 98:99"},
    109                       B([["101", "13"], ["100", "12"], ["98", "3"],
    110                          ["94", "9"], ["91", "3"]]))
    111 
    112   def testMakeComment(self):
    113     self.assertEquals("#   Line 1\n#   Line 2\n#",
    114                       MakeComment("    Line 1\n    Line 2\n"))
    115     self.assertEquals("#Line 1\n#Line 2",
    116                       MakeComment("Line 1\n Line 2"))
    117 
    118   def testStripComments(self):
    119     self.assertEquals("    Line 1\n    Line 3\n",
    120         StripComments("    Line 1\n#   Line 2\n    Line 3\n#\n"))
    121     self.assertEquals("\nLine 2 ### Test\n #",
    122         StripComments("###\n# \n\n#  Line 1\nLine 2 ### Test\n #"))
    123 
    124   def testMakeChangeLogBodySimple(self):
    125     commits = [
    126           ["Title text 1",
    127            "Title text 1\n\nBUG=\n",
    128            "author1 (at] chromium.org"],
    129           ["Title text 2.",
    130            "Title text 2\n\nBUG=1234\n",
    131            "author2 (at] chromium.org"],
    132         ]
    133     self.assertEquals("        Title text 1.\n"
    134                       "        (author1 (at] chromium.org)\n\n"
    135                       "        Title text 2 (Chromium issue 1234).\n"
    136                       "        (author2 (at] chromium.org)\n\n",
    137                       MakeChangeLogBody(commits))
    138 
    139   def testMakeChangeLogBodyEmpty(self):
    140     self.assertEquals("", MakeChangeLogBody([]))
    141 
    142   def testMakeChangeLogBodyAutoFormat(self):
    143     commits = [
    144           ["Title text 1!",
    145            "Title text 1\nLOG=y\nBUG=\n",
    146            "author1 (at] chromium.org"],
    147           ["Title text 2",
    148            "Title text 2\n\nBUG=1234\n",
    149            "author2 (at] chromium.org"],
    150           ["Title text 3",
    151            "Title text 3\n\nBUG=1234\nLOG = Yes\n",
    152            "author3 (at] chromium.org"],
    153           ["Title text 3",
    154            "Title text 4\n\nBUG=1234\nLOG=\n",
    155            "author4 (at] chromium.org"],
    156         ]
    157     self.assertEquals("        Title text 1.\n\n"
    158                       "        Title text 3 (Chromium issue 1234).\n\n",
    159                       MakeChangeLogBody(commits, True))
    160 
    161   def testRegressWrongLogEntryOnTrue(self):
    162     body = """
    163 Check elimination: Learn from if(CompareMap(x)) on true branch.
    164 
    165 BUG=
    166 R=verwaest (at] chromium.org
    167 
    168 Committed: https://code.google.com/p/v8/source/detail?r=18210
    169 """
    170     self.assertEquals("", MakeChangeLogBody([["title", body, "author"]], True))
    171 
    172   def testMakeChangeLogBugReferenceEmpty(self):
    173     self.assertEquals("", MakeChangeLogBugReference(""))
    174     self.assertEquals("", MakeChangeLogBugReference("LOG="))
    175     self.assertEquals("", MakeChangeLogBugReference(" BUG ="))
    176     self.assertEquals("", MakeChangeLogBugReference("BUG=none\t"))
    177 
    178   def testMakeChangeLogBugReferenceSimple(self):
    179     self.assertEquals("(issue 987654)",
    180                       MakeChangeLogBugReference("BUG = v8:987654"))
    181     self.assertEquals("(Chromium issue 987654)",
    182                       MakeChangeLogBugReference("BUG=987654 "))
    183 
    184   def testMakeChangeLogBugReferenceFromBody(self):
    185     self.assertEquals("(Chromium issue 1234567)",
    186                       MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n"
    187                                                 " BUG=\tchromium:1234567\t\n"
    188                                                 "R=somebody\n"))
    189 
    190   def testMakeChangeLogBugReferenceMultiple(self):
    191     # All issues should be sorted and grouped. Multiple references to the same
    192     # issue should be filtered.
    193     self.assertEquals("(issues 123, 234, Chromium issue 345)",
    194                       MakeChangeLogBugReference("Title\n\n"
    195                                                 "BUG=v8:234\n"
    196                                                 "  BUG\t= 345, \tv8:234,\n"
    197                                                 "BUG=v8:123\n"
    198                                                 "R=somebody\n"))
    199     self.assertEquals("(Chromium issues 123, 234)",
    200                       MakeChangeLogBugReference("Title\n\n"
    201                                                 "BUG=234,,chromium:123 \n"
    202                                                 "R=somebody\n"))
    203     self.assertEquals("(Chromium issues 123, 234)",
    204                       MakeChangeLogBugReference("Title\n\n"
    205                                                 "BUG=chromium:234, , 123\n"
    206                                                 "R=somebody\n"))
    207     self.assertEquals("(issues 345, 456)",
    208                       MakeChangeLogBugReference("Title\n\n"
    209                                                 "\t\tBUG=v8:345,v8:456\n"
    210                                                 "R=somebody\n"))
    211     self.assertEquals("(issue 123, Chromium issues 345, 456)",
    212                       MakeChangeLogBugReference("Title\n\n"
    213                                                 "BUG=chromium:456\n"
    214                                                 "BUG = none\n"
    215                                                 "R=somebody\n"
    216                                                 "BUG=456,v8:123, 345"))
    217 
    218   # TODO(machenbach): These test don't make much sense when the formatting is
    219   # done later.
    220   def testMakeChangeLogBugReferenceLong(self):
    221     # -----------------00--------10--------20--------30--------
    222     self.assertEquals("(issues 234, 1234567890, 1234567"
    223                       "8901234567890, Chromium issues 12345678,"
    224                       " 123456789)",
    225                       MakeChangeLogBugReference("BUG=v8:234\n"
    226                                                 "BUG=v8:1234567890\n"
    227                                                 "BUG=v8:12345678901234567890\n"
    228                                                 "BUG=123456789\n"
    229                                                 "BUG=12345678\n"))
    230     # -----------------00--------10--------20--------30--------
    231     self.assertEquals("(issues 234, 1234567890, 1234567"
    232                       "8901234567890, Chromium issues"
    233                       " 123456789, 1234567890)",
    234                       MakeChangeLogBugReference("BUG=v8:234\n"
    235                                                 "BUG=v8:12345678901234567890\n"
    236                                                 "BUG=v8:1234567890\n"
    237                                                 "BUG=123456789\n"
    238                                                 "BUG=1234567890\n"))
    239     # -----------------00--------10--------20--------30--------
    240     self.assertEquals("(Chromium issues 234, 1234567890"
    241                       ", 12345678901234567, "
    242                       "1234567890123456789)",
    243                       MakeChangeLogBugReference("BUG=234\n"
    244                                                 "BUG=12345678901234567\n"
    245                                                 "BUG=1234567890123456789\n"
    246                                                 "BUG=1234567890\n"))
    247 
    248 
    249 def Cmd(*args, **kwargs):
    250   """Convenience function returning a shell command test expectation."""
    251   return {
    252     "name": "command",
    253     "args": args,
    254     "ret": args[-1],
    255     "cb": kwargs.get("cb"),
    256     "cwd": kwargs.get("cwd", TEST_CONFIG["DEFAULT_CWD"]),
    257   }
    258 
    259 
    260 def RL(text, cb=None):
    261   """Convenience function returning a readline test expectation."""
    262   return {
    263     "name": "readline",
    264     "args": [],
    265     "ret": text,
    266     "cb": cb,
    267     "cwd": None,
    268   }
    269 
    270 
    271 def URL(*args, **kwargs):
    272   """Convenience function returning a readurl test expectation."""
    273   return {
    274     "name": "readurl",
    275     "args": args[:-1],
    276     "ret": args[-1],
    277     "cb": kwargs.get("cb"),
    278     "cwd": None,
    279   }
    280 
    281 
    282 class SimpleMock(object):
    283   def __init__(self):
    284     self._recipe = []
    285     self._index = -1
    286 
    287   def Expect(self, recipe):
    288     self._recipe = recipe
    289 
    290   def Call(self, name, *args, **kwargs):  # pragma: no cover
    291     self._index += 1
    292     try:
    293       expected_call = self._recipe[self._index]
    294     except IndexError:
    295       raise NoRetryException("Calling %s %s" % (name, " ".join(args)))
    296 
    297     if not isinstance(expected_call, dict):
    298       raise NoRetryException("Found wrong expectation type for %s %s" %
    299                              (name, " ".join(args)))
    300 
    301     if expected_call["name"] != name:
    302       raise NoRetryException("Expected action: %s %s - Actual: %s" %
    303           (expected_call["name"], expected_call["args"], name))
    304 
    305     # Check if the given working directory matches the expected one.
    306     if expected_call["cwd"] != kwargs.get("cwd"):
    307       raise NoRetryException("Expected cwd: %s in %s %s - Actual: %s" %
    308           (expected_call["cwd"],
    309            expected_call["name"],
    310            expected_call["args"],
    311            kwargs.get("cwd")))
    312 
    313     # The number of arguments in the expectation must match the actual
    314     # arguments.
    315     if len(args) > len(expected_call['args']):
    316       raise NoRetryException("When calling %s with arguments, the "
    317           "expectations must consist of at least as many arguments." %
    318           name)
    319 
    320     # Compare expected and actual arguments.
    321     for (expected_arg, actual_arg) in zip(expected_call['args'], args):
    322       if expected_arg != actual_arg:
    323         raise NoRetryException("Expected: %s - Actual: %s" %
    324                                (expected_arg, actual_arg))
    325 
    326     # The expected call contains an optional callback for checking the context
    327     # at the time of the call.
    328     if expected_call['cb']:
    329       try:
    330         expected_call['cb']()
    331       except:
    332         tb = traceback.format_exc()
    333         raise NoRetryException("Caught exception from callback: %s" % tb)
    334 
    335     # If the return value is an exception, raise it instead of returning.
    336     if isinstance(expected_call['ret'], Exception):
    337       raise expected_call['ret']
    338     return expected_call['ret']
    339 
    340   def AssertFinished(self):  # pragma: no cover
    341     if self._index < len(self._recipe) -1:
    342       raise NoRetryException("Called mock too seldom: %d vs. %d" %
    343                              (self._index, len(self._recipe)))
    344 
    345 
    346 class ScriptTest(unittest.TestCase):
    347   def MakeEmptyTempFile(self):
    348     handle, name = tempfile.mkstemp()
    349     os.close(handle)
    350     self._tmp_files.append(name)
    351     return name
    352 
    353   def MakeEmptyTempDirectory(self):
    354     name = tempfile.mkdtemp()
    355     self._tmp_files.append(name)
    356     return name
    357 
    358 
    359   def WriteFakeVersionFile(self, minor=22, build=4, patch=0):
    360     version_file = os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE)
    361     if not os.path.exists(os.path.dirname(version_file)):
    362       os.makedirs(os.path.dirname(version_file))
    363     with open(version_file, "w") as f:
    364       f.write("  // Some line...\n")
    365       f.write("\n")
    366       f.write("#define MAJOR_VERSION    3\n")
    367       f.write("#define MINOR_VERSION    %s\n" % minor)
    368       f.write("#define BUILD_NUMBER     %s\n" % build)
    369       f.write("#define PATCH_LEVEL      %s\n" % patch)
    370       f.write("  // Some line...\n")
    371       f.write("#define IS_CANDIDATE_VERSION 0\n")
    372 
    373   def MakeStep(self):
    374     """Convenience wrapper."""
    375     options = ScriptsBase(TEST_CONFIG, self, self._state).MakeOptions([])
    376     return MakeStep(step_class=Step, state=self._state,
    377                     config=TEST_CONFIG, side_effect_handler=self,
    378                     options=options)
    379 
    380   def RunStep(self, script=PushToTrunk, step_class=Step, args=None):
    381     """Convenience wrapper."""
    382     args = args if args is not None else ["-m"]
    383     return script(TEST_CONFIG, self, self._state).RunSteps([step_class], args)
    384 
    385   def Call(self, fun, *args, **kwargs):
    386     print "Calling %s with %s and %s" % (str(fun), str(args), str(kwargs))
    387 
    388   def Command(self, cmd, args="", prefix="", pipe=True, cwd=None):
    389     print "%s %s" % (cmd, args)
    390     print "in %s" % cwd
    391     return self._mock.Call("command", cmd + " " + args, cwd=cwd)
    392 
    393   def ReadLine(self):
    394     return self._mock.Call("readline")
    395 
    396   def ReadURL(self, url, params):
    397     if params is not None:
    398       return self._mock.Call("readurl", url, params)
    399     else:
    400       return self._mock.Call("readurl", url)
    401 
    402   def ReadClusterFuzzAPI(self, api_key, **params):
    403     # TODO(machenbach): Use a mock for this and add a test that stops rolling
    404     # due to clustefuzz results.
    405     return []
    406 
    407   def Sleep(self, seconds):
    408     pass
    409 
    410   def GetDate(self):
    411     return "1999-07-31"
    412 
    413   def GetUTCStamp(self):
    414     return "100000"
    415 
    416   def Expect(self, *args):
    417     """Convenience wrapper."""
    418     self._mock.Expect(*args)
    419 
    420   def setUp(self):
    421     self._mock = SimpleMock()
    422     self._tmp_files = []
    423     self._state = {}
    424     TEST_CONFIG["DEFAULT_CWD"] = self.MakeEmptyTempDirectory()
    425 
    426   def tearDown(self):
    427     if os.path.exists(TEST_CONFIG["PERSISTFILE_BASENAME"]):
    428       shutil.rmtree(TEST_CONFIG["PERSISTFILE_BASENAME"])
    429 
    430     # Clean up temps. Doesn't work automatically.
    431     for name in self._tmp_files:
    432       if os.path.isfile(name):
    433         os.remove(name)
    434       if os.path.isdir(name):
    435         shutil.rmtree(name)
    436 
    437     self._mock.AssertFinished()
    438 
    439   def testGitMock(self):
    440     self.Expect([Cmd("git --version", "git version 1.2.3"),
    441                  Cmd("git dummy", "")])
    442     self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
    443     self.assertEquals("", self.MakeStep().Git("dummy"))
    444 
    445   def testCommonPrepareDefault(self):
    446     self.Expect([
    447       Cmd("git status -s -uno", ""),
    448       Cmd("git status -s -b -uno", "## some_branch"),
    449       Cmd("git svn fetch", ""),
    450       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
    451       RL("Y"),
    452       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
    453     ])
    454     self.MakeStep().CommonPrepare()
    455     self.MakeStep().PrepareBranch()
    456     self.assertEquals("some_branch", self._state["current_branch"])
    457 
    458   def testCommonPrepareNoConfirm(self):
    459     self.Expect([
    460       Cmd("git status -s -uno", ""),
    461       Cmd("git status -s -b -uno", "## some_branch"),
    462       Cmd("git svn fetch", ""),
    463       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
    464       RL("n"),
    465     ])
    466     self.MakeStep().CommonPrepare()
    467     self.assertRaises(Exception, self.MakeStep().PrepareBranch)
    468     self.assertEquals("some_branch", self._state["current_branch"])
    469 
    470   def testCommonPrepareDeleteBranchFailure(self):
    471     self.Expect([
    472       Cmd("git status -s -uno", ""),
    473       Cmd("git status -s -b -uno", "## some_branch"),
    474       Cmd("git svn fetch", ""),
    475       Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
    476       RL("Y"),
    477       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], None),
    478     ])
    479     self.MakeStep().CommonPrepare()
    480     self.assertRaises(Exception, self.MakeStep().PrepareBranch)
    481     self.assertEquals("some_branch", self._state["current_branch"])
    482 
    483   def testInitialEnvironmentChecks(self):
    484     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
    485     os.environ["EDITOR"] = "vi"
    486     self.Expect([
    487       Cmd("which vi", "/usr/bin/vi"),
    488     ])
    489     self.MakeStep().InitialEnvironmentChecks(TEST_CONFIG["DEFAULT_CWD"])
    490 
    491   def testReadAndPersistVersion(self):
    492     self.WriteFakeVersionFile(build=5)
    493     step = self.MakeStep()
    494     step.ReadAndPersistVersion()
    495     self.assertEquals("3", step["major"])
    496     self.assertEquals("22", step["minor"])
    497     self.assertEquals("5", step["build"])
    498     self.assertEquals("0", step["patch"])
    499 
    500   def testRegex(self):
    501     self.assertEqual("(issue 321)",
    502                      re.sub(r"BUG=v8:(.*)$", r"(issue \1)", "BUG=v8:321"))
    503     self.assertEqual("(Chromium issue 321)",
    504                      re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", "BUG=321"))
    505 
    506     cl = "  too little\n\ttab\ttab\n         too much\n        trailing  "
    507     cl = MSub(r"\t", r"        ", cl)
    508     cl = MSub(r"^ {1,7}([^ ])", r"        \1", cl)
    509     cl = MSub(r"^ {9,80}([^ ])", r"        \1", cl)
    510     cl = MSub(r" +$", r"", cl)
    511     self.assertEqual("        too little\n"
    512                      "        tab        tab\n"
    513                      "        too much\n"
    514                      "        trailing", cl)
    515 
    516     self.assertEqual("//\n#define BUILD_NUMBER  3\n",
    517                      MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$",
    518                           r"\g<space>3",
    519                           "//\n#define BUILD_NUMBER  321\n"))
    520 
    521   def testPreparePushRevision(self):
    522     # Tests the default push hash used when the --revision option is not set.
    523     self.Expect([
    524       Cmd("git log -1 --format=%H HEAD", "push_hash")
    525     ])
    526 
    527     self.RunStep(PushToTrunk, PreparePushRevision)
    528     self.assertEquals("push_hash", self._state["push_hash"])
    529 
    530   def testPrepareChangeLog(self):
    531     self.WriteFakeVersionFile()
    532     TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
    533 
    534     self.Expect([
    535       Cmd("git log --format=%H 1234..push_hash", "rev1\nrev2\nrev3\nrev4"),
    536       Cmd("git log -1 --format=%s rev1", "Title text 1"),
    537       Cmd("git log -1 --format=%B rev1", "Title\n\nBUG=\nLOG=y\n"),
    538       Cmd("git log -1 --format=%an rev1", "author1 (at] chromium.org"),
    539       Cmd("git log -1 --format=%s rev2", "Title text 2."),
    540       Cmd("git log -1 --format=%B rev2", "Title\n\nBUG=123\nLOG= \n"),
    541       Cmd("git log -1 --format=%an rev2", "author2 (at] chromium.org"),
    542       Cmd("git log -1 --format=%s rev3", "Title text 3"),
    543       Cmd("git log -1 --format=%B rev3", "Title\n\nBUG=321\nLOG=true\n"),
    544       Cmd("git log -1 --format=%an rev3", "author3 (at] chromium.org"),
    545       Cmd("git log -1 --format=%s rev4", "Title text 4"),
    546       Cmd("git log -1 --format=%B rev4",
    547        ("Title\n\nBUG=456\nLOG=Y\n\n"
    548         "Review URL: https://codereview.chromium.org/9876543210\n")),
    549       URL("https://codereview.chromium.org/9876543210/description",
    550           "Title\n\nBUG=456\nLOG=N\n\n"),
    551       Cmd("git log -1 --format=%an rev4", "author4 (at] chromium.org"),
    552     ])
    553 
    554     self._state["last_push_bleeding_edge"] = "1234"
    555     self._state["push_hash"] = "push_hash"
    556     self._state["version"] = "3.22.5"
    557     self.RunStep(PushToTrunk, PrepareChangeLog)
    558 
    559     actual_cl = FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
    560 
    561     expected_cl = """1999-07-31: Version 3.22.5
    562 
    563         Title text 1.
    564 
    565         Title text 3 (Chromium issue 321).
    566 
    567         Performance and stability improvements on all platforms.
    568 #
    569 # The change log above is auto-generated. Please review if all relevant
    570 # commit messages from the list below are included.
    571 # All lines starting with # will be stripped.
    572 #
    573 #       Title text 1.
    574 #       (author1 (at] chromium.org)
    575 #
    576 #       Title text 2 (Chromium issue 123).
    577 #       (author2 (at] chromium.org)
    578 #
    579 #       Title text 3 (Chromium issue 321).
    580 #       (author3 (at] chromium.org)
    581 #
    582 #       Title text 4 (Chromium issue 456).
    583 #       (author4 (at] chromium.org)
    584 #
    585 #"""
    586 
    587     self.assertEquals(expected_cl, actual_cl)
    588 
    589   def testEditChangeLog(self):
    590     TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
    591     TextToFile("  New  \n\tLines  \n", TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
    592     os.environ["EDITOR"] = "vi"
    593     self.Expect([
    594       RL(""),  # Open editor.
    595       Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""),
    596     ])
    597 
    598     self.RunStep(PushToTrunk, EditChangeLog)
    599 
    600     self.assertEquals("New\n        Lines",
    601                       FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"]))
    602 
    603   # Version on trunk: 3.22.4.0. Version on master (bleeding_edge): 3.22.6.
    604   # Make sure that the increment is 3.22.7.0.
    605   def testIncrementVersion(self):
    606     self.WriteFakeVersionFile()
    607     self._state["last_push_trunk"] = "hash1"
    608     self._state["latest_build"] = "6"
    609     self._state["latest_version"] = "3.22.6.0"
    610 
    611     self.Expect([
    612       Cmd("git checkout -f hash1 -- src/version.cc", ""),
    613       Cmd("git checkout -f svn/bleeding_edge -- src/version.cc",
    614           "", cb=lambda: self.WriteFakeVersionFile(22, 6)),
    615       RL("Y"),  # Increment build number.
    616     ])
    617 
    618     self.RunStep(PushToTrunk, IncrementVersion)
    619 
    620     self.assertEquals("3", self._state["new_major"])
    621     self.assertEquals("22", self._state["new_minor"])
    622     self.assertEquals("7", self._state["new_build"])
    623     self.assertEquals("0", self._state["new_patch"])
    624 
    625   def _TestSquashCommits(self, change_log, expected_msg):
    626     TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
    627     with open(TEST_CONFIG["CHANGELOG_ENTRY_FILE"], "w") as f:
    628       f.write(change_log)
    629 
    630     self.Expect([
    631       Cmd("git diff svn/trunk hash1", "patch content"),
    632       Cmd("git svn find-rev hash1", "123455\n"),
    633     ])
    634 
    635     self._state["push_hash"] = "hash1"
    636     self._state["date"] = "1999-11-11"
    637 
    638     self.RunStep(PushToTrunk, SquashCommits)
    639     self.assertEquals(FileToText(TEST_CONFIG["COMMITMSG_FILE"]), expected_msg)
    640 
    641     patch = FileToText(TEST_CONFIG["PATCH_FILE"])
    642     self.assertTrue(re.search(r"patch content", patch))
    643 
    644   def testSquashCommitsUnformatted(self):
    645     change_log = """1999-11-11: Version 3.22.5
    646 
    647         Log text 1.
    648         Chromium issue 12345
    649 
    650         Performance and stability improvements on all platforms.\n"""
    651     commit_msg = """Version 3.22.5 (based on bleeding_edge revision r123455)
    652 
    653 Log text 1. Chromium issue 12345
    654 
    655 Performance and stability improvements on all platforms."""
    656     self._TestSquashCommits(change_log, commit_msg)
    657 
    658   def testSquashCommitsFormatted(self):
    659     change_log = """1999-11-11: Version 3.22.5
    660 
    661         Long commit message that fills more than 80 characters (Chromium issue
    662         12345).
    663 
    664         Performance and stability improvements on all platforms.\n"""
    665     commit_msg = """Version 3.22.5 (based on bleeding_edge revision r123455)
    666 
    667 Long commit message that fills more than 80 characters (Chromium issue 12345).
    668 
    669 Performance and stability improvements on all platforms."""
    670     self._TestSquashCommits(change_log, commit_msg)
    671 
    672   def testSquashCommitsQuotationMarks(self):
    673     change_log = """Line with "quotation marks".\n"""
    674     commit_msg = """Line with "quotation marks"."""
    675     self._TestSquashCommits(change_log, commit_msg)
    676 
    677   def _PushToTrunk(self, force=False, manual=False):
    678     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
    679 
    680     # The version file on bleeding edge has build level 5, while the version
    681     # file from trunk has build level 4.
    682     self.WriteFakeVersionFile(build=5)
    683 
    684     TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
    685     TEST_CONFIG["CHANGELOG_FILE"] = self.MakeEmptyTempFile()
    686     bleeding_edge_change_log = "2014-03-17: Sentinel\n"
    687     TextToFile(bleeding_edge_change_log, TEST_CONFIG["CHANGELOG_FILE"])
    688     os.environ["EDITOR"] = "vi"
    689 
    690     def ResetChangeLog():
    691       """On 'git co -b new_branch svn/trunk', and 'git checkout -- ChangeLog',
    692       the ChangLog will be reset to its content on trunk."""
    693       trunk_change_log = """1999-04-05: Version 3.22.4
    694 
    695         Performance and stability improvements on all platforms.\n"""
    696       TextToFile(trunk_change_log, TEST_CONFIG["CHANGELOG_FILE"])
    697 
    698     def ResetToTrunk():
    699       ResetChangeLog()
    700       self.WriteFakeVersionFile()
    701 
    702     def CheckSVNCommit():
    703       commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
    704       self.assertEquals(
    705 """Version 3.22.5 (based on bleeding_edge revision r123455)
    706 
    707 Log text 1 (issue 321).
    708 
    709 Performance and stability improvements on all platforms.""", commit)
    710       version = FileToText(
    711           os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
    712       self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
    713       self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
    714       self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version))
    715       self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
    716       self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
    717 
    718       # Check that the change log on the trunk branch got correctly modified.
    719       change_log = FileToText(TEST_CONFIG["CHANGELOG_FILE"])
    720       self.assertEquals(
    721 """1999-07-31: Version 3.22.5
    722 
    723         Log text 1 (issue 321).
    724 
    725         Performance and stability improvements on all platforms.
    726 
    727 
    728 1999-04-05: Version 3.22.4
    729 
    730         Performance and stability improvements on all platforms.\n""",
    731           change_log)
    732 
    733     force_flag = " -f" if not manual else ""
    734     expectations = []
    735     if not force:
    736       expectations.append(Cmd("which vi", "/usr/bin/vi"))
    737     expectations += [
    738       Cmd("git status -s -uno", ""),
    739       Cmd("git status -s -b -uno", "## some_branch\n"),
    740       Cmd("git svn fetch", ""),
    741       Cmd("git branch", "  branch1\n* branch2\n"),
    742       Cmd("git branch", "  branch1\n* branch2\n"),
    743       Cmd("git checkout -b %s svn/bleeding_edge" % TEST_CONFIG["BRANCHNAME"],
    744           ""),
    745       Cmd("git svn find-rev r123455", "push_hash\n"),
    746       Cmd(("git log -1 --format=%H --grep="
    747            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
    748            "svn/trunk"), "hash2\n"),
    749       Cmd("git log -1 hash2", "Log message\n"),
    750     ]
    751     if manual:
    752       expectations.append(RL("Y"))  # Confirm last push.
    753     expectations += [
    754       Cmd("git log -1 --format=%s hash2",
    755        "Version 3.4.5 (based on bleeding_edge revision r1234)\n"),
    756       Cmd("git svn find-rev r1234", "hash3\n"),
    757       Cmd("git checkout -f svn/bleeding_edge -- src/version.cc",
    758           "", cb=self.WriteFakeVersionFile),
    759       Cmd("git checkout -f hash2 -- src/version.cc", "",
    760           cb=self.WriteFakeVersionFile),
    761     ]
    762     if manual:
    763       expectations.append(RL(""))  # Increment build number.
    764     expectations += [
    765       Cmd("git log --format=%H hash3..push_hash", "rev1\n"),
    766       Cmd("git log -1 --format=%s rev1", "Log text 1.\n"),
    767       Cmd("git log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
    768       Cmd("git log -1 --format=%an rev1", "author1 (at] chromium.org\n"),
    769     ]
    770     if manual:
    771       expectations.append(RL(""))  # Open editor.
    772     if not force:
    773       expectations.append(
    774           Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""))
    775     expectations += [
    776       Cmd("git svn fetch", "fetch result\n"),
    777       Cmd("git checkout -f svn/bleeding_edge", ""),
    778       Cmd("git diff svn/trunk push_hash", "patch content\n"),
    779       Cmd("git svn find-rev push_hash", "123455\n"),
    780       Cmd("git checkout -b %s svn/trunk" % TEST_CONFIG["TRUNKBRANCH"], "",
    781           cb=ResetToTrunk),
    782       Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""),
    783       Cmd("git checkout -f svn/trunk -- %s" % TEST_CONFIG["CHANGELOG_FILE"], "",
    784           cb=ResetChangeLog),
    785       Cmd("git checkout -f svn/trunk -- src/version.cc", "",
    786           cb=self.WriteFakeVersionFile),
    787       Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
    788           cb=CheckSVNCommit),
    789     ]
    790     if manual:
    791       expectations.append(RL("Y"))  # Sanity check.
    792     expectations += [
    793       Cmd("git svn dcommit 2>&1",
    794           "Some output\nCommitted r123456\nSome output\n"),
    795       Cmd("git svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""),
    796       Cmd("git checkout -f some_branch", ""),
    797       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
    798       Cmd("git branch -D %s" % TEST_CONFIG["TRUNKBRANCH"], ""),
    799     ]
    800     self.Expect(expectations)
    801 
    802     args = ["-a", "author (at] chromium.org", "--revision", "123455"]
    803     if force: args.append("-f")
    804     if manual: args.append("-m")
    805     else: args += ["-r", "reviewer (at] chromium.org"]
    806     PushToTrunk(TEST_CONFIG, self).Run(args)
    807 
    808     cl = FileToText(TEST_CONFIG["CHANGELOG_FILE"])
    809     self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
    810     self.assertTrue(re.search(r"        Log text 1 \(issue 321\).", cl))
    811     self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
    812 
    813     # Note: The version file is on build number 5 again in the end of this test
    814     # since the git command that merges to the bleeding edge branch is mocked
    815     # out.
    816 
    817   def testPushToTrunkManual(self):
    818     self._PushToTrunk(manual=True)
    819 
    820   def testPushToTrunkSemiAutomatic(self):
    821     self._PushToTrunk()
    822 
    823   def testPushToTrunkForced(self):
    824     self._PushToTrunk(force=True)
    825 
    826   C_V8_22624_LOG = """V8 CL.
    827 
    828 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22624 123
    829 
    830 """
    831 
    832   C_V8_123455_LOG = """V8 CL.
    833 
    834 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123455 123
    835 
    836 """
    837 
    838   C_V8_123456_LOG = """V8 CL.
    839 
    840 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123456 123
    841 
    842 """
    843 
    844   def testChromiumRoll(self):
    845     googlers_mapping_py = "%s-mapping.py" % TEST_CONFIG["PERSISTFILE_BASENAME"]
    846     with open(googlers_mapping_py, "w") as f:
    847       f.write("""
    848 def list_to_dict(entries):
    849   return {"g_name@google.com": "c_name@chromium.org"}
    850 def get_list():
    851   pass""")
    852 
    853     # Setup fake directory structures.
    854     TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
    855     TextToFile("", os.path.join(TEST_CONFIG["CHROMIUM"], ".git"))
    856     chrome_dir = TEST_CONFIG["CHROMIUM"]
    857     os.makedirs(os.path.join(chrome_dir, "v8"))
    858 
    859     # Write fake deps file.
    860     TextToFile("Some line\n   \"v8_revision\": \"123444\",\n  some line",
    861                os.path.join(chrome_dir, "DEPS"))
    862     def WriteDeps():
    863       TextToFile("Some line\n   \"v8_revision\": \"22624\",\n  some line",
    864                  os.path.join(chrome_dir, "DEPS"))
    865 
    866     expectations = [
    867       Cmd("git fetch origin", ""),
    868       Cmd(("git log -1 --format=%H --grep="
    869            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
    870            "origin/master"), "push_hash\n"),
    871       Cmd("git log -1 --format=%B push_hash", self.C_V8_22624_LOG),
    872       Cmd("git log -1 --format=%s push_hash",
    873           "Version 3.22.5 (based on bleeding_edge revision r22622)\n"),
    874       URL("https://chromium-build.appspot.com/p/chromium/sheriff_v8.js",
    875           "document.write('g_name')"),
    876       Cmd("git status -s -uno", "", cwd=chrome_dir),
    877       Cmd("git checkout -f master", "", cwd=chrome_dir),
    878       Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir),
    879       Cmd("git pull", "", cwd=chrome_dir),
    880       Cmd("git fetch origin", ""),
    881       Cmd("git checkout -b v8-roll-22624", "", cwd=chrome_dir),
    882       Cmd("roll-dep v8 22624", "rolled", cb=WriteDeps, cwd=chrome_dir),
    883       Cmd(("git commit -am \"Update V8 to version 3.22.5 "
    884            "(based on bleeding_edge revision r22622).\n\n"
    885            "Please reply to the V8 sheriff c_name (at] chromium.org in "
    886            "case of problems.\n\nTBR=c_name (at] chromium.org\" "
    887            "--author \"author (at] chromium.org <author (at] chromium.org>\""),
    888           "", cwd=chrome_dir),
    889       Cmd("git cl upload --send-mail --email \"author (at] chromium.org\" -f", "",
    890           cwd=chrome_dir),
    891     ]
    892     self.Expect(expectations)
    893 
    894     args = ["-a", "author (at] chromium.org", "-c", chrome_dir,
    895             "--sheriff", "--googlers-mapping", googlers_mapping_py,
    896             "-r", "reviewer (at] chromium.org"]
    897     ChromiumRoll(TEST_CONFIG, self).Run(args)
    898 
    899     deps = FileToText(os.path.join(chrome_dir, "DEPS"))
    900     self.assertTrue(re.search("\"v8_revision\": \"22624\"", deps))
    901 
    902   def testCheckLastPushRecently(self):
    903     self.Expect([
    904       Cmd(("git log -1 --format=%H --grep="
    905            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
    906            "svn/trunk"), "hash2\n"),
    907       Cmd("git log -1 --format=%s hash2",
    908           "Version 3.4.5 (based on bleeding_edge revision r99)\n"),
    909     ])
    910 
    911     self._state["lkgr"] = "101"
    912 
    913     self.assertRaises(Exception, lambda: self.RunStep(auto_push.AutoPush,
    914                                                       CheckLastPush,
    915                                                       AUTO_PUSH_ARGS))
    916 
    917   def testAutoPush(self):
    918     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
    919     TEST_CONFIG["SETTINGS_LOCATION"] = "~/.doesnotexist"
    920 
    921     self.Expect([
    922       Cmd("git status -s -uno", ""),
    923       Cmd("git status -s -b -uno", "## some_branch\n"),
    924       Cmd("git svn fetch", ""),
    925       URL("https://v8-status.appspot.com/current?format=json",
    926           "{\"message\": \"Tree is throttled\"}"),
    927       URL("https://v8-status.appspot.com/lkgr", Exception("Network problem")),
    928       URL("https://v8-status.appspot.com/lkgr", "100"),
    929       Cmd(("git log -1 --format=%H --grep=\""
    930            "^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\""
    931            " svn/trunk"), "push_hash\n"),
    932       Cmd("git log -1 --format=%s push_hash",
    933           "Version 3.4.5 (based on bleeding_edge revision r79)\n"),
    934     ])
    935 
    936     auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"])
    937 
    938     state = json.loads(FileToText("%s-state.json"
    939                                   % TEST_CONFIG["PERSISTFILE_BASENAME"]))
    940 
    941     self.assertEquals("100", state["lkgr"])
    942 
    943   def testAutoPushStoppedBySettings(self):
    944     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
    945     TEST_CONFIG["SETTINGS_LOCATION"] = self.MakeEmptyTempFile()
    946     TextToFile("{\"enable_auto_push\": false}",
    947                TEST_CONFIG["SETTINGS_LOCATION"])
    948 
    949     self.Expect([
    950       Cmd("git status -s -uno", ""),
    951       Cmd("git status -s -b -uno", "## some_branch\n"),
    952       Cmd("git svn fetch", ""),
    953     ])
    954 
    955     def RunAutoPush():
    956       auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS)
    957     self.assertRaises(Exception, RunAutoPush)
    958 
    959   def testAutoPushStoppedByTreeStatus(self):
    960     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
    961     TEST_CONFIG["SETTINGS_LOCATION"] = "~/.doesnotexist"
    962 
    963     self.Expect([
    964       Cmd("git status -s -uno", ""),
    965       Cmd("git status -s -b -uno", "## some_branch\n"),
    966       Cmd("git svn fetch", ""),
    967       URL("https://v8-status.appspot.com/current?format=json",
    968           "{\"message\": \"Tree is throttled (no push)\"}"),
    969     ])
    970 
    971     def RunAutoPush():
    972       auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS)
    973     self.assertRaises(Exception, RunAutoPush)
    974 
    975   def testAutoRollExistingRoll(self):
    976     self.Expect([
    977       URL("https://codereview.chromium.org/search",
    978           "owner=author%40chromium.org&limit=30&closed=3&format=json",
    979           ("{\"results\": [{\"subject\": \"different\"},"
    980            "{\"subject\": \"Update V8 to Version...\"}]}")),
    981     ])
    982 
    983     result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
    984         AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]])
    985     self.assertEquals(0, result)
    986 
    987   # Snippet from the original DEPS file.
    988   FAKE_DEPS = """
    989 vars = {
    990   "v8_revision": "abcd123455",
    991 }
    992 deps = {
    993   "src/v8":
    994     (Var("googlecode_url") % "v8") + "/" + Var("v8_branch") + "@" +
    995     Var("v8_revision"),
    996 }
    997 """
    998 
    999   def testAutoRollUpToDate(self):
   1000     TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
   1001     TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
   1002     self.Expect([
   1003       URL("https://codereview.chromium.org/search",
   1004           "owner=author%40chromium.org&limit=30&closed=3&format=json",
   1005           ("{\"results\": [{\"subject\": \"different\"}]}")),
   1006       Cmd(("git log -1 --format=%H --grep="
   1007            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
   1008            "origin/master"), "push_hash\n"),
   1009       Cmd("git log -1 --format=%B push_hash", self.C_V8_22624_LOG),
   1010       Cmd("git log -1 --format=%B abcd123455", self.C_V8_123455_LOG),
   1011     ])
   1012 
   1013     result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
   1014         AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]])
   1015     self.assertEquals(0, result)
   1016 
   1017   def testAutoRoll(self):
   1018     TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
   1019     TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
   1020     TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"]  = self.MakeEmptyTempFile()
   1021     TextToFile("fake key", TEST_CONFIG["CLUSTERFUZZ_API_KEY_FILE"])
   1022 
   1023     self.Expect([
   1024       URL("https://codereview.chromium.org/search",
   1025           "owner=author%40chromium.org&limit=30&closed=3&format=json",
   1026           ("{\"results\": [{\"subject\": \"different\"}]}")),
   1027       Cmd(("git log -1 --format=%H --grep="
   1028            "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*\" "
   1029            "origin/master"), "push_hash\n"),
   1030       Cmd("git log -1 --format=%B push_hash", self.C_V8_123456_LOG),
   1031       Cmd("git log -1 --format=%B abcd123455", self.C_V8_123455_LOG),
   1032     ])
   1033 
   1034     result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
   1035         AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"], "--roll"])
   1036     self.assertEquals(0, result)
   1037 
   1038   def testMergeToBranch(self):
   1039     TEST_CONFIG["ALREADY_MERGING_SENTINEL_FILE"] = self.MakeEmptyTempFile()
   1040     TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
   1041     self.WriteFakeVersionFile(build=5)
   1042     os.environ["EDITOR"] = "vi"
   1043     extra_patch = self.MakeEmptyTempFile()
   1044 
   1045     def VerifyPatch(patch):
   1046       return lambda: self.assertEquals(patch,
   1047           FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
   1048 
   1049     msg = """Version 3.22.5.1 (merged r12345, r23456, r34567, r45678, r56789)
   1050 
   1051 Title4
   1052 
   1053 Title2
   1054 
   1055 Title3
   1056 
   1057 Title1
   1058 
   1059 Revert "Something"
   1060 
   1061 BUG=123,234,345,456,567,v8:123
   1062 LOG=N
   1063 """
   1064 
   1065     def VerifySVNCommit():
   1066       commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
   1067       self.assertEquals(msg, commit)
   1068       version = FileToText(
   1069           os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
   1070       self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
   1071       self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
   1072       self.assertTrue(re.search(r"#define PATCH_LEVEL\s+1", version))
   1073       self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
   1074 
   1075     self.Expect([
   1076       Cmd("git status -s -uno", ""),
   1077       Cmd("git status -s -b -uno", "## some_branch\n"),
   1078       Cmd("git svn fetch", ""),
   1079       Cmd("git branch", "  branch1\n* branch2\n"),
   1080       Cmd("git checkout -b %s svn/trunk" % TEST_CONFIG["BRANCHNAME"], ""),
   1081       Cmd(("git log --format=%H --grep=\"Port r12345\" "
   1082            "--reverse svn/bleeding_edge"),
   1083           "hash1\nhash2"),
   1084       Cmd("git svn find-rev hash1 svn/bleeding_edge", "45678"),
   1085       Cmd("git log -1 --format=%s hash1", "Title1"),
   1086       Cmd("git svn find-rev hash2 svn/bleeding_edge", "23456"),
   1087       Cmd("git log -1 --format=%s hash2", "Title2"),
   1088       Cmd(("git log --format=%H --grep=\"Port r23456\" "
   1089            "--reverse svn/bleeding_edge"),
   1090           ""),
   1091       Cmd(("git log --format=%H --grep=\"Port r34567\" "
   1092            "--reverse svn/bleeding_edge"),
   1093           "hash3"),
   1094       Cmd("git svn find-rev hash3 svn/bleeding_edge", "56789"),
   1095       Cmd("git log -1 --format=%s hash3", "Title3"),
   1096       RL("Y"),  # Automatically add corresponding ports (34567, 56789)?
   1097       Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
   1098       # Simulate svn being down which stops the script.
   1099       Cmd("git svn find-rev r23456 svn/bleeding_edge", None),
   1100       # Restart script in the failing step.
   1101       Cmd("git svn find-rev r12345 svn/bleeding_edge", "hash4"),
   1102       Cmd("git svn find-rev r23456 svn/bleeding_edge", "hash2"),
   1103       Cmd("git svn find-rev r34567 svn/bleeding_edge", "hash3"),
   1104       Cmd("git svn find-rev r45678 svn/bleeding_edge", "hash1"),
   1105       Cmd("git svn find-rev r56789 svn/bleeding_edge", "hash5"),
   1106       Cmd("git log -1 --format=%s hash4", "Title4"),
   1107       Cmd("git log -1 --format=%s hash2", "Title2"),
   1108       Cmd("git log -1 --format=%s hash3", "Title3"),
   1109       Cmd("git log -1 --format=%s hash1", "Title1"),
   1110       Cmd("git log -1 --format=%s hash5", "Revert \"Something\""),
   1111       Cmd("git log -1 hash4", "Title4\nBUG=123\nBUG=234"),
   1112       Cmd("git log -1 hash2", "Title2\n BUG = v8:123,345"),
   1113       Cmd("git log -1 hash3", "Title3\nLOG=n\nBUG=567, 456"),
   1114       Cmd("git log -1 hash1", "Title1\nBUG="),
   1115       Cmd("git log -1 hash5", "Revert \"Something\"\nBUG=none"),
   1116       Cmd("git log -1 -p hash4", "patch4"),
   1117       Cmd(("git apply --index --reject \"%s\"" %
   1118            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
   1119           "", cb=VerifyPatch("patch4")),
   1120       Cmd("git log -1 -p hash2", "patch2"),
   1121       Cmd(("git apply --index --reject \"%s\"" %
   1122            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
   1123           "", cb=VerifyPatch("patch2")),
   1124       Cmd("git log -1 -p hash3", "patch3"),
   1125       Cmd(("git apply --index --reject \"%s\"" %
   1126            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
   1127           "", cb=VerifyPatch("patch3")),
   1128       Cmd("git log -1 -p hash1", "patch1"),
   1129       Cmd(("git apply --index --reject \"%s\"" %
   1130            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
   1131           "", cb=VerifyPatch("patch1")),
   1132       Cmd("git log -1 -p hash5", "patch5\n"),
   1133       Cmd(("git apply --index --reject \"%s\"" %
   1134            TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
   1135           "", cb=VerifyPatch("patch5\n")),
   1136       Cmd("git apply --index --reject \"%s\"" % extra_patch, ""),
   1137       RL("Y"),  # Automatically increment patch level?
   1138       Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], ""),
   1139       RL("reviewer (at] chromium.org"),  # V8 reviewer.
   1140       Cmd("git cl upload --send-mail -r \"reviewer (at] chromium.org\" "
   1141           "--bypass-hooks", ""),
   1142       Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""),
   1143       RL("LGTM"),  # Enter LGTM for V8 CL.
   1144       Cmd("git cl presubmit", "Presubmit successfull\n"),
   1145       Cmd("git cl dcommit -f --bypass-hooks", "Closing issue\n",
   1146           cb=VerifySVNCommit),
   1147       Cmd("git svn fetch", ""),
   1148       Cmd(("git log -1 --format=%%H --grep=\"%s\" svn/trunk"
   1149            % msg.replace("\"", "\\\"")), "hash6"),
   1150       Cmd("git svn find-rev hash6", "1324"),
   1151       Cmd(("svn copy -r 1324 https://v8.googlecode.com/svn/trunk "
   1152            "https://v8.googlecode.com/svn/tags/3.22.5.1 -m "
   1153            "\"Tagging version 3.22.5.1\""), ""),
   1154       Cmd("git checkout -f some_branch", ""),
   1155       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
   1156     ])
   1157 
   1158     # r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
   1159     # ports of r12345. r56789 is the MIPS port of r34567.
   1160     args = ["-f", "-p", extra_patch, "--branch", "trunk", "12345", "23456",
   1161             "34567"]
   1162 
   1163     # The first run of the script stops because of the svn being down.
   1164     self.assertRaises(GitFailedException,
   1165         lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
   1166 
   1167     # Test that state recovery after restarting the script works.
   1168     args += ["-s", "3"]
   1169     MergeToBranch(TEST_CONFIG, self).Run(args)
   1170 
   1171   def testReleases(self):
   1172     tag_response_text = """
   1173 ------------------------------------------------------------------------
   1174 r22631 | author1 (at] chromium.org | 2014-07-28 02:05:29 +0200 (Mon, 28 Jul 2014)
   1175 Changed paths:
   1176    A /tags/3.28.43 (from /trunk:22630)
   1177 
   1178 Tagging version 3.28.43
   1179 ------------------------------------------------------------------------
   1180 r22629 | author2 (at] chromium.org | 2014-07-26 05:09:29 +0200 (Sat, 26 Jul 2014)
   1181 Changed paths:
   1182    A /tags/3.28.41 (from /branches/bleeding_edge:22626)
   1183 
   1184 Tagging version 3.28.41
   1185 ------------------------------------------------------------------------
   1186 r22556 | author3 (at] chromium.org | 2014-07-23 13:31:59 +0200 (Wed, 23 Jul 2014)
   1187 Changed paths:
   1188    A /tags/3.27.34.7 (from /branches/3.27:22555)
   1189 
   1190 Tagging version 3.27.34.7
   1191 ------------------------------------------------------------------------
   1192 r22627 | author4 (at] chromium.org | 2014-07-26 01:39:15 +0200 (Sat, 26 Jul 2014)
   1193 Changed paths:
   1194    A /tags/3.28.40 (from /branches/bleeding_edge:22624)
   1195 
   1196 Tagging version 3.28.40
   1197 ------------------------------------------------------------------------
   1198 """
   1199     c_hash2_commit_log = """Revert something.
   1200 
   1201 BUG=12345
   1202 
   1203 Reason:
   1204 > Some reason.
   1205 > Cr-Commit-Position: refs/heads/master@{#12345}
   1206 > git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12345 003-1c4
   1207 
   1208 Review URL: https://codereview.chromium.org/12345
   1209 
   1210 Cr-Commit-Position: refs/heads/master@{#4567}
   1211 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4567 0039-1c4b
   1212 
   1213 """
   1214     c_hash3_commit_log = """Simple.
   1215 
   1216 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b
   1217 
   1218 """
   1219     json_output = self.MakeEmptyTempFile()
   1220     csv_output = self.MakeEmptyTempFile()
   1221     self.WriteFakeVersionFile()
   1222 
   1223     TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
   1224     chrome_dir = TEST_CONFIG["CHROMIUM"]
   1225     chrome_v8_dir = os.path.join(chrome_dir, "v8")
   1226     os.makedirs(chrome_v8_dir)
   1227     def WriteDEPS(revision):
   1228       TextToFile("Line\n   \"v8_revision\": \"%s\",\n  line\n" % revision,
   1229                  os.path.join(chrome_dir, "DEPS"))
   1230     WriteDEPS(567)
   1231 
   1232     def ResetVersion(minor, build, patch=0):
   1233       return lambda: self.WriteFakeVersionFile(minor=minor,
   1234                                                build=build,
   1235                                                patch=patch)
   1236 
   1237     def ResetDEPS(revision):
   1238       return lambda: WriteDEPS(revision)
   1239 
   1240     self.Expect([
   1241       Cmd("git status -s -uno", ""),
   1242       Cmd("git status -s -b -uno", "## some_branch\n"),
   1243       Cmd("git svn fetch", ""),
   1244       Cmd("git branch", "  branch1\n* branch2\n"),
   1245       Cmd("git checkout -b %s" % TEST_CONFIG["BRANCHNAME"], ""),
   1246       Cmd("git branch -r", "  svn/3.21\n  svn/3.3\n"),
   1247       Cmd("git reset --hard svn/3.3", ""),
   1248       Cmd("git log --format=%H", "hash1\nhash2"),
   1249       Cmd("git diff --name-only hash1 hash1^", ""),
   1250       Cmd("git diff --name-only hash2 hash2^", VERSION_FILE),
   1251       Cmd("git checkout -f hash2 -- %s" % VERSION_FILE, "",
   1252           cb=ResetVersion(3, 1, 1)),
   1253       Cmd("git log -1 --format=%B hash2",
   1254           "Version 3.3.1.1 (merged 12)\n\nReview URL: fake.com\n"),
   1255       Cmd("git log -1 --format=%s hash2", ""),
   1256       Cmd("git svn find-rev hash2", "234"),
   1257       Cmd("git log -1 --format=%ci hash2", "18:15"),
   1258       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
   1259           cb=ResetVersion(22, 5)),
   1260       Cmd("git reset --hard svn/3.21", ""),
   1261       Cmd("git log --format=%H", "hash3\nhash4\nhash5\n"),
   1262       Cmd("git diff --name-only hash3 hash3^", VERSION_FILE),
   1263       Cmd("git checkout -f hash3 -- %s" % VERSION_FILE, "",
   1264           cb=ResetVersion(21, 2)),
   1265       Cmd("git log -1 --format=%B hash3", ""),
   1266       Cmd("git log -1 --format=%s hash3", ""),
   1267       Cmd("git svn find-rev hash3", "123"),
   1268       Cmd("git log -1 --format=%ci hash3", "03:15"),
   1269       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
   1270           cb=ResetVersion(22, 5)),
   1271       Cmd("git reset --hard svn/trunk", ""),
   1272       Cmd("git log --format=%H", "hash6\n"),
   1273       Cmd("git diff --name-only hash6 hash6^", VERSION_FILE),
   1274       Cmd("git checkout -f hash6 -- %s" % VERSION_FILE, "",
   1275           cb=ResetVersion(22, 3)),
   1276       Cmd("git log -1 --format=%B hash6", ""),
   1277       Cmd("git log -1 --format=%s hash6", ""),
   1278       Cmd("git svn find-rev hash6", "345"),
   1279       Cmd("git log -1 --format=%ci hash6", ""),
   1280       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
   1281           cb=ResetVersion(22, 5)),
   1282       Cmd("git reset --hard svn/bleeding_edge", ""),
   1283       Cmd("svn log https://v8.googlecode.com/svn/tags -v --limit 20",
   1284           tag_response_text),
   1285       Cmd("git svn find-rev r22626", "hash_22626"),
   1286       Cmd("git svn find-rev hash_22626", "22626"),
   1287       Cmd("git log -1 --format=%ci hash_22626", "01:23"),
   1288       Cmd("git svn find-rev r22624", "hash_22624"),
   1289       Cmd("git svn find-rev hash_22624", "22624"),
   1290       Cmd("git log -1 --format=%ci hash_22624", "02:34"),
   1291       Cmd("git status -s -uno", "", cwd=chrome_dir),
   1292       Cmd("git checkout -f master", "", cwd=chrome_dir),
   1293       Cmd("git pull", "", cwd=chrome_dir),
   1294       Cmd("git checkout -b %s" % TEST_CONFIG["BRANCHNAME"], "", cwd=chrome_dir),
   1295       Cmd("git fetch origin", "", cwd=chrome_v8_dir),
   1296       Cmd("git log --format=%H --grep=\"V8\"", "c_hash1\nc_hash2\nc_hash3\n",
   1297           cwd=chrome_dir),
   1298       Cmd("git diff --name-only c_hash1 c_hash1^", "", cwd=chrome_dir),
   1299       Cmd("git diff --name-only c_hash2 c_hash2^", "DEPS", cwd=chrome_dir),
   1300       Cmd("git checkout -f c_hash2 -- DEPS", "",
   1301           cb=ResetDEPS("0123456789012345678901234567890123456789"),
   1302           cwd=chrome_dir),
   1303       Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log,
   1304           cwd=chrome_dir),
   1305       Cmd("git rev-list -n 1 0123456789012345678901234567890123456789",
   1306           "0123456789012345678901234567890123456789", cwd=chrome_v8_dir),
   1307       Cmd("git log -1 --format=%B 0123456789012345678901234567890123456789",
   1308           self.C_V8_22624_LOG, cwd=chrome_v8_dir),
   1309       Cmd("git diff --name-only c_hash3 c_hash3^", "DEPS", cwd=chrome_dir),
   1310       Cmd("git checkout -f c_hash3 -- DEPS", "", cb=ResetDEPS(345),
   1311           cwd=chrome_dir),
   1312       Cmd("git log -1 --format=%B c_hash3", c_hash3_commit_log,
   1313           cwd=chrome_dir),
   1314       Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS(567),
   1315           cwd=chrome_dir),
   1316       Cmd("git branch -r", " weird/123\n  branch-heads/7\n", cwd=chrome_dir),
   1317       Cmd("git checkout -f branch-heads/7 -- DEPS", "", cb=ResetDEPS(345),
   1318           cwd=chrome_dir),
   1319       Cmd("git checkout -f HEAD -- DEPS", "", cb=ResetDEPS(567),
   1320           cwd=chrome_dir),
   1321       Cmd("git checkout -f master", "", cwd=chrome_dir),
   1322       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], "", cwd=chrome_dir),
   1323       Cmd("git checkout -f some_branch", ""),
   1324       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
   1325     ])
   1326 
   1327     args = ["-c", TEST_CONFIG["CHROMIUM"],
   1328             "--json", json_output,
   1329             "--csv", csv_output,
   1330             "--max-releases", "1"]
   1331     Releases(TEST_CONFIG, self).Run(args)
   1332 
   1333     # Check expected output.
   1334     csv = ("3.28.41,bleeding_edge,22626,,\r\n"
   1335            "3.28.40,bleeding_edge,22624,4567,\r\n"
   1336            "3.22.3,trunk,345,3456:4566,\r\n"
   1337            "3.21.2,3.21,123,,\r\n"
   1338            "3.3.1.1,3.3,234,,12\r\n")
   1339     self.assertEquals(csv, FileToText(csv_output))
   1340 
   1341     expected_json = [
   1342       {"bleeding_edge": "22626", "patches_merged": "", "version": "3.28.41",
   1343        "chromium_revision": "", "branch": "bleeding_edge", "revision": "22626",
   1344        "review_link": "", "date": "01:23", "chromium_branch": "",
   1345        "revision_link": "https://code.google.com/p/v8/source/detail?r=22626"},
   1346       {"bleeding_edge": "22624", "patches_merged": "", "version": "3.28.40",
   1347        "chromium_revision": "4567", "branch": "bleeding_edge",
   1348        "revision": "22624", "review_link": "", "date": "02:34",
   1349        "chromium_branch": "",
   1350        "revision_link": "https://code.google.com/p/v8/source/detail?r=22624"},
   1351       {"bleeding_edge": "", "patches_merged": "", "version": "3.22.3",
   1352        "chromium_revision": "3456:4566", "branch": "trunk", "revision": "345",
   1353        "review_link": "", "date": "", "chromium_branch": "7",
   1354        "revision_link": "https://code.google.com/p/v8/source/detail?r=345"},
   1355       {"patches_merged": "", "bleeding_edge": "", "version": "3.21.2",
   1356        "chromium_revision": "", "branch": "3.21", "revision": "123",
   1357        "review_link": "", "date": "03:15", "chromium_branch": "",
   1358        "revision_link": "https://code.google.com/p/v8/source/detail?r=123"},
   1359       {"patches_merged": "12", "bleeding_edge": "", "version": "3.3.1.1",
   1360        "chromium_revision": "", "branch": "3.3", "revision": "234",
   1361        "review_link": "fake.com", "date": "18:15", "chromium_branch": "",
   1362        "revision_link": "https://code.google.com/p/v8/source/detail?r=234"},
   1363     ]
   1364     self.assertEquals(expected_json, json.loads(FileToText(json_output)))
   1365 
   1366 
   1367   def _bumpUpVersion(self):
   1368     self.WriteFakeVersionFile()
   1369 
   1370     def ResetVersion(minor, build, patch=0):
   1371       return lambda: self.WriteFakeVersionFile(minor=minor,
   1372                                                build=build,
   1373                                                patch=patch)
   1374 
   1375     return [
   1376       Cmd("git status -s -uno", ""),
   1377       Cmd("git checkout -f bleeding_edge", "", cb=ResetVersion(11, 4)),
   1378       Cmd("git pull", ""),
   1379       Cmd("git branch", ""),
   1380       Cmd("git checkout -f bleeding_edge", ""),
   1381       Cmd("git log -1 --format=%H", "latest_hash"),
   1382       Cmd("git diff --name-only latest_hash latest_hash^", ""),
   1383       URL("https://v8-status.appspot.com/lkgr", "12345"),
   1384       Cmd("git checkout -f bleeding_edge", ""),
   1385       Cmd(("git log --format=%H --grep="
   1386            "\"^git-svn-id: [^@]*@12345 [A-Za-z0-9-]*$\""),
   1387           "lkgr_hash"),
   1388       Cmd("git checkout -b auto-bump-up-version lkgr_hash", ""),
   1389       Cmd("git checkout -f bleeding_edge", ""),
   1390       Cmd("git branch", ""),
   1391       Cmd("git diff --name-only lkgr_hash lkgr_hash^", ""),
   1392       Cmd("git checkout -f master", "", cb=ResetVersion(11, 5)),
   1393       Cmd("git pull", ""),
   1394       URL("https://v8-status.appspot.com/current?format=json",
   1395           "{\"message\": \"Tree is open\"}"),
   1396       Cmd("git checkout -b auto-bump-up-version bleeding_edge", "",
   1397           cb=ResetVersion(11, 4)),
   1398       Cmd("git commit -am \"[Auto-roll] Bump up version to 3.11.6.0\n\n"
   1399           "TBR=author (at] chromium.org\" "
   1400           "--author \"author (at] chromium.org <author (at] chromium.org>\"", ""),
   1401     ]
   1402 
   1403   def testBumpUpVersionGit(self):
   1404     expectations = self._bumpUpVersion()
   1405     expectations += [
   1406       Cmd("git cl upload --send-mail --email \"author (at] chromium.org\" -f "
   1407           "--bypass-hooks", ""),
   1408       Cmd("git cl dcommit -f --bypass-hooks", ""),
   1409       Cmd("git checkout -f bleeding_edge", ""),
   1410       Cmd("git branch", "auto-bump-up-version\n* bleeding_edge"),
   1411       Cmd("git branch -D auto-bump-up-version", ""),
   1412     ]
   1413     self.Expect(expectations)
   1414 
   1415     BumpUpVersion(TEST_CONFIG, self).Run(["-a", "author (at] chromium.org"])
   1416 
   1417   def testBumpUpVersionSvn(self):
   1418     svn_root = self.MakeEmptyTempDirectory()
   1419     expectations = self._bumpUpVersion()
   1420     expectations += [
   1421       Cmd("git diff HEAD^ HEAD", "patch content"),
   1422       Cmd("svn update", "", cwd=svn_root),
   1423       Cmd("svn status", "", cwd=svn_root),
   1424       Cmd("patch -d branches/bleeding_edge -p1 -i %s" %
   1425           TEST_CONFIG["PATCH_FILE"], "Applied patch...", cwd=svn_root),
   1426       Cmd("svn commit --non-interactive --username=author (at] chromium.org "
   1427           "--config-dir=[CONFIG_DIR] "
   1428           "-m \"[Auto-roll] Bump up version to 3.11.6.0\"",
   1429           "", cwd=svn_root),
   1430       Cmd("git checkout -f bleeding_edge", ""),
   1431       Cmd("git branch", "auto-bump-up-version\n* bleeding_edge"),
   1432       Cmd("git branch -D auto-bump-up-version", ""),
   1433     ]
   1434     self.Expect(expectations)
   1435 
   1436     BumpUpVersion(TEST_CONFIG, self).Run(
   1437         ["-a", "author (at] chromium.org",
   1438          "--svn", svn_root,
   1439          "--svn-config", "[CONFIG_DIR]"])
   1440 
   1441   def testAutoTag(self):
   1442     self.WriteFakeVersionFile()
   1443 
   1444     def ResetVersion(minor, build, patch=0):
   1445       return lambda: self.WriteFakeVersionFile(minor=minor,
   1446                                                build=build,
   1447                                                patch=patch)
   1448 
   1449     self.Expect([
   1450       Cmd("git status -s -uno", ""),
   1451       Cmd("git status -s -b -uno", "## some_branch\n"),
   1452       Cmd("git svn fetch", ""),
   1453       Cmd("git branch", "  branch1\n* branch2\n"),
   1454       Cmd("git checkout -f master", ""),
   1455       Cmd("git svn rebase", ""),
   1456       Cmd("git checkout -b %s" % TEST_CONFIG["BRANCHNAME"], "",
   1457           cb=ResetVersion(4, 5)),
   1458       Cmd("git branch -r",
   1459           "svn/tags/3.4.2\nsvn/tags/3.2.1.0\nsvn/branches/3.4"),
   1460       Cmd(("git log --format=%H --grep="
   1461            "\"\\[Auto\\-roll\\] Bump up version to\""),
   1462           "hash125\nhash118\nhash111\nhash101"),
   1463       Cmd("git checkout -f hash125 -- %s" % VERSION_FILE, "",
   1464           cb=ResetVersion(4, 4)),
   1465       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
   1466           cb=ResetVersion(4, 5)),
   1467       Cmd("git checkout -f hash118 -- %s" % VERSION_FILE, "",
   1468           cb=ResetVersion(4, 3)),
   1469       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
   1470           cb=ResetVersion(4, 5)),
   1471       Cmd("git checkout -f hash111 -- %s" % VERSION_FILE, "",
   1472           cb=ResetVersion(4, 2)),
   1473       Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
   1474           cb=ResetVersion(4, 5)),
   1475       URL("https://v8-status.appspot.com/revisions?format=json",
   1476           "[{\"revision\": \"126\", \"status\": true},"
   1477            "{\"revision\": \"123\", \"status\": true},"
   1478            "{\"revision\": \"112\", \"status\": true}]"),
   1479       Cmd("git svn find-rev hash118", "118"),
   1480       Cmd("git svn find-rev hash125", "125"),
   1481       Cmd("git svn find-rev r123", "hash123"),
   1482       Cmd("git log -1 --format=%at hash123", "1"),
   1483       Cmd("git reset --hard hash123", ""),
   1484       Cmd("git svn tag 3.4.3 -m \"Tagging version 3.4.3\"", ""),
   1485       Cmd("git checkout -f some_branch", ""),
   1486       Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
   1487     ])
   1488 
   1489     AutoTag(TEST_CONFIG, self).Run(["-a", "author (at] chromium.org"])
   1490 
   1491   # Test that we bail out if the last change was a version change.
   1492   def testBumpUpVersionBailout1(self):
   1493     self._state["latest"] = "latest_hash"
   1494 
   1495     self.Expect([
   1496       Cmd("git diff --name-only latest_hash latest_hash^", VERSION_FILE),
   1497     ])
   1498 
   1499     self.assertEquals(0,
   1500         self.RunStep(BumpUpVersion, LastChangeBailout, ["--dry_run"]))
   1501 
   1502   # Test that we bail out if the lkgr was a version change.
   1503   def testBumpUpVersionBailout2(self):
   1504     self._state["lkgr"] = "lkgr_hash"
   1505 
   1506     self.Expect([
   1507       Cmd("git diff --name-only lkgr_hash lkgr_hash^", VERSION_FILE),
   1508     ])
   1509 
   1510     self.assertEquals(0,
   1511         self.RunStep(BumpUpVersion, LKGRVersionUpToDateBailout, ["--dry_run"]))
   1512 
   1513   # Test that we bail out if the last version is already newer than the lkgr's
   1514   # version.
   1515   def testBumpUpVersionBailout3(self):
   1516     self._state["lkgr"] = "lkgr_hash"
   1517     self._state["lkgr_version"] = "3.22.4.0"
   1518     self._state["latest_version"] = "3.22.5.0"
   1519 
   1520     self.Expect([
   1521       Cmd("git diff --name-only lkgr_hash lkgr_hash^", ""),
   1522     ])
   1523 
   1524     self.assertEquals(0,
   1525         self.RunStep(BumpUpVersion, LKGRVersionUpToDateBailout, ["--dry_run"]))
   1526 
   1527 
   1528 class SystemTest(unittest.TestCase):
   1529   def testReload(self):
   1530     step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
   1531                     side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER)
   1532     body = step.Reload(
   1533 """------------------------------------------------------------------------
   1534 r17997 | machenbach (at] chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines
   1535 
   1536 Prepare push to trunk.  Now working on version 3.23.11.
   1537 
   1538 R=danno (at] chromium.org
   1539 
   1540 Review URL: https://codereview.chromium.org/83173002
   1541 
   1542 ------------------------------------------------------------------------""")
   1543     self.assertEquals(
   1544 """Prepare push to trunk.  Now working on version 3.23.11.
   1545 
   1546 R=danno (at] chromium.org
   1547 
   1548 Committed: https://code.google.com/p/v8/source/detail?r=17997""", body)
   1549