test_scripts.py 58.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#!/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
30
import shutil
31
import tempfile
32
import traceback
33 34
import unittest

35
import auto_push
36
from auto_push import LastReleaseBailout
37
import auto_roll
38 39
import common_includes
from common_includes import *
40 41
import create_release
from create_release import CreateRelease
42 43
import merge_to_branch
from merge_to_branch import *
44 45
import push_to_candidates
from push_to_candidates import *
46 47
import chromium_roll
from chromium_roll import ChromiumRoll
48 49
import releases
from releases import Releases
50
from auto_tag import AutoTag
51 52 53


TEST_CONFIG = {
54
  "DEFAULT_CWD": None,
55
  "BRANCHNAME": "test-prepare-push",
machenbach's avatar
machenbach committed
56 57 58 59 60 61 62
  "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",
63 64
  "SETTINGS_LOCATION": None,
  "ALREADY_MERGING_SENTINEL_FILE":
65
      "/tmp/test-merge-to-branch-tempfile-already-merging",
66
  "TEMPORARY_PATCH_FILE": "/tmp/test-merge-to-branch-tempfile-temporary-patch",
67 68
}

69

70
AUTO_PUSH_ARGS = [
71 72 73 74
  "-a", "author@chromium.org",
  "-r", "reviewer@chromium.org",
]

75

76
class ToplevelTest(unittest.TestCase):
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
  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",
105
                       "3": "91:93, 98:99"},
106 107 108
                      B([["101", "13"], ["100", "12"], ["98", "3"],
                         ["94", "9"], ["91", "3"]]))

109 110 111 112 113 114 115 116 117 118 119 120
  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 #"))

121
  def testMakeChangeLogBodySimple(self):
122
    commits = [
123
          ["Title text 1",
124
           "Title text 1\n\nBUG=\n",
125
           "author1@chromium.org"],
126
          ["Title text 2.",
127
           "Title text 2\n\nBUG=1234\n",
128
           "author2@chromium.org"],
129
        ]
130
    self.assertEquals("        Title text 1.\n"
131
                      "        (author1@chromium.org)\n\n"
132
                      "        Title text 2 (Chromium issue 1234).\n"
133
                      "        (author2@chromium.org)\n\n",
134 135 136
                      MakeChangeLogBody(commits))

  def testMakeChangeLogBodyEmpty(self):
137 138 139 140
    self.assertEquals("", MakeChangeLogBody([]))

  def testMakeChangeLogBodyAutoFormat(self):
    commits = [
141
          ["Title text 1!",
142
           "Title text 1\nLOG=y\nBUG=\n",
143 144
           "author1@chromium.org"],
          ["Title text 2",
145
           "Title text 2\n\nBUG=1234\n",
146 147
           "author2@chromium.org"],
          ["Title text 3",
148
           "Title text 3\n\nBUG=1234\nLOG = Yes\n",
149 150
           "author3@chromium.org"],
          ["Title text 3",
151
           "Title text 4\n\nBUG=1234\nLOG=\n",
152
           "author4@chromium.org"],
153
        ]
154 155
    self.assertEquals("        Title text 1.\n\n"
                      "        Title text 3 (Chromium issue 1234).\n\n",
156
                      MakeChangeLogBody(commits, True))
157

158 159 160 161 162 163 164 165 166 167 168
  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))

169 170 171 172 173 174 175
  def testMakeChangeLogBugReferenceEmpty(self):
    self.assertEquals("", MakeChangeLogBugReference(""))
    self.assertEquals("", MakeChangeLogBugReference("LOG="))
    self.assertEquals("", MakeChangeLogBugReference(" BUG ="))
    self.assertEquals("", MakeChangeLogBugReference("BUG=none\t"))

  def testMakeChangeLogBugReferenceSimple(self):
176
    self.assertEquals("(issue 987654)",
177
                      MakeChangeLogBugReference("BUG = v8:987654"))
178
    self.assertEquals("(Chromium issue 987654)",
179 180 181
                      MakeChangeLogBugReference("BUG=987654 "))

  def testMakeChangeLogBugReferenceFromBody(self):
