3 # commit_tests.py: testing fancy commit cases.
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2007 CollabNet. All rights reserved.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://subversion.tigris.org/license-1.html.
14 # If newer versions of this license are posted there, you may use a
15 # newer version instead, at your option.
17 ######################################################################
20 import string
, sys
, os
, re
26 Skip
= svntest
.testcase
.Skip
27 SkipUnless
= svntest
.testcase
.SkipUnless
28 XFail
= svntest
.testcase
.XFail
29 Item
= svntest
.wc
.StateItem
31 from svntest
.main
import server_has_revprop_commit
, \
32 server_gets_client_capabilities
33 from svntest
.actions
import inject_conflict_into_wc
35 ######################################################################
39 def is_non_posix_os_or_cygwin_platform():
40 return (not svntest
.main
.is_posix_os()) or sys
.platform
== 'cygwin'
42 def get_standard_state(wc_dir
):
43 """Return a status list reflecting the local mods made by
44 make_standard_slew_of_changes()."""
46 state
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
48 state
.tweak('', 'A/D', 'A/D/G/pi', status
=' M')
49 state
.tweak('A/B/lambda', status
='M ')
50 state
.tweak('A/B/E', 'A/D/H/chi', status
='R ')
51 state
.tweak('A/B/E/alpha', 'A/B/E/beta', 'A/C', 'A/D/gamma',
52 'A/D/G/rho', status
='D ')
53 state
.tweak('A/D/H/omega', status
='MM')
57 'Q' : Item(status
='A ', wc_rev
=0),
58 'Q/floo' : Item(status
='A ', wc_rev
=0),
59 'A/D/H/gloo' : Item(status
='A ', wc_rev
=0),
60 'A/B/E/bloo' : Item(status
='A ', wc_rev
=0),
66 def make_standard_slew_of_changes(wc_dir
):
67 """Make a specific set of local mods to WC_DIR. These will be used
68 by every commit-test. Verify the 'svn status' output, and return the
69 (pre-commit) status tree."""
71 # Cache current working directory, move into wc_dir
77 svntest
.main
.run_svn(None, 'add', 'Q')
79 # Remove two directories
80 svntest
.main
.run_svn(None, 'rm', os
.path
.join('A', 'B', 'E'))
81 svntest
.main
.run_svn(None, 'rm', os
.path
.join('A', 'C'))
83 # Replace one of the removed directories
84 svntest
.main
.run_svn(None, 'add', os
.path
.join('A', 'B', 'E'))
86 # Make property mods to two directories
87 svntest
.main
.run_svn(None, 'propset', 'foo', 'bar', os
.curdir
)
88 svntest
.main
.run_svn(None, 'propset', 'foo2', 'bar2', os
.path
.join('A', 'D'))
91 svntest
.main
.file_append(os
.path
.join('A', 'B', 'E', 'bloo'), "hi")
92 svntest
.main
.file_append(os
.path
.join('A', 'D', 'H', 'gloo'), "hello")
93 svntest
.main
.file_append(os
.path
.join('Q', 'floo'), "yo")
94 svntest
.main
.run_svn(None, 'add', os
.path
.join('A', 'B', 'E', 'bloo'))
95 svntest
.main
.run_svn(None, 'add', os
.path
.join('A', 'D', 'H', 'gloo'))
96 svntest
.main
.run_svn(None, 'add', os
.path
.join('Q', 'floo'))
99 svntest
.main
.run_svn(None, 'rm', os
.path
.join('A', 'D', 'G', 'rho'))
100 svntest
.main
.run_svn(None, 'rm', os
.path
.join('A', 'D', 'H', 'chi'))
101 svntest
.main
.run_svn(None, 'rm', os
.path
.join('A', 'D', 'gamma'))
103 # Replace one of the removed files
104 svntest
.main
.file_append(os
.path
.join('A', 'D', 'H', 'chi'), "chi")
105 svntest
.main
.run_svn(None, 'add', os
.path
.join('A', 'D', 'H', 'chi'))
107 # Make textual mods to two files
108 svntest
.main
.file_append(os
.path
.join('A', 'B', 'lambda'), "new ltext")
109 svntest
.main
.file_append(os
.path
.join('A', 'D', 'H', 'omega'), "new otext")
111 # Make property mods to three files
112 svntest
.main
.run_svn(None, 'propset', 'blue', 'azul',
113 os
.path
.join('A', 'D', 'H', 'omega'))
114 svntest
.main
.run_svn(None, 'propset', 'green', 'verde',
115 os
.path
.join('Q', 'floo'))
116 svntest
.main
.run_svn(None, 'propset', 'red', 'rojo',
117 os
.path
.join('A', 'D', 'G', 'pi'))
122 # Build an expected status tree.
123 expected_status
= get_standard_state(wc_dir
)
125 # Verify status -- all local mods should be present.
126 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
128 return expected_status
131 ######################################################################
134 # Each test must return on success or raise on failure.
137 #----------------------------------------------------------------------
139 def commit_one_file(sbox
):
145 expected_status
= make_standard_slew_of_changes(wc_dir
)
147 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
149 # Create expected state.
150 expected_output
= svntest
.wc
.State(wc_dir
, {
151 'A/D/H/omega' : Item(verb
='Sending'),
153 expected_status
.tweak('A/D/H/omega', wc_rev
=2, status
=' ')
155 # Commit the one file.
156 svntest
.actions
.run_and_verify_commit(wc_dir
,
163 #----------------------------------------------------------------------
165 def commit_one_new_file(sbox
):
166 "commit one newly added file"
171 expected_status
= make_standard_slew_of_changes(wc_dir
)
173 gloo_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'gloo')
175 # Create expected state.
176 expected_output
= svntest
.wc
.State(wc_dir
, {
177 'A/D/H/gloo' : Item(verb
='Adding'),
179 expected_status
.tweak('A/D/H/gloo', wc_rev
=2, status
=' ')
181 # Commit the one file.
182 svntest
.actions
.run_and_verify_commit(wc_dir
,
189 #----------------------------------------------------------------------
191 def commit_one_new_binary_file(sbox
):
192 "commit one newly added binary file"
197 expected_status
= make_standard_slew_of_changes(wc_dir
)
199 gloo_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'gloo')
200 svntest
.main
.run_svn(None, 'propset', 'svn:mime-type',
201 'application/octet-stream', gloo_path
)
203 # Create expected state.
204 expected_output
= svntest
.wc
.State(wc_dir
, {
205 'A/D/H/gloo' : Item(verb
='Adding (bin)'),
207 expected_status
.tweak('A/D/H/gloo', wc_rev
=2, status
=' ')
209 # Commit the one file.
210 svntest
.actions
.run_and_verify_commit(wc_dir
,
217 #----------------------------------------------------------------------
219 def commit_multiple_targets(sbox
):
220 "commit multiple targets"
225 # This test will commit three targets: psi, B, and pi. In that order.
227 # Make local mods to many files.
228 AB_path
= os
.path
.join(wc_dir
, 'A', 'B')
229 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
230 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
231 pi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'pi')
232 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
233 psi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'psi')
234 svntest
.main
.file_append(lambda_path
, 'new appended text for lambda')
235 svntest
.main
.file_append(rho_path
, 'new appended text for rho')
236 svntest
.main
.file_append(pi_path
, 'new appended text for pi')
237 svntest
.main
.file_append(omega_path
, 'new appended text for omega')
238 svntest
.main
.file_append(psi_path
, 'new appended text for psi')
240 # Just for kicks, add a property to A/D/G as well. We'll make sure
241 # that it *doesn't* get committed.
242 ADG_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
243 svntest
.main
.run_svn(None, 'propset', 'foo', 'bar', ADG_path
)
245 # Create expected output tree for 'svn ci'. We should see changes
246 # only on these three targets, no others.
247 expected_output
= svntest
.wc
.State(wc_dir
, {
248 'A/D/H/psi' : Item(verb
='Sending'),
249 'A/B/lambda' : Item(verb
='Sending'),
250 'A/D/G/pi' : Item(verb
='Sending'),
253 # Create expected status tree; all local revisions should be at 1,
254 # but our three targets should be at 2.
255 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
256 expected_status
.tweak('A/D/H/psi', 'A/B/lambda', 'A/D/G/pi', wc_rev
=2)
258 # rho and omega should still display as locally modified:
259 expected_status
.tweak('A/D/G/rho', 'A/D/H/omega', status
='M ')
261 # A/D/G should still have a local property set, too.
262 expected_status
.tweak('A/D/G', status
=' M')
264 svntest
.actions
.run_and_verify_commit(wc_dir
,
268 psi_path
, AB_path
, pi_path
)
270 #----------------------------------------------------------------------
273 def commit_multiple_targets_2(sbox
):
274 "commit multiple targets, 2nd variation"
279 # This test will commit four targets: psi, B, omega and pi. In that order.
281 # Make local mods to many files.
282 AB_path
= os
.path
.join(wc_dir
, 'A', 'B')
283 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
284 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
285 pi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'pi')
286 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
287 psi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'psi')
288 svntest
.main
.file_append(lambda_path
, 'new appended text for lambda')
289 svntest
.main
.file_append(rho_path
, 'new appended text for rho')
290 svntest
.main
.file_append(pi_path
, 'new appended text for pi')
291 svntest
.main
.file_append(omega_path
, 'new appended text for omega')
292 svntest
.main
.file_append(psi_path
, 'new appended text for psi')
294 # Just for kicks, add a property to A/D/G as well. We'll make sure
295 # that it *doesn't* get committed.
296 ADG_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
297 svntest
.main
.run_svn(None, 'propset', 'foo', 'bar', ADG_path
)
299 # Created expected output tree for 'svn ci'. We should see changes
300 # only on these three targets, no others.
301 expected_output
= svntest
.wc
.State(wc_dir
, {
302 'A/D/H/psi' : Item(verb
='Sending'),
303 'A/B/lambda' : Item(verb
='Sending'),
304 'A/D/H/omega' : Item(verb
='Sending'),
305 'A/D/G/pi' : Item(verb
='Sending'),
308 # Create expected status tree; all local revisions should be at 1,
309 # but our four targets should be at 2.
310 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
311 expected_status
.tweak('A/D/H/psi', 'A/B/lambda', 'A/D/G/pi', 'A/D/H/omega',
314 # rho should still display as locally modified:
315 expected_status
.tweak('A/D/G/rho', status
='M ')
317 # A/D/G should still have a local property set, too.
318 expected_status
.tweak('A/D/G', status
=' M')
320 svntest
.actions
.run_and_verify_commit(wc_dir
,
327 #----------------------------------------------------------------------
329 def commit_inclusive_dir(sbox
):
330 "commit wc_dir/A/D -- includes D. (anchor=A, tgt=D)"
335 expected_status
= make_standard_slew_of_changes(wc_dir
)
337 D_path
= os
.path
.join(wc_dir
, 'A', 'D')
339 # Create expected state.
340 expected_output
= svntest
.wc
.State(wc_dir
, {
341 'A/D' : Item(verb
='Sending'),
342 'A/D/G/pi' : Item(verb
='Sending'),
343 'A/D/G/rho' : Item(verb
='Deleting'),
344 'A/D/H/gloo' : Item(verb
='Adding'),
345 'A/D/H/chi' : Item(verb
='Replacing'),
346 'A/D/H/omega' : Item(verb
='Sending'),
347 'A/D/gamma' : Item(verb
='Deleting'),
350 expected_status
.remove('A/D/G/rho', 'A/D/gamma')
351 expected_status
.tweak('A/D', 'A/D/G/pi', 'A/D/H/omega',
352 wc_rev
=2, status
=' ')
353 expected_status
.tweak('A/D/H/chi', 'A/D/H/gloo', wc_rev
=2, status
=' ')
355 # Commit the one file.
356 svntest
.actions
.run_and_verify_commit(wc_dir
,
362 #----------------------------------------------------------------------
364 def commit_top_dir(sbox
):
365 "commit wc_dir -- (anchor=wc_dir, tgt={})"
370 expected_status
= make_standard_slew_of_changes(wc_dir
)
372 # Create expected state.
373 expected_output
= svntest
.wc
.State(wc_dir
, {
374 '' : Item(verb
='Sending'),
375 'Q' : Item(verb
='Adding'),
376 'Q/floo' : Item(verb
='Adding'),
377 'A/B/E' : Item(verb
='Replacing'),
378 'A/B/E/bloo' : Item(verb
='Adding'),
379 'A/B/lambda' : Item(verb
='Sending'),
380 'A/C' : Item(verb
='Deleting'),
381 'A/D' : Item(verb
='Sending'),
382 'A/D/G/pi' : Item(verb
='Sending'),
383 'A/D/G/rho' : Item(verb
='Deleting'),
384 'A/D/H/gloo' : Item(verb
='Adding'),
385 'A/D/H/chi' : Item(verb
='Replacing'),
386 'A/D/H/omega' : Item(verb
='Sending'),
387 'A/D/gamma' : Item(verb
='Deleting'),
390 expected_status
.remove('A/D/G/rho', 'A/D/gamma', 'A/C',
391 'A/B/E/alpha', 'A/B/E/beta')
392 expected_status
.tweak('A/D', 'A/D/G/pi', 'A/D/H/omega', 'Q/floo', '',
393 wc_rev
=2, status
=' ')
394 expected_status
.tweak('A/D/H/chi', 'Q', 'A/B/E', 'A/B/E/bloo', 'A/B/lambda',
395 'A/D/H/gloo', wc_rev
=2, status
=' ')
397 # Commit the one file.
398 svntest
.actions
.run_and_verify_commit(wc_dir
,
404 #----------------------------------------------------------------------
406 # Regression test for bug reported by Jon Trowbridge:
408 # From: Jon Trowbridge <trow@ximian.com>
409 # Subject: svn segfaults if you commit a file that hasn't been added
410 # To: dev@subversion.tigris.org
411 # Date: 17 Jul 2001 03:20:55 -0500
412 # Message-Id: <995358055.16975.5.camel@morimoto>
414 # The problem is that report_single_mod in libsvn_wc/adm_crawler.c is
415 # called with its entry parameter as NULL, but the code doesn't
416 # check that entry is non-NULL before trying to dereference it.
418 # This bug never had an issue number.
420 def commit_unversioned_thing(sbox
):
421 "committing unversioned object produces error"
426 # Create an unversioned file in the wc.
427 svntest
.main
.file_append(os
.path
.join(wc_dir
, 'blorg'), "nothing to see")
429 # Commit a non-existent file and *expect* failure:
430 svntest
.actions
.run_and_verify_commit(wc_dir
,
433 "is not under version control",
434 os
.path
.join(wc_dir
,'blorg'))
436 #----------------------------------------------------------------------
438 # regression test for bug #391
440 def nested_dir_replacements(sbox
):
441 "replace two nested dirs, verify empty contents"
446 # Delete and re-add A/D (a replacement), and A/D/H (another replace).
447 svntest
.main
.run_svn(None, 'rm', os
.path
.join(wc_dir
, 'A', 'D'))
448 svntest
.main
.run_svn(None, 'add', '--depth=empty',
449 os
.path
.join(wc_dir
, 'A', 'D'))
450 svntest
.main
.run_svn(None, 'add', '--depth=empty',
451 os
.path
.join(wc_dir
, 'A', 'D', 'H'))
453 # For kicks, add new file A/D/bloo.
454 svntest
.main
.file_append(os
.path
.join(wc_dir
, 'A', 'D', 'bloo'), "hi")
455 svntest
.main
.run_svn(None, 'add', os
.path
.join(wc_dir
, 'A', 'D', 'bloo'))
457 # Verify pre-commit status:
459 # - A/D and A/D/H should both be scheduled as "R" at rev 1
460 # (rev 1 because they both existed before at rev 1)
462 # - A/D/bloo scheduled as "A" at rev 0
463 # (rev 0 because it did not exist before)
465 # - ALL other children of A/D scheduled as "D" at rev 1
467 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
468 expected_status
.tweak('A/D', 'A/D/H', status
='R ', wc_rev
=1)
469 expected_status
.add({
470 'A/D/bloo' : Item(status
='A ', wc_rev
=0),
472 expected_status
.tweak('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
473 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', 'A/D/gamma',
476 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
478 # Build expected post-commit trees:
480 # Create expected output tree.
481 expected_output
= svntest
.wc
.State(wc_dir
, {
482 'A/D' : Item(verb
='Replacing'),
483 'A/D/H' : Item(verb
='Adding'),
484 'A/D/bloo' : Item(verb
='Adding'),
487 # Created expected status tree.
488 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
489 expected_status
.tweak('A/D', 'A/D/H', wc_rev
=2)
490 expected_status
.add({
491 'A/D/bloo' : Item(status
=' ', wc_rev
=2),
493 expected_status
.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
494 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', 'A/D/gamma')
496 # Commit from the top of the working copy and verify output & status.
497 svntest
.actions
.run_and_verify_commit(wc_dir
,
503 #----------------------------------------------------------------------
505 # Testing part 1 of the "Greg Hudson" problem -- specifically, that
506 # our use of the "existence=deleted" flag is working properly in cases
507 # where the parent directory's revision lags behind a deleted child's
510 def hudson_part_1(sbox
):
511 "hudson prob 1.0: delete file, commit, update"
516 # Remove gamma from the working copy.
517 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
518 svntest
.main
.run_svn(None, 'rm', gamma_path
)
520 # Create expected commit output.
521 expected_output
= svntest
.wc
.State(wc_dir
, {
522 'A/D/gamma' : Item(verb
='Deleting'),
525 # After committing, status should show no sign of gamma.
526 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
527 expected_status
.remove('A/D/gamma')
529 # Commit the deletion of gamma and verify.
530 svntest
.actions
.run_and_verify_commit(wc_dir
,
535 # Now gamma should be marked as `deleted' under the hood. When we
536 # update, we should no output, and a perfect, virginal status list
537 # at revision 2. (The `deleted' entry should be removed.)
539 # Expected output of update: nothing.
540 expected_output
= svntest
.wc
.State(wc_dir
, {})
542 # Expected disk tree: everything but gamma
543 expected_disk
= svntest
.main
.greek_state
.copy()
544 expected_disk
.remove('A/D/gamma')
546 # Expected status after update: totally clean revision 2, minus gamma.
547 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
548 expected_status
.remove('A/D/gamma')
550 svntest
.actions
.run_and_verify_update(wc_dir
,
556 #----------------------------------------------------------------------
558 # Testing part 1 of the "Greg Hudson" problem -- variation on previous
559 # test, removing a directory instead of a file this time.
561 def hudson_part_1_variation_1(sbox
):
562 "hudson prob 1.1: delete dir, commit, update"
567 # Remove H from the working copy.
568 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
569 svntest
.main
.run_svn(None, 'rm', H_path
)
571 # Create expected commit output.
572 expected_output
= svntest
.wc
.State(wc_dir
, {
573 'A/D/H' : Item(verb
='Deleting'),
576 # After committing, status should show no sign of H or its contents
577 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
578 expected_status
.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
580 # Commit the deletion of H and verify.
581 svntest
.actions
.run_and_verify_commit(wc_dir
,
586 # Now H should be marked as `deleted' under the hood. When we
587 # update, we should no see output, and a perfect, virginal status
588 # list at revision 2. (The `deleted' entry should be removed.)
590 # Expected output of update: H gets a no-op deletion.
591 expected_output
= svntest
.wc
.State(wc_dir
, {})
593 # Expected disk tree: everything except files in H
594 expected_disk
= svntest
.main
.greek_state
.copy()
595 expected_disk
.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
597 # Expected status after update: totally clean revision 2, minus H.
598 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
599 expected_status
.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
601 svntest
.actions
.run_and_verify_update(wc_dir
,
606 #----------------------------------------------------------------------
608 # Testing part 1 of the "Greg Hudson" problem -- variation 2. In this
609 # test, we make sure that a file that is BOTH `deleted' and scheduled
610 # for addition can be correctly committed & merged.
612 def hudson_part_1_variation_2(sbox
):
613 "hudson prob 1.2: delete, commit, re-add, commit"
618 # Remove gamma from the working copy.
619 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
620 svntest
.main
.run_svn(None, 'rm', gamma_path
)
622 # Create expected commit output.
623 expected_output
= svntest
.wc
.State(wc_dir
, {
624 'A/D/gamma' : Item(verb
='Deleting'),
627 # After committing, status should show no sign of gamma.
628 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
629 expected_status
.remove('A/D/gamma')
631 # Commit the deletion of gamma and verify.
632 svntest
.actions
.run_and_verify_commit(wc_dir
,
637 # Now gamma should be marked as `deleted' under the hood.
638 # Go ahead and re-add gamma, so that is *also* scheduled for addition.
639 svntest
.main
.file_append(gamma_path
, "added gamma")
640 svntest
.main
.run_svn(None, 'add', gamma_path
)
642 # For sanity, examine status: it should show a revision 2 tree with
643 # gamma scheduled for addition.
644 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
645 expected_status
.tweak('A/D/gamma', wc_rev
=0, status
='A ')
647 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
649 # Create expected commit output.
650 expected_output
= svntest
.wc
.State(wc_dir
, {
651 'A/D/gamma' : Item(verb
='Adding'),
654 # After committing, status should show only gamma at revision 3.
655 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
656 expected_status
.tweak('A/D/gamma', wc_rev
=3)
658 svntest
.actions
.run_and_verify_commit(wc_dir
,
664 #----------------------------------------------------------------------
666 # Testing part 2 of the "Greg Hudson" problem.
668 # In this test, we make sure that we're UNABLE to commit a propchange
669 # on an out-of-date directory.
671 def hudson_part_2(sbox
):
672 "hudson prob 2.0: prop commit on old dir fails"
677 # Remove gamma from the working copy.
678 D_path
= os
.path
.join(wc_dir
, 'A', 'D')
679 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
680 svntest
.main
.run_svn(None, 'rm', gamma_path
)
682 # Create expected commit output.
683 expected_output
= svntest
.wc
.State(wc_dir
, {
684 'A/D/gamma' : Item(verb
='Deleting'),
687 # After committing, status should show no sign of gamma.
688 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
689 expected_status
.remove('A/D/gamma')
691 # Commit the deletion of gamma and verify.
692 svntest
.actions
.run_and_verify_commit(wc_dir
,
697 # Now gamma should be marked as `deleted' under the hood, at
698 # revision 2. Meanwhile, A/D is still lagging at revision 1.
700 # Make a propchange on A/D
701 svntest
.main
.run_svn(None, 'ps', 'foo', 'bar', D_path
)
703 # Commit and *expect* a repository Merge failure:
704 svntest
.actions
.run_and_verify_commit(wc_dir
,
710 #----------------------------------------------------------------------
712 # Test a possible regression in our 'deleted' post-commit handling.
714 # This test moves files from one subdir to another, commits, then
715 # updates the empty directory. Nothing should be printed, assuming
716 # all the moved files are properly marked as 'deleted' and reported to
719 def hudson_part_2_1(sbox
):
720 "hudson prob 2.1: move files, update empty dir"
725 # Move all the files in H to G
726 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
727 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
728 chi_path
= os
.path
.join(H_path
, 'chi')
729 psi_path
= os
.path
.join(H_path
, 'psi')
730 omega_path
= os
.path
.join(H_path
, 'omega')
732 svntest
.main
.run_svn(None, 'mv', chi_path
, G_path
)
733 svntest
.main
.run_svn(None, 'mv', psi_path
, G_path
)
734 svntest
.main
.run_svn(None, 'mv', omega_path
, G_path
)
736 # Create expected commit output.
737 expected_output
= svntest
.wc
.State(wc_dir
, {
738 'A/D/H/chi' : Item(verb
='Deleting'),
739 'A/D/H/omega' : Item(verb
='Deleting'),
740 'A/D/H/psi' : Item(verb
='Deleting'),
741 'A/D/G/chi' : Item(verb
='Adding'),
742 'A/D/G/omega' : Item(verb
='Adding'),
743 'A/D/G/psi' : Item(verb
='Adding'),
746 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
747 expected_status
.remove('A/D/H/chi')
748 expected_status
.remove('A/D/H/omega')
749 expected_status
.remove('A/D/H/psi')
750 expected_status
.add({ 'A/D/G/chi' :
751 Item(wc_rev
=2, status
=' ') })
752 expected_status
.add({ 'A/D/G/omega' :
753 Item(wc_rev
=2, status
=' ') })
754 expected_status
.add({ 'A/D/G/psi' :
755 Item(wc_rev
=2, status
=' ') })
757 svntest
.actions
.run_and_verify_commit(wc_dir
,
762 # Now, assuming all three files in H are marked as 'deleted', an
763 # update of H should print absolutely nothing.
764 expected_output
= svntest
.wc
.State(wc_dir
, { })
766 # Reuse expected_status
767 expected_status
.tweak(wc_rev
=2)
769 expected_disk
= svntest
.main
.greek_state
.copy()
770 expected_disk
.remove('A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
772 'A/D/G/chi' : Item("This is the file 'chi'.\n"),
775 'A/D/G/omega' : Item("This is the file 'omega'.\n"),
778 'A/D/G/psi' : Item("This is the file 'psi'.\n"),
781 svntest
.actions
.run_and_verify_update(wc_dir
,
786 #----------------------------------------------------------------------
793 # Get paths to the working copy and repository
795 repo_dir
= sbox
.repo_dir
797 # Create a hook that appends its name to a log file.
798 hook_format
= """import sys
799 fp = open(sys.argv[1] + '/hooks.log', 'a')
803 # Setup the hook configs to log data to a file
804 start_commit_hook
= svntest
.main
.get_start_commit_hook_path(repo_dir
)
805 svntest
.main
.create_python_hook_script(start_commit_hook
,
806 hook_format
% "start_commit_hook")
808 pre_commit_hook
= svntest
.main
.get_pre_commit_hook_path(repo_dir
)
809 svntest
.main
.create_python_hook_script(pre_commit_hook
,
810 hook_format
% "pre_commit_hook")
812 post_commit_hook
= svntest
.main
.get_post_commit_hook_path(repo_dir
)
813 svntest
.main
.create_python_hook_script(post_commit_hook
,
814 hook_format
% "post_commit_hook")
816 # Modify iota just so there is something to commit.
817 iota_path
= os
.path
.join(wc_dir
, "iota")
818 svntest
.main
.file_append(iota_path
, "More stuff in iota")
820 # Commit, no output expected.
821 svntest
.actions
.run_and_verify_svn(None, [], [],
823 '-m', 'log msg', wc_dir
)
825 # Now check the logfile
826 expected_data
= [ 'start_commit_hook\n', 'pre_commit_hook\n', 'post_commit_hook\n' ]
828 logfilename
= os
.path
.join(repo_dir
, "hooks.log")
829 if os
.path
.exists(logfilename
):
830 fp
= open(logfilename
)
832 raise svntest
.verify
.SVNUnexpectedOutput("hook logfile %s not found")\
835 actual_data
= fp
.readlines()
837 os
.unlink(logfilename
)
838 svntest
.verify
.compare_and_display_lines('wrong hook logfile content',
840 expected_data
, actual_data
)
842 #----------------------------------------------------------------------
844 # Regression test for bug #469, whereby merge() was once reporting
845 # erroneous conflicts due to Ancestor < Target < Source, in terms of
846 # node-rev-id parentage.
848 def merge_mixed_revisions(sbox
):
849 "commit mixed-rev wc (no erroneous merge error)"
854 # Make some convenient paths.
855 iota_path
= os
.path
.join(wc_dir
, 'iota')
856 H_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H')
857 chi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'chi')
858 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
860 # Here's the reproduction formula, in 5 parts.
861 # Hoo, what a buildup of state!
863 # 1. echo "moo" >> iota; echo "moo" >> A/D/H/chi; svn ci
864 svntest
.main
.file_append(iota_path
, "moo")
865 svntest
.main
.file_append(chi_path
, "moo")
867 expected_output
= svntest
.wc
.State(wc_dir
, {
868 'iota' : Item(verb
='Sending'),
869 'A/D/H/chi' : Item(verb
='Sending'),
872 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
873 expected_status
.tweak('iota', 'A/D/H/chi', wc_rev
=2)
875 svntest
.actions
.run_and_verify_commit(wc_dir
,
882 expected_status
= svntest
.wc
.State(wc_dir
, {
883 'A/D/H' : Item(status
=' ', wc_rev
=2),
884 'A/D/H/chi' : Item(status
=' ', wc_rev
=2),
885 'A/D/H/omega' : Item(status
=' ', wc_rev
=2),
886 'A/D/H/psi' : Item(status
=' ', wc_rev
=2),
888 expected_disk
= svntest
.wc
.State('', {
889 'omega' : Item("This is the file 'omega'.\n"),
890 'chi' : Item("This is the file 'chi'.\nmoo"),
891 'psi' : Item("This is the file 'psi'.\n"),
893 expected_output
= svntest
.wc
.State(wc_dir
, { })
894 svntest
.actions
.run_and_verify_update(H_path
,
900 # 3. echo "moo" >> iota; svn ci iota
901 svntest
.main
.file_append(iota_path
, "moo2")
902 expected_output
= svntest
.wc
.State(wc_dir
, {
903 'iota' : Item(verb
='Sending'),
905 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
906 expected_status
.tweak('A/D/H', 'A/D/H/omega', 'A/D/H/chi', 'A/D/H/psi',
908 expected_status
.tweak('iota', wc_rev
=3)
910 svntest
.actions
.run_and_verify_commit(wc_dir
,
916 # 4. echo "moo" >> A/D/H/chi; svn ci A/D/H/chi
917 svntest
.main
.file_append(chi_path
, "moo3")
918 expected_output
= svntest
.wc
.State(wc_dir
, {
919 'A/D/H/chi' : Item(verb
='Sending'),
921 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
922 expected_status
.tweak('A/D/H/chi', wc_rev
=4)
923 expected_status
.tweak('A/D/H', 'A/D/H/omega', 'A/D/H/psi', wc_rev
=2)
924 expected_status
.tweak('iota', wc_rev
=3)
925 svntest
.actions
.run_and_verify_commit(wc_dir
,
930 # 5. echo "moo" >> iota; svn ci iota
931 svntest
.main
.file_append(iota_path
, "moomoo")
932 expected_output
= svntest
.wc
.State(wc_dir
, {
933 'iota' : Item(verb
='Sending'),
935 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
936 expected_status
.tweak('A/D/H', 'A/D/H/omega', 'A/D/H/psi', wc_rev
=2)
937 expected_status
.tweak('A/D/H/chi', wc_rev
=4)
938 expected_status
.tweak('iota', wc_rev
=5)
939 svntest
.actions
.run_and_verify_commit(wc_dir
,
944 # At this point, here is what our tree should look like:
945 # _ 1 ( 5) working_copies/commit_tests-10
946 # _ 1 ( 5) working_copies/commit_tests-10/A
947 # _ 1 ( 5) working_copies/commit_tests-10/A/B
948 # _ 1 ( 5) working_copies/commit_tests-10/A/B/E
949 # _ 1 ( 5) working_copies/commit_tests-10/A/B/E/alpha
950 # _ 1 ( 5) working_copies/commit_tests-10/A/B/E/beta
951 # _ 1 ( 5) working_copies/commit_tests-10/A/B/F
952 # _ 1 ( 5) working_copies/commit_tests-10/A/B/lambda
953 # _ 1 ( 5) working_copies/commit_tests-10/A/C
954 # _ 1 ( 5) working_copies/commit_tests-10/A/D
955 # _ 1 ( 5) working_copies/commit_tests-10/A/D/G
956 # _ 1 ( 5) working_copies/commit_tests-10/A/D/G/pi
957 # _ 1 ( 5) working_copies/commit_tests-10/A/D/G/rho
958 # _ 1 ( 5) working_copies/commit_tests-10/A/D/G/tau
959 # _ 2 ( 5) working_copies/commit_tests-10/A/D/H
960 # _ 4 ( 5) working_copies/commit_tests-10/A/D/H/chi
961 # _ 2 ( 5) working_copies/commit_tests-10/A/D/H/omega
962 # _ 2 ( 5) working_copies/commit_tests-10/A/D/H/psi
963 # _ 1 ( 5) working_copies/commit_tests-10/A/D/gamma
964 # _ 1 ( 5) working_copies/commit_tests-10/A/mu
965 # _ 5 ( 5) working_copies/commit_tests-10/iota
967 # At this point, we're ready to modify omega and iota, and commit
968 # from the top. We should *not* get a conflict!
970 svntest
.main
.file_append(iota_path
, "finalmoo")
971 svntest
.main
.file_append(omega_path
, "finalmoo")
973 expected_output
= svntest
.wc
.State(wc_dir
, {
974 'iota' : Item(verb
='Sending'),
975 'A/D/H/omega' : Item(verb
='Sending'),
977 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
978 expected_status
.tweak('iota', 'A/D/H/omega', wc_rev
=6)
979 expected_status
.tweak('A/D/H', 'A/D/H/psi', wc_rev
=2)
980 expected_status
.tweak('A/D/H/chi', wc_rev
=4)
981 svntest
.actions
.run_and_verify_commit(wc_dir
,
986 #----------------------------------------------------------------------
988 def commit_uri_unsafe(sbox
):
989 "commit files and dirs with URI-unsafe characters"
994 # Note: on Windows, files can't have angle brackets in them, so we
995 # don't tests that case.
996 if svntest
.main
.windows
or sys
.platform
== 'cygwin':
997 angle_name
= '_angle_'
998 nasty_name
= '#![]{}()__%'
1000 angle_name
= '<angle>'
1001 nasty_name
= '#![]{}()<>%'
1003 # Make some convenient paths.
1004 hash_dir
= os
.path
.join(wc_dir
, '#hash#')
1005 nasty_dir
= os
.path
.join(wc_dir
, nasty_name
)
1006 space_path
= os
.path
.join(wc_dir
, 'A', 'D', 'space path')
1007 bang_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'bang!')
1008 bracket_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'bra[ket')
1009 brace_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'bra{e')
1010 angle_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', angle_name
)
1011 paren_path
= os
.path
.join(wc_dir
, 'A', 'D', 'pare)(theses')
1012 percent_path
= os
.path
.join(wc_dir
, '#hash#', 'percen%')
1013 nasty_path
= os
.path
.join(wc_dir
, 'A', nasty_name
)
1017 svntest
.main
.file_append(space_path
, "This path has a space in it.")
1018 svntest
.main
.file_append(bang_path
, "This path has a bang in it.")
1019 svntest
.main
.file_append(bracket_path
, "This path has a bracket in it.")
1020 svntest
.main
.file_append(brace_path
, "This path has a brace in it.")
1021 svntest
.main
.file_append(angle_path
, "This path has angle brackets in it.")
1022 svntest
.main
.file_append(paren_path
, "This path has parentheses in it.")
1023 svntest
.main
.file_append(percent_path
, "This path has a percent in it.")
1024 svntest
.main
.file_append(nasty_path
, "This path has all sorts of ick in it.")
1026 add_list
= [hash_dir
,
1027 nasty_dir
, # not xml-safe
1032 angle_path
, # not xml-safe
1035 nasty_path
, # not xml-safe
1037 for item
in add_list
:
1038 svntest
.main
.run_svn(None, 'add', '--depth=empty', item
)
1040 expected_output
= svntest
.wc
.State(wc_dir
, {
1041 '#hash#' : Item(verb
='Adding'),
1042 nasty_name
: Item(verb
='Adding'),
1043 'A/D/space path' : Item(verb
='Adding'),
1044 'A/D/H/bang!' : Item(verb
='Adding'),
1045 'A/D/H/bra[ket' : Item(verb
='Adding'),
1046 'A/D/H/bra{e' : Item(verb
='Adding'),
1047 'A/D/H/' + angle_name
: Item(verb
='Adding'),
1048 'A/D/pare)(theses' : Item(verb
='Adding'),
1049 '#hash#/percen%' : Item(verb
='Adding'),
1050 'A/' + nasty_name
: Item(verb
='Adding'),
1053 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1055 # Items in our add list will be at rev 2
1056 for item
in expected_output
.desc
.keys():
1057 expected_status
.add({ item
: Item(wc_rev
=2, status
=' ') })
1059 svntest
.actions
.run_and_verify_commit(wc_dir
,
1065 #----------------------------------------------------------------------
1067 def commit_deleted_edited(sbox
):
1068 "commit deleted yet edited files"
1071 wc_dir
= sbox
.wc_dir
1073 # Make some convenient paths.
1074 iota_path
= os
.path
.join(wc_dir
, 'iota')
1075 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1078 svntest
.main
.file_append(iota_path
, "This file has been edited.")
1079 svntest
.main
.file_append(mu_path
, "This file has been edited.")
1081 # Schedule the files for removal.
1082 svntest
.main
.run_svn(None, 'remove', '--force', iota_path
)
1083 svntest
.main
.run_svn(None, 'remove', '--force', mu_path
)
1085 # Make our output list
1086 expected_output
= svntest
.wc
.State(wc_dir
, {
1087 'iota' : Item(verb
='Deleting'),
1088 'A/mu' : Item(verb
='Deleting'),
1091 # Items in the status list are all at rev 1, except the two things
1092 # we changed...but then, they don't exist at all.
1093 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1094 expected_status
.remove('iota', 'A/mu')
1096 svntest
.actions
.run_and_verify_commit(wc_dir
,
1101 #----------------------------------------------------------------------
1103 def commit_in_dir_scheduled_for_addition(sbox
):
1104 "commit a file inside dir scheduled for addition"
1107 wc_dir
= sbox
.wc_dir
1109 A_path
= os
.path
.join(wc_dir
, 'A')
1110 Z_path
= os
.path
.join(wc_dir
, 'Z')
1111 mu_path
= os
.path
.join(wc_dir
, 'Z', 'mu')
1113 svntest
.main
.run_svn(None, 'move', A_path
, Z_path
)
1115 # Commit a copied thing inside an added-with-history directory,
1116 # expecting a specific error to occur!
1117 svntest
.actions
.run_and_verify_commit(wc_dir
,
1123 Q_path
= os
.path
.join(wc_dir
, 'Q')
1124 bloo_path
= os
.path
.join(Q_path
, 'bloo')
1127 svntest
.main
.file_append(bloo_path
, "New contents.")
1128 svntest
.main
.run_svn(None, 'add', Q_path
)
1130 # Commit a regular added thing inside an added directory,
1131 # expecting a specific error to occur!
1132 svntest
.actions
.run_and_verify_commit(wc_dir
,
1135 "not under version control",
1138 #----------------------------------------------------------------------
1140 # Does this make sense now that deleted files are always removed from the wc?
1141 def commit_rmd_and_deleted_file(sbox
):
1142 "commit deleted (and missing) file"
1145 wc_dir
= sbox
.wc_dir
1146 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1149 svntest
.main
.run_svn(None, 'rm', mu_path
)
1151 # Commit, hoping to see no errors
1152 svntest
.actions
.run_and_verify_svn("Output on stderr where none expected",
1153 svntest
.verify
.AnyOutput
, [],
1154 'commit', '-m', 'logmsg', mu_path
)
1156 #----------------------------------------------------------------------
1158 # Issue #644 which failed over ra_neon.
1159 def commit_add_file_twice(sbox
):
1160 "issue 644 attempt to add a file twice"
1163 wc_dir
= sbox
.wc_dir
1166 gloo_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'gloo')
1167 svntest
.main
.file_append(gloo_path
, "hello")
1168 svntest
.main
.run_svn(None, 'add', gloo_path
)
1170 # Create expected output tree.
1171 expected_output
= svntest
.wc
.State(wc_dir
, {
1172 'A/D/H/gloo' : Item(verb
='Adding'),
1175 # Created expected status tree.
1176 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1177 expected_status
.add({
1178 'A/D/H/gloo' : Item(status
=' ', wc_rev
=2),
1181 # Commit should succeed
1182 svntest
.actions
.run_and_verify_commit(wc_dir
,
1188 # Update to state before commit
1189 svntest
.main
.run_svn(None, 'up', '-r', '1', wc_dir
)
1191 # Create the file again
1192 svntest
.main
.file_append(gloo_path
, "hello")
1193 svntest
.main
.run_svn(None, 'add', gloo_path
)
1195 # Commit and *expect* a failure:
1196 svntest
.actions
.run_and_verify_commit(wc_dir
,
1202 #----------------------------------------------------------------------
1204 # There was a problem that committing from a directory that had a
1205 # longer name than the working copy directory caused the commit notify
1206 # messages to display truncated/random filenames.
1208 def commit_from_long_dir(sbox
):
1209 "commit from a dir with a longer name than the wc"
1212 wc_dir
= sbox
.wc_dir
1214 was_dir
= os
.getcwd()
1215 abs_wc_dir
= os
.path
.realpath(os
.path
.join(was_dir
, wc_dir
))
1217 # something to commit
1218 svntest
.main
.file_append(os
.path
.join(wc_dir
, 'iota'), "modified iota")
1220 # Create expected output tree.
1221 expected_output
= svntest
.wc
.State('', {
1222 'iota' : Item(verb
='Sending'),
1225 # Any length name was enough to provoke the original bug, but
1226 # keeping its length less than that of the filename 'iota' avoided
1227 # random behaviour, but still caused the test to fail
1231 os
.mkdir(extra_name
)
1232 os
.chdir(extra_name
)
1234 svntest
.actions
.run_and_verify_commit(abs_wc_dir
,
1240 #----------------------------------------------------------------------
1242 def commit_with_lock(sbox
):
1243 "try to commit when directory is locked"
1246 # modify gamma and lock its directory
1247 wc_dir
= sbox
.wc_dir
1249 D_path
= os
.path
.join(wc_dir
, 'A', 'D')
1250 gamma_path
= os
.path
.join(D_path
, 'gamma')
1251 svntest
.main
.file_append(gamma_path
, "modified gamma")
1252 svntest
.actions
.lock_admin_dir(D_path
)
1254 # this commit should fail
1255 svntest
.actions
.run_and_verify_commit(wc_dir
,
1258 'svn: Working copy \'.*\' locked',
1262 svntest
.actions
.run_and_verify_svn("Output on stderr where none expected",
1266 # this commit should succeed
1267 expected_output
= svntest
.wc
.State(wc_dir
, {
1268 'A/D/gamma' : Item(verb
='Sending'),
1270 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1271 expected_status
.tweak('A/D/gamma', wc_rev
=2)
1272 svntest
.actions
.run_and_verify_commit(wc_dir
,
1278 #----------------------------------------------------------------------
1280 # Explicitly commit the current directory. This did at one point fail
1281 # in post-commit processing due to a path canonicalization problem.
1283 def commit_current_dir(sbox
):
1284 "commit the current directory"
1288 wc_dir
= sbox
.wc_dir
1289 svntest
.main
.run_svn(None, 'propset', 'pname', 'pval', wc_dir
)
1291 was_cwd
= os
.getcwd()
1295 expected_output
= svntest
.wc
.State('.', {
1296 '.' : Item(verb
='Sending'),
1298 svntest
.actions
.run_and_verify_commit('.',
1305 # I can't get the status check to work as part of run_and_verify_commit.
1306 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1307 expected_status
.tweak('', wc_rev
=2, status
=' ')
1308 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1310 #----------------------------------------------------------------------
1312 # Check that the pending txn gets removed from the repository after
1315 def failed_commit(sbox
):
1316 "commit with conflicts and check txn in repo"
1319 wc_dir
= sbox
.wc_dir
1321 # Make the other working copy
1322 other_wc_dir
= sbox
.add_wc_path('other')
1323 svntest
.actions
.duplicate_dir(wc_dir
, other_wc_dir
)
1325 # Make different changes in the two working copies
1326 iota_path
= os
.path
.join(wc_dir
, "iota")
1327 svntest
.main
.file_append(iota_path
, "More stuff in iota")
1329 other_iota_path
= os
.path
.join(other_wc_dir
, "iota")
1330 svntest
.main
.file_append(other_iota_path
, "More different stuff in iota")
1332 # Commit both working copies. The second commit should fail.
1333 svntest
.actions
.run_and_verify_svn("Output on stderr where none expected",
1334 svntest
.verify
.AnyOutput
, [],
1335 'commit', '-m', 'log', wc_dir
)
1337 svntest
.actions
.run_and_verify_svn("Output on stderr expected",
1338 None, svntest
.verify
.AnyOutput
,
1339 'commit', '-m', 'log', other_wc_dir
)
1341 # Now list the txns in the repo. The list should be empty.
1342 exit_code
, output
, errput
= svntest
.main
.run_svnadmin('lstxns',
1344 svntest
.verify
.compare_and_display_lines(
1345 "Error running 'svnadmin lstxns'.",
1346 'STDERR', [], errput
)
1347 svntest
.verify
.compare_and_display_lines(
1348 "Output of 'svnadmin lstxns' is unexpected.",
1349 'STDOUT', [], output
)
1351 #----------------------------------------------------------------------
1353 # Commit from multiple working copies is not yet supported. At
1354 # present an error is generated and none of the working copies change.
1355 # Related to issue 959, this test here doesn't use svn:externals but the
1356 # behaviour needs to be considered.
1358 def commit_multiple_wc(sbox
):
1359 "attempted commit from multiple wc fails"
1362 wc_dir
= sbox
.wc_dir
1364 # Checkout a second working copy
1365 wc2_dir
= os
.path
.join(wc_dir
, 'A', 'wc2')
1367 svntest
.actions
.run_and_verify_svn("Output on stderr where none expected",
1368 svntest
.verify
.AnyOutput
, [],
1372 # Modify both working copies
1373 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1374 svntest
.main
.file_append(mu_path
, 'appended mu text')
1375 lambda2_path
= os
.path
.join(wc2_dir
, 'A', 'B', 'lambda')
1376 svntest
.main
.file_append(lambda2_path
, 'appended lambda2 text')
1378 # Verify modified status
1379 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1380 expected_status
.tweak('A/mu', status
='M ')
1381 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1382 expected_status2
= svntest
.actions
.get_virginal_state(wc2_dir
, 1)
1383 expected_status2
.tweak('A/B/lambda', status
='M ')
1384 svntest
.actions
.run_and_verify_status(wc2_dir
, expected_status2
)
1386 # Commit should fail, even though one target is a "child" of the other.
1387 svntest
.actions
.run_and_verify_svn("Unexpectedly not locked",
1388 None, svntest
.verify
.AnyOutput
,
1389 'commit', '-m', 'log',
1392 # Verify status unchanged
1393 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1394 svntest
.actions
.run_and_verify_status(wc2_dir
, expected_status2
)
1397 def commit_nonrecursive(sbox
):
1398 "commit named targets with -N (issues #1195, #1239)"
1401 wc_dir
= sbox
.wc_dir
1403 ### Note: the original recipes used 'add -N'. These days, we use
1404 ### --depth={empty,files}, and both the code and the comments below
1405 ### have been adjusted to reflect this.
1407 #####################################################
1410 ### 1. Create these directories and files:
1419 ### 2. run 'svn add --depth=empty <all of the above>'
1421 ### 3. run 'svn ci -N <all of the above>'
1423 ### (The bug was that only 4 entities would get committed, when it
1424 ### should be 6: dir2/ and file4 were left out.)
1426 # These paths are relative to the top of the test's working copy.
1427 file1_path
= 'file1'
1429 file2_path
= os
.path
.join('dir1', 'file2')
1430 file3_path
= os
.path
.join('dir1', 'file3')
1431 dir2_path
= os
.path
.join('dir1', 'dir2')
1432 file4_path
= os
.path
.join('dir1', 'dir2', 'file4')
1434 # Create the new files and directories.
1435 svntest
.main
.file_append(os
.path
.join(wc_dir
, file1_path
), 'this is file1')
1436 os
.mkdir(os
.path
.join(wc_dir
, dir1_path
))
1437 svntest
.main
.file_append(os
.path
.join(wc_dir
, file2_path
), 'this is file2')
1438 svntest
.main
.file_append(os
.path
.join(wc_dir
, file3_path
), 'this is file3')
1439 os
.mkdir(os
.path
.join(wc_dir
, dir2_path
))
1440 svntest
.main
.file_append(os
.path
.join(wc_dir
, file4_path
), 'this is file4')
1442 # Add them to version control.
1443 svntest
.actions
.run_and_verify_svn(None, svntest
.verify
.AnyOutput
, [],
1444 'add', '--depth=empty',
1445 os
.path
.join(wc_dir
, file1_path
),
1446 os
.path
.join(wc_dir
, dir1_path
),
1447 os
.path
.join(wc_dir
, file2_path
),
1448 os
.path
.join(wc_dir
, file3_path
),
1449 os
.path
.join(wc_dir
, dir2_path
),
1450 os
.path
.join(wc_dir
, file4_path
))
1452 # Commit. We should see all 6 items (2 dirs, 4 files) get sent.
1453 expected_output
= svntest
.wc
.State(
1455 { file1_path
: Item(verb
='Adding'),
1456 dir1_path
: Item(verb
='Adding'),
1457 file2_path
: Item(verb
='Adding'),
1458 file3_path
: Item(verb
='Adding'),
1459 dir2_path
: Item(verb
='Adding'),
1460 file4_path
: Item(verb
='Adding'),
1464 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1465 expected_status
.add({
1466 file1_path
: Item(status
=' ', wc_rev
=2),
1467 dir1_path
: Item(status
=' ', wc_rev
=2),
1468 file2_path
: Item(status
=' ', wc_rev
=2),
1469 file3_path
: Item(status
=' ', wc_rev
=2),
1470 dir2_path
: Item(status
=' ', wc_rev
=2),
1471 file4_path
: Item(status
=' ', wc_rev
=2),
1474 svntest
.actions
.run_and_verify_commit(wc_dir
,
1479 os
.path
.join(wc_dir
, file1_path
),
1480 os
.path
.join(wc_dir
, dir1_path
),
1481 os
.path
.join(wc_dir
, file2_path
),
1482 os
.path
.join(wc_dir
, file3_path
),
1483 os
.path
.join(wc_dir
, dir2_path
),
1484 os
.path
.join(wc_dir
, file4_path
))
1486 #######################################################################
1488 ### There's some complex history here; please bear with me.
1490 ### First there was issue #1239, which had the following recipe:
1492 ### 1. Create these directories and files:
1499 ### dirA/dirB/nocommit
1501 ### 2. run 'svn add --depth=empty <all of the above>'
1503 ### 3. run 'svn ci -N <all but nocommit>'
1505 ### (In this recipe, 'add -N' has been changed to 'add --depth...',
1506 ### but 'ci -N' has been left as-is, for reasons explained below.)
1508 ### Issue #1239 claimed a two-part bug: that step 3 would try to
1509 ### commit the file `nocommit' when it shouldn't, and that it would
1510 ### get an error anyway:
1513 ### Adding wc/dirA/fileA
1514 ### Adding wc/dirA/fileB
1515 ### Adding wc/dirA/dirB
1516 ### Adding wc/dirA/dirB/nocommit
1517 ### Adding wc/dirA/dirB/fileC
1518 ### Transmitting file data ....svn: A problem occurred; \
1519 ### see later errors for details
1520 ### svn: Commit succeeded, but other errors follow:
1521 ### svn: Problem running log
1522 ### svn: Error bumping revisions post-commit (details follow):
1523 ### svn: in directory
1524 ### 'F:/Programmation/Projets/subversion/svnant/test/wc/dirA'
1525 ### svn: start_handler: error processing command 'committed' in
1526 ### 'F:/Programmation/Projets/subversion/svnant/test/wc/dirA'
1527 ### svn: Working copy not locked
1528 ### svn: directory not locked
1529 ### (F:/Programmation/Projets/subversion/svnant/test/wc)
1531 ### However, this was all in the days before --depth, and depended
1532 ### on an idiosyncratic interpretation of -N, one which required
1533 ### commit to behave differently from other commands taking -N.
1535 ### These days, -N should be equivalent to --depth=files in almost
1536 ### all cases. There are some exceptions (e.g., status), but commit
1537 ### is not an exception. Thus, the above recipe is now incorrect,
1538 ### because "wc/dirA/dirB" was given as an explicit target, and
1539 ### therefore the file "wc/dirA/dirB/nocommit" *should* have been
1540 ### committed after all, since it's a file child of a named target
1541 ### and -N means --depth=files.
1543 ### So we really need two tests: one for commit -N (--depth=files),
1544 ### and another for --depth=empty. I've changed this test to cover
1545 ### the -N case, and added 'commit_propmods_with_depth_empty' to
1546 ### depth_tests.py to cover the --depth=empty case.
1548 # Now add these directories and files, except the last:
1550 fileA_path
= os
.path
.join('dirA', 'fileA')
1551 fileB_path
= os
.path
.join('dirA', 'fileB')
1552 dirB_path
= os
.path
.join('dirA', 'dirB')
1553 nope_1_path
= os
.path
.join(dirB_path
, 'nope_1')
1554 nope_2_path
= os
.path
.join(dirB_path
, 'nope_2')
1556 # Create the new files and directories.
1557 os
.mkdir(os
.path
.join(wc_dir
, dirA_path
))
1558 svntest
.main
.file_append(os
.path
.join(wc_dir
, fileA_path
), 'fileA')
1559 svntest
.main
.file_append(os
.path
.join(wc_dir
, fileB_path
), 'fileB')
1560 os
.mkdir(os
.path
.join(wc_dir
, dirB_path
))
1561 svntest
.main
.file_append(os
.path
.join(wc_dir
, nope_1_path
), 'nope_1')
1562 svntest
.main
.file_append(os
.path
.join(wc_dir
, nope_2_path
), 'nope_2')
1564 # Add them to version control.
1565 svntest
.actions
.run_and_verify_svn(None, svntest
.verify
.AnyOutput
, [],
1566 'add', '--depth=empty',
1567 os
.path
.join(wc_dir
, dirA_path
),
1568 os
.path
.join(wc_dir
, fileA_path
),
1569 os
.path
.join(wc_dir
, fileB_path
),
1570 os
.path
.join(wc_dir
, dirB_path
),
1571 os
.path
.join(wc_dir
, nope_1_path
),
1572 os
.path
.join(wc_dir
, nope_2_path
))
1574 expected_output
= svntest
.wc
.State(
1576 { dirA_path
: Item(verb
='Adding'),
1577 fileA_path
: Item(verb
='Adding'),
1578 fileB_path
: Item(verb
='Adding'),
1582 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1584 # Expect the leftovers from the first part of the test.
1585 expected_status
.add({
1586 file1_path
: Item(status
=' ', wc_rev
=2),
1587 dir1_path
: Item(status
=' ', wc_rev
=2),
1588 file2_path
: Item(status
=' ', wc_rev
=2),
1589 file3_path
: Item(status
=' ', wc_rev
=2),
1590 dir2_path
: Item(status
=' ', wc_rev
=2),
1591 file4_path
: Item(status
=' ', wc_rev
=2),
1594 # Expect some commits and some non-commits from this part of the test.
1595 expected_status
.add({
1596 dirA_path
: Item(status
=' ', wc_rev
=3),
1597 fileA_path
: Item(status
=' ', wc_rev
=3),
1598 fileB_path
: Item(status
=' ', wc_rev
=3),
1599 dirB_path
: Item(status
='A ', wc_rev
=0),
1600 nope_1_path
: Item(status
='A ', wc_rev
=0),
1601 nope_2_path
: Item(status
='A ', wc_rev
=0)
1604 svntest
.actions
.run_and_verify_commit(wc_dir
,
1608 '-N', os
.path
.join(wc_dir
, dirA_path
))
1610 #----------------------------------------------------------------------
1611 # Regression for #1017: ra_neon was allowing the deletion of out-of-date
1612 # files or dirs, which majorly violates Subversion's semantics.
1615 def commit_out_of_date_deletions(sbox
):
1616 "commit deletion of out-of-date file or dir"
1619 wc_dir
= sbox
.wc_dir
1621 # Make a backup copy of the working copy
1622 wc_backup
= sbox
.add_wc_path('backup')
1623 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
1625 # Change omega's text, and make a propchange to A/C directory
1626 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
1627 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
1628 svntest
.main
.file_append(omega_path
, 'appended omega text')
1629 svntest
.main
.run_svn(None, 'propset', 'fooprop', 'foopropval', C_path
)
1631 # Commit revision 2.
1632 expected_output
= svntest
.wc
.State(wc_dir
, {
1633 'A/D/H/omega' : Item(verb
='Sending'),
1634 'A/C' : Item(verb
='Sending'),
1636 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1637 expected_status
.tweak('A/D/H/omega', 'A/C', wc_rev
=2, status
=' ')
1639 svntest
.actions
.run_and_verify_commit(wc_dir
,
1645 # Now, in the second working copy, schedule both omega and C for deletion.
1646 omega_path
= os
.path
.join(wc_backup
, 'A', 'D', 'H', 'omega')
1647 C_path
= os
.path
.join(wc_backup
, 'A', 'C')
1648 svntest
.main
.run_svn(None, 'rm', omega_path
, C_path
)
1650 # Attempt to delete omega. This should return an (expected)
1651 # out-of-dateness error.
1652 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'commit', '-m',
1654 for line
in errlines
:
1655 if re
.match(".*[Oo]ut.of.date.*", line
):
1658 raise svntest
.Failure
1660 # Attempt to delete directory C. This should return an (expected)
1661 # out-of-dateness error.
1662 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'commit', '-m',
1664 for line
in errlines
:
1665 if re
.match(".*[Oo]ut.of.date.*", line
):
1668 raise svntest
.Failure
1670 def commit_with_bad_log_message(sbox
):
1671 "commit with a log message containing bad data"
1674 wc_dir
= sbox
.wc_dir
1676 iota_path
= os
.path
.join(wc_dir
, 'iota')
1677 log_msg_path
= os
.path
.join(wc_dir
, 'log-message')
1679 # Make a random change, so there's something to commit.
1680 svntest
.main
.file_append(iota_path
, 'fish')
1682 # Create a log message containing a zero-byte.
1683 svntest
.main
.file_append(log_msg_path
, '\x00')
1685 # Commit and expect an error.
1686 svntest
.actions
.run_and_verify_commit(wc_dir
,
1688 "contains a zero byte",
1692 def from_wc_top_with_bad_editor(sbox
):
1693 "commit with invalid external editor cmd"
1695 # Shortly after revision 5407, Vladimir Prus posted this bug recipe:
1700 # svnadmin create repo
1701 # svn mkdir file:///tmp/repo/foo -m ""
1702 # svn co file:///tmp/repo/foo wc
1704 # svn ps svn:externals "lib http://something.org/lib" .
1707 # The final 'svn ci' would seg fault because of a problem in
1708 # calculating the paths to insert in the initial log message that
1709 # gets passed to the editor.
1711 # So this regression test is primarily about making sure the seg
1712 # fault is gone, and only secondarily about testing that we get the
1713 # expected error from passing a bad editor cmd to Subversion.
1716 wc_dir
= sbox
.wc_dir
1718 svntest
.actions
.run_and_verify_svn("Unexpected failure from propset.",
1719 svntest
.verify
.AnyOutput
, [],
1720 'pset', 'fish', 'food', wc_dir
)
1722 exit_code
, out
, err
= svntest
.actions
.run_and_verify_svn(
1723 "Commit succeeded when should have failed.",
1724 None, svntest
.verify
.AnyOutput
,
1725 'ci', '--editor-cmd', 'no_such-editor')
1727 err
= string
.join(map(string
.strip
, err
), ' ')
1728 if not (re
.match(".*no_such-editor.*", err
)
1729 and re
.match(".*Commit failed.*", err
)):
1730 print "Commit failed, but not in the way expected."
1731 raise svntest
.Failure
1734 def mods_in_schedule_delete(sbox
):
1735 "commit with mods in schedule delete"
1738 wc_dir
= sbox
.wc_dir
1740 # Schedule a delete, then put in local mods
1741 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
1742 svntest
.actions
.run_and_verify_svn(None, svntest
.verify
.AnyOutput
, [],
1744 foo_path
= os
.path
.join(C_path
, 'foo')
1745 foo_contents
= 'zig\nzag\n'
1746 svntest
.main
.file_append(foo_path
, foo_contents
)
1748 # Commit should succeed
1749 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1750 expected_status
.remove('A/C')
1751 expected_output
= svntest
.wc
.State(wc_dir
, {
1752 'A/C' : Item(verb
='Deleting'),
1754 svntest
.actions
.run_and_verify_commit(wc_dir
,
1755 expected_output
, expected_status
,
1758 # Unversioned file still exists
1759 actual_contents
= svntest
.main
.file_read(foo_path
)
1760 if actual_contents
!= foo_contents
:
1761 raise svntest
.Failure
1764 #----------------------------------------------------------------------
1771 wc_dir
= sbox
.wc_dir
1773 tab_file
= os
.path
.join(wc_dir
, 'A', "tab\tfile")
1774 tab_dir
= os
.path
.join(wc_dir
, 'A', "tab\tdir")
1775 source_url
= sbox
.repo_url
+ "/source_dir"
1776 tab_url
= sbox
.repo_url
+ "/tab%09dir"
1778 svntest
.main
.file_append(tab_file
, "This file has a tab in it.")
1781 def match_bad_tab_path(path
, errlines
):
1782 match_re
= ".*: Invalid control character '0x09' in path .*"
1783 for line
in errlines
:
1784 if re
.match (match_re
, line
):
1787 raise svntest
.Failure("Failed to find match_re in " + str(errlines
))
1790 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'add', tab_file
)
1791 match_bad_tab_path(tab_file
, errlines
)
1794 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'add', tab_dir
)
1795 match_bad_tab_path(tab_dir
, errlines
)
1798 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'mkdir',
1799 '-m', 'msg', tab_url
)
1800 match_bad_tab_path(tab_dir
, errlines
)
1803 svntest
.main
.run_svn(1,
1804 'mkdir', '-m', 'msg', source_url
)
1805 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'copy',
1807 source_url
, tab_url
)
1808 match_bad_tab_path(tab_dir
, errlines
)
1811 exit_code
, outlines
, errlines
= svntest
.main
.run_svn(1, 'mv', '-m', 'msg',
1812 source_url
, tab_url
)
1813 match_bad_tab_path(tab_dir
, errlines
)
1815 #----------------------------------------------------------------------
1817 def local_mods_are_not_commits(sbox
):
1818 "local ops should not be treated like commits"
1822 # Some commands can run on either a URL or a local path. These
1823 # commands take a log message, intended for the URL case.
1824 # Therefore, they should make sure that getting a log message for
1825 # a local operation errors (because not committing).
1827 # This is in commit_tests.py because the unifying theme is that
1828 # commits are *not* happening. And because there was no better
1829 # place to put it :-).
1832 wc_dir
= sbox
.wc_dir
1833 expected_error
= '.*Local, non-commit operations do not take a log message.*'
1836 svntest
.actions
.run_and_verify_svn(None, None, expected_error
,
1837 'cp', '-m', 'log msg',
1838 os
.path
.join(wc_dir
, 'iota'),
1839 os
.path
.join(wc_dir
, 'iota2'))
1842 svntest
.actions
.run_and_verify_svn(None, None, expected_error
,
1843 'cp', '-m', 'log msg',
1844 sbox
.repo_url
+ "/iota",
1845 os
.path
.join(wc_dir
, 'iota2'))
1848 svntest
.actions
.run_and_verify_svn(None, None, expected_error
,
1849 'rm', '-m', 'log msg',
1850 os
.path
.join(wc_dir
, 'A', 'D', 'gamma'))
1853 svntest
.actions
.run_and_verify_svn(None, None, expected_error
,
1854 'mkdir', '-m', 'log msg',
1855 os
.path
.join(wc_dir
, 'newdir'))
1858 svntest
.actions
.run_and_verify_svn(None, None, expected_error
,
1859 'cp', '-m', 'log msg',
1860 os
.path
.join(wc_dir
, 'A', 'mu'),
1861 os
.path
.join(wc_dir
, 'A', 'yu'))
1863 # Helper for hook tests: returns the "hook failed" line, with precise
1864 # wording that changed with Subversion 1.5.
1865 def hook_failure_message(hookname
):
1866 if svntest
.main
.server_minor_version
< 5:
1867 return "'%s' hook failed with error output:\n" % hookname
1869 if hookname
in ["start-commit", "pre-commit"]:
1871 elif hookname
== "pre-revprop-change":
1872 action
= "Revprop change"
1873 elif hookname
== "pre-lock":
1875 elif hookname
== "pre-unlock":
1880 message
= "%s hook failed (exit code 1)" % (hookname
,)
1882 message
= "%s blocked by %s hook (exit code 1)" % (action
, hookname
)
1883 return message
+ " with output:\n"
1886 #----------------------------------------------------------------------
1887 # Test if the post-commit error message is returned back to the svn
1888 # client and is displayed as a warning.
1890 def post_commit_hook_test(sbox
):
1891 "post commit hook failure case testing"
1895 # Get paths to the working copy and repository
1896 wc_dir
= sbox
.wc_dir
1897 repo_dir
= sbox
.repo_dir
1900 svntest
.actions
.create_failing_post_commit_hook(repo_dir
)
1902 # Modify iota just so there is something to commit.
1903 iota_path
= os
.path
.join(wc_dir
, "iota")
1904 svntest
.main
.file_append(iota_path
, "lakalakalakalaka")
1906 # Now, commit and examine the output (we happen to know that the
1907 # filesystem will report an absolute path because that's the way the
1908 # filesystem is created by this test suite.
1909 expected_output
= [ "Sending "+ iota_path
+ "\n",
1910 "Transmitting file data .\n",
1911 "Committed revision 2.\n",
1913 "Warning: " + hook_failure_message('post-commit'),
1914 "Post-commit hook failed\n",
1917 svntest
.actions
.run_and_verify_svn(None, expected_output
, [],
1918 'ci', '-m', 'log msg', iota_path
)
1920 #----------------------------------------------------------------------
1921 # Commit two targets non-recursively, but both targets should be the
1922 # same folder (in multiple variations). Test that svn handles this correctly.
1923 def commit_same_folder_in_targets(sbox
):
1924 "commit two targets, both the same folder"
1927 wc_dir
= sbox
.wc_dir
1929 iota_path
= os
.path
.join(wc_dir
, 'iota')
1931 svntest
.main
.file_append(iota_path
, "added extra line to file iota")
1933 # Create expected output tree.
1934 expected_output
= svntest
.wc
.State(wc_dir
, {
1935 'iota' : Item(verb
='Sending'),
1938 # Created expected status tree.
1939 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1940 expected_status
.tweak('iota', wc_rev
=2)
1942 # Commit the wc_dir and iota.
1943 svntest
.actions
.run_and_verify_commit(wc_dir
,
1951 #----------------------------------------------------------------------
1952 # test for issue 2459: verify that commit fails when a file with mixed
1953 # eol-styles is included, and show an error message which includes the
1955 def commit_inconsistent_eol(sbox
):
1956 "commit files with inconsistent eol should fail"
1959 wc_dir
= sbox
.wc_dir
1961 iota_path
= os
.path
.join(wc_dir
, 'iota')
1962 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1964 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', 'native', iota_path
)
1965 svntest
.main
.file_append_binary(iota_path
,
1966 "added extra line to file iota\012"
1967 "added extra line to file iota\015")
1968 svntest
.main
.file_append(mu_path
, "added extra line to file mu\n"
1969 "added extra line to file mu\n")
1971 expected_err
= ".*iota.*"
1973 svntest
.actions
.run_and_verify_svn(None, None, expected_err
,
1974 'commit', '-m', 'log message',
1978 def mkdir_with_revprop(sbox
):
1979 "set revision props during remote mkdir"
1982 remote_dir
= sbox
.repo_url
+ "/dir"
1984 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
1985 '--with-revprop', 'bug=42', remote_dir
)
1987 expected
= svntest
.verify
.UnorderedOutput(
1988 ['Unversioned properties on revision 2:\n',
1989 ' svn:author\n',' svn:date\n', ' svn:log\n',
1991 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
1992 '--revprop', '-r', 2, sbox
.repo_url
)
1993 svntest
.actions
.run_and_verify_svn(None, '42', [], 'propget', 'bug',
1994 '--revprop', '-r', 2, sbox
.repo_url
)
1997 def delete_with_revprop(sbox
):
1998 "set revision props during remote delete"
2001 remote_dir
= sbox
.repo_url
+ "/dir"
2002 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
2005 svntest
.actions
.run_and_verify_svn(None, None, [], 'delete', '-m', 'msg',
2006 '--with-revprop', 'bug=52', remote_dir
)
2008 expected
= svntest
.verify
.UnorderedOutput(
2009 ['Unversioned properties on revision 3:\n',
2010 ' svn:author\n',' svn:date\n', ' svn:log\n',
2012 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2013 '--revprop', '-r', 3, sbox
.repo_url
)
2014 svntest
.actions
.run_and_verify_svn(None, '52', [], 'propget', 'bug',
2015 '--revprop', '-r', 3, sbox
.repo_url
)
2018 def commit_with_revprop(sbox
):
2019 "set revision props during commit"
2022 wc_dir
= sbox
.wc_dir
2023 expected_status
= make_standard_slew_of_changes(wc_dir
)
2025 omega_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'omega')
2026 gloo_path
= os
.path
.join(wc_dir
, 'A', 'D', 'H', 'gloo')
2027 expected_output
= svntest
.wc
.State(wc_dir
, {
2028 'A/D/H/omega' : Item(verb
='Sending'),
2029 'A/D/H/gloo' : Item(verb
='Adding'),
2032 expected_status
.tweak('A/D/H/omega', wc_rev
=2, status
=' ')
2033 expected_status
.tweak('A/D/H/gloo', wc_rev
=2, status
=' ')
2035 svntest
.actions
.run_and_verify_commit(wc_dir
,
2040 '--with-revprop', 'bug=62',
2041 omega_path
, gloo_path
)
2043 expected
= svntest
.verify
.UnorderedOutput(
2044 ['Unversioned properties on revision 2:\n',
2045 ' svn:author\n',' svn:date\n', ' svn:log\n',
2047 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2048 '--revprop', '-r', 2, sbox
.repo_url
)
2049 svntest
.actions
.run_and_verify_svn(None, '62', [], 'propget', 'bug',
2050 '--revprop', '-r', 2, sbox
.repo_url
)
2053 def import_with_revprop(sbox
):
2054 "set revision props during import"
2057 local_dir
= os
.path
.join(sbox
.wc_dir
, 'folder')
2058 local_file
= os
.path
.join(sbox
.wc_dir
, 'folder', 'file')
2060 svntest
.main
.file_write(local_file
, "xxxx")
2062 svntest
.actions
.run_and_verify_svn(None, None, [], 'import', '-m', 'msg',
2063 '--with-revprop', 'bug=72', local_dir
,
2066 expected
= svntest
.verify
.UnorderedOutput(
2067 ['Unversioned properties on revision 2:\n',
2068 ' svn:author\n',' svn:date\n', ' svn:log\n',
2070 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2071 '--revprop', '-r', 2, sbox
.repo_url
)
2072 svntest
.actions
.run_and_verify_svn(None, '72', [], 'propget', 'bug',
2073 '--revprop', '-r', 2, sbox
.repo_url
)
2076 def copy_R2R_with_revprop(sbox
):
2077 "set revision props during repos-to-repos copy"
2080 remote_dir1
= sbox
.repo_url
+ "/dir1"
2081 remote_dir2
= sbox
.repo_url
+ "/dir2"
2082 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
2085 svntest
.actions
.run_and_verify_svn(None, None, [], 'copy', '-m', 'msg',
2086 '--with-revprop', 'bug=82', remote_dir1
,
2089 expected
= svntest
.verify
.UnorderedOutput(
2090 ['Unversioned properties on revision 3:\n',
2091 ' svn:author\n',' svn:date\n', ' svn:log\n',
2093 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2094 '--revprop', '-r', 3, sbox
.repo_url
)
2095 svntest
.actions
.run_and_verify_svn(None, '82', [], 'propget', 'bug',
2096 '--revprop', '-r', 3, sbox
.repo_url
)
2099 def copy_WC2R_with_revprop(sbox
):
2100 "set revision props during wc-to-repos copy"
2103 remote_dir
= sbox
.repo_url
+ "/dir"
2104 local_dir
= os
.path
.join(sbox
.wc_dir
, 'folder')
2105 svntest
.actions
.run_and_verify_svn(None, None, [],
2108 svntest
.actions
.run_and_verify_svn(None, None, [], 'copy', '-m', 'msg',
2109 '--with-revprop', 'bug=92', local_dir
,
2112 expected
= svntest
.verify
.UnorderedOutput(
2113 ['Unversioned properties on revision 2:\n',
2114 ' svn:author\n',' svn:date\n', ' svn:log\n',
2116 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2117 '--revprop', '-r', 2, sbox
.repo_url
)
2118 svntest
.actions
.run_and_verify_svn(None, '92', [], 'propget', 'bug',
2119 '--revprop', '-r', 2, sbox
.repo_url
)
2122 def move_R2R_with_revprop(sbox
):
2123 "set revision props during repos-to-repos move"
2126 remote_dir1
= sbox
.repo_url
+ "/dir1"
2127 remote_dir2
= sbox
.repo_url
+ "/dir2"
2128 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
2131 svntest
.actions
.run_and_verify_svn(None, None, [], 'move', '-m', 'msg',
2132 '--with-revprop', 'bug=102', remote_dir1
,
2135 expected
= svntest
.verify
.UnorderedOutput(
2136 ['Unversioned properties on revision 3:\n',
2137 ' svn:author\n',' svn:date\n', ' svn:log\n',
2139 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2140 '--revprop', '-r', 3, sbox
.repo_url
)
2141 svntest
.actions
.run_and_verify_svn(None, '102', [], 'propget', 'bug',
2142 '--revprop', '-r', 3, sbox
.repo_url
)
2145 def propedit_with_revprop(sbox
):
2146 "set revision props during remote property edit"
2149 svntest
.main
.use_editor('append_foo')
2151 svntest
.actions
.run_and_verify_svn(None, None, [], 'propedit', '-m', 'msg',
2152 '--with-revprop', 'bug=112', 'prop',
2155 expected
= svntest
.verify
.UnorderedOutput(
2156 ['Unversioned properties on revision 2:\n',
2157 ' svn:author\n',' svn:date\n', ' svn:log\n',
2159 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2160 '--revprop', '-r', 2, sbox
.repo_url
)
2161 svntest
.actions
.run_and_verify_svn(None, '112', [], 'propget', 'bug',
2162 '--revprop', '-r', 2, sbox
.repo_url
)
2165 def set_multiple_props_with_revprop(sbox
):
2166 "set multiple revision props during remote mkdir"
2169 remote_dir
= sbox
.repo_url
+ "/dir"
2171 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
2172 '--with-revprop', 'bug=32',
2173 '--with-revprop', 'ref=22', remote_dir
)
2175 expected
= svntest
.verify
.UnorderedOutput(
2176 ['Unversioned properties on revision 2:\n',
2177 ' svn:author\n',' svn:date\n', ' svn:log\n',
2178 ' bug\n', ' ref\n'])
2179 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2180 '--revprop', '-r', 2, sbox
.repo_url
)
2181 svntest
.actions
.run_and_verify_svn(None, '32', [], 'propget', 'bug',
2182 '--revprop', '-r', 2, sbox
.repo_url
)
2183 svntest
.actions
.run_and_verify_svn(None, '22', [], 'propget', 'ref',
2184 '--revprop', '-r', 2, sbox
.repo_url
)
2187 def use_empty_value_in_revprop_pair(sbox
):
2188 "set revprop without value ('') during remote mkdir"
2191 remote_dir
= sbox
.repo_url
+ "/dir"
2193 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
2194 '--with-revprop', 'bug=',
2195 '--with-revprop', 'ref=', remote_dir
)
2197 expected
= svntest
.verify
.UnorderedOutput(
2198 ['Unversioned properties on revision 2:\n',
2199 ' svn:author\n',' svn:date\n', ' svn:log\n',
2200 ' bug\n', ' ref\n'])
2201 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2202 '--revprop', '-r', 2, sbox
.repo_url
)
2203 svntest
.actions
.run_and_verify_svn(None, '', [], 'propget', 'bug',
2204 '--revprop', '-r', 2, sbox
.repo_url
)
2205 svntest
.actions
.run_and_verify_svn(None, '', [], 'propget', 'ref',
2206 '--revprop', '-r', 2, sbox
.repo_url
)
2209 def no_equals_in_revprop_pair(sbox
):
2210 "set revprop without '=' during remote mkdir"
2213 remote_dir
= sbox
.repo_url
+ "/dir"
2214 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', '-m', 'msg',
2215 '--with-revprop', 'bug',
2216 '--with-revprop', 'ref', remote_dir
)
2218 expected
= svntest
.verify
.UnorderedOutput(
2219 ['Unversioned properties on revision 2:\n',
2220 ' svn:author\n',' svn:date\n', ' svn:log\n',
2221 ' bug\n', ' ref\n'])
2222 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'proplist',
2223 '--revprop', '-r', 2, sbox
.repo_url
)
2224 svntest
.actions
.run_and_verify_svn(None, '', [], 'propget', 'bug',
2225 '--revprop', '-r', 2, sbox
.repo_url
)
2226 svntest
.actions
.run_and_verify_svn(None, '', [], 'propget', 'ref',
2227 '--revprop', '-r', 2, sbox
.repo_url
)
2230 def set_invalid_revprops(sbox
):
2231 "set invalid revision props during remote mkdir"
2234 remote_dir
= sbox
.repo_url
+ "/dir"
2235 # Try to set svn: revprops.
2236 expected
= '.*Standard properties can\'t.*'
2237 svntest
.actions
.run_and_verify_svn(None, [], expected
, 'mkdir', '-m', 'msg',
2238 '--with-revprop', 'svn:author=42', remote_dir
)
2239 svntest
.actions
.run_and_verify_svn(None, [], expected
, 'mkdir', '-m', 'msg',
2240 '--with-revprop', 'svn:log=42', remote_dir
)
2241 svntest
.actions
.run_and_verify_svn(None, [], expected
, 'mkdir', '-m', 'msg',
2242 '--with-revprop', 'svn:date=42', remote_dir
)
2243 svntest
.actions
.run_and_verify_svn(None, [], expected
, 'mkdir', '-m', 'msg',
2244 '--with-revprop', 'svn:foo=bar', remote_dir
)
2246 # Empty revprop pair.
2247 svntest
.actions
.run_and_verify_svn(None, [],
2248 'svn: Revision property pair is empty',
2249 'mkdir', '-m', 'msg',
2250 '--with-revprop', '',
2253 #----------------------------------------------------------------------
2255 def start_commit_hook_test(sbox
):
2256 "start-commit hook failure case testing"
2260 # Get paths to the working copy and repository
2261 wc_dir
= sbox
.wc_dir
2262 repo_dir
= sbox
.repo_dir
2264 # Create a hook that outputs a message to stderr and returns exit code 1
2265 hook_code
= """import sys
2266 sys.stderr.write("Start-commit hook failed")
2269 # Setup the hook configs to log data to a file
2270 start_commit_hook
= svntest
.main
.get_start_commit_hook_path(repo_dir
)
2271 svntest
.main
.create_python_hook_script(start_commit_hook
, hook_code
)
2273 # Modify iota just so there is something to commit.
2274 iota_path
= os
.path
.join(wc_dir
, "iota")
2275 svntest
.main
.file_append(iota_path
, "More stuff in iota")
2277 # Commit, expect error code 1
2278 exit_code
, actual_stdout
, actual_stderr
= svntest
.main
.run_svn(
2279 1, 'ci', '--quiet', '-m', 'log msg', wc_dir
)
2281 # No stdout expected
2282 svntest
.verify
.compare_and_display_lines('Start-commit hook test',
2283 'STDOUT', [], actual_stdout
)
2285 # Compare only the last two lines of stderr since the preceding ones
2286 # contain source code file and line numbers.
2287 if len(actual_stderr
) > 2:
2288 actual_stderr
= actual_stderr
[-2:]
2289 expected_stderr
= [ "svn: " + hook_failure_message('start-commit'),
2290 "Start-commit hook failed\n"
2292 svntest
.verify
.compare_and_display_lines('Start-commit hook test',
2294 expected_stderr
, actual_stderr
)
2296 #----------------------------------------------------------------------
2298 def pre_commit_hook_test(sbox
):
2299 "pre-commit hook failure case testing"
2303 # Get paths to the working copy and repository
2304 wc_dir
= sbox
.wc_dir
2305 repo_dir
= sbox
.repo_dir
2307 # Create a hook that outputs a message to stderr and returns exit code 1
2308 hook_code
= """import sys
2309 sys.stderr.write("Pre-commit hook failed")
2312 # Setup the hook configs to log data to a file
2313 pre_commit_hook
= svntest
.main
.get_pre_commit_hook_path(repo_dir
)
2314 svntest
.main
.create_python_hook_script(pre_commit_hook
, hook_code
)
2316 # Modify iota just so there is something to commit.
2317 iota_path
= os
.path
.join(wc_dir
, "iota")
2318 svntest
.main
.file_append(iota_path
, "More stuff in iota")
2320 # Commit, expect error code 1
2321 exit_code
, actual_stdout
, actual_stderr
= svntest
.main
.run_svn(
2322 1, 'ci', '--quiet', '-m', 'log msg', wc_dir
)
2324 # No stdout expected
2325 svntest
.verify
.compare_and_display_lines('Pre-commit hook test',
2326 'STDOUT', [], actual_stdout
)
2328 # Compare only the last two lines of stderr since the preceding ones
2329 # contain source code file and line numbers.
2330 if len(actual_stderr
) > 2:
2331 actual_stderr
= actual_stderr
[-2:]
2332 expected_stderr
= [ "svn: " + hook_failure_message('pre-commit'),
2333 "Pre-commit hook failed\n"
2335 svntest
.verify
.compare_and_display_lines('Pre-commit hook test',
2337 expected_stderr
, actual_stderr
)
2339 #----------------------------------------------------------------------
2341 def versioned_log_message(sbox
):
2342 "'svn commit -F foo' when foo is a versioned file"
2346 os
.chdir(sbox
.wc_dir
)
2348 iota_path
= os
.path
.join('iota')
2349 mu_path
= os
.path
.join('A', 'mu')
2350 log_path
= os
.path
.join('A', 'D', 'H', 'omega')
2352 svntest
.main
.file_append(iota_path
, "2")
2354 # try to check in a change using a versioned file as your log entry.
2355 svntest
.actions
.run_and_verify_svn(None, None, svntest
.verify
.AnyOutput
,
2356 'ci', '-F', log_path
)
2358 # force it. should not produce any errors.
2359 svntest
.actions
.run_and_verify_svn(None, None, [],
2360 'ci', '-F', log_path
, '--force-log')
2362 svntest
.main
.file_append(mu_path
, "2")
2364 # try the same thing, but specifying the file to commit explicitly.
2365 svntest
.actions
.run_and_verify_svn(None, None, svntest
.verify
.AnyOutput
,
2366 'ci', '-F', log_path
, mu_path
)
2368 # force it... should succeed.
2369 svntest
.actions
.run_and_verify_svn(None, None, [],
2372 '--force-log', mu_path
)
2374 #----------------------------------------------------------------------
2376 def changelist_near_conflict(sbox
):
2377 "'svn commit --changelist=foo' above a conflict"
2381 wc_dir
= sbox
.wc_dir
2382 iota_path
= os
.path
.join(wc_dir
, "iota")
2383 mu_path
= os
.path
.join(wc_dir
, "A", "mu")
2384 gloo_path
= os
.path
.join(wc_dir
, "A", "D", "H", "gloo")
2386 expected_status
= make_standard_slew_of_changes(wc_dir
)
2388 # Create a changelist.
2389 changelist_name
= "logical-changeset"
2390 svntest
.actions
.run_and_verify_svn(None, None, [],
2391 "changelist", changelist_name
,
2394 # Create a conflict (making r2 in the process).
2395 inject_conflict_into_wc(sbox
, 'iota', iota_path
,
2396 None, expected_status
, 2)
2398 # Commit the changelist.
2399 expected_output
= svntest
.wc
.State(wc_dir
, {
2400 "A/D/H/gloo" : Item(verb
='Adding'),
2402 expected_status
.tweak("A/D/H/gloo", wc_rev
=3, status
=" ")
2403 svntest
.actions
.run_and_verify_commit(wc_dir
,
2407 "--changelist=" + changelist_name
,
2408 "-m", "msg", wc_dir
)
2411 #----------------------------------------------------------------------
2413 def commit_out_of_date_file(sbox
):
2414 "try to commit a file that is out-of-date"
2417 wc_dir
= sbox
.wc_dir
2419 # Make a backup copy of the working copy
2420 wc_backup
= sbox
.add_wc_path('backup')
2421 svntest
.actions
.duplicate_dir(wc_dir
, wc_backup
)
2423 pi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'pi')
2424 backup_pi_path
= os
.path
.join(wc_backup
, 'A', 'D', 'G', 'pi')
2426 svntest
.main
.file_append(pi_path
, "new line\n")
2427 expected_output
= svntest
.wc
.State(wc_dir
, {
2428 "A/D/G/pi" : Item(verb
='Sending'),
2430 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2431 expected_status
.tweak("A/D/G/pi", wc_rev
=2, status
=" ")
2432 svntest
.actions
.run_and_verify_commit(wc_dir
,
2436 "-m", "log message", wc_dir
)
2438 svntest
.main
.file_append(backup_pi_path
, "hello")
2439 expected_err
= ".*(pi.*out of date|Out of date.*pi).*"
2440 svntest
.actions
.run_and_verify_svn(None, None, expected_err
,
2441 'commit', '-m', 'log message',
2444 def start_commit_detect_capabilities(sbox
):
2445 "start-commit hook sees client capabilities" # Issue #2991
2447 wc_dir
= sbox
.wc_dir
2448 repos_dir
= sbox
.repo_dir
2450 # Create a start-commit hook that detects the "mergeinfo" capability.
2451 hook_text
= "import sys\n" + \
2452 "fp = open(sys.argv[1] + '/hooks.log', 'w')\n" + \
2453 "caps = sys.argv[3].split(':')\n" + \
2454 "if 'mergeinfo' in caps:\n" + \
2455 " fp.write('yes')\n" + \
2457 " fp.write('no')\n" + \
2460 start_commit_hook
= svntest
.main
.get_start_commit_hook_path(repos_dir
)
2461 svntest
.main
.create_python_hook_script(start_commit_hook
, hook_text
)
2464 iota_path
= os
.path
.join(wc_dir
, "iota")
2465 svntest
.main
.file_append(iota_path
, "More stuff in iota")
2466 svntest
.actions
.run_and_verify_svn(None, [], [], 'ci', '--quiet',
2467 '-m', 'log msg', wc_dir
)
2469 # Check that "mergeinfo" was detected.
2470 log_path
= os
.path
.join(repos_dir
, "hooks.log")
2471 if os
.path
.exists(log_path
):
2472 data
= open(log_path
).read()
2475 raise svntest
.verify
.SVNUnexpectedOutput("'%s' not found") % log_path
2477 raise svntest
.Failure
2479 def commit_url(sbox
):
2480 "'svn commit SOME_URL' should error"
2482 wc_dir
= sbox
.wc_dir
2483 repos_url
= sbox
.repo_url
2485 # Commit directly to a URL
2486 svntest
.actions
.run_and_verify_commit(None,
2489 "Must give local path",
2493 ########################################################################
2496 # list all tests here, starting with None:
2499 commit_one_new_file
,
2500 commit_one_new_binary_file
,
2501 commit_multiple_targets
,
2502 commit_multiple_targets_2
,
2503 commit_inclusive_dir
,
2505 commit_unversioned_thing
,
2506 nested_dir_replacements
,
2508 hudson_part_1_variation_1
,
2509 hudson_part_1_variation_2
,
2513 merge_mixed_revisions
,
2515 commit_deleted_edited
,
2516 commit_in_dir_scheduled_for_addition
,
2517 commit_rmd_and_deleted_file
,
2518 commit_add_file_twice
,
2519 commit_from_long_dir
,
2523 commit_nonrecursive
,
2525 commit_out_of_date_deletions
,
2526 commit_with_bad_log_message
,
2527 from_wc_top_with_bad_editor
,
2528 mods_in_schedule_delete
,
2529 Skip(tab_test
, is_non_posix_os_or_cygwin_platform
),
2530 local_mods_are_not_commits
,
2531 post_commit_hook_test
,
2532 commit_same_folder_in_targets
,
2533 commit_inconsistent_eol
,
2534 SkipUnless(mkdir_with_revprop
, server_has_revprop_commit
),
2535 SkipUnless(delete_with_revprop
, server_has_revprop_commit
),
2536 SkipUnless(commit_with_revprop
, server_has_revprop_commit
),
2537 SkipUnless(import_with_revprop
, server_has_revprop_commit
),
2538 SkipUnless(copy_R2R_with_revprop
, server_has_revprop_commit
),
2539 SkipUnless(copy_WC2R_with_revprop
, server_has_revprop_commit
),
2540 SkipUnless(move_R2R_with_revprop
, server_has_revprop_commit
),
2541 SkipUnless(propedit_with_revprop
, server_has_revprop_commit
),
2542 SkipUnless(set_multiple_props_with_revprop
,
2543 server_has_revprop_commit
),
2544 SkipUnless(use_empty_value_in_revprop_pair
,
2545 server_has_revprop_commit
),
2546 SkipUnless(no_equals_in_revprop_pair
, server_has_revprop_commit
),
2547 SkipUnless(set_invalid_revprops
, server_has_revprop_commit
),
2548 start_commit_hook_test
,
2549 pre_commit_hook_test
,
2550 versioned_log_message
,
2551 changelist_near_conflict
,
2552 commit_out_of_date_file
,
2553 SkipUnless(start_commit_detect_capabilities
,
2554 server_gets_client_capabilities
),
2558 if __name__
== '__main__':
2559 svntest
.main
.run_tests(test_list
)