OLD | NEW |
---|---|
(Empty) | |
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 | |
38 | |
39 TEST_CONFIG = { | |
40 BRANCHNAME: "test-prepare-push", | |
41 TRUNKBRANCH: "test-trunk-push", | |
42 PERSISTFILE_BASENAME: "/tmp/test-v8-push-to-trunk-tempfile", | |
43 TEMP_BRANCH: "test-prepare-push-temporary-branch-created-by-script", | |
44 DOT_GIT_LOCATION: None, | |
45 VERSION_FILE: None, | |
46 CHANGELOG_FILE: None, | |
47 CHANGELOG_ENTRY_FILE: "/tmp/test-v8-push-to-trunk-tempfile-changelog-entry", | |
48 PATCH_FILE: "/tmp/test-v8-push-to-trunk-tempfile-patch", | |
49 COMMITMSG_FILE: "/tmp/test-v8-push-to-trunk-tempfile-commitmsg", | |
50 CHROMIUM: "/tmp/test-v8-push-to-trunk-tempfile-chromium", | |
51 DEPS_FILE: "/tmp/test-v8-push-to-trunk-tempfile-chromium/DEPS", | |
52 } | |
53 | |
54 | |
55 class ScriptTest(unittest.TestCase): | |
56 def MakeEmptyTempFile(self): | |
57 handle, name = tempfile.mkstemp() | |
58 os.close(handle) | |
59 self._tmp_files.append(name) | |
60 return name | |
61 | |
62 def MakeTempVersionFile(self): | |
63 name = self.MakeEmptyTempFile() | |
64 with open(name, "w") as f: | |
65 f.write(" // Some line...\n") | |
66 f.write("\n") | |
67 f.write("#define MAJOR_VERSION 3\n") | |
68 f.write("#define MINOR_VERSION 22\n") | |
69 f.write("#define BUILD_NUMBER 5\n") | |
70 f.write("#define PATCH_LEVEL 0\n") | |
71 return name | |
72 | |
73 def MakeStep(self, step_class=Step, state=None): | |
74 state = state if state is not None else {} | |
Jakob Kummerow
2013/11/06 16:37:23
shorter:
state = state or {}
Michael Achenbach
2013/11/07 15:56:46
It was like that because of a test that checked th
| |
75 step = step_class() | |
76 step.SetConfig(TEST_CONFIG) | |
77 step.SetState(state) | |
78 step.SetNumber(0) | |
79 step.SetSideEffectHandler(self) | |
80 return step | |
81 | |
82 def GitMock(self, cmd, args="", pipe=True): | |
83 self._git_index += 1 | |
84 try: | |
85 git_invokation = self._git_recipe[self._git_index] | |
Jakob Kummerow
2013/11/06 16:37:23
nit: git_invocation
Michael Achenbach
2013/11/07 15:56:46
Done.
| |
86 except IndexError: | |
87 raise Exception("Calling git %s" % args) | |
88 if git_invokation[0] != args: | |
89 raise Exception("Expected: %s - Actual: %s" % (git_invokation[0], args)) | |
90 if len(git_invokation) == 3: | |
91 # Run optional function checking the context during this git command. | |
92 git_invokation[2]() | |
93 return git_invokation[1] | |
94 | |
95 def LogMock(self, cmd, args=""): | |
96 print "Log: %s %s" % (cmd, args) | |
97 | |
98 MOCKS = { | |
99 "git": GitMock, | |
100 "vi": LogMock, | |
101 } | |
102 | |
103 def Command(self, cmd, args="", prefix="", pipe=True): | |
104 return ScriptTest.MOCKS[cmd](self, cmd, args) | |
105 | |
106 def ReadLine(self): | |
107 self._rl_index += 1 | |
108 try: | |
109 return self._rl_recipe[self._rl_index] | |
110 except IndexError: | |
111 raise Exception("Calling readline too often") | |
112 | |
113 def setUp(self): | |
114 self._git_recipe = [] | |
115 self._git_index = -1 | |
116 self._rl_recipe = [] | |
117 self._rl_index = -1 | |
118 self._tmp_files = [] | |
119 | |
120 def tearDown(self): | |
121 Command("rm", "-rf %s*" % TEST_CONFIG[PERSISTFILE_BASENAME]) | |
122 | |
123 # Clean up temps. Doesn't work automatically. | |
124 for name in self._tmp_files: | |
125 if os.path.exists(name): | |
126 os.remove(name) | |
127 | |
128 if self._git_index < len(self._git_recipe) -1: | |
129 raise Exception("Called git too seldom: %d vs. %d" % (self._git_index, | |
130 len(self._git_recipe))) | |
Jakob Kummerow
2013/11/06 16:37:23
nit: break after '%'
Michael Achenbach
2013/11/07 15:56:46
Done.
| |
131 if self._rl_index < len(self._rl_recipe) -1: | |
132 raise Exception("Too little imput: %d vs. %d" % (self._rl_index, | |
Jakob Kummerow
2013/11/06 16:37:23
nit: s/imput/input/, break after '%'
Michael Achenbach
2013/11/07 15:56:46
Done.
| |
133 len(self._rl_recipe))) | |
134 | |
135 def testPersistRestore(self): | |
136 self.MakeStep().Persist("test1", "") | |
137 self.assertEquals("", self.MakeStep().Restore("test1")) | |
138 self.MakeStep().Persist("test2", "AB123") | |
139 self.assertEquals("AB123", self.MakeStep().Restore("test2")) | |
140 | |
141 def testGitOrig(self): | |
142 self.assertTrue(Command("git", "--version").startswith("git version")) | |
143 | |
144 def testGitMock(self): | |
145 self._git_recipe = [["--version", "git version 1.2.3"], ["dummy", ""]] | |
146 self.assertTrue(self.MakeStep().Git("--version").startswith("git version")) | |
Jakob Kummerow
2013/11/06 16:37:23
why not assertEquals(..., "git version 1.2.3")?
Michael Achenbach
2013/11/07 15:56:46
Done.
| |
147 self.assertEquals("", self.MakeStep().Git("dummy")) | |
148 | |
149 def testCommonPrepareDefault(self): | |
150 self._git_recipe = [ | |
151 ["status -s -uno", ""], | |
152 ["status -s -b -uno", "## some_branch"], | |
153 ["svn fetch", ""], | |
154 ["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]], | |
155 ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""], | |
156 ["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""], | |
157 ["branch", ""], | |
158 ] | |
159 self._rl_recipe = ["Y"] | |
160 self.MakeStep().CommonPrepare() | |
161 self.assertEquals("some_branch", self.MakeStep().Restore("current_branch")) | |
162 | |
163 def testCommonPrepareNoConfirm(self): | |
164 self._git_recipe = [ | |
165 ["status -s -uno", ""], | |
166 ["status -s -b -uno", "## some_branch"], | |
167 ["svn fetch", ""], | |
168 ["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]], | |
169 ] | |
170 self._rl_recipe = ["n"] | |
171 self.assertRaises(Exception, self.MakeStep().CommonPrepare) | |
172 self.assertEquals("some_branch", self.MakeStep().Restore("current_branch")) | |
173 | |
174 def testCommonPrepareDeleteBranchFailure(self): | |
175 self._git_recipe = [ | |
176 ["status -s -uno", ""], | |
177 ["status -s -b -uno", "## some_branch"], | |
178 ["svn fetch", ""], | |
179 ["branch", " branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]], | |
180 ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], None], | |
181 ] | |
182 self._rl_recipe = ["Y"] | |
183 self.assertRaises(Exception, self.MakeStep().CommonPrepare) | |
184 self.assertEquals("some_branch", self.MakeStep().Restore("current_branch")) | |
185 | |
186 def testInitialEnvironmentChecks(self): | |
187 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() | |
188 os.environ["EDITOR"] = "vi" | |
189 self.MakeStep().InitialEnvironmentChecks() | |
190 | |
191 def testReadAndPersistVersion(self): | |
192 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() | |
193 state = {} | |
194 self.MakeStep(state=state).ReadAndPersistVersion() | |
195 self.assertEquals("3", self.MakeStep().Restore("major")) | |
196 self.assertEquals("22", self.MakeStep().Restore("minor")) | |
197 self.assertEquals("5", self.MakeStep().Restore("build")) | |
198 self.assertEquals("0", self.MakeStep().Restore("patch")) | |
199 self.assertEquals("3", state["major"]) | |
200 self.assertEquals("22", state["minor"]) | |
201 self.assertEquals("5", state["build"]) | |
202 self.assertEquals("0", state["patch"]) | |
203 | |
204 def testRegex(self): | |
Jakob Kummerow
2013/11/06 16:37:23
This is better than having no test for the regexes
Michael Achenbach
2013/11/07 15:56:46
This is rather a playground, where you can go back
| |
205 self.assertEqual("issue 321", | |
206 re.sub(r"BUG=v8:(.*)$", r"issue \1", "BUG=v8:321")) | |
207 self.assertEqual("Chromium issue 321", | |
208 re.sub(r"BUG=(.*)$", r"Chromium issue \1", "BUG=321")) | |
209 | |
210 cl = " too little\n\ttab\ttab\n too much\n trailing " | |
211 cl = MSub(r"\t", r" ", cl) | |
212 cl = MSub(r"^ {1,7}([^ ])", r" \1", cl) | |
213 cl = MSub(r"^ {9,80}([^ ])", r" \1", cl) | |
214 cl = MSub(r" +$", r"", cl) | |
215 self.assertEqual(" too little\n tab tab\n too " | |
Jakob Kummerow
2013/11/06 16:37:23
I'd break the line after every "\n" to make it obv
Michael Achenbach
2013/11/07 15:56:46
Done.
| |
216 "much\n trailing", cl) | |
217 | |
218 self.assertEqual("//\n#define BUILD_NUMBER 3\n", | |
219 MSub(r"(?<=#define BUILD_NUMBER)(?P<space>\s+)\d*$", | |
220 r"\g<space>3", | |
221 "//\n#define BUILD_NUMBER 321\n")) | |
222 | |
223 def testPrepareChangeLog(self): | |
224 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() | |
225 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() | |
226 | |
227 self._git_recipe = [ | |
228 ["log 1234..HEAD --format=%H", "rev1\nrev2"], | |
229 ["log -1 rev1 --format=\"%w(80,8,8)%s\"", " Title text 1"], | |
230 ["log -1 rev1 --format=\"%B\"", "Title\n\nBUG=\n"], | |
231 ["log -1 rev1 --format=\"%w(80,8,8)(%an)\"", | |
232 " author1@chromium.org"], | |
233 ["log -1 rev2 --format=\"%w(80,8,8)%s\"", " Title text 2"], | |
234 ["log -1 rev2 --format=\"%B\"", "Title\n\nBUG=321\n"], | |
235 ["log -1 rev2 --format=\"%w(80,8,8)(%an)\"", | |
236 " author2@chromium.org"], | |
237 ] | |
238 | |
239 self.MakeStep().Persist("last_push", "1234") | |
240 self.MakeStep(PrepareChangeLog).Run() | |
241 | |
242 cl = FileToText(TEST_CONFIG[CHANGELOG_ENTRY_FILE]) | |
243 self.assertTrue(re.search(r"\d+\-\d+\-\d+: Version 3\.22\.5", cl)) | |
244 self.assertTrue(re.search(r" Title text 1", cl)) | |
245 self.assertTrue(re.search(r" Title text 2", cl)) | |
246 self.assertTrue(re.search(r" author1@chromium.org", cl)) | |
247 self.assertTrue(re.search(r" author2@chromium.org", cl)) | |
248 self.assertTrue(re.search(r" Chromium issue 321", cl)) | |
249 self.assertFalse(re.search(r"BUG=", cl)) | |
250 self.assertEquals("3", self.MakeStep().Restore("major")) | |
251 self.assertEquals("22", self.MakeStep().Restore("minor")) | |
252 self.assertEquals("5", self.MakeStep().Restore("build")) | |
253 self.assertEquals("0", self.MakeStep().Restore("patch")) | |
254 | |
255 def testEditChangeLog(self): | |
256 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() | |
257 TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile() | |
258 TextToFile(" Original CL", TEST_CONFIG[CHANGELOG_FILE]) | |
259 TextToFile(" New \n\tLines \n", TEST_CONFIG[CHANGELOG_ENTRY_FILE]) | |
260 os.environ["EDITOR"] = "vi" | |
261 | |
262 self._rl_recipe = [ | |
263 "", # Open editor. | |
264 ] | |
265 | |
266 self.MakeStep(EditChangeLog).Run() | |
267 | |
268 self.assertEquals(" New\n Lines\n\n\n Original CL", | |
269 FileToText(TEST_CONFIG[CHANGELOG_FILE])) | |
270 | |
271 def testIncrementVersion(self): | |
272 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() | |
273 self.MakeStep().Persist("build", "5") | |
274 | |
275 self._rl_recipe = [ | |
276 "Y", # Increment build number. | |
277 ] | |
278 | |
279 self.MakeStep(IncrementVersion).Run() | |
280 | |
281 self.assertEquals("3", self.MakeStep().Restore("new_major")) | |
282 self.assertEquals("22", self.MakeStep().Restore("new_minor")) | |
283 self.assertEquals("6", self.MakeStep().Restore("new_build")) | |
284 self.assertEquals("0", self.MakeStep().Restore("new_patch")) | |
285 | |
286 def testSquashCommits(self): | |
287 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() | |
288 with open(TEST_CONFIG[CHANGELOG_ENTRY_FILE], "w") as f: | |
289 f.write("1999-11-11: Version 3.22.5\n") | |
290 f.write("\n") | |
291 f.write(" Log text 1.\n") | |
292 f.write(" Chromium issue 12345\n") | |
293 f.write("\n") | |
294 f.write(" Performance and stability improvements on all " | |
295 "platforms.\n") | |
296 | |
297 self._git_recipe = [ | |
298 ["diff svn/trunk hash1", "patch content"], | |
299 ] | |
300 | |
301 self.MakeStep().Persist("prepare_commit_hash", "hash1") | |
302 self.MakeStep().Persist("date", "1999-11-11") | |
303 | |
304 self.MakeStep(SquashCommits).Run() | |
305 | |
306 msg = FileToText(TEST_CONFIG[COMMITMSG_FILE]) | |
307 self.assertTrue(re.search(r"Version 3\.22\.5", msg)) | |
308 self.assertTrue(re.search(r"Performance and stability", msg)) | |
309 self.assertTrue(re.search(r"Log text 1\. Chromium issue 12345", msg)) | |
310 self.assertFalse(re.search(r"\d+\-\d+\-\d+", msg)) | |
311 | |
312 patch = FileToText(TEST_CONFIG[ PATCH_FILE]) | |
313 self.assertTrue(re.search(r"patch content", patch)) | |
314 | |
315 def testPushToTrunk(self): | |
316 TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() | |
317 TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile() | |
318 TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile() | |
319 TEST_CONFIG[CHANGELOG_FILE] = self.MakeEmptyTempFile() | |
320 if not os.path.exists(TEST_CONFIG[CHROMIUM]): | |
321 os.makedirs(TEST_CONFIG[CHROMIUM]) | |
322 TextToFile("1999-04-05: Version 3.22.4", TEST_CONFIG[CHANGELOG_FILE]) | |
323 TextToFile("Some line\n \"v8_revision\": 123444,\n some line", | |
324 TEST_CONFIG[DEPS_FILE]) | |
325 os.environ["EDITOR"] = "vi" | |
326 | |
327 def CheckVersionIncrement(): | |
328 version = FileToText(TEST_CONFIG[VERSION_FILE]) | |
329 self.assertTrue(re.search(r"#define BUILD_NUMBER\s+6", version)) | |
330 | |
331 def CheckCommitMsg(): | |
332 version = FileToText(TEST_CONFIG[COMMITMSG_FILE]) | |
333 self.assertTrue(re.search(r"Version 3.22.5", version)) | |
334 self.assertTrue(re.search(r"Log text 1. issue 321", version)) | |
335 | |
336 self._git_recipe = [ | |
337 ["status -s -uno", ""], | |
338 ["status -s -b -uno", "## some_branch\n"], | |
339 ["svn fetch", ""], | |
340 ["branch", " branch1\n* branch2\n"], | |
341 ["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""], | |
342 ["branch", " branch1\n* branch2\n"], | |
343 ["branch", " branch1\n* branch2\n"], | |
344 ["checkout -b %s svn/bleeding_edge" % TEST_CONFIG[BRANCHNAME], ""], | |
345 ["log -1 --format=%H ChangeLog", "1234\n"], | |
346 ["log -1 1234", "Last push ouput\n"], | |
347 ["log 1234..HEAD --format=%H", "rev1\n"], | |
348 ["log -1 rev1 --format=\"%w(80,8,8)%s\"", " Log text 1.\n"], | |
349 ["log -1 rev1 --format=\"%B\"", "Text\nBUG=v8:321\nText\n"], | |
350 ["log -1 rev1 --format=\"%w(80,8,8)(%an)\"", | |
351 " author1@chromium.org\n"], | |
352 [("commit -a -m \"Prepare push to trunk. " | |
353 "Now working on version 3.22.6.\""), | |
354 " 2 files changed\n", | |
355 CheckVersionIncrement], | |
356 ["cl upload -r \"reviewer@chromium.org\" --send-mail", "done\n"], | |
357 ["cl dcommit", "Closing issue\n"], | |
358 ["svn fetch", "fetch result\n"], | |
359 ["checkout svn/bleeding_edge", ""], | |
360 [("log -1 --format=%H --grep=\"Prepare push to trunk. " | |
361 "Now working on version 3.22.6.\""), | |
362 "hash1\n"], | |
363 ["diff svn/trunk hash1", "patch content\n"], | |
364 ["checkout -b %s svn/trunk" % TEST_CONFIG[TRUNKBRANCH], ""], | |
365 ["apply --index --reject \"%s\"" % TEST_CONFIG[PATCH_FILE], ""], | |
366 ["add \"%s\"" % TEST_CONFIG[VERSION_FILE], ""], | |
367 ["commit -F \"%s\"" % TEST_CONFIG[COMMITMSG_FILE], "", CheckCommitMsg], | |
368 ["svn dcommit 2>&1", "Some output\nCommitted r123456\nSome output\n"], | |
369 ["svn tag 3.22.5 -m \"Tagging version 3.22.5\"", ""], | |
370 ["status -s -uno", ""], | |
371 ["checkout master", ""], | |
372 ["pull", ""], | |
373 ["checkout -b \"v8-roll-123456\"", ""], | |
374 [("commit -am \"Update V8 to version 3.22.5.\n\n" | |
375 "TBR=reviewer@chromium.org\""), | |
376 ""], | |
377 ["cl upload --send-mail", ""], | |
378 ["checkout -f some_branch", ""], | |
379 ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""], | |
380 ["branch -D %s" % TEST_CONFIG[BRANCHNAME], ""], | |
381 ["branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""], | |
382 ] | |
383 self._rl_recipe = [ | |
384 "Y", # Confirm last push. | |
385 "", # Open editor. | |
386 "Y", # Increment build number. | |
387 "reviewer@chromium.org", # V8 reviewer. | |
388 "LGTX", # Enter LGTM for V8 CL (wrong). | |
389 "LGTM", # Enter LGTM for V8 CL. | |
390 "Y", # Sanity check. | |
391 "reviewer@chromium.org", # Chromium reviewer. | |
392 ] | |
393 | |
394 class Options( object ): | |
395 pass | |
396 | |
397 options = Options() | |
398 options.s = 0 | |
399 options.l = None | |
400 options.c = TEST_CONFIG[CHROMIUM] | |
401 RunScript(TEST_CONFIG, options, self) | |
402 | |
403 deps = FileToText(TEST_CONFIG[DEPS_FILE]) | |
404 self.assertTrue(re.search("\"v8_revision\": 123456", deps)) | |
405 | |
406 cl = FileToText(TEST_CONFIG[CHANGELOG_FILE]) | |
407 self.assertTrue(re.search(r"\d\d\d\d\-\d+\-\d+: Version 3\.22\.5", cl)) | |
408 self.assertTrue(re.search(r" Log text 1", cl)) | |
409 self.assertTrue(re.search(r" issue 321", cl)) | |
410 self.assertTrue(re.search(r"1999\-04\-05: Version 3\.22\.4", cl)) | |
411 | |
412 # Note: The version file is on build number 5 again in the end of this test | |
413 # since the git command that merges to the bleeding edge branch is mocked | |
414 # out. | |
OLD | NEW |