OLD | NEW |
| (Empty) |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 import collections | |
6 | |
7 from infra.services.gnumbd import inner_loop as gnumbd | |
8 content_of = gnumbd.content_of | |
9 | |
10 REAL = 'refs/heads/master' | |
11 PEND = 'refs/pending/heads/master' | |
12 PEND_TAG = 'refs/pending-tags/heads/master' | |
13 | |
14 BRANCH = 'refs/branch-heads/cool_branch' | |
15 BRANCH_PEND = 'refs/pending/branch-heads/cool_branch' | |
16 BRANCH_TAG = 'refs/pending-tags/branch-heads/cool_branch' | |
17 | |
18 | |
19 GNUMBD_TESTS = {} | |
20 def gnumbd_test(f): | |
21 GNUMBD_TESTS[f.__name__] = f | |
22 return f | |
23 | |
24 | |
25 # Error cases | |
26 @gnumbd_test | |
27 def no_real_ref(origin, _local, _config_ref, RUN, CHECKPOINT): | |
28 origin[PEND].synthesize_commit('Hello world') | |
29 CHECKPOINT('One commit in origin') | |
30 RUN() | |
31 CHECKPOINT('Origin should not have changed') | |
32 | |
33 | |
34 @gnumbd_test | |
35 def no_pending_tag(origin, _local, _config_ref, RUN, CHECKPOINT): | |
36 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
37 origin[PEND].update_to(base_commit) | |
38 origin[PEND].synthesize_commit('Hello world') | |
39 CHECKPOINT('Two commits in origin') | |
40 RUN() | |
41 CHECKPOINT('Origin should not have changed') | |
42 | |
43 | |
44 @gnumbd_test | |
45 def bad_position_footer(origin, _local, _config_ref, RUN, CHECKPOINT): | |
46 base_commit = origin[REAL].synthesize_commit( | |
47 'Base commit', footers={gnumbd.COMMIT_POSITION: ['BlobbyGumpus!']}) | |
48 for ref in (PEND, PEND_TAG): | |
49 origin[ref].update_to(base_commit) | |
50 | |
51 origin[PEND].synthesize_commit('Hello world') | |
52 CHECKPOINT('Bad master commit footer') | |
53 RUN() | |
54 CHECKPOINT('Should be the same') | |
55 assert origin[REAL].commit == base_commit | |
56 | |
57 | |
58 @gnumbd_test | |
59 def bad_svn_footer(origin, _local, _config_ref, RUN, CHECKPOINT): | |
60 base_commit = origin[REAL].synthesize_commit( | |
61 'Base commit', footers={gnumbd.GIT_SVN_ID: ['BlobbyGumpus!']}) | |
62 for ref in (PEND, PEND_TAG): | |
63 origin[ref].update_to(base_commit) | |
64 | |
65 origin[PEND].synthesize_commit('Hello world') | |
66 CHECKPOINT('Bad master commit footer') | |
67 RUN() | |
68 CHECKPOINT('Should be the same') | |
69 assert origin[REAL].commit == base_commit | |
70 | |
71 | |
72 @gnumbd_test | |
73 def no_position_footer(origin, _local, _config_ref, RUN, CHECKPOINT): | |
74 base_commit = origin[REAL].synthesize_commit( | |
75 'Base commit', footers={'Sup': ['Not a footer']}) | |
76 for ref in (PEND, PEND_TAG): | |
77 origin[ref].update_to(base_commit) | |
78 | |
79 origin[PEND].synthesize_commit('Hello world') | |
80 CHECKPOINT('Master has no position footer') | |
81 RUN() | |
82 CHECKPOINT('Should be the same') | |
83 assert origin[REAL].commit == base_commit | |
84 | |
85 | |
86 @gnumbd_test | |
87 def merge_commits_fail(origin, _local, _config_ref, RUN, CHECKPOINT): | |
88 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
89 for ref in (PEND, PEND_TAG): | |
90 origin[ref].update_to(base_commit) | |
91 | |
92 o_commit = origin['refs/heads/other'].synthesize_commit('Incoming merge!', 20) | |
93 m_commit = base_commit.alter( | |
94 parents=(base_commit.hsh, o_commit.hsh), | |
95 message_lines=['Two for one!'], | |
96 footers={k: None for k in base_commit.data.footers} | |
97 ) | |
98 | |
99 origin[PEND].update_to(m_commit) | |
100 origin[PEND].synthesize_commit('Hello world') | |
101 | |
102 CHECKPOINT('The setup.') | |
103 RUN() | |
104 CHECKPOINT('Should be the same') | |
105 | |
106 | |
107 @gnumbd_test | |
108 def manual_merge_commits_ok(origin, _local, _config_ref, RUN, CHECKPOINT): | |
109 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
110 | |
111 o_commit = origin['refs/heads/other'].synthesize_commit('Incoming merge!', 20) | |
112 footers = {k: None for k in base_commit.data.footers} | |
113 footers[gnumbd.COMMIT_POSITION] = ['refs/heads/master@{#101}'] | |
114 | |
115 m_commit = base_commit.alter( | |
116 parents=(base_commit.hsh, o_commit.hsh), | |
117 message_lines=['Two for one!'], | |
118 footers=footers | |
119 ) | |
120 origin[REAL].update_to(m_commit) | |
121 for ref in (PEND, PEND_TAG): | |
122 origin[ref].update_to(m_commit) | |
123 | |
124 origin[PEND].synthesize_commit('Hello world') | |
125 | |
126 CHECKPOINT('The setup.') | |
127 RUN() | |
128 CHECKPOINT('Hello world landed w/o a hitch') | |
129 | |
130 | |
131 @gnumbd_test | |
132 def no_number_on_parent(origin, local, _config_ref, RUN, CHECKPOINT): | |
133 base_commit = origin[REAL].synthesize_commit('Base without number') | |
134 user_commit = origin[PEND].synthesize_commit('Hello world') | |
135 CHECKPOINT('One commit in origin') | |
136 RUN() | |
137 CHECKPOINT('Should still only have 1 commit') | |
138 assert local[PEND].commit == user_commit | |
139 assert local[REAL].commit == base_commit | |
140 | |
141 | |
142 # Normal cases | |
143 @gnumbd_test | |
144 def incoming_svn_id_drops(origin, _local, _config_ref, RUN, CHECKPOINT): | |
145 base_commit = origin[REAL].synthesize_commit('Base commit', 100, svn=True) | |
146 for ref in (PEND, PEND_TAG): | |
147 origin[ref].update_to(base_commit) | |
148 | |
149 user_commit = origin[PEND].synthesize_commit('Hello world') | |
150 CHECKPOINT('Two commits in origin') | |
151 RUN() | |
152 CHECKPOINT('Hello world should be 101') | |
153 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
154 assert origin[REAL].commit.parent == base_commit | |
155 | |
156 | |
157 # pending > master == tag | |
158 @gnumbd_test | |
159 def normal_update(origin, _local, _config_ref, RUN, CHECKPOINT): | |
160 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
161 for ref in (PEND, PEND_TAG): | |
162 origin[ref].update_to(base_commit) | |
163 | |
164 user_commit = origin[PEND].synthesize_commit('Hello world') | |
165 CHECKPOINT('Two commits') | |
166 RUN() | |
167 CHECKPOINT('Hello world should be 101') | |
168 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
169 assert origin[REAL].commit.parent == base_commit | |
170 | |
171 | |
172 # master == pending == tag | |
173 @gnumbd_test | |
174 def steady_state(origin, _local, _config_ref, RUN, CHECKPOINT): | |
175 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
176 for ref in (PEND, PEND_TAG): | |
177 origin[ref].update_to(base_commit) | |
178 | |
179 user_commit = origin[PEND].synthesize_commit('Hello world') | |
180 RUN(include_log=False) | |
181 CHECKPOINT('Hello world should be 101') | |
182 RUN() | |
183 CHECKPOINT('Hello world should still be 101') | |
184 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
185 assert origin[REAL].commit.parent == base_commit | |
186 | |
187 | |
188 # master == pending > tag | |
189 @gnumbd_test | |
190 def tag_lagging_no_actual(origin, _local, _config_ref, RUN, CHECKPOINT): | |
191 origin[REAL].synthesize_commit('Root commit', 99) | |
192 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
193 for ref in (PEND, PEND_TAG): | |
194 origin[ref].update_to(base_commit) | |
195 | |
196 user_commit = origin[PEND].synthesize_commit('Hello world') | |
197 | |
198 RUN(include_log=False) | |
199 origin[PEND_TAG].update_to(origin[PEND_TAG].commit.parent.parent) | |
200 | |
201 CHECKPOINT('Tag on root (2 behind pend)') | |
202 RUN() | |
203 CHECKPOINT('Tag caught up') | |
204 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
205 assert origin[REAL].commit.parent == base_commit | |
206 assert origin[PEND_TAG].commit == origin[PEND].commit | |
207 | |
208 | |
209 # pending > master > tag | |
210 @gnumbd_test | |
211 def tag_lagging(origin, _local, _config_ref, RUN, CHECKPOINT): | |
212 origin[REAL].synthesize_commit('Root commit', 99) | |
213 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
214 for ref in (PEND, PEND_TAG): | |
215 origin[ref].update_to(base_commit) | |
216 | |
217 origin[PEND].synthesize_commit('Hello world') | |
218 | |
219 RUN(include_log=False) | |
220 landed_commit = origin[REAL].commit | |
221 | |
222 origin[PEND_TAG].update_to(origin[PEND_TAG].commit.parent.parent) | |
223 user_commit = origin[PEND].synthesize_commit('New commit') | |
224 | |
225 CHECKPOINT('Tag on root (3 behind pend). Real 1 behind pend') | |
226 RUN() | |
227 CHECKPOINT('Tag + pending caught up') | |
228 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
229 assert origin[REAL].commit.parent == landed_commit | |
230 assert origin[PEND_TAG].commit == origin[PEND].commit | |
231 | |
232 | |
233 @gnumbd_test | |
234 def multi_pending(origin, _local, _config_ref, RUN, CHECKPOINT): | |
235 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
236 for ref in (PEND, PEND_TAG): | |
237 origin[ref].update_to(base_commit) | |
238 | |
239 user_commit1 = origin[PEND].synthesize_commit('Hello world') | |
240 user_commit2 = origin[PEND].synthesize_commit('Cat food') | |
241 CHECKPOINT('Two pending commits') | |
242 RUN() | |
243 CHECKPOINT('And now they\'re on master') | |
244 assert content_of(origin[REAL].commit.parent) == content_of(user_commit1) | |
245 assert content_of(origin[REAL].commit) == content_of(user_commit2) | |
246 assert origin[REAL].commit.parent.parent == base_commit | |
247 | |
248 | |
249 # Inconsistency | |
250 | |
251 # tag > pending | |
252 # Implicitly covers: | |
253 # * master > tag > pending | |
254 # * tag > pending > master | |
255 # * tag > master > pending | |
256 # * tag > pending == master | |
257 @gnumbd_test | |
258 def master_tag_ahead_pending(origin, _local, _config_ref, RUN, CHECKPOINT): | |
259 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
260 for ref in (PEND, PEND_TAG): | |
261 origin[ref].update_to(base_commit) | |
262 | |
263 origin[PEND].synthesize_commit('Hello world') | |
264 RUN(include_log=False) | |
265 | |
266 origin[PEND].update_to(base_commit) | |
267 CHECKPOINT('Master and tag ahead of pending') | |
268 RUN() | |
269 CHECKPOINT('Should see errors and no change') | |
270 | |
271 | |
272 # pending > tag > master | |
273 @gnumbd_test | |
274 def normal_with_master_lag(origin, _local, _config_ref, RUN, CHECKPOINT): | |
275 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
276 for ref in (PEND, PEND_TAG): | |
277 origin[ref].update_to(base_commit) | |
278 | |
279 origin[PEND].synthesize_commit('Hello world') | |
280 RUN(include_log=False) | |
281 | |
282 # master moves back | |
283 origin[REAL].update_to(base_commit) | |
284 | |
285 # pending gets a new commit | |
286 origin[PEND].synthesize_commit('New pending') | |
287 | |
288 CHECKPOINT('Master is behind, pending is ahead of tag') | |
289 RUN() | |
290 CHECKPOINT('Should see errors and no change') | |
291 | |
292 # fix by rewinding tag | |
293 origin[PEND_TAG].update_to(origin[PEND_TAG].commit.parent) | |
294 CHECKPOINT('Fix by rewinding tag') | |
295 RUN() | |
296 CHECKPOINT('All better') | |
297 | |
298 | |
299 @gnumbd_test | |
300 def master_ahead_tag_ahead_pending(origin, _local, _config_ref, RUN, | |
301 CHECKPOINT): | |
302 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
303 for ref in (PEND, PEND_TAG): | |
304 origin[ref].update_to(base_commit) | |
305 | |
306 origin[REAL].synthesize_commit('Directly landed commit!') | |
307 origin[PEND_TAG].synthesize_commit('Tag ahead of pending') | |
308 | |
309 CHECKPOINT('Master and tag have diverged, pend lags') | |
310 RUN() | |
311 CHECKPOINT('Should have errored and nothing changed') | |
312 | |
313 | |
314 # master > pending == tag | |
315 @gnumbd_test | |
316 def master_ahead(origin, _local, _config_ref, RUN, CHECKPOINT): | |
317 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
318 for ref in (PEND, PEND_TAG): | |
319 origin[ref].update_to(base_commit) | |
320 | |
321 base_commit = origin[REAL].synthesize_commit('Directly landed commit!') | |
322 | |
323 CHECKPOINT('Master contains a commit whose content isn\'t in pending') | |
324 RUN() | |
325 CHECKPOINT('Should have errored and nothing changed') | |
326 assert origin[REAL].commit == base_commit | |
327 | |
328 | |
329 # pending == tag > master | |
330 @gnumbd_test | |
331 def master_behind(origin, _local, _config_ref, RUN, CHECKPOINT): | |
332 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
333 for ref in (PEND, PEND_TAG): | |
334 origin[ref].update_to(base_commit) | |
335 | |
336 user_commit = origin[PEND].synthesize_commit('Hello world') | |
337 origin[PEND_TAG].update_to(user_commit) | |
338 CHECKPOINT('Master should have new commit but does not') | |
339 RUN() | |
340 CHECKPOINT('Error and no change') | |
341 | |
342 | |
343 # master > pending > tag | |
344 @gnumbd_test | |
345 def master_mismatch_and_pend(origin, _local, _config_ref, RUN, CHECKPOINT): | |
346 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
347 for ref in (PEND, PEND_TAG): | |
348 origin[ref].update_to(base_commit) | |
349 origin[PEND].synthesize_commit('Hello world') | |
350 | |
351 base_commit = origin[REAL].synthesize_commit('Directly landed commit!') | |
352 | |
353 CHECKPOINT('Master contains a commit whose content isn\'t in pending') | |
354 RUN() | |
355 CHECKPOINT('Should have errored and nothing changed') | |
356 assert origin[REAL].commit == base_commit | |
357 | |
358 | |
359 # Branching | |
360 @gnumbd_test | |
361 def branch(origin, _local, config_ref, RUN, CHECKPOINT): | |
362 new_globs = config_ref['enabled_refglobs'] + ['refs/branch-heads/*'] | |
363 config_ref.update(enabled_refglobs=new_globs) | |
364 | |
365 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
366 for ref in (PEND, PEND_TAG): | |
367 origin[ref].update_to(base_commit) | |
368 | |
369 origin[PEND].synthesize_commit('Hello world') | |
370 CHECKPOINT('Pending commit', include_config=True) | |
371 RUN() | |
372 CHECKPOINT('And now it\'s on master', include_config=True) | |
373 | |
374 # Build a new branch | |
375 for ref in (BRANCH, BRANCH_TAG, BRANCH_PEND): | |
376 origin[ref].update_to(origin[REAL].commit) | |
377 | |
378 origin[BRANCH_PEND].synthesize_commit('Branch commit!') | |
379 CHECKPOINT('New branch with pending', include_config=True) | |
380 RUN() | |
381 CHECKPOINT('Pending commit now on branch', include_config=True) | |
382 | |
383 origin[BRANCH_PEND].synthesize_commit('Another branch commit') | |
384 CHECKPOINT('New pending commit for branch', include_config=True) | |
385 RUN() | |
386 CHECKPOINT('Second pending commit now on branch', include_config=True) | |
387 | |
388 assert origin[BRANCH].commit.data.footers[gnumbd.BRANCHED_FROM] == ( | |
389 '%s-%s' % ( | |
390 origin[REAL].commit.hsh, | |
391 origin[REAL].commit.data.footers[gnumbd.COMMIT_POSITION][0] | |
392 ), | |
393 ) | |
394 | |
395 | |
396 @gnumbd_test | |
397 def branch_from_branch(origin, _local, config_ref, RUN, CHECKPOINT): | |
398 new_globs = config_ref['enabled_refglobs'] + ['refs/branch-heads/*'] | |
399 config_ref.update(enabled_refglobs=new_globs) | |
400 | |
401 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
402 for ref in (PEND, PEND_TAG): | |
403 origin[ref].update_to(base_commit) | |
404 | |
405 origin[PEND].synthesize_commit('Hello world') | |
406 RUN(include_log=False) | |
407 | |
408 # Build a new branch | |
409 for ref in (BRANCH, BRANCH_TAG, BRANCH_PEND): | |
410 origin[ref].update_to(origin[REAL].commit) | |
411 | |
412 origin[BRANCH_PEND].synthesize_commit('Branch commit!') | |
413 RUN(include_log=False) | |
414 | |
415 CHECKPOINT('Branch 1 in place', include_config=True) | |
416 | |
417 yo_branch = BRANCH+'_yo' | |
418 yo_branch_tag = BRANCH_TAG+'_yo' | |
419 yo_branch_pend = BRANCH_PEND+'_yo' | |
420 for ref in (yo_branch, yo_branch_tag, yo_branch_pend): | |
421 origin[ref].update_to(origin[BRANCH].commit) | |
422 | |
423 origin[yo_branch_pend].synthesize_commit('Super branchey commit') | |
424 CHECKPOINT('New pending commit for branch', include_config=True) | |
425 RUN() | |
426 CHECKPOINT('Second pending commit now on branch', include_config=True) | |
427 | |
428 assert origin[yo_branch].commit.data.footers[gnumbd.BRANCHED_FROM] == ( | |
429 '%s-%s' % ( | |
430 origin[BRANCH].commit.hsh, | |
431 origin[BRANCH].commit.data.footers[gnumbd.COMMIT_POSITION][0] | |
432 ), | |
433 '%s-%s' % ( | |
434 origin[REAL].commit.hsh, | |
435 origin[REAL].commit.data.footers[gnumbd.COMMIT_POSITION][0] | |
436 ), | |
437 ) | |
438 | |
439 | |
440 # Extra footers | |
441 @gnumbd_test | |
442 def extra_user_footer(origin, _local, _config_ref, RUN, CHECKPOINT): | |
443 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
444 for ref in (PEND, PEND_TAG): | |
445 origin[ref].update_to(base_commit) | |
446 | |
447 user_commit = origin[PEND].synthesize_commit( | |
448 'Hello world', footers=collections.OrderedDict([ | |
449 ('Change-Id', ['Icafebabe1cec6eadfeba']), | |
450 ('Reviewed-by', [ | |
451 'Cool Dudette 64 <cd64@example.com>', | |
452 'Epic Sky Troll <est@example.com>', | |
453 ]), | |
454 ('Tested-by', ['Lol JK <lol_jk@example.com>']) | |
455 ])) | |
456 CHECKPOINT('The setup...') | |
457 RUN() | |
458 CHECKPOINT('The new footers should appear after the current ones') | |
459 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
460 assert origin[REAL].commit.parent == base_commit | |
461 | |
462 | |
463 @gnumbd_test | |
464 def extra_user_footer_bad(origin, _local, _config_ref, RUN, CHECKPOINT): | |
465 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
466 for ref in (PEND, PEND_TAG): | |
467 origin[ref].update_to(base_commit) | |
468 | |
469 user_commit = origin[PEND].synthesize_commit( | |
470 'Hello world', footers=collections.OrderedDict([ | |
471 ('Cr-Double-Secret', ['I can impersonate the daemon!']), | |
472 ('git-svn-id', ['Well... this should never happen']) | |
473 ])) | |
474 CHECKPOINT('Two commits') | |
475 RUN() | |
476 CHECKPOINT('The bogus footers should be gone') | |
477 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
478 assert origin[REAL].commit.data.footers == { | |
479 gnumbd.COMMIT_POSITION: (gnumbd.FMT_COMMIT_POSITION(origin[REAL], 101),) | |
480 } | |
481 | |
482 | |
483 @gnumbd_test | |
484 def enforce_commit_timestamps(origin, _local, _config_ref, RUN, CHECKPOINT): | |
485 base_commit = origin[REAL].synthesize_commit('Base commit', 100) | |
486 for ref in (PEND, PEND_TAG): | |
487 origin[ref].update_to(base_commit) | |
488 | |
489 # cheat and rewind the TestClock | |
490 origin._clock._time -= 100 # pylint: disable=W0212 | |
491 | |
492 user_commit = origin[PEND].synthesize_commit('Hello world') | |
493 assert ( | |
494 user_commit.data.committer.timestamp.secs < | |
495 base_commit.data.committer.timestamp.secs | |
496 ) | |
497 | |
498 CHECKPOINT('%r has a timestamp behind %r' % ( | |
499 user_commit.hsh, base_commit.hsh), include_committer=True) | |
500 RUN() | |
501 CHECKPOINT('Presto! Timestamp is fixed', include_committer=True) | |
502 assert content_of(origin[REAL].commit) == content_of(user_commit) | |
503 assert origin[REAL].commit.parent == base_commit | |
504 assert ( | |
505 origin[REAL].commit.data.committer.timestamp.secs > | |
506 origin[REAL].commit.parent.data.committer.timestamp.secs | |
507 ) | |
OLD | NEW |