182
    self.assertEquals("(Chromium issue 1234567)",
183 184 185 186 187 188 189
                      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.
190
    self.assertEquals("(issues 123, 234, Chromium issue 345)",
191 192 193 194 195
                      MakeChangeLogBugReference("Title\n\n"
                                                "BUG=v8:234\n"
                                                "  BUG\t= 345, \tv8:234,\n"
                                                "BUG=v8:123\n"
                                                "R=somebody\n"))
196
    self.assertEquals("(Chromium issues 123, 234)",
197 198 199
                      MakeChangeLogBugReference("Title\n\n"
                                                "BUG=234,,chromium:123 \n"
                                                "R=somebody\n"))
200
    self.assertEquals("(Chromium issues 123, 234)",
201 202 203
                      MakeChangeLogBugReference("Title\n\n"
                                                "BUG=chromium:234, , 123\n"
                                                "R=somebody\n"))
204
    self.assertEquals("(issues 345, 456)",
205 206 207
                      MakeChangeLogBugReference("Title\n\n"
                                                "\t\tBUG=v8:345,v8:456\n"
                                                "R=somebody\n"))
208
    self.assertEquals("(issue 123, Chromium issues 345, 456)",
209 210 211 212 213 214
                      MakeChangeLogBugReference("Title\n\n"
                                                "BUG=chromium:456\n"
                                                "BUG = none\n"
                                                "R=somebody\n"
                                                "BUG=456,v8:123, 345"))

215 216
  # TODO(machenbach): These test don't make much sense when the formatting is
  # done later.
217 218
  def testMakeChangeLogBugReferenceLong(self):
    # -----------------00--------10--------20--------30--------
219 220 221
    self.assertEquals("(issues 234, 1234567890, 1234567"
                      "8901234567890, Chromium issues 12345678,"
                      " 123456789)",
222 223 224 225 226 227
                      MakeChangeLogBugReference("BUG=v8:234\n"
                                                "BUG=v8:1234567890\n"
                                                "BUG=v8:12345678901234567890\n"
                                                "BUG=123456789\n"
                                                "BUG=12345678\n"))
    # -----------------00--------10--------20--------30--------
228 229 230
    self.assertEquals("(issues 234, 1234567890, 1234567"
                      "8901234567890, Chromium issues"
                      " 123456789, 1234567890)",
231 232 233 234 235 236
                      MakeChangeLogBugReference("BUG=v8:234\n"
                                                "BUG=v8:12345678901234567890\n"
                                                "BUG=v8:1234567890\n"
                                                "BUG=123456789\n"
                                                "BUG=1234567890\n"))
    # -----------------00--------10--------20--------30--------
237 238 239
    self.assertEquals("(Chromium issues 234, 1234567890"
                      ", 12345678901234567, "
                      "1234567890123456789)",
240 241 242 243 244
                      MakeChangeLogBugReference("BUG=234\n"
                                                "BUG=12345678901234567\n"
                                                "BUG=1234567890123456789\n"
                                                "BUG=1234567890\n"))

245

246
def Cmd(*args, **kwargs):
247
  """Convenience function returning a shell command test expectation."""
248
  return {
249
    "name": "command",
250
    "args": args,
251 252
    "ret": args[-1],
    "cb": kwargs.get("cb"),
253
    "cwd": kwargs.get("cwd", TEST_CONFIG["DEFAULT_CWD"]),
254 255 256 257 258
  }


def RL(text, cb=None):
  """Convenience function returning a readline test expectation."""
259 260 261 262 263 264 265
  return {
    "name": "readline",
    "args": [],
    "ret": text,
    "cb": cb,
    "cwd": None,
  }
266 267 268 269 270 271 272 273 274


def URL(*args, **kwargs):
  """Convenience function returning a readurl test expectation."""
  return {
    "name": "readurl",
    "args": args[:-1],
    "ret": args[-1],
    "cb": kwargs.get("cb"),
275
    "cwd": None,
276 277 278
  }


279
class SimpleMock(object):
280
  def __init__(self):
281 282 283 284 285 286
    self._recipe = []
    self._index = -1

  def Expect(self, recipe):
    self._recipe = recipe

287
  def Call(self, name, *args, **kwargs):  # pragma: no cover
288 289 290 291
    self._index += 1
    try:
      expected_call = self._recipe[self._index]
    except IndexError:
292
      raise NoRetryException("Calling %s %s" % (name, " ".join(args)))
293 294

    if not isinstance(expected_call, dict):
295 296
      raise NoRetryException("Found wrong expectation type for %s %s" %
                             (name, " ".join(args)))
297

298 299 300
    if expected_call["name"] != name:
      raise NoRetryException("Expected action: %s %s - Actual: %s" %
          (expected_call["name"], expected_call["args"], name))
301

302 303 304 305 306 307 308 309
    # 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")))

310 311
    # The number of arguments in the expectation must match the actual
    # arguments.
312
    if len(args) > len(expected_call['args']):
313
      raise NoRetryException("When calling %s with arguments, the "
314
          "expectations must consist of at least as many arguments." %
315
          name)
316 317

    # Compare expected and actual arguments.
318
    for (expected_arg, actual_arg) in zip(expected_call['args'], args):
319
      if expected_arg != actual_arg:
320 321
        raise NoRetryException("Expected: %s - Actual: %s" %
                               (expected_arg, actual_arg))
322

323 324 325
    # The expected call contains an optional callback for checking the context
    # at the time of the call.
    if expected_call['cb']:
326
      try:
327
        expected_call['cb']()
328 329 330
      except:
        tb = traceback.format_exc()
        raise NoRetryException("Caught exception from callback: %s" % tb)
331 332

    # If the return value is an exception, raise it instead of returning.
333 334 335
    if isinstance(expected_call['ret'], Exception):
      raise expected_call['ret']
    return expected_call['ret']
336

337
  def AssertFinished(self):  # pragma: no cover
338
    if self._index < len(self._recipe) -1:
339 340
      raise NoRetryException("Called mock too seldom: %d vs. %d" %
                             (self._index, len(self._recipe)))
341 342


343 344 345 346 347 348 349
class ScriptTest(unittest.TestCase):
  def MakeEmptyTempFile(self):
    handle, name = tempfile.mkstemp()
    os.close(handle)
    self._tmp_files.append(name)
    return name

350 351 352 353 354 355
  def MakeEmptyTempDirectory(self):
    name = tempfile.mkdtemp()
    self._tmp_files.append(name)
    return name


356
  def WriteFakeVersionFile(self, major=3, minor=22, build=4, patch=0):
357 358 359 360
    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:
361 362
      f.write("  // Some line...\n")
      f.write("\n")
363 364 365 366
      f.write("#define V8_MAJOR_VERSION    %s\n" % major)
      f.write("#define V8_MINOR_VERSION    %s\n" % minor)
      f.write("#define V8_BUILD_NUMBER     %s\n" % build)
      f.write("#define V8_PATCH_LEVEL      %s\n" % patch)
367
      f.write("  // Some line...\n")
368
      f.write("#define V8_IS_CANDIDATE_VERSION 0\n")
369

370 371 372 373 374 375 376
  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)

machenbach's avatar
machenbach committed
377
  def RunStep(self, script=PushToCandidates, step_class=Step, args=None):
378
    """Convenience wrapper."""
379
    args = args if args is not None else ["-m"]
380
    return script(TEST_CONFIG, self, self._state).RunSteps([step_class], args)
381

382 383 384
  def Call(self, fun, *args, **kwargs):
    print "Calling %s with %s and %s" % (str(fun), str(args), str(kwargs))

385
  def Command(self, cmd, args="", prefix="", pipe=True, cwd=None):
386
    print "%s %s" % (cmd, args)
387 388
    print "in %s" % cwd
    return self._mock.Call("command", cmd + " " + args, cwd=cwd)
389 390

  def ReadLine(self):
391
    return self._mock.Call("readline")
392

393 394
  def ReadURL(self, url, params):
    if params is not None:
395
      return self._mock.Call("readurl", url, params)
396
    else:
397
      return self._mock.Call("readurl", url)
398

399 400 401
  def Sleep(self, seconds):
    pass

402 403 404
  def GetDate(self):
    return "1999-07-31"

405
  def GetUTCStamp(self):
406
    return "1000000"
407

408
  def Expect(self, *args):
409
    """Convenience wrapper."""
410
    self._mock.Expect(*args)
411 412

  def setUp(self):
