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
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.
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.
35 from auto_push import CheckLastPush
36 from auto_push import SETTINGS_LOCATION
37 import common_includes
38 from common_includes import *
39 import merge_to_branch
40 from merge_to_branch import *
42 from push_to_trunk import *
44 from chromium_roll import CHROMIUM
45 from chromium_roll import DEPS_FILE
46 from chromium_roll import ChromiumRoll
50 BRANCHNAME: "test-prepare-push",
51 TRUNKBRANCH: "test-trunk-push",
52 PERSISTFILE_BASENAME: "/tmp/test-v8-push-to-trunk-tempfile",
53 TEMP_BRANCH: "test-prepare-push-temporary-branch-created-by-script",
54 DOT_GIT_LOCATION: None,
57 CHANGELOG_ENTRY_FILE: "/tmp/test-v8-push-to-trunk-tempfile-changelog-entry",
58 PATCH_FILE: "/tmp/test-v8-push-to-trunk-tempfile-patch",
59 COMMITMSG_FILE: "/tmp/test-v8-push-to-trunk-tempfile-commitmsg",
60 CHROMIUM: "/tmp/test-v8-push-to-trunk-tempfile-chromium",
61 DEPS_FILE: "/tmp/test-v8-push-to-trunk-tempfile-chromium/DEPS",
62 SETTINGS_LOCATION: None,
63 ALREADY_MERGING_SENTINEL_FILE:
64 "/tmp/test-merge-to-branch-tempfile-already-merging",
65 COMMIT_HASHES_FILE: "/tmp/test-merge-to-branch-tempfile-PATCH_COMMIT_HASHES",
66 TEMPORARY_PATCH_FILE: "/tmp/test-merge-to-branch-tempfile-temporary-patch",
71 "-a", "author@chromium.org",
72 "-r", "reviewer@chromium.org",
76 class ToplevelTest(unittest.TestCase):
77 def testMakeComment(self):
78 self.assertEquals("# Line 1\n# Line 2\n#",
79 MakeComment(" Line 1\n Line 2\n"))
80 self.assertEquals("#Line 1\n#Line 2",
81 MakeComment("Line 1\n Line 2"))
83 def testStripComments(self):
84 self.assertEquals(" Line 1\n Line 3\n",
85 StripComments(" Line 1\n# Line 2\n Line 3\n#\n"))
86 self.assertEquals("\nLine 2 ### Test\n #",
87 StripComments("###\n# \n\n# Line 1\nLine 2 ### Test\n #"))
89 def testMakeChangeLogBodySimple(self):
92 "Title text 1\n\nBUG=\n",
93 "author1@chromium.org"],
95 "Title text 2\n\nBUG=1234\n",
96 "author2@chromium.org"],
98 self.assertEquals(" Title text 1.\n"
99 " (author1@chromium.org)\n\n"
100 " Title text 2 (Chromium issue 1234).\n"
101 " (author2@chromium.org)\n\n",
102 MakeChangeLogBody(commits))
104 def testMakeChangeLogBodyEmpty(self):
105 self.assertEquals("", MakeChangeLogBody([]))
107 def testMakeChangeLogBodyAutoFormat(self):
110 "Title text 1\nLOG=y\nBUG=\n",
111 "author1@chromium.org"],
113 "Title text 2\n\nBUG=1234\n",
114 "author2@chromium.org"],
116 "Title text 3\n\nBUG=1234\nLOG = Yes\n",
117 "author3@chromium.org"],
119 "Title text 4\n\nBUG=1234\nLOG=\n",
120 "author4@chromium.org"],
122 self.assertEquals(" Title text 1.\n\n"
123 " Title text 3 (Chromium issue 1234).\n\n",
124 MakeChangeLogBody(commits, True))
126 def testRegressWrongLogEntryOnTrue(self):
128 Check elimination: Learn from if(CompareMap(x)) on true branch.
131 R=verwaest@chromium.org
133 Committed: https://code.google.com/p/v8/source/detail?r=18210
135 self.assertEquals("", MakeChangeLogBody([["title", body, "author"]], True))
137 def testMakeChangeLogBugReferenceEmpty(self):
138 self.assertEquals("", MakeChangeLogBugReference(""))
139 self.assertEquals("", MakeChangeLogBugReference("LOG="))
140 self.assertEquals("", MakeChangeLogBugReference(" BUG ="))
141 self.assertEquals("", MakeChangeLogBugReference("BUG=none\t"))
143 def testMakeChangeLogBugReferenceSimple(self):
144 self.assertEquals("(issue 987654)",
145 MakeChangeLogBugReference("BUG = v8:987654"))
146 self.assertEquals("(Chromium issue 987654)",
147 MakeChangeLogBugReference("BUG=987654 "))
149 def testMakeChangeLogBugReferenceFromBody(self):
150 self.assertEquals("(Chromium issue 1234567)",
151 MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n"
152 " BUG=\tchromium:1234567\t\n"
155 def testMakeChangeLogBugReferenceMultiple(self):
156 # All issues should be sorted and grouped. Multiple references to the same
157 # issue should be filtered.
158 self.assertEquals("(issues 123, 234, Chromium issue 345)",
159 MakeChangeLogBugReference("Title\n\n"
161 " BUG\t= 345, \tv8:234,\n"
164 self.assertEquals("(Chromium issues 123, 234)",
165 MakeChangeLogBugReference("Title\n\n"
166 "BUG=234,,chromium:123 \n"
168 self.assertEquals("(Chromium issues 123, 234)",
169 MakeChangeLogBugReference("Title\n\n"
170 "BUG=chromium:234, , 123\n"
172 self.assertEquals("(issues 345, 456)",
173 MakeChangeLogBugReference("Title\n\n"
174 "\t\tBUG=v8:345,v8:456\n"
176 self.assertEquals("(issue 123, Chromium issues 345, 456)",
177 MakeChangeLogBugReference("Title\n\n"
181 "BUG=456,v8:123, 345"))
183 # TODO(machenbach): These test don't make much sense when the formatting is
185 def testMakeChangeLogBugReferenceLong(self):
186 # -----------------00--------10--------20--------30--------
187 self.assertEquals("(issues 234, 1234567890, 1234567"
188 "8901234567890, Chromium issues 12345678,"
190 MakeChangeLogBugReference("BUG=v8:234\n"
191 "BUG=v8:1234567890\n"
192 "BUG=v8:12345678901234567890\n"
195 # -----------------00--------10--------20--------30--------
196 self.assertEquals("(issues 234, 1234567890, 1234567"
197 "8901234567890, Chromium issues"
198 " 123456789, 1234567890)",
199 MakeChangeLogBugReference("BUG=v8:234\n"
200 "BUG=v8:12345678901234567890\n"
201 "BUG=v8:1234567890\n"
204 # -----------------00--------10--------20--------30--------
205 self.assertEquals("(Chromium issues 234, 1234567890"
206 ", 12345678901234567, "
207 "1234567890123456789)",
208 MakeChangeLogBugReference("BUG=234\n"
209 "BUG=12345678901234567\n"
210 "BUG=1234567890123456789\n"
214 def Git(*args, **kwargs):
215 """Convenience function returning a git test expectation."""
220 "cb": kwargs.get("cb"),
224 def RL(text, cb=None):
225 """Convenience function returning a readline test expectation."""
226 return {"name": "readline", "args": [], "ret": text, "cb": cb}
229 def URL(*args, **kwargs):
230 """Convenience function returning a readurl test expectation."""
235 "cb": kwargs.get("cb"),
239 class SimpleMock(object):
240 def __init__(self, name):
245 def Expect(self, recipe):
246 self._recipe = recipe
248 def Call(self, name, *args): # pragma: no cover
251 expected_call = self._recipe[self._index]
253 raise NoRetryException("Calling %s %s" % (name, " ".join(args)))
255 if not isinstance(expected_call, dict):
256 raise NoRetryException("Found wrong expectation type for %s %s"
257 % (name, " ".join(args)))
260 # The number of arguments in the expectation must match the actual
262 if len(args) > len(expected_call['args']):
263 raise NoRetryException("When calling %s with arguments, the "
264 "expectations must consist of at least as many arguments.")
266 # Compare expected and actual arguments.
267 for (expected_arg, actual_arg) in zip(expected_call['args'], args):
268 if expected_arg != actual_arg:
269 raise NoRetryException("Expected: %s - Actual: %s"
270 % (expected_arg, actual_arg))
272 # The expected call contains an optional callback for checking the context
273 # at the time of the call.
274 if expected_call['cb']:
276 expected_call['cb']()
278 tb = traceback.format_exc()
279 raise NoRetryException("Caught exception from callback: %s" % tb)
281 # If the return value is an exception, raise it instead of returning.
282 if isinstance(expected_call['ret'], Exception):
283 raise expected_call['ret']
284 return expected_call['ret']
286 def AssertFinished(self): # pragma: no cover
287 if self._index < len(self._recipe) -1:
288 raise NoRetryException("Called %s too seldom: %d vs. %d"
289 % (self._name, self._index, len(self._recipe)))
292 class ScriptTest(unittest.TestCase):
293 def MakeEmptyTempFile(self):
294 handle, name = tempfile.mkstemp()
296 self._tmp_files.append(name)
299 def WriteFakeVersionFile(self, build=4):
300 with open(TEST_CONFIG[VERSION_FILE], "w") as f:
301 f.write(" // Some line...\n")
303 f.write("#define MAJOR_VERSION 3\n")
304 f.write("#define MINOR_VERSION 22\n")
305 f.write("#define BUILD_NUMBER %s\n" % build)
306 f.write("#define PATCH_LEVEL 0\n")
307 f.write(" // Some line...\n")
308 f.write("#define IS_CANDIDATE_VERSION 0\n")
311 """Convenience wrapper."""
312 options = ScriptsBase(TEST_CONFIG, self, self._state).MakeOptions([])
313 return MakeStep(step_class=Step, state=self._state,
314 config=TEST_CONFIG, side_effect_handler=self,
317 def RunStep(self, script=PushToTrunk, step_class=Step, args=None):
318 """Convenience wrapper."""
319 args = args or ["-m"]
320 return script(TEST_CONFIG, self, self._state).RunSteps([step_class], args)
322 def GitMock(self, cmd, args="", pipe=True):
323 print "%s %s" % (cmd, args)
324 return self._git_mock.Call("git", args)
326 def LogMock(self, cmd, args=""):
327 print "Log: %s %s" % (cmd, args)
331 # TODO(machenbach): Little hack to reuse the git mock for the one svn call
332 # in merge-to-branch. The command should be made explicit in the test
338 def Call(self, fun, *args, **kwargs):
339 print "Calling %s with %s and %s" % (str(fun), str(args), str(kwargs))
341 def Command(self, cmd, args="", prefix="", pipe=True):
342 return ScriptTest.MOCKS[cmd](self, cmd, args)
345 return self._rl_mock.Call("readline")
347 def ReadURL(self, url, params):
348 if params is not None:
349 return self._url_mock.Call("readurl", url, params)
351 return self._url_mock.Call("readurl", url)
353 def Sleep(self, seconds):
359 def ExpectGit(self, *args):
360 """Convenience wrapper."""
361 self._git_mock.Expect(*args)
363 def ExpectReadline(self, *args):
364 """Convenience wrapper."""
365 self._rl_mock.Expect(*args)
367 def ExpectReadURL(self, *args):
368 """Convenience wrapper."""
369 self._url_mock.Expect(*args)
372 self._git_mock = SimpleMock("git")
373 self._rl_mock = SimpleMock("readline")
374 self._url_mock = SimpleMock("readurl")
379 Command("rm", "-rf %s*" % TEST_CONFIG[PERSISTFILE_BASENAME])
381 # Clean up temps. Doesn't work automatically.
382 for name in self._tmp_files:
383 if os.path.exists(name):
386 self._git_mock.AssertFinished()
387 self._rl_mock.AssertFinished()
388 self._url_mock.AssertFinished()
390 def testGitOrig(self):
391 self.assertTrue(Command("git", "--version").startswith("git version"))
393 def testGitMock(self):
394 self.ExpectGit([Git("--version", "git version 1.2.3"), Git("dummy", "")])
395 self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
396 self.assertEquals("", self.MakeStep().Git("dummy"))
398 def testCommonPrepareDefault(self):
400 Git("status -s -uno", ""),
401 Git("status -s -b -uno", "## some_branch"),
402 Git("svn fetch", ""),
403 Git("branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]),
404 Git("branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""),
405 Git("checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""),
408 self.ExpectReadline([RL("Y")])
409 self.MakeStep().CommonPrepare()
410 self.MakeStep().PrepareBranch()
411 self.assertEquals("some_branch", self._state["current_branch"])
413 def testCommonPrepareNoConfirm(self):
415 Git("status -s -uno", ""),
416 Git("status -s -b -uno", "## some_branch"),
417 Git("svn fetch", ""),
418 Git("branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]),
420 self.ExpectReadline([RL("n")])
421 self.MakeStep().CommonPrepare()
422 self.assertRaises(Exception, self.MakeStep().PrepareBranch)
423 self.assertEquals("some_branch", self._state["current_branch"])
425 def testCommonPrepareDeleteBranchFailure(self):
427 Git("status -s -uno", ""),
428 Git("status -s -b -uno", "## some_branch"),
429 Git("svn fetch", ""),
430 Git("branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]),
431 Git("branch -D %s" % TEST_CONFIG[TEMP_BRANCH], None),
433 self.ExpectReadline([RL("Y")])
434 self.MakeStep().CommonPrepare()
435 self.assertRaises(Exception, self.MakeStep().PrepareBranch)
436 self.assertEquals("some_branch", self._state["current_branch"])
438 def testInitialEnvironmentChecks(self):
439 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
440 os.environ["EDITOR"] = "vi"
441 self.MakeStep().InitialEnvironmentChecks()
443 def testReadAndPersistVersion(self):
444 TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
445 self.WriteFakeVersionFile(build=5)
446 step = self.MakeStep()
447 step.ReadAndPersistVersion()
448 self.assertEquals("3", step["major"])
449 self.assertEquals("22", step["minor"])
450 self.assertEquals("5", step["build"])
451 self.assertEquals("0", step["patch"])
454 self.assertEqual("(issue 321)",
455 re.sub(r"BUG=v8:(.*)$", r"(issue \1)", "BUG=v8:321"))
456 self.assertEqual("(Chromium issue 321)",
457 re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", "BUG=321"))
459 cl = " too little\n\ttab\ttab\n too much\n trailing "
460 cl = MSub(r"\t", r" ", cl)
461 cl = MSub(r"^ {1,7}([^ ])", r" \1", cl)
462 cl = MSub(r"^ {9,80}([^ ])", r" \1", cl)
463 cl = MSub(r" +$", r"", cl)
464 self.assertEqual(" too little\n"
469 self.assertEqual("//\n#define BUILD_NUMBER 3\n",
470 MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$",
472 "//\n#define BUILD_NUMBER 321\n"))
474 def testPreparePushRevision(self):
475 # Tests the default push hash used when the --revision option is not set.
477 Git("log -1 --format=%H HEAD", "push_hash")
480 self.RunStep(PushToTrunk, PreparePushRevision)
481 self.assertEquals("push_hash", self._state["push_hash"])
483 def testPrepareChangeLog(self):
484 TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
485 self.WriteFakeVersionFile()
486 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
489 Git("log --format=%H 1234..push_hash", "rev1\nrev2\nrev3\nrev4"),
490 Git("log -1 --format=%s rev1", "Title text 1"),
491 Git("log -1 --format=%B rev1", "Title\n\nBUG=\nLOG=y\n"),
492 Git("log -1 --format=%an rev1", "author1@chromium.org"),
493 Git("log -1 --format=%s rev2", "Title text 2."),
494 Git("log -1 --format=%B rev2", "Title\n\nBUG=123\nLOG= \n"),
495 Git("log -1 --format=%an rev2", "author2@chromium.org"),
496 Git("log -1 --format=%s rev3", "Title text 3"),
497 Git("log -1 --format=%B rev3", "Title\n\nBUG=321\nLOG=true\n"),
498 Git("log -1 --format=%an rev3", "author3@chromium.org"),
499 Git("log -1 --format=%s rev4", "Title text 4"),
500 Git("log -1 --format=%B rev4",
501 ("Title\n\nBUG=456\nLOG=Y\n\n"
502 "Review URL: https://codereview.chromium.org/9876543210\n")),
503 Git("log -1 --format=%an rev4", "author4@chromium.org"),
506 # The cl for rev4 on rietveld has an updated LOG flag.
508 URL("https://codereview.chromium.org/9876543210/description",
509 "Title\n\nBUG=456\nLOG=N\n\n"),
512 self._state["last_push_bleeding_edge"] = "1234"
513 self._state["push_hash"] = "push_hash"
514 self._state["version"] = "3.22.5"
515 self.RunStep(PushToTrunk, PrepareChangeLog)
517 actual_cl = FileToText(TEST_CONFIG[CHANGELOG_ENTRY_FILE])
519 expected_cl = """1999-07-31: Version 3.22.5
523 Title text 3 (Chromium issue 321).
525 Performance and stability improvements on all platforms.
527 # The change log above is auto-generated. Please review if all relevant
528 # commit messages from the list below are included.
529 # All lines starting with # will be stripped.
532 # (author1@chromium.org)
534 # Title text 2 (Chromium issue 123).
535 # (author2@chromium.org)
537 # Title text 3 (Chromium issue 321).
538 # (author3@chromium.org)
540 # Title text 4 (Chromium issue 456).
541 # (author4@chromium.org)
545 self.assertEquals(expected_cl, actual_cl)
547 def testEditChangeLog(self):
548 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
549 TextToFile(" New \n\tLines \n", TEST_CONFIG[CHANGELOG_ENTRY_FILE])
550 os.environ["EDITOR"] = "vi"
552 self.ExpectReadline([
553 RL(""), # Open editor.
556 self.RunStep(PushToTrunk, EditChangeLog)
558 self.assertEquals("New\n Lines",
559 FileToText(TEST_CONFIG[CHANGELOG_ENTRY_FILE]))
561 def testIncrementVersion(self):
562 TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
563 self.WriteFakeVersionFile()
564 self._state["last_push_trunk"] = "hash1"
567 Git("checkout -f hash1 -- %s" % TEST_CONFIG[VERSION_FILE], "")
570 self.ExpectReadline([
571 RL("Y"), # Increment build number.
574 self.RunStep(PushToTrunk, IncrementVersion)
576 self.assertEquals("3", self._state["new_major"])
577 self.assertEquals("22", self._state["new_minor"])
578 self.assertEquals("5", self._state["new_build"])
579 self.assertEquals("0", self._state["new_patch"])
581 def _TestSquashCommits(self, change_log, expected_msg):
582 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
583 with open(TEST_CONFIG[CHANGELOG_ENTRY_FILE], "w") as f:
587 Git("diff svn/trunk hash1", "patch content"),
588 Git("svn find-rev hash1", "123455\n"),
591 self._state["push_hash"] = "hash1"
592 self._state["date"] = "1999-11-11"
594 self.RunStep(PushToTrunk, SquashCommits)
595 self.assertEquals(FileToText(TEST_CONFIG[COMMITMSG_FILE]), expected_msg)
597 patch = FileToText(TEST_CONFIG[ PATCH_FILE])
598 self.assertTrue(re.search(r"patch content", patch))
600 def testSquashCommitsUnformatted(self):
601 change_log = """1999-11-11: Version 3.22.5
606 Performance and stability improvements on all platforms.\n"""
607 commit_msg = """Version 3.22.5 (based on bleeding_edge revision r123455)
609 Log text 1. Chromium issue 12345
611 Performance and stability improvements on all platforms."""
612 self._TestSquashCommits(change_log, commit_msg)
614 def testSquashCommitsFormatted(self):
615 change_log = """1999-11-11: Version 3.22.5
617 Long commit message that fills more than 80 characters (Chromium issue
620 Performance and stability improvements on all platforms.\n"""
621 commit_msg = """Version 3.22.5 (based on bleeding_edge revision r123455)
623 Long commit message that fills more than 80 characters (Chromium issue 12345).
625 Performance and stability improvements on all platforms."""
626 self._TestSquashCommits(change_log, commit_msg)
628 def testSquashCommitsQuotationMarks(self):
629 change_log = """Line with "quotation marks".\n"""
630 commit_msg = """Line with "quotation marks"."""
631 self._TestSquashCommits(change_log, commit_msg)
633 def _PushToTrunk(self, force=False, manual=False):
634 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
636 # The version file on bleeding edge has build level 5, while the version
637 # file from trunk has build level 4.
638 TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
639 self.WriteFakeVersionFile(build=5)
641 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
642 TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile()
643 bleeding_edge_change_log = "2014-03-17: Sentinel\n"
644 TextToFile(bleeding_edge_change_log, TEST_CONFIG[CHANGELOG_FILE])
645 os.environ["EDITOR"] = "vi"
647 def ResetChangeLog():
648 """On 'git co -b new_branch svn/trunk', and 'git checkout -- ChangeLog',
649 the ChangLog will be reset to its content on trunk."""
650 trunk_change_log = """1999-04-05: Version 3.22.4
652 Performance and stability improvements on all platforms.\n"""
653 TextToFile(trunk_change_log, TEST_CONFIG[CHANGELOG_FILE])
657 self.WriteFakeVersionFile()
659 def CheckSVNCommit():
660 commit = FileToText(TEST_CONFIG[COMMITMSG_FILE])
662 """Version 3.22.5 (based on bleeding_edge revision r123455)
664 Log text 1 (issue 321).
666 Performance and stability improvements on all platforms.""", commit)
667 version = FileToText(TEST_CONFIG[VERSION_FILE])
668 self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
669 self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
670 self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version))
671 self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version))
672 self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
674 # Check that the change log on the trunk branch got correctly modified.
675 change_log = FileToText(TEST_CONFIG[CHANGELOG_FILE])
677 """1999-07-31: Version 3.22.5
679 Log text 1 (issue 321).
681 Performance and stability improvements on all platforms.
684 1999-04-05: Version 3.22.4
686 Performance and stability improvements on all platforms.\n""",
689 force_flag = " -f" if not manual else ""
691 Git("status -s -uno", ""),
692 Git("status -s -b -uno", "## some_branch\n"),
693 Git("svn fetch", ""),
694 Git("branch", " branch1\n* branch2\n"),
695 Git("checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""),
696 Git("branch", " branch1\n* branch2\n"),
697 Git("branch", " branch1\n* branch2\n"),
698 Git("checkout -b %s svn/bleeding_edge" % TEST_CONFIG[BRANCHNAME], ""),
699 Git("svn find-rev r123455", "push_hash\n"),
700 Git(("log -1 --format=%H --grep="
701 "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
702 "svn/trunk"), "hash2\n"),
703 Git("log -1 hash2", "Log message\n"),
704 Git("log -1 --format=%s hash2",
705 "Version 3.4.5 (based on bleeding_edge revision r1234)\n"),
706 Git("svn find-rev r1234", "hash3\n"),
707 Git("checkout -f hash2 -- %s" % TEST_CONFIG[VERSION_FILE], "",
708 cb=self.WriteFakeVersionFile),
709 Git("log --format=%H hash3..push_hash", "rev1\n"),
710 Git("log -1 --format=%s rev1", "Log text 1.\n"),
711 Git("log -1 --format=%B rev1", "Text\nLOG=YES\nBUG=v8:321\nText\n"),
712 Git("log -1 --format=%an rev1", "author1@chromium.org\n"),
713 Git("svn fetch", "fetch result\n"),
714 Git("checkout -f svn/bleeding_edge", ""),
715 Git("diff svn/trunk push_hash", "patch content\n"),
716 Git("svn find-rev push_hash", "123455\n"),
717 Git("checkout -b %s svn/trunk" % TEST_CONFIG[TRUNKBRANCH], "",
719 Git("apply --index --reject \"%s\"" % TEST_CONFIG[PATCH_FILE], ""),
720 Git("checkout -f svn/trunk -- %s" % TEST_CONFIG[CHANGELOG_FILE], "",
722 Git("checkout -f svn/trunk -- %s" % TEST_CONFIG[VERSION_FILE], "",
723 cb=self.WriteFakeVersionFile),
724 Git("commit -aF \"%s\"" % TEST_CONFIG[COMMITMSG_FILE], "",
726 Git("svn dcommit 2>&1", "Some output\nCommitted r123456\nSome output\n"),
727 Git("svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""),
728 Git("checkout -f some_branch", ""),
729 Git("branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""),
730 Git("branch -D %s" % TEST_CONFIG[BRANCHNAME], ""),
731 Git("branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""),
734 # Expected keyboard input in manual mode:
736 self.ExpectReadline([
737 RL("Y"), # Confirm last push.
738 RL(""), # Open editor.
739 RL("Y"), # Increment build number.
740 RL("Y"), # Sanity check.
743 # Expected keyboard input in semi-automatic mode and forced mode:
745 self.ExpectReadline([])
747 args = ["-a", "author@chromium.org", "--revision", "123455"]
748 if force: args.append("-f")
749 if manual: args.append("-m")
750 else: args += ["-r", "reviewer@chromium.org"]
751 PushToTrunk(TEST_CONFIG, self).Run(args)
753 cl = FileToText(TEST_CONFIG[CHANGELOG_FILE])
754 self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl))
755 self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl))
756 self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl))
758 # Note: The version file is on build number 5 again in the end of this test
759 # since the git command that merges to the bleeding edge branch is mocked
762 def testPushToTrunkManual(self):
763 self._PushToTrunk(manual=True)
765 def testPushToTrunkSemiAutomatic(self):
768 def testPushToTrunkForced(self):
769 self._PushToTrunk(force=True)
772 def _ChromiumRoll(self, force=False, manual=False):
773 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
774 if not os.path.exists(TEST_CONFIG[CHROMIUM]):
775 os.makedirs(TEST_CONFIG[CHROMIUM])
776 TextToFile("Some line\n \"v8_revision\": \"123444\",\n some line",
777 TEST_CONFIG[DEPS_FILE])
779 os.environ["EDITOR"] = "vi"
780 force_flag = " -f" if not manual else ""
782 Git("status -s -uno", ""),
783 Git("status -s -b -uno", "## some_branch\n"),
784 Git("svn fetch", ""),
785 Git(("log -1 --format=%H --grep="
786 "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
787 "svn/trunk"), "push_hash\n"),
788 Git("svn find-rev push_hash", "123455\n"),
789 Git("log -1 --format=%s push_hash",
790 "Version 3.22.5 (based on bleeding_edge revision r123454)\n"),
791 Git("status -s -uno", ""),
792 Git("checkout -f master", ""),
794 Git("checkout -b v8-roll-123455", ""),
795 Git(("commit -am \"Update V8 to version 3.22.5 "
796 "(based on bleeding_edge revision r123454).\n\n"
797 "TBR=reviewer@chromium.org\""),
799 Git(("cl upload --send-mail --email \"author@chromium.org\"%s"
803 # Expected keyboard input in manual mode:
805 self.ExpectReadline([
806 RL("reviewer@chromium.org"), # Chromium reviewer.
809 # Expected keyboard input in semi-automatic mode and forced mode:
811 self.ExpectReadline([])
813 args = ["-a", "author@chromium.org", "-c", TEST_CONFIG[CHROMIUM]]
814 if force: args.append("-f")
815 if manual: args.append("-m")
816 else: args += ["-r", "reviewer@chromium.org"]
817 ChromiumRoll(TEST_CONFIG, self).Run(args)
819 deps = FileToText(TEST_CONFIG[DEPS_FILE])
820 self.assertTrue(re.search("\"v8_revision\": \"123455\"", deps))
822 def testChromiumRollManual(self):
823 self._ChromiumRoll(manual=True)
825 def testChromiumRollSemiAutomatic(self):
828 def testChromiumRollForced(self):
829 self._ChromiumRoll(force=True)
831 def testCheckLastPushRecently(self):
833 Git(("log -1 --format=%H --grep="
834 "\"^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\" "
835 "svn/trunk"), "hash2\n"),
836 Git("log -1 --format=%s hash2",
837 "Version 3.4.5 (based on bleeding_edge revision r99)\n"),
840 self._state["lkgr"] = "101"
842 self.assertRaises(Exception, lambda: self.RunStep(auto_push.AutoPush,
846 def testAutoPush(self):
847 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
848 TEST_CONFIG[SETTINGS_LOCATION] = "~/.doesnotexist"
851 URL("https://v8-status.appspot.com/current?format=json",
852 "{\"message\": \"Tree is throttled\"}"),
853 URL("https://v8-status.appspot.com/lkgr", Exception("Network problem")),
854 URL("https://v8-status.appspot.com/lkgr", "100"),
858 Git("status -s -uno", ""),
859 Git("status -s -b -uno", "## some_branch\n"),
860 Git("svn fetch", ""),
861 Git(("log -1 --format=%H --grep=\""
862 "^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based\""
863 " svn/trunk"), "push_hash\n"),
864 Git("log -1 --format=%s push_hash",
865 "Version 3.4.5 (based on bleeding_edge revision r79)\n"),
868 auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS + ["--push"])
870 state = json.loads(FileToText("%s-state.json"
871 % TEST_CONFIG[PERSISTFILE_BASENAME]))
873 self.assertEquals("100", state["lkgr"])
875 def testAutoPushStoppedBySettings(self):
876 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
877 TEST_CONFIG[SETTINGS_LOCATION] = self.MakeEmptyTempFile()
878 TextToFile("{\"enable_auto_push\": false}", TEST_CONFIG[SETTINGS_LOCATION])
880 self.ExpectReadURL([])
883 Git("status -s -uno", ""),
884 Git("status -s -b -uno", "## some_branch\n"),
885 Git("svn fetch", ""),
889 auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS)
890 self.assertRaises(Exception, RunAutoPush)
892 def testAutoPushStoppedByTreeStatus(self):
893 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
894 TEST_CONFIG[SETTINGS_LOCATION] = "~/.doesnotexist"
897 URL("https://v8-status.appspot.com/current?format=json",
898 "{\"message\": \"Tree is throttled (no push)\"}"),
902 Git("status -s -uno", ""),
903 Git("status -s -b -uno", "## some_branch\n"),
904 Git("svn fetch", ""),
908 auto_push.AutoPush(TEST_CONFIG, self).Run(AUTO_PUSH_ARGS)
909 self.assertRaises(Exception, RunAutoPush)
911 def testMergeToBranch(self):
912 TEST_CONFIG[ALREADY_MERGING_SENTINEL_FILE] = self.MakeEmptyTempFile()
913 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
914 TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile()
915 self.WriteFakeVersionFile(build=5)
916 os.environ["EDITOR"] = "vi"
917 extra_patch = self.MakeEmptyTempFile()
919 def VerifyPatch(patch):
920 return lambda: self.assertEquals(patch,
921 FileToText(TEST_CONFIG[TEMPORARY_PATCH_FILE]))
923 msg = """Merged r12345, r23456, r34567, r45678, r56789 into trunk branch.
935 BUG=123,234,345,456,567,v8:123
939 def VerifySVNCommit():
940 commit = FileToText(TEST_CONFIG[COMMITMSG_FILE])
941 self.assertEquals(msg, commit)
942 version = FileToText(TEST_CONFIG[VERSION_FILE])
943 self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version))
944 self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version))
945 self.assertTrue(re.search(r"#define PATCH_LEVEL\s+1", version))
946 self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
949 Git("status -s -uno", ""),
950 Git("status -s -b -uno", "## some_branch\n"),
951 Git("svn fetch", ""),
952 Git("branch", " branch1\n* branch2\n"),
953 Git("checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""),
954 Git("branch", " branch1\n* branch2\n"),
955 Git("checkout -b %s svn/trunk" % TEST_CONFIG[BRANCHNAME], ""),
956 Git("log --format=%H --grep=\"Port r12345\" --reverse svn/bleeding_edge",
958 Git("svn find-rev hash1 svn/bleeding_edge", "45678"),
959 Git("log -1 --format=%s hash1", "Title1"),
960 Git("svn find-rev hash2 svn/bleeding_edge", "23456"),
961 Git("log -1 --format=%s hash2", "Title2"),
962 Git("log --format=%H --grep=\"Port r23456\" --reverse svn/bleeding_edge",
964 Git("log --format=%H --grep=\"Port r34567\" --reverse svn/bleeding_edge",
966 Git("svn find-rev hash3 svn/bleeding_edge", "56789"),
967 Git("log -1 --format=%s hash3", "Title3"),
968 Git("svn find-rev r12345 svn/bleeding_edge", "hash4"),
969 # Simulate svn being down which stops the script.
970 Git("svn find-rev r23456 svn/bleeding_edge", None),
971 # Restart script in the failing step.
972 Git("svn find-rev r12345 svn/bleeding_edge", "hash4"),
973 Git("svn find-rev r23456 svn/bleeding_edge", "hash2"),
974 Git("svn find-rev r34567 svn/bleeding_edge", "hash3"),
975 Git("svn find-rev r45678 svn/bleeding_edge", "hash1"),
976 Git("svn find-rev r56789 svn/bleeding_edge", "hash5"),
977 Git("log -1 --format=%s hash4", "Title4"),
978 Git("log -1 --format=%s hash2", "Title2"),
979 Git("log -1 --format=%s hash3", "Title3"),
980 Git("log -1 --format=%s hash1", "Title1"),
981 Git("log -1 --format=%s hash5", "Title5"),
982 Git("log -1 hash4", "Title4\nBUG=123\nBUG=234"),
983 Git("log -1 hash2", "Title2\n BUG = v8:123,345"),
984 Git("log -1 hash3", "Title3\nLOG=n\nBUG=567, 456"),
985 Git("log -1 hash1", "Title1"),
986 Git("log -1 hash5", "Title5"),
987 Git("log -1 -p hash4", "patch4"),
988 Git("apply --index --reject \"%s\"" % TEST_CONFIG[TEMPORARY_PATCH_FILE],
989 "", cb=VerifyPatch("patch4")),
990 Git("log -1 -p hash2", "patch2"),
991 Git("apply --index --reject \"%s\"" % TEST_CONFIG[TEMPORARY_PATCH_FILE],
992 "", cb=VerifyPatch("patch2")),
993 Git("log -1 -p hash3", "patch3"),
994 Git("apply --index --reject \"%s\"" % TEST_CONFIG[TEMPORARY_PATCH_FILE],
995 "", cb=VerifyPatch("patch3")),
996 Git("log -1 -p hash1", "patch1"),
997 Git("apply --index --reject \"%s\"" % TEST_CONFIG[TEMPORARY_PATCH_FILE],
998 "", cb=VerifyPatch("patch1")),
999 Git("log -1 -p hash5", "patch5\n"),
1000 Git("apply --index --reject \"%s\"" % TEST_CONFIG[TEMPORARY_PATCH_FILE],
1001 "", cb=VerifyPatch("patch5\n")),
1002 Git("apply --index --reject \"%s\"" % extra_patch, ""),
1003 Git("commit -aF \"%s\"" % TEST_CONFIG[COMMITMSG_FILE], ""),
1004 Git("cl upload --send-mail -r \"reviewer@chromium.org\"", ""),
1005 Git("checkout -f %s" % TEST_CONFIG[BRANCHNAME], ""),
1006 Git("cl presubmit", "Presubmit successfull\n"),
1007 Git("cl dcommit -f --bypass-hooks", "Closing issue\n", cb=VerifySVNCommit),
1008 Git("svn fetch", ""),
1009 Git("log -1 --format=%%H --grep=\"%s\" svn/trunk" % msg, "hash6"),
1010 Git("svn find-rev hash6", "1324"),
1011 Git(("copy -r 1324 https://v8.googlecode.com/svn/trunk "
1012 "https://v8.googlecode.com/svn/tags/3.22.5.1 -m "
1013 "\"Tagging version 3.22.5.1\""), ""),
1014 Git("checkout -f some_branch", ""),
1015 Git("branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""),
1016 Git("branch -D %s" % TEST_CONFIG[BRANCHNAME], ""),
1019 self.ExpectReadline([
1020 RL("Y"), # Automatically add corresponding ports (34567, 56789)?
1021 RL("Y"), # Automatically increment patch level?
1022 RL("reviewer@chromium.org"), # V8 reviewer.
1023 RL("LGTM"), # Enter LGTM for V8 CL.
1026 # r12345 and r34567 are patches. r23456 (included) and r45678 are the MIPS
1027 # ports of r12345. r56789 is the MIPS port of r34567.
1028 args = ["-f", "-p", extra_patch, "--branch", "trunk", "12345", "23456",
1031 # The first run of the script stops because of the svn being down.
1032 self.assertRaises(GitFailedException,
1033 lambda: MergeToBranch(TEST_CONFIG, self).Run(args))
1035 # Test that state recovery after restarting the script works.
1037 MergeToBranch(TEST_CONFIG, self).Run(args)
1040 class SystemTest(unittest.TestCase):
1041 def testReload(self):
1042 step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={},
1043 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER)
1045 """------------------------------------------------------------------------
1046 r17997 | machenbach@chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines
1048 Prepare push to trunk. Now working on version 3.23.11.
1050 R=danno@chromium.org
1052 Review URL: https://codereview.chromium.org/83173002
1054 ------------------------------------------------------------------------""")
1056 """Prepare push to trunk. Now working on version 3.23.11.
1058 R=danno@chromium.org
1060 Committed: https://code.google.com/p/v8/source/detail?r=17997""", body)