1 #!/usr/bin/env python 2 # Copyright 2013 the V8 project authors. All rights reserved. 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions are 5 # met: 6 # 7 # * Redistributions of source code must retain the above copyright 8 # notice, this list of conditions and the following disclaimer. 9 # * Redistributions in binary form must reproduce the above 10 # copyright notice, this list of conditions and the following 11 # disclaimer in the documentation and/or other materials provided 12 # with the distribution. 13 # * Neither the name of Google Inc. nor the names of its 14 # contributors may be used to endorse or promote products derived 15 # from this software without specific prior written permission. 16 # 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 import os 30 import tempfile 31 import unittest 32 33 import common_includes 34 from common_includes import * 35 import push_to_trunk 36 from push_to_trunk import * 37 import auto_roll 38 39 40 TEST_CONFIG = { 41 BRANCHNAME: "test-prepare-push", 42 TRUNKBRANCH: "test-trunk-push", 43 PERSISTFILE_BASENAME: "/tmp/test-v8-push-to-trunk-tempfile", 44 TEMP_BRANCH: "test-prepare-push-temporary-branch-created-by-script", 45 DOT_GIT_LOCATION: None, 46 VERSION_FILE: None, 47 CHANGELOG_FILE: None, 48 CHANGELOG_ENTRY_FILE: "/tmp/test-v8-push-to-trunk-tempfile-changelog-entry", 49 PATCH_FILE: "/tmp/test-v8-push-to-trunk-tempfile-patch", 50 COMMITMSG_FILE: "/tmp/test-v8-push-to-trunk-tempfile-commitmsg", 51 CHROMIUM: "/tmp/test-v8-push-to-trunk-tempfile-chromium", 52 DEPS_FILE: "/tmp/test-v8-push-to-trunk-tempfile-chromium/DEPS", 53 } 54 55 56 def MakeOptions(s=0, l=None, f=False, m=True, r=None, c=None): 57 """Convenience wrapper.""" 58 class Options(object): 59 pass 60 options = Options() 61 options.s = s 62 options.l = l 63 options.f = f 64 options.m = m 65 options.r = r 66 options.c = c 67 return options 68 69 70 class ToplevelTest(unittest.TestCase): 71 def testMakeComment(self): 72 self.assertEquals("# Line 1\n# Line 2\n#", 73 MakeComment(" Line 1\n Line 2\n")) 74 self.assertEquals("#Line 1\n#Line 2", 75 MakeComment("Line 1\n Line 2")) 76 77 def testStripComments(self): 78 self.assertEquals(" Line 1\n Line 3\n", 79 StripComments(" Line 1\n# Line 2\n Line 3\n#\n")) 80 self.assertEquals("\nLine 2 ### Test\n #", 81 StripComments("###\n# \n\n# Line 1\nLine 2 ### Test\n #")) 82 83 def testMakeChangeLogBodySimple(self): 84 commits = [ 85 ["Title text 1", 86 "Title text 1\n\nBUG=\n", 87 "author1 (at] chromium.org"], 88 ["Title text 2.", 89 "Title text 2\n\nBUG=1234\n", 90 "author2 (at] chromium.org"], 91 ] 92 self.assertEquals(" Title text 1.\n" 93 " (author1 (at] chromium.org)\n\n" 94 " Title text 2 (Chromium issue 1234).\n" 95 " (author2 (at] chromium.org)\n\n", 96 MakeChangeLogBody(commits)) 97 98 def testMakeChangeLogBodyEmpty(self): 99 self.assertEquals("", MakeChangeLogBody([])) 100 101 def testMakeChangeLogBodyAutoFormat(self): 102 commits = [ 103 ["Title text 1!", 104 "Title text 1\nLOG=y\nBUG=\n", 105 "author1 (at] chromium.org"], 106 ["Title text 2", 107 "Title text 2\n\nBUG=1234\n", 108 "author2 (at] chromium.org"], 109 ["Title text 3", 110 "Title text 3\n\nBUG=1234\nLOG = Yes\n", 111 "author3 (at] chromium.org"], 112 ["Title text 3", 113 "Title text 4\n\nBUG=1234\nLOG=\n", 114 "author4 (at] chromium.org"], 115 ] 116 self.assertEquals(" Title text 1.\n\n" 117 " Title text 3 (Chromium issue 1234).\n\n", 118 MakeChangeLogBody(commits, True)) 119 120 def testRegressWrongLogEntryOnTrue(self): 121 body = """ 122 Check elimination: Learn from if(CompareMap(x)) on true branch. 123 124 BUG= 125 R=verwaest (at] chromium.org 126 127 Committed: https://code.google.com/p/v8/source/detail?r=18210 128 """ 129 self.assertEquals("", MakeChangeLogBody([["title", body, "author"]], True)) 130 131 def testMakeChangeLogBugReferenceEmpty(self): 132 self.assertEquals("", MakeChangeLogBugReference("")) 133 self.assertEquals("", MakeChangeLogBugReference("LOG=")) 134 self.assertEquals("", MakeChangeLogBugReference(" BUG =")) 135 self.assertEquals("", MakeChangeLogBugReference("BUG=none\t")) 136 137 def testMakeChangeLogBugReferenceSimple(self): 138 self.assertEquals("(issue 987654)", 139 MakeChangeLogBugReference("BUG = v8:987654")) 140 self.assertEquals("(Chromium issue 987654)", 141 MakeChangeLogBugReference("BUG=987654 ")) 142 143 def testMakeChangeLogBugReferenceFromBody(self): 144 self.assertEquals("(Chromium issue 1234567)", 145 MakeChangeLogBugReference("Title\n\nTBR=\nBUG=\n" 146 " BUG=\tchromium:1234567\t\n" 147 "R=somebody\n")) 148 149 def testMakeChangeLogBugReferenceMultiple(self): 150 # All issues should be sorted and grouped. Multiple references to the same 151 # issue should be filtered. 152 self.assertEquals("(issues 123, 234, Chromium issue 345)", 153 MakeChangeLogBugReference("Title\n\n" 154 "BUG=v8:234\n" 155 " BUG\t= 345, \tv8:234,\n" 156 "BUG=v8:123\n" 157 "R=somebody\n")) 158 self.assertEquals("(Chromium issues 123, 234)", 159 MakeChangeLogBugReference("Title\n\n" 160 "BUG=234,,chromium:123 \n" 161 "R=somebody\n")) 162 self.assertEquals("(Chromium issues 123, 234)", 163 MakeChangeLogBugReference("Title\n\n" 164 "BUG=chromium:234, , 123\n" 165 "R=somebody\n")) 166 self.assertEquals("(issues 345, 456)", 167 MakeChangeLogBugReference("Title\n\n" 168 "\t\tBUG=v8:345,v8:456\n" 169 "R=somebody\n")) 170 self.assertEquals("(issue 123, Chromium issues 345, 456)", 171 MakeChangeLogBugReference("Title\n\n" 172 "BUG=chromium:456\n" 173 "BUG = none\n" 174 "R=somebody\n" 175 "BUG=456,v8:123, 345")) 176 177 # TODO(machenbach): These test don't make much sense when the formatting is 178 # done later. 179 def testMakeChangeLogBugReferenceLong(self): 180 # -----------------00--------10--------20--------30-------- 181 self.assertEquals("(issues 234, 1234567890, 1234567" 182 "8901234567890, Chromium issues 12345678," 183 " 123456789)", 184 MakeChangeLogBugReference("BUG=v8:234\n" 185 "BUG=v8:1234567890\n" 186 "BUG=v8:12345678901234567890\n" 187 "BUG=123456789\n" 188 "BUG=12345678\n")) 189 # -----------------00--------10--------20--------30-------- 190 self.assertEquals("(issues 234, 1234567890, 1234567" 191 "8901234567890, Chromium issues" 192 " 123456789, 1234567890)", 193 MakeChangeLogBugReference("BUG=v8:234\n" 194 "BUG=v8:12345678901234567890\n" 195 "BUG=v8:1234567890\n" 196 "BUG=123456789\n" 197 "BUG=1234567890\n")) 198 # -----------------00--------10--------20--------30-------- 199 self.assertEquals("(Chromium issues 234, 1234567890" 200 ", 12345678901234567, " 201 "1234567890123456789)", 202 MakeChangeLogBugReference("BUG=234\n" 203 "BUG=12345678901234567\n" 204 "BUG=1234567890123456789\n" 205 "BUG=1234567890\n")) 206 207 208 class SimpleMock(object): 209 def __init__(self, name): 210 self._name = name 211 self._recipe = [] 212 self._index = -1 213 214 def Expect(self, recipe): 215 self._recipe = recipe 216 217 def Call(self, *args): 218 self._index += 1 219 try: 220 expected_call = self._recipe[self._index] 221 except IndexError: 222 raise Exception("Calling %s %s" % (self._name, " ".join(args))) 223 224 # Pack expectations without arguments into a list. 225 if not isinstance(expected_call, list): 226 expected_call = [expected_call] 227 228 # The number of arguments in the expectation must match the actual 229 # arguments. 230 if len(args) > len(expected_call): 231 raise Exception("When calling %s with arguments, the expectations " 232 "must consist of at least as many arguments.") 233 234 # Compare expected and actual arguments. 235 for (expected_arg, actual_arg) in zip(expected_call, args): 236 if expected_arg != actual_arg: 237 raise Exception("Expected: %s - Actual: %s" 238 % (expected_arg, actual_arg)) 239 240 # The expectation list contains a mandatory return value and an optional 241 # callback for checking the context at the time of the call. 242 if len(expected_call) == len(args) + 2: 243 expected_call[len(args) + 1]() 244 return_value = expected_call[len(args)] 245 246 # If the return value is an exception, raise it instead of returning. 247 if isinstance(return_value, Exception): 248 raise return_value 249 return return_value 250 251 def AssertFinished(self): 252 if self._index < len(self._recipe) -1: 253 raise Exception("Called %s too seldom: %d vs. %d" 254 % (self._name, self._index, len(self._recipe))) 255 256 257 class ScriptTest(unittest.TestCase): 258 def MakeEmptyTempFile(self): 259 handle, name = tempfile.mkstemp() 260 os.close(handle) 261 self._tmp_files.append(name) 262 return name 263 264 def MakeTempVersionFile(self): 265 name = self.MakeEmptyTempFile() 266 with open(name, "w") as f: 267 f.write(" // Some line...\n") 268 f.write("\n") 269 f.write("#define MAJOR_VERSION 3\n") 270 f.write("#define MINOR_VERSION 22\n") 271 f.write("#define BUILD_NUMBER 5\n") 272 f.write("#define PATCH_LEVEL 0\n") 273 f.write(" // Some line...\n") 274 f.write("#define IS_CANDIDATE_VERSION 0\n") 275 return name 276 277 def MakeStep(self, step_class=Step, state=None, options=None): 278 """Convenience wrapper.""" 279 options = options or MakeOptions() 280 return MakeStep(step_class=step_class, number=0, state=state, 281 config=TEST_CONFIG, options=options, 282 side_effect_handler=self) 283 284 def GitMock(self, cmd, args="", pipe=True): 285 print "%s %s" % (cmd, args) 286 return self._git_mock.Call(args) 287 288 def LogMock(self, cmd, args=""): 289 print "Log: %s %s" % (cmd, args) 290 291 MOCKS = { 292 "git": GitMock, 293 "vi": LogMock, 294 } 295 296 def Command(self, cmd, args="", prefix="", pipe=True): 297 return ScriptTest.MOCKS[cmd](self, cmd, args) 298 299 def ReadLine(self): 300 return self._rl_mock.Call() 301 302 def ReadURL(self, url): 303 return self._url_mock.Call(url) 304 305 def Sleep(self, seconds): 306 pass 307 308 def GetDate(self): 309 return "1999-07-31" 310 311 def ExpectGit(self, *args): 312 """Convenience wrapper.""" 313 self._git_mock.Expect(*args) 314 315 def ExpectReadline(self, *args): 316 """Convenience wrapper.""" 317 self._rl_mock.Expect(*args) 318 319 def ExpectReadURL(self, *args): 320 """Convenience wrapper.""" 321 self._url_mock.Expect(*args) 322 323 def setUp(self): 324 self._git_mock = SimpleMock("git") 325 self._rl_mock = SimpleMock("readline") 326 self._url_mock = SimpleMock("readurl") 327 self._tmp_files = [] 328 329 def tearDown(self): 330 Command("rm", "-rf %s*" % TEST_CONFIG[PERSISTFILE_BASENAME]) 331 332 # Clean up temps. Doesn't work automatically. 333 for name in self._tmp_files: 334 if os.path.exists(name): 335 os.remove(name) 336 337 self._git_mock.AssertFinished() 338 self._rl_mock.AssertFinished() 339 self._url_mock.AssertFinished() 340 341 def testPersistRestore(self): 342 self.MakeStep().Persist("test1", "") 343 self.assertEquals("", self.MakeStep().Restore("test1")) 344 self.MakeStep().Persist("test2", "AB123") 345 self.assertEquals("AB123", self.MakeStep().Restore("test2")) 346 347 def testGitOrig(self): 348 self.assertTrue(Command("git", "--version").startswith("git version")) 349 350 def testGitMock(self): 351 self.ExpectGit([["--version", "git version 1.2.3"], ["dummy", ""]]) 352 self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version")) 353 self.assertEquals("", self.MakeStep().Git("dummy")) 354 355 def testCommonPrepareDefault(self): 356 self.ExpectGit([ 357 ["status -s -uno", ""], 358 ["status -s -b -uno", "## some_branch"], 359 ["svn fetch", ""], 360 ["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]], 361 ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""], 362 ["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""], 363 ["branch", ""], 364 ]) 365 self.ExpectReadline(["Y"]) 366 self.MakeStep().CommonPrepare() 367 self.MakeStep().PrepareBranch() 368 self.assertEquals("some_branch", self.MakeStep().Restore("current_branch")) 369 370 def testCommonPrepareNoConfirm(self): 371 self.ExpectGit([ 372 ["status -s -uno", ""], 373 ["status -s -b -uno", "## some_branch"], 374 ["svn fetch", ""], 375 ["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]], 376 ]) 377 self.ExpectReadline(["n"]) 378 self.MakeStep().CommonPrepare() 379 self.assertRaises(Exception, self.MakeStep().PrepareBranch) 380 self.assertEquals("some_branch", self.MakeStep().Restore("current_branch")) 381 382 def testCommonPrepareDeleteBranchFailure(self): 383 self.ExpectGit([ 384 ["status -s -uno", ""], 385 ["status -s -b -uno", "## some_branch"], 386 ["svn fetch", ""], 387 ["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]], 388 ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], None], 389 ]) 390 self.ExpectReadline(["Y"]) 391 self.MakeStep().CommonPrepare() 392 self.assertRaises(Exception, self.MakeStep().PrepareBranch) 393 self.assertEquals("some_branch", self.MakeStep().Restore("current_branch")) 394 395 def testInitialEnvironmentChecks(self): 396 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() 397 os.environ["EDITOR"] = "vi" 398 self.MakeStep().InitialEnvironmentChecks() 399 400 def testReadAndPersistVersion(self): 401 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() 402 step = self.MakeStep() 403 step.ReadAndPersistVersion() 404 self.assertEquals("3", self.MakeStep().Restore("major")) 405 self.assertEquals("22", self.MakeStep().Restore("minor")) 406 self.assertEquals("5", self.MakeStep().Restore("build")) 407 self.assertEquals("0", self.MakeStep().Restore("patch")) 408 self.assertEquals("3", step._state["major"]) 409 self.assertEquals("22", step._state["minor"]) 410 self.assertEquals("5", step._state["build"]) 411 self.assertEquals("0", step._state["patch"]) 412 413 def testRegex(self): 414 self.assertEqual("(issue 321)", 415 re.sub(r"BUG=v8:(.*)$", r"(issue \1)", "BUG=v8:321")) 416 self.assertEqual("(Chromium issue 321)", 417 re.sub(r"BUG=(.*)$", r"(Chromium issue \1)", "BUG=321")) 418 419 cl = " too little\n\ttab\ttab\n too much\n trailing " 420 cl = MSub(r"\t", r" ", cl) 421 cl = MSub(r"^ {1,7}([^ ])", r" \1", cl) 422 cl = MSub(r"^ {9,80}([^ ])", r" \1", cl) 423 cl = MSub(r" +$", r"", cl) 424 self.assertEqual(" too little\n" 425 " tab tab\n" 426 " too much\n" 427 " trailing", cl) 428 429 self.assertEqual("//\n#define BUILD_NUMBER 3\n", 430 MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$", 431 r"\g<space>3", 432 "//\n#define BUILD_NUMBER 321\n")) 433 434 def testPrepareChangeLog(self): 435 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() 436 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() 437 438 self.ExpectGit([ 439 ["log 1234..HEAD --format=%H", "rev1\nrev2\nrev3\nrev4"], 440 ["log -1 rev1 --format=\"%s\"", "Title text 1"], 441 ["log -1 rev1 --format=\"%B\"", "Title\n\nBUG=\nLOG=y\n"], 442 ["log -1 rev1 --format=\"%an\"", "author1 (at] chromium.org"], 443 ["log -1 rev2 --format=\"%s\"", "Title text 2."], 444 ["log -1 rev2 --format=\"%B\"", "Title\n\nBUG=123\nLOG= \n"], 445 ["log -1 rev2 --format=\"%an\"", "author2 (at] chromium.org"], 446 ["log -1 rev3 --format=\"%s\"", "Title text 3"], 447 ["log -1 rev3 --format=\"%B\"", "Title\n\nBUG=321\nLOG=true\n"], 448 ["log -1 rev3 --format=\"%an\"", "author3 (at] chromium.org"], 449 ["log -1 rev4 --format=\"%s\"", "Title text 4"], 450 ["log -1 rev4 --format=\"%B\"", 451 ("Title\n\nBUG=456\nLOG=Y\n\n" 452 "Review URL: https://codereview.chromium.org/9876543210\n")], 453 ["log -1 rev4 --format=\"%an\"", "author4 (at] chromium.org"], 454 ]) 455 456 # The cl for rev4 on rietveld has an updated LOG flag. 457 self.ExpectReadURL([ 458 ["https://codereview.chromium.org/9876543210/description", 459 "Title\n\nBUG=456\nLOG=N\n\n"], 460 ]) 461 462 self.MakeStep().Persist("last_push", "1234") 463 self.MakeStep(PrepareChangeLog).Run() 464 465 actual_cl = FileToText(TEST_CONFIG[CHANGELOG_ENTRY_FILE]) 466 467 expected_cl = """1999-07-31: Version 3.22.5 468 469 Title text 1. 470 471 Title text 3 (Chromium issue 321). 472 473 Performance and stability improvements on all platforms. 474 # 475 # The change log above is auto-generated. Please review if all relevant 476 # commit messages from the list below are included. 477 # All lines starting with # will be stripped. 478 # 479 # Title text 1. 480 # (author1 (at] chromium.org) 481 # 482 # Title text 2 (Chromium issue 123). 483 # (author2 (at] chromium.org) 484 # 485 # Title text 3 (Chromium issue 321). 486 # (author3 (at] chromium.org) 487 # 488 # Title text 4 (Chromium issue 456). 489 # (author4 (at] chromium.org) 490 # 491 #""" 492 493 self.assertEquals(expected_cl, actual_cl) 494 self.assertEquals("3", self.MakeStep().Restore("major")) 495 self.assertEquals("22", self.MakeStep().Restore("minor")) 496 self.assertEquals("5", self.MakeStep().Restore("build")) 497 self.assertEquals("0", self.MakeStep().Restore("patch")) 498 499 def testEditChangeLog(self): 500 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() 501 TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile() 502 TextToFile(" Original CL", TEST_CONFIG[CHANGELOG_FILE]) 503 TextToFile(" New \n\tLines \n", TEST_CONFIG[CHANGELOG_ENTRY_FILE]) 504 os.environ["EDITOR"] = "vi" 505 506 self.ExpectReadline([ 507 "", # Open editor. 508 ]) 509 510 self.MakeStep(EditChangeLog).Run() 511 512 self.assertEquals("New\n Lines\n\n\n Original CL", 513 FileToText(TEST_CONFIG[CHANGELOG_FILE])) 514 515 def testIncrementVersion(self): 516 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() 517 self.MakeStep().Persist("build", "5") 518 519 self.ExpectReadline([ 520 "Y", # Increment build number. 521 ]) 522 523 self.MakeStep(IncrementVersion).Run() 524 525 self.assertEquals("3", self.MakeStep().Restore("new_major")) 526 self.assertEquals("22", self.MakeStep().Restore("new_minor")) 527 self.assertEquals("6", self.MakeStep().Restore("new_build")) 528 self.assertEquals("0", self.MakeStep().Restore("new_patch")) 529 530 def testLastChangeLogEntries(self): 531 TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile() 532 l = """ 533 Fixed something. 534 (issue 1234)\n""" 535 for _ in xrange(10): l = l + l 536 537 cl_chunk = """2013-11-12: Version 3.23.2\n%s 538 Performance and stability improvements on all platforms.\n\n\n""" % l 539 540 cl_chunk_full = cl_chunk + cl_chunk + cl_chunk 541 TextToFile(cl_chunk_full, TEST_CONFIG[CHANGELOG_FILE]) 542 543 cl = GetLastChangeLogEntries(TEST_CONFIG[CHANGELOG_FILE]) 544 self.assertEquals(cl_chunk, cl) 545 546 def testSquashCommits(self): 547 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() 548 with open(TEST_CONFIG[CHANGELOG_ENTRY_FILE], "w") as f: 549 f.write("1999-11-11: Version 3.22.5\n") 550 f.write("\n") 551 f.write(" Log text 1.\n") 552 f.write(" Chromium issue 12345\n") 553 f.write("\n") 554 f.write(" Performance and stability improvements on all " 555 "platforms.\n") 556 557 self.ExpectGit([ 558 ["diff svn/trunk hash1", "patch content"], 559 ]) 560 561 self.MakeStep().Persist("prepare_commit_hash", "hash1") 562 self.MakeStep().Persist("date", "1999-11-11") 563 564 self.MakeStep(SquashCommits).Run() 565 566 msg = FileToText(TEST_CONFIG[COMMITMSG_FILE]) 567 self.assertTrue(re.search(r"Version 3\.22\.5", msg)) 568 self.assertTrue(re.search(r"Performance and stability", msg)) 569 self.assertTrue(re.search(r"Log text 1\. Chromium issue 12345", msg)) 570 self.assertFalse(re.search(r"\d+\-\d+\-\d+", msg)) 571 572 patch = FileToText(TEST_CONFIG[ PATCH_FILE]) 573 self.assertTrue(re.search(r"patch content", patch)) 574 575 def _PushToTrunk(self, force=False, manual=False): 576 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() 577 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() 578 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() 579 TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile() 580 if not os.path.exists(TEST_CONFIG[CHROMIUM]): 581 os.makedirs(TEST_CONFIG[CHROMIUM]) 582 TextToFile("1999-04-05: Version 3.22.4", TEST_CONFIG[CHANGELOG_FILE]) 583 TextToFile("Some line\n \"v8_revision\": \"123444\",\n some line", 584 TEST_CONFIG[DEPS_FILE]) 585 os.environ["EDITOR"] = "vi" 586 587 def CheckPreparePush(): 588 cl = FileToText(TEST_CONFIG[CHANGELOG_FILE]) 589 self.assertTrue(re.search(r"Version 3.22.5", cl)) 590 self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl)) 591 self.assertFalse(re.search(r" \(author1@chromium\.org\)", cl)) 592 593 # Make sure all comments got stripped. 594 self.assertFalse(re.search(r"^#", cl, flags=re.M)) 595 596 version = FileToText(TEST_CONFIG[VERSION_FILE]) 597 self.assertTrue(re.search(r"#define BUILD_NUMBER\s+6", version)) 598 599 def CheckUpload(): 600 cl = FileToText(TEST_CONFIG[CHANGELOG_FILE]) 601 602 def CheckSVNCommit(): 603 commit = FileToText(TEST_CONFIG[COMMITMSG_FILE]) 604 self.assertTrue(re.search(r"Version 3.22.5", commit)) 605 self.assertTrue(re.search(r"Log text 1 \(issue 321\).", commit)) 606 version = FileToText(TEST_CONFIG[VERSION_FILE]) 607 self.assertTrue(re.search(r"#define MINOR_VERSION\s+22", version)) 608 self.assertTrue(re.search(r"#define BUILD_NUMBER\s+5", version)) 609 self.assertFalse(re.search(r"#define BUILD_NUMBER\s+6", version)) 610 self.assertTrue(re.search(r"#define PATCH_LEVEL\s+0", version)) 611 self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version)) 612 613 force_flag = " -f" if not manual else "" 614 review_suffix = "\n\nTBR=reviewer (at] chromium.org" if not manual else "" 615 self.ExpectGit([ 616 ["status -s -uno", ""], 617 ["status -s -b -uno", "## some_branch\n"], 618 ["svn fetch", ""], 619 ["branch", " branch1\n* branch2\n"], 620 ["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""], 621 ["branch", " branch1\n* branch2\n"], 622 ["branch", " branch1\n* branch2\n"], 623 ["checkout -b %s svn/bleeding_edge" % TEST_CONFIG[BRANCHNAME], ""], 624 ["log -1 --format=%H ChangeLog", "1234\n"], 625 ["log -1 1234", "Last push ouput\n"], 626 ["log 1234..HEAD --format=%H", "rev1\n"], 627 ["log -1 rev1 --format=\"%s\"", "Log text 1.\n"], 628 ["log -1 rev1 --format=\"%B\"", "Text\nLOG=YES\nBUG=v8:321\nText\n"], 629 ["log -1 rev1 --format=\"%an\"", "author1 (at] chromium.org\n"], 630 [("commit -a -m \"Prepare push to trunk. " 631 "Now working on version 3.22.6.%s\"" % review_suffix), 632 " 2 files changed\n", 633 CheckPreparePush], 634 ["cl upload -r \"reviewer (at] chromium.org\" --send-mail%s" % force_flag, 635 "done\n"], 636 ["cl dcommit -f", "Closing issue\n"], 637 ["svn fetch", "fetch result\n"], 638 ["checkout svn/bleeding_edge", ""], 639 [("log -1 --format=%H --grep=\"Prepare push to trunk. " 640 "Now working on version 3.22.6.\""), 641 "hash1\n"], 642 ["diff svn/trunk hash1", "patch content\n"], 643 ["checkout -b %s svn/trunk" % TEST_CONFIG[TRUNKBRANCH], ""], 644 ["apply --index --reject \"%s\"" % TEST_CONFIG[PATCH_FILE], ""], 645 ["add \"%s\"" % TEST_CONFIG[VERSION_FILE], ""], 646 ["commit -F \"%s\"" % TEST_CONFIG[COMMITMSG_FILE], "", CheckSVNCommit], 647 ["svn dcommit 2>&1", "Some output\nCommitted r123456\nSome output\n"], 648 ["svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""], 649 ["status -s -uno", ""], 650 ["checkout master", ""], 651 ["pull", ""], 652 ["checkout -b v8-roll-123456", ""], 653 [("commit -am \"Update V8 to version 3.22.5.\n\n" 654 "TBR=reviewer (at] chromium.org\""), 655 ""], 656 ["cl upload --send-mail%s" % force_flag, ""], 657 ["checkout -f some_branch", ""], 658 ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""], 659 ["branch -D %s" % TEST_CONFIG[BRANCHNAME], ""], 660 ["branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""], 661 ]) 662 663 # Expected keyboard input in manual mode: 664 if manual: 665 self.ExpectReadline([ 666 "Y", # Confirm last push. 667 "", # Open editor. 668 "Y", # Increment build number. 669 "reviewer (at] chromium.org", # V8 reviewer. 670 "LGTX", # Enter LGTM for V8 CL (wrong). 671 "LGTM", # Enter LGTM for V8 CL. 672 "Y", # Sanity check. 673 "reviewer (at] chromium.org", # Chromium reviewer. 674 ]) 675 676 # Expected keyboard input in semi-automatic mode: 677 if not manual and not force: 678 self.ExpectReadline([ 679 "LGTM", # Enter LGTM for V8 CL. 680 ]) 681 682 # No keyboard input in forced mode: 683 if force: 684 self.ExpectReadline([]) 685 686 options = MakeOptions(f=force, m=manual, 687 r="reviewer (at] chromium.org" if not manual else None, 688 c = TEST_CONFIG[CHROMIUM]) 689 RunPushToTrunk(TEST_CONFIG, options, self) 690 691 deps = FileToText(TEST_CONFIG[DEPS_FILE]) 692 self.assertTrue(re.search("\"v8_revision\": \"123456\"", deps)) 693 694 cl = FileToText(TEST_CONFIG[CHANGELOG_FILE]) 695 self.assertTrue(re.search(r"^\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl)) 696 self.assertTrue(re.search(r" Log text 1 \(issue 321\).", cl)) 697 self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl)) 698 699 # Note: The version file is on build number 5 again in the end of this test 700 # since the git command that merges to the bleeding edge branch is mocked 701 # out. 702 703 def testPushToTrunkManual(self): 704 self._PushToTrunk(manual=True) 705 706 def testPushToTrunkSemiAutomatic(self): 707 self._PushToTrunk() 708 709 def testPushToTrunkForced(self): 710 self._PushToTrunk(force=True) 711 712 def testAutoRoll(self): 713 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() 714 715 self.ExpectReadURL([ 716 ["https://v8-status.appspot.com/lkgr", Exception("Network problem")], 717 ["https://v8-status.appspot.com/lkgr", "100"], 718 ]) 719 720 self.ExpectGit([ 721 ["status -s -uno", ""], 722 ["status -s -b -uno", "## some_branch\n"], 723 ["svn fetch", ""], 724 ["svn log -1 --oneline", "r101 | Text"], 725 ]) 726 727 auto_roll.RunAutoRoll(TEST_CONFIG, MakeOptions(m=False, f=True), self) 728 729 self.assertEquals("100", self.MakeStep().Restore("lkgr")) 730 self.assertEquals("101", self.MakeStep().Restore("latest")) 731 732 733 class SystemTest(unittest.TestCase): 734 def testReload(self): 735 step = MakeStep(step_class=PrepareChangeLog, number=0, state={}, config={}, 736 options=None, 737 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER) 738 body = step.Reload( 739 """------------------------------------------------------------------------ 740 r17997 | machenbach (at] chromium.org | 2013-11-22 11:04:04 +0100 (...) | 6 lines 741 742 Prepare push to trunk. Now working on version 3.23.11. 743 744 R=danno (at] chromium.org 745 746 Review URL: https://codereview.chromium.org/83173002 747 748 ------------------------------------------------------------------------""") 749 self.assertEquals( 750 """Prepare push to trunk. Now working on version 3.23.11. 751 752 R=danno (at] chromium.org 753 754 Committed: https://code.google.com/p/v8/source/detail?r=17997""", body) 755