413
    self._mock = SimpleMock()
414
    self._tmp_files = []
415
    self._state = {}
416
    TEST_CONFIG["DEFAULT_CWD"] = self.MakeEmptyTempDirectory()
417 418

  def tearDown(self):
419 420
    if os.path.exists(TEST_CONFIG["PERSISTFILE_BASENAME"]):
      shutil.rmtree(TEST_CONFIG["PERSISTFILE_BASENAME"])
421 422 423

    # Clean up temps. Doesn't work automatically.
    for name in self._tmp_files:
424
      if os.path.isfile(name):
425
        os.remove(name)
426 427
      if os.path.isdir(name):
        shutil.rmtree(name)
428

429
    self._mock.AssertFinished()
430 431

  def testGitMock(self):
432 433
    self.Expect([Cmd("git --version", "git version 1.2.3"),
                 Cmd("git dummy", "")])
434 435 436 437
    self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
    self.assertEquals("", self.MakeStep().Git("dummy"))

  def testCommonPrepareDefault(self):
438
    self.Expect([
439
      Cmd("git status -s -uno", ""),
440
      Cmd("git checkout -f origin/master", ""),
441
      Cmd("git fetch", ""),
442
      Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
443
      RL("Y"),
444
      Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
445
    ])
446
    self.MakeStep().CommonPrepare()
447
    self.MakeStep().PrepareBranch()
448 449

  def testCommonPrepareNoConfirm(self):
450
    self.Expect([
451
      Cmd("git status -s -uno", ""),
452
      Cmd("git checkout -f origin/master", ""),
453
      Cmd("git fetch", ""),
454
      Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
455
      RL("n"),
456
    ])
457 458
    self.MakeStep().CommonPrepare()
    self.assertRaises(Exception, self.MakeStep().PrepareBranch)
459 460

  def testCommonPrepareDeleteBranchFailure(self):
461
    self.Expect([
462
      Cmd("git status -s -uno", ""),
463
      Cmd("git checkout -f origin/master", ""),
464
      Cmd("git fetch", ""),
465
      Cmd("git branch", "  branch1\n* %s" % TEST_CONFIG["BRANCHNAME"]),
466
      RL("Y"),
467
      Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], None),
468
    ])
469 470
    self.MakeStep().CommonPrepare()
    self.assertRaises(Exception, self.MakeStep().PrepareBranch)
471 472

  def testInitialEnvironmentChecks(self):
473
    TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
474
    os.environ["EDITOR"] = "vi"
475 476 477
    self.Expect([
      Cmd("which vi", "/usr/bin/vi"),
    ])
478
    self.MakeStep().InitialEnvironmentChecks(TEST_CONFIG["DEFAULT_CWD"])
479

480 481 482 483 484 485 486 487 488 489 490
  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", ""),
    ])
491
    args = ["--branch", "candidates", "ab12345"]
492 493 494 495 496
    self._state["version"] = "tag_name"
    self._state["commit_title"] = "Title"
    self.assertRaises(Exception,
        lambda: self.RunStep(MergeToBranch, TagRevision, args))

497
  def testReadAndPersistVersion(self):
498
    self.WriteFakeVersionFile(build=5)
499 500
    step = self.MakeStep()
    step.ReadAndPersistVersion()
501 502 503 504
    self.assertEquals("3", step["major"])
    self.assertEquals("22", step["minor"])
    self.assertEquals("5", step["build"])
    self.assertEquals("0", step["patch"])
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521

  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)

522 523
    self.assertEqual("//\n#define V8_BUILD_NUMBER  3\n",
                     MSub(r"(?<=#define V8_BUILD_NUMBER)(?P<space>\s+)\d*$",
524
                          r"\g<space>3",
525
                          "//\n#define V8_BUILD_NUMBER  321\n"))
526

527 528
  def testPreparePushRevision(self):
    # Tests the default push hash used when the --revision option is not set.
529
    self.Expect([
530
      Cmd("git log -1 --format=%H HEAD", "push_hash")
531 532
    ])

machenbach's avatar
machenbach committed
533
    self.RunStep(PushToCandidates, PreparePushRevision)
534 535
    self.assertEquals("push_hash", self._state["push_hash"])

536
  def testPrepareChangeLog(self):
537
    self.WriteFakeVersionFile()
538
    TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
539

540
    self.Expect([
541 542 543 544 545 546 547 548 549 550 551 552
      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",
553
       ("Title\n\nBUG=456\nLOG=Y\n\n"
554 555 556
        "Review URL: https://codereview.chromium.org/9876543210\n")),
      URL("https://codereview.chromium.org/9876543210/description",
          "Title\n\nBUG=456\nLOG=N\n\n"),
557
      Cmd("git log -1 --format=%an rev4", "author4@chromium.org"),
558
    ])
559

machenbach's avatar
machenbach committed
560
    self._state["last_push_master"] = "1234"
561
    self._state["push_hash"] = "push_hash"
562
    self._state["version"] = "3.22.5"
machenbach's avatar
machenbach committed
563
    self.RunStep(PushToCandidates, PrepareChangeLog)
564

565
    actual_cl = FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
566

567
    expected_cl = """1999-07-31: Version 3.22.5
568

569
        Title text 1.
570

571
        Title text 3 (Chromium issue 321).
572

573
        Performance and stability improvements on all platforms.
574
#
575 576 577
# 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.
578
#
579
#       Title text 1.
580
#       (author1@chromium.org)
581
#
582 583
#       Title text 2 (Chromium issue 123).
#       (author2@chromium.org)
584
#
585 586
#       Title text 3 (Chromium issue 321).
#       (author3@chromium.org)
587
#
588 589
#       Title text 4 (Chromium issue 456).
#       (author4@chromium.org)
590
#
591 592
#"""

593
    self.assertEquals(expected_cl, actual_cl)
594 595

  def testEditChangeLog(self):
596 597
    TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
    TextToFile("  New  \n\tLines  \n", TEST_CONFIG["CHANGELOG_ENTRY_FILE"])
598
    os.environ["EDITOR"] = "vi"
599
    self.Expect([
600
      RL(""),  # Open editor.
601
      Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""),
602
    ])
603

machenbach's avatar
machenbach committed
604
    self.RunStep(PushToCandidates, EditChangeLog)
605

606
    self.assertEquals("New\n        Lines",
607
                      FileToText(TEST_CONFIG["CHANGELOG_ENTRY_FILE"]))
608

609 610 611 612 613 614 615
  TAGS = """
4425.0
0.0.0.0
3.9.6
3.22.4
test_tag
"""
616

617 618
  # Version as tag: 3.22.4.0. Version on master: 3.22.6.
  # Make sure that the latest version is 3.22.6.0.
619
  def testIncrementVersion(self):
620
    self.Expect([
621
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
622
      Cmd("git tag", self.TAGS),
623
      Cmd("git checkout -f origin/master -- include/v8-version.h",
624
          "", cb=lambda: self.WriteFakeVersionFile(3, 22, 6)),
625
    ])
626

627
    self.RunStep(PushToCandidates, IncrementVersion)
628

629 630 631 632
    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"])
633

634
  def _TestSquashCommits(self, change_log, expected_msg):
635 636
    TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
    with open(TEST_CONFIG["CHANGELOG_ENTRY_FILE"], "w") as f:
637
      f.write(change_log)
638

639
    self.Expect([
640
      Cmd("git diff origin/candidates hash1", "patch content"),
641
    ])
642

643
    self._state["push_hash"] = "hash1"
644
    self._state["date"] = "1999-11-11"
645

machenbach's avatar
machenbach committed
646
    self.RunStep(PushToCandidates, SquashCommits)
647
    self.assertEquals(FileToText(TEST_CONFIG["COMMITMSG_FILE"]), expected_msg)
648

649
    patch = FileToText(TEST_CONFIG["PATCH_FILE"])
650 651
    self.assertTrue(re.search(r"patch content", patch))

652 653 654 655 656 657 658
  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"""
659
    commit_msg = """Version 3.22.5 (based on hash1)
660 661 662 663 664 665 666 667 668 669 670 671 672

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"""
673
    commit_msg = """Version 3.22.5 (based on hash1)
674 675 676 677 678 679 680 681 682 683 684

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)

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
  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])

machenbach's avatar
machenbach committed
700
  def _PushToCandidates(self, force=False, manual=False):
701
    TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
702

machenbach's avatar
machenbach committed
703 704
    # The version file on master has build level 5, while the version
    # file from candidates has build level 4.
705 706
    self.WriteFakeVersionFile(build=5)

707
    TEST_CONFIG["CHANGELOG_ENTRY_FILE"] = self.MakeEmptyTempFile()
machenbach's avatar
machenbach committed
708 709
    master_change_log = "2014-03-17: Sentinel\n"
    TextToFile(master_change_log,
710
               os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
711 712
    os.environ["EDITOR"] = "vi"

713 714 715 716 717 718 719 720 721 722 723 724
    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."""

725
    def ResetChangeLog():
machenbach's avatar
machenbach committed
726 727 728 729
      """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
730 731

        Performance and stability improvements on all platforms.\n"""
machenbach's avatar
machenbach committed
732
      TextToFile(candidates_change_log,
733
                 os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
734

machenbach's avatar
machenbach committed
735
    def ResetToCandidates():
736 737 738
      ResetChangeLog()
      self.WriteFakeVersionFile()

739
    def CheckVersionCommit():
740
      commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
741
      self.assertEquals(commit_msg, commit)
742 743
      version = FileToText(
          os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
744 745 746 747 748 749
      self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
      self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
      self.assertFalse(re.search(r"#define V8_BUILD_NUMBER\s+6", version))
      self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+0", version))
      self.assertTrue(
          re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
750

machenbach's avatar
machenbach committed
751 752
      # Check that the change log on the candidates branch got correctly
      # modified.
753 754
      change_log = FileToText(
          os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
755 756 757 758 759 760 761 762 763 764 765 766 767
      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)

768
    force_flag = " -f" if not manual else ""
769 770 771 772
    expectations = []
    if not force:
      expectations.append(Cmd("which vi", "/usr/bin/vi"))
    expectations += [
773
      Cmd("git status -s -uno", ""),
774
      Cmd("git checkout -f origin/master", ""),
775
      Cmd("git fetch", ""),
776 777
      Cmd("git branch", "  branch1\n* branch2\n"),
      Cmd("git branch", "  branch1\n* branch2\n"),
778
      Cmd(("git new-branch %s --upstream origin/master" %
779
           TEST_CONFIG["BRANCHNAME"]), ""),
780
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
781
      Cmd("git tag", self.TAGS),
782
      Cmd("git checkout -f origin/master -- include/v8-version.h",
783
          "", cb=self.WriteFakeVersionFile),
784 785 786
      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"),
787
      Cmd("git log --format=%H abc3..push_hash", "rev1\n"),
788 789 790
      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"),
791
    ]
792 793
    if manual:
      expectations.append(RL(""))  # Open editor.
794
    if not force:
795 796
      expectations.append(
          Cmd("vi %s" % TEST_CONFIG["CHANGELOG_ENTRY_FILE"], ""))
797
    expectations += [
798 799 800 801
      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" %
machenbach's avatar
machenbach committed
802
           TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates),
803
      Cmd("git apply --index --reject \"%s\"" % TEST_CONFIG["PATCH_FILE"], ""),
804 805
      Cmd("git checkout -f origin/candidates -- ChangeLog", "",
          cb=ResetChangeLog),
806
      Cmd("git checkout -f origin/candidates -- include/v8-version.h", "",
807
          cb=self.WriteFakeVersionFile),
808 809 810 811 812 813 814 815
      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", ""),
machenbach's avatar
machenbach committed
816
      Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
817
      Cmd(("git new-branch %s --upstream origin/candidates" %
machenbach's avatar
machenbach committed
818
           TEST_CONFIG["CANDIDATESBRANCH"]), "", cb=ResetToCandidates),
819
      Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
820
          cb=CheckVersionCommit),
821
      Cmd("git cl land -f --bypass-hooks", ""),
822
      Cmd("git fetch", ""),
machenbach@chromium.org's avatar
machenbach@chromium.org committed
823 824
      Cmd("git log -1 --format=%H --grep="
          "\"Version 3.22.5 (based on push_hash)\""
825 826 827
          " origin/candidates", "hsh_to_tag"),
      Cmd("git tag 3.22.5 hsh_to_tag", ""),
      Cmd("git push origin 3.22.5", ""),
828
      Cmd("git checkout -f origin/master", ""),
829
      Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
machenbach's avatar
machenbach committed
830
      Cmd("git branch -D %s" % TEST_CONFIG["CANDIDATESBRANCH"], ""),
831
    ]
832
    self.Expect(expectations)
833

834
    args = ["-a", "author@chromium.org", "--revision", "push_hash"]
835 836 837
    if force: args.append("-f")
    if manual: args.append("-m")
    else: args += ["-r", "reviewer@chromium.org"]
machenbach's avatar
machenbach committed
838
    PushToCandidates(TEST_CONFIG, self).Run(args)
839

840
    cl = FileToText(os.path.join(TEST_CONFIG["DEFAULT_CWD"], CHANGELOG_FILE))
841 842
    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))
843 844 845
    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
machenbach's avatar
machenbach committed
846
    # since the git command that merges to master is mocked out.
847

machenbach's avatar
machenbach committed
848 849
  def testPushToCandidatesManual(self):
    self._PushToCandidates(manual=True)
850

machenbach's avatar
machenbach committed
851 852
  def testPushToCandidatesSemiAutomatic(self):
    self._PushToCandidates()
853

machenbach's avatar
machenbach committed
854 855
  def testPushToCandidatesForced(self):
    self._PushToCandidates(force=True)
856

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
  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))
886 887 888 889 890 891
      self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
      self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
      self.assertFalse(re.search(r"#define V8_BUILD_NUMBER\s+6", version))
      self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+0", version))
      self.assertTrue(
          re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910

      # 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 = [
911 912 913 914
      Cmd("git fetch origin "
          "+refs/heads/*:refs/heads/* "
          "+refs/pending/*:refs/pending/* "
          "+refs/pending-tags/*:refs/pending-tags/*", ""),
915 916 917 918
      Cmd("git checkout -f origin/master", ""),
      Cmd("git branch", ""),
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
      Cmd("git tag", self.TAGS),
919
      Cmd("git checkout -f origin/master -- include/v8-version.h",
920 921
          "", cb=self.WriteFakeVersionFile),
      Cmd("git log -1 --format=%H 3.22.4", "release_hash\n"),
922 923
      Cmd("git log -1 --format=%s release_hash", "Version 3.22.4\n"),
      Cmd("git log -1 --format=%H release_hash^", "abc3\n"),
924 925 926 927 928
      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", ""),
929
      Cmd("git checkout -b work-branch push_hash", ""),
930
      Cmd("git checkout -f 3.22.4 -- ChangeLog", "", cb=ResetChangeLog),
931
      Cmd("git checkout -f 3.22.4 -- include/v8-version.h", "",
932 933 934 935
          cb=self.WriteFakeVersionFile),
      Cmd("git commit -aF \"%s\"" % TEST_CONFIG["COMMITMSG_FILE"], "",
          cb=CheckVersionCommit),
      Cmd("git push origin "
936
          "refs/heads/work-branch:refs/pending/heads/3.22.5 "
937
          "push_hash:refs/pending-tags/heads/3.22.5 "
938
          "push_hash:refs/heads/3.22.5", ""),
939 940
      Cmd("git fetch", ""),
      Cmd("git log -1 --format=%H --grep="
941
          "\"Version 3.22.5\" origin/3.22.5", "hsh_to_tag"),
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
      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.

964 965 966 967
  C_V8_22624_LOG = """V8 CL.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22624 123

968 969 970 971 972 973
"""

  C_V8_123455_LOG = """V8 CL.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123455 123

974 975 976 977 978 979 980 981
"""

  C_V8_123456_LOG = """V8 CL.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@123456 123

"""

982 983 984
  ROLL_COMMIT_MSG = """Update V8 to version 3.22.4 (based on abc).

Summary of changes available at:
985
https://chromium.googlesource.com/v8/v8/+log/last_rol..roll_hsh
986 987 988

Please follow these instructions for assigning/CC'ing issues:
https://code.google.com/p/v8-wiki/wiki/TriagingIssues
989

990 991 992
TBR=g_name@chromium.org,reviewer@chromium.org"""

  def testChromiumRoll(self):
993
    # Setup fake directory structures.
994 995 996
    TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
    TextToFile("", os.path.join(TEST_CONFIG["CHROMIUM"], ".git"))
    chrome_dir = TEST_CONFIG["CHROMIUM"]
997 998 999
    os.makedirs(os.path.join(chrome_dir, "v8"))

    # Write fake deps file.
1000
    TextToFile("Some line\n   \"v8_revision\": \"123444\",\n  some line",
1001
               os.path.join(chrome_dir, "DEPS"))
1002
    def WriteDeps():
1003
      TextToFile("Some line\n   \"v8_revision\": \"22624\",\n  some line",
1004
                 os.path.join(chrome_dir, "DEPS"))
1005

1006
    expectations = [
1007
      Cmd("git fetch origin", ""),
1008
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1009
      Cmd("git log -1 --format=%s roll_hsh",
1010
          "Version 3.22.4 (based on abc)\n"),
1011
      Cmd("git describe --tags roll_hsh", "3.22.4"),
1012
      Cmd("git describe --tags last_roll_hsh", "3.22.2.1"),
1013 1014
      URL("https://chromium-build.appspot.com/p/chromium/sheriff_v8.js",
          "document.write('g_name')"),
1015 1016
      Cmd("git status -s -uno", "", cwd=chrome_dir),
      Cmd("git checkout -f master", "", cwd=chrome_dir),
1017
      Cmd("git branch", "", cwd=chrome_dir),
1018 1019
      Cmd("gclient sync --nohooks", "syncing...", cwd=chrome_dir),
      Cmd("git pull", "", cwd=chrome_dir),
1020
      Cmd("git fetch origin", ""),
1021
      Cmd("git new-branch work-branch", "", cwd=chrome_dir),
1022
      Cmd("roll-dep-svn v8 roll_hsh", "rolled", cb=WriteDeps, cwd=chrome_dir),
1023 1024 1025
      Cmd(("git commit -am \"%s\" "
           "--author \"author@chromium.org <author@chromium.org>\"" %
           self.ROLL_COMMIT_MSG),
1026 1027 1028
          "", cwd=chrome_dir),
      Cmd("git cl upload --send-mail --email \"author@chromium.org\" -f", "",
          cwd=chrome_dir),
1029 1030
      Cmd("git checkout -f master", "", cwd=chrome_dir),
      Cmd("git branch -D work-branch", "", cwd=chrome_dir),
1031 1032
    ]
    self.Expect(expectations)
1033

1034
    args = ["-a", "author@chromium.org", "-c", chrome_dir,
1035
            "--sheriff",
1036
            "-r", "reviewer@chromium.org",
1037 1038
            "--last-roll", "last_roll_hsh",
            "roll_hsh"]
1039 1040
    ChromiumRoll(TEST_CONFIG, self).Run(args)

1041
    deps = FileToText(os.path.join(chrome_dir, "DEPS"))
1042
    self.assertTrue(re.search("\"v8_revision\": \"22624\"", deps))
1043

1044
  def testCheckLastPushRecently(self):
1045
    self.Expect([
1046 1047 1048 1049 1050 1051
      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"),
1052 1053
    ])

1054
    self._state["candidate"] = "abc123"
1055
    self.assertEquals(0, self.RunStep(
1056
        auto_push.AutoPush, LastReleaseBailout, AUTO_PUSH_ARGS))
1057

1058
  def testAutoPush(self):
1059
    self.Expect([
1060
      Cmd("git fetch", ""),
1061 1062 1063 1064 1065 1066 1067 1068
      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"),
1069 1070
    ])

1071
    auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"])
1072

1073
    state = json.loads(FileToText("%s-state.json"
1074
                                  % TEST_CONFIG["PERSISTFILE_BASENAME"]))
1075

1076
    self.assertEquals("abc123", state["candidate"])
1077

1078
  def testAutoRollExistingRoll(self):
1079
    self.Expect([
1080 1081 1082 1083 1084 1085 1086
      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(
1087
        AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]])
1088
    self.assertEquals(0, result)
1089 1090 1091 1092

  # Snippet from the original DEPS file.
  FAKE_DEPS = """
vars = {
1093
  "v8_revision": "abcd123455",
1094 1095 1096 1097 1098 1099 1100 1101 1102
}
deps = {
  "src/v8":
    (Var("googlecode_url") % "v8") + "/" + Var("v8_branch") + "@" +
    Var("v8_revision"),
}
"""

  def testAutoRollUpToDate(self):
1103 1104
    TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
    TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
1105
    self.Expect([
1106 1107 1108
      URL("https://codereview.chromium.org/search",
          "owner=author%40chromium.org&limit=30&closed=3&format=json",
          ("{\"results\": [{\"subject\": \"different\"}]}")),
1109
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1110 1111 1112 1113 1114
      Cmd("git rev-list --max-age=740800 --tags",
          "bad_tag\nhash_234\nhash_123"),
      Cmd("git describe --tags bad_tag", ""),
      Cmd("git describe --tags hash_234", "3.22.4"),
      Cmd("git describe --tags hash_123", "3.22.3"),
1115 1116 1117
      Cmd("git describe --tags abcd123455", "3.22.4"),
      Cmd("git describe --tags hash_234", "3.22.4"),
      Cmd("git describe --tags hash_123", "3.22.3"),
1118 1119 1120
    ])

    result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
1121
        AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"]])
1122
    self.assertEquals(0, result)
1123 1124

  def testAutoRoll(self):
1125 1126
    TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
    TextToFile(self.FAKE_DEPS, os.path.join(TEST_CONFIG["CHROMIUM"], "DEPS"))
1127 1128

    self.Expect([
1129 1130 1131
      URL("https://codereview.chromium.org/search",
          "owner=author%40chromium.org&limit=30&closed=3&format=json",
          ("{\"results\": [{\"subject\": \"different\"}]}")),
1132
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
1133 1134 1135 1136 1137
      Cmd("git rev-list --max-age=740800 --tags",
          "bad_tag\nhash_234\nhash_123"),
      Cmd("git describe --tags bad_tag", ""),
      Cmd("git describe --tags hash_234", "3.22.4"),
      Cmd("git describe --tags hash_123", "3.22.3"),
1138 1139
      Cmd("git describe --tags abcd123455", "3.22.3.1"),
      Cmd("git describe --tags hash_234", "3.22.4"),
1140 1141 1142
    ])

    result = auto_roll.AutoRoll(TEST_CONFIG, self).Run(
1143
        AUTO_PUSH_ARGS + ["-c", TEST_CONFIG["CHROMIUM"], "--roll"])
1144 1145
    self.assertEquals(0, result)

1146
  def testMergeToBranch(self):
1147
    TEST_CONFIG["ALREADY_MERGING_SENTINEL_FILE"] = self.MakeEmptyTempFile()
1148
    TextToFile("", os.path.join(TEST_CONFIG["DEFAULT_CWD"], ".git"))
1149
    self.WriteFakeVersionFile(build=5)
1150 1151 1152 1153 1154
    os.environ["EDITOR"] = "vi"
    extra_patch = self.MakeEmptyTempFile()

    def VerifyPatch(patch):
      return lambda: self.assertEquals(patch,
1155
          FileToText(TEST_CONFIG["TEMPORARY_PATCH_FILE"]))
1156

1157
    msg = """Version 3.22.5.1 (cherry-pick)
1158

1159 1160 1161 1162 1163
Merged ab12345
Merged ab23456
Merged ab34567
Merged ab45678
Merged ab56789
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178

Title4

Title2

Title3

Title1

Revert "Something"

BUG=123,234,345,456,567,v8:123
LOG=N
"""

machenbach's avatar
machenbach committed
1179
    def VerifyLand():
1180 1181 1182 1183
      commit = FileToText(TEST_CONFIG["COMMITMSG_FILE"])
      self.assertEquals(msg, commit)
      version = FileToText(
          os.path.join(TEST_CONFIG["DEFAULT_CWD"], VERSION_FILE))
1184 1185 1186 1187 1188
      self.assertTrue(re.search(r"#define V8_MINOR_VERSION\s+22", version))
      self.assertTrue(re.search(r"#define V8_BUILD_NUMBER\s+5", version))
      self.assertTrue(re.search(r"#define V8_PATCH_LEVEL\s+1", version))
      self.assertTrue(
          re.search(r"#define V8_IS_CANDIDATE_VERSION\s+0", version))
1189 1190 1191

    self.Expect([
      Cmd("git status -s -uno", ""),
1192
      Cmd("git checkout -f origin/master", ""),
1193 1194
      Cmd("git fetch", ""),
      Cmd("git branch", "  branch1\n* branch2\n"),
1195
      Cmd("git new-branch %s --upstream refs/remotes/origin/candidates" %
1196
          TEST_CONFIG["BRANCHNAME"], ""),
1197
      Cmd(("git log --format=%H --grep=\"Port ab12345\" "
1198
           "--reverse origin/master"),
1199 1200 1201 1202
          "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\" "
1203 1204
           "--reverse origin/master"),
          ""),
1205
      Cmd(("git log --format=%H --grep=\"Port ab34567\" "
1206
           "--reverse origin/master"),
1207 1208 1209 1210 1211
          "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),
1212
      # Restart script in the failing step.
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
      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"),
1224 1225 1226
      Cmd(("git apply --index --reject \"%s\"" %
           TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
          "", cb=VerifyPatch("patch4")),
1227
      Cmd("git log -1 -p ab23456", "patch2"),
1228 1229 1230
      Cmd(("git apply --index --reject \"%s\"" %
           TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
          "", cb=VerifyPatch("patch2")),
1231
      Cmd("git log -1 -p ab34567", "patch3"),
1232 1233 1234
      Cmd(("git apply --index --reject \"%s\"" %
           TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
          "", cb=VerifyPatch("patch3")),
1235
      Cmd("git log -1 -p ab45678", "patch1"),
1236 1237 1238
      Cmd(("git apply --index --reject \"%s\"" %
           TEST_CONFIG["TEMPORARY_PATCH_FILE"]),
          "", cb=VerifyPatch("patch1")),
1239
      Cmd("git log -1 -p ab56789", "patch5\n"),
1240 1241 1242 1243 1244 1245 1246 1247
      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\" "
1248
          "--bypass-hooks --cc \"ulan@chromium.org\"", ""),
1249 1250 1251
      Cmd("git checkout -f %s" % TEST_CONFIG["BRANCHNAME"], ""),
      RL("LGTM"),  # Enter LGTM for V8 CL.
      Cmd("git cl presubmit", "Presubmit successfull\n"),
1252
      Cmd("git cl land -f --bypass-hooks", "Closing issue\n",
machenbach's avatar
machenbach committed
1253
          cb=VerifyLand),
1254 1255
      Cmd("git fetch", ""),
      Cmd("git log -1 --format=%H --grep=\""
1256
          "Version 3.22.5.1 (cherry-pick)"
1257
          "\" refs/remotes/origin/candidates",
1258 1259 1260
          ""),
      Cmd("git fetch", ""),
      Cmd("git log -1 --format=%H --grep=\""
1261
          "Version 3.22.5.1 (cherry-pick)"
1262
          "\" refs/remotes/origin/candidates",
1263 1264 1265
          "hsh_to_tag"),
      Cmd("git tag 3.22.5.1 hsh_to_tag", ""),
      Cmd("git push origin 3.22.5.1", ""),
1266
      Cmd("git checkout -f origin/master", ""),
1267 1268 1269
      Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], ""),
    ])

1270 1271
    # ab12345 and ab34567 are patches. ab23456 (included) and ab45678 are the
    # MIPS ports of ab12345. ab56789 is the MIPS port of ab34567.
1272
    args = ["-f", "-p", extra_patch, "--branch", "candidates",
1273
            "ab12345", "ab23456", "ab34567"]
1274

1275
    # The first run of the script stops because of git being down.
1276
    self.assertRaises(GitFailedException,
1277
        lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
1278 1279

    # Test that state recovery after restarting the script works.
1280
    args += ["-s", "4"]
1281
    MergeToBranch(TEST_CONFIG, self).Run(args)
1282

1283
  def testReleases(self):
1284 1285 1286 1287
    c_hash1_commit_log = """Update V8 to Version 4.2.71.

Cr-Commit-Position: refs/heads/master@{#5678}
"""
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
    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

1307
"""
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
    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}
1323 1324 1325 1326
"""
    c_hash_456_commit_log = """Version 4.2.71.

Cr-Commit-Position: refs/heads/4.2.71@{#1}
1327
"""
1328
    c_deps = "Line\n   \"v8_revision\": \"%s\",\n  line\n"
1329

1330 1331 1332 1333
    json_output = self.MakeEmptyTempFile()
    csv_output = self.MakeEmptyTempFile()
    self.WriteFakeVersionFile()

1334 1335
    TEST_CONFIG["CHROMIUM"] = self.MakeEmptyTempDirectory()
    chrome_dir = TEST_CONFIG["CHROMIUM"]
1336 1337
    chrome_v8_dir = os.path.join(chrome_dir, "v8")
    os.makedirs(chrome_v8_dir)
1338

1339 1340 1341
    def ResetVersion(major, minor, build, patch=0):
      return lambda: self.WriteFakeVersionFile(major=major,
                                               minor=minor,
1342 1343 1344
                                               build=build,
                                               patch=patch)

1345
    self.Expect([
1346
      Cmd("git status -s -uno", ""),
1347
      Cmd("git checkout -f origin/master", ""),
1348
      Cmd("git fetch", ""),
1349
      Cmd("git branch", "  branch1\n* branch2\n"),
1350
      Cmd("git new-branch %s" % TEST_CONFIG["BRANCHNAME"], ""),
1351 1352
      Cmd("git fetch origin +refs/tags/*:refs/tags/*", ""),
      Cmd("git rev-list --max-age=395200 --tags",
1353
          "bad_tag\nhash_234\nhash_123\nhash_345\nhash_456\n"),
1354 1355 1356 1357
      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"),
1358
      Cmd("git describe --tags hash_456", "4.2.71"),
1359 1360
      Cmd("git diff --name-only hash_234 hash_234^", VERSION_FILE),
      Cmd("git checkout -f hash_234 -- %s" % VERSION_FILE, "",
1361
          cb=ResetVersion(3, 3, 1, 1)),
1362
      Cmd("git branch -r --contains hash_234", "  branch-heads/3.3\n"),
1363
      Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
1364
      Cmd("git log -1 --format=%s hash_234", ""),
1365
      Cmd("git log -1 --format=%B hash_234", c_hash_234_commit_log),
1366
      Cmd("git log -1 --format=%ci hash_234", "18:15"),
1367
      Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1368
          cb=ResetVersion(3, 22, 5)),
1369 1370
      Cmd("git diff --name-only hash_123 hash_123^", VERSION_FILE),
      Cmd("git checkout -f hash_123 -- %s" % VERSION_FILE, "",
1371
          cb=ResetVersion(3, 21, 2)),
1372
      Cmd("git branch -r --contains hash_123", "  branch-heads/3.21\n"),
1373
      Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
1374
      Cmd("git log -1 --format=%s hash_123", ""),
1375
      Cmd("git log -1 --format=%B hash_123", c_hash_123_commit_log),
1376
      Cmd("git log -1 --format=%ci hash_123", "03:15"),
1377
      Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1378
          cb=ResetVersion(3, 22, 5)),
1379 1380
      Cmd("git diff --name-only hash_345 hash_345^", VERSION_FILE),
      Cmd("git checkout -f hash_345 -- %s" % VERSION_FILE, "",
1381
          cb=ResetVersion(3, 22, 3)),
1382
      Cmd("git branch -r --contains hash_345", "  origin/candidates\n"),
1383
      Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
1384
      Cmd("git log -1 --format=%s hash_345", ""),
1385
      Cmd("git log -1 --format=%B hash_345", c_hash_345_commit_log),
1386
      Cmd("git log -1 --format=%ci hash_345", ""),
1387
      Cmd("git checkout -f HEAD -- %s" % VERSION_FILE, "",
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
          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)),
1403 1404
      Cmd("git fetch origin +refs/heads/*:refs/remotes/origin/* "
          "+refs/branch-heads/*:refs/remotes/branch-heads/*", "",
1405
          cwd=chrome_dir),
1406
      Cmd("git fetch origin", "", cwd=chrome_v8_dir),
1407 1408
      Cmd("git log --format=%H --grep=\"V8\" origin/master -- DEPS",
          "c_hash1\nc_hash2\nc_hash3\n",
1409
          cwd=chrome_dir),
1410
      Cmd("git show c_hash1:DEPS", c_deps % "hash_456", cwd=chrome_dir),
1411
      Cmd("git log -1 --format=%B c_hash1", c_hash1_commit_log,
1412
          cwd=chrome_dir),
1413
      Cmd("git show c_hash2:DEPS", c_deps % "hash_345", cwd=chrome_dir),
1414 1415
      Cmd("git log -1 --format=%B c_hash2", c_hash2_commit_log,
          cwd=chrome_dir),
1416
      Cmd("git show c_hash3:DEPS", c_deps % "deadbeef", cwd=chrome_dir),
1417 1418 1419
      Cmd("git log -1 --format=%B c_hash3", c_hash3_commit_log,
          cwd=chrome_dir),
      Cmd("git branch -r", " weird/123\n  branch-heads/7\n", cwd=chrome_dir),
1420
      Cmd("git show refs/branch-heads/7:DEPS", c_deps % "hash_345",
1421
          cwd=chrome_dir),
1422 1423 1424
      URL("http://omahaproxy.appspot.com/all.json", """[{
        "os": "win",
        "versions": [{
1425 1426
          "version": "2.2.2.2",
          "v8_version": "22.2.2.2",
1427 1428
          "current_reldate": "04/09/15",
          "os": "win",
1429 1430
          "channel": "canary",
          "previous_version": "1.1.1.0"
1431 1432
          }]
        }]"""),
1433 1434 1435 1436 1437 1438
      URL("http://omahaproxy.appspot.com/v8.json?version=1.1.1.0", """{
        "chromium_version": "1.1.1.0",
        "v8_version": "11.1.1.0"
        }"""),
      Cmd("git rev-list -1 11.1.1", "v8_previous_version_hash"),
      Cmd("git rev-list -1 22.2.2.2", "v8_version_hash"),
1439
      Cmd("git checkout -f origin/master", ""),
1440
      Cmd("git branch -D %s" % TEST_CONFIG["BRANCHNAME"], "")
1441 1442
    ])

1443
    args = ["-c", TEST_CONFIG["CHROMIUM"],
1444 1445 1446 1447 1448 1449
            "--json", json_output,
            "--csv", csv_output,
            "--max-releases", "1"]
    Releases(TEST_CONFIG, self).Run(args)

    # Check expected output.
1450 1451
    csv = ("4.2.71,4.2.71,1,5678,\r\n"
           "3.22.3,candidates,345,4567:5677,\r\n"
1452
           "3.21.2,3.21,123,,\r\n"
1453
           "3.3.1.1,3.3,234,,abc12\r\n")
1454 1455
    self.assertEquals(csv, FileToText(csv_output))

1456 1457 1458
    expected_json = {"chrome_releases":{
                                        "canaries": [
                                                     {
1459
                           "chrome_version": "2.2.2.2",
1460 1461
                           "os": "win",
                           "release_date": "04/09/15",
1462 1463 1464 1465
                           "v8_version": "22.2.2.2",
                           "v8_version_hash": "v8_version_hash",
                           "v8_previous_version": "11.1.1.0",
                           "v8_previous_version_hash": "v8_previous_version_hash"
1466 1467
                           }]},
                     "releases":[
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
      {
        "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",
      },
1483 1484 1485
      {
        "revision": "345",
        "revision_git": "hash_345",
1486 1487
        "master_position": "",
        "master_hash": "",
1488 1489
        "patches_merged": "",
        "version": "3.22.3",
1490
        "chromium_revision": "4567:5677",
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
        "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": "",
1501 1502
        "master_position": "",
        "master_hash": "",
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
        "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",
1514
        "patches_merged": "abc12",
1515 1516
        "master_position": "",
        "master_hash": "",
1517 1518 1519 1520 1521 1522 1523
        "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",
1524 1525
      },],
    }
1526 1527
    self.assertEquals(expected_json, json.loads(FileToText(json_output)))

1528

1529 1530
class SystemTest(unittest.TestCase):
  def testReload(self):
1531 1532
    options = ScriptsBase(
        TEST_CONFIG, DEFAULT_SIDE_EFFECT_HANDLER, {}).MakeOptions([])
1533
    step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
1534
                    options=options,
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
                    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)