Fix compiler warning due to missing function prototype.
[svn.git] / subversion / tests / cmdline / special_tests.py
blob6e6d891ad930e52dfc4383967e1651fd2227f6fb
1 #!/usr/bin/env python
3 # special_tests.py: testing special and reserved file handling
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 ######################################################################
19 # General modules
20 import sys, os, re
22 # Our testing module
23 import svntest
25 from svntest.main import server_has_mergeinfo
27 # (abbreviation)
28 Skip = svntest.testcase.Skip
29 SkipUnless = svntest.testcase.SkipUnless
30 XFail = svntest.testcase.XFail
31 Item = svntest.wc.StateItem
34 ######################################################################
35 # Tests
37 # Each test must return on success or raise on failure.
40 #----------------------------------------------------------------------
42 def general_symlink(sbox):
43 "general symlink handling"
45 sbox.build()
46 wc_dir = sbox.wc_dir
48 # First try to just commit a symlink
49 newfile_path = os.path.join(wc_dir, 'newfile')
50 linktarget_path = os.path.join(wc_dir, 'linktarget')
51 svntest.main.file_append(linktarget_path, 'this is just a link target')
52 os.symlink('linktarget', newfile_path)
53 svntest.main.run_svn(None, 'add', newfile_path, linktarget_path)
55 expected_output = svntest.wc.State(wc_dir, {
56 'newfile' : Item(verb='Adding'),
57 'linktarget' : Item(verb='Adding'),
60 # Run a diff and verify that we get the correct output
61 exit_code, stdout_lines, stderr_lines = svntest.main.run_svn(1, 'diff',
62 wc_dir)
64 regex = '^\+link linktarget'
65 for line in stdout_lines:
66 if re.match(regex, line):
67 break
68 else:
69 raise svntest.Failure
71 # Commit and make sure everything is good
72 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
73 expected_status.add({
74 'newfile' : Item(status=' ', wc_rev=2),
75 'linktarget' : Item(status=' ', wc_rev=2),
78 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
79 expected_status, None,
80 wc_dir)
82 ## Now we should update to the previous version, verify that no
83 ## symlink is present, then update back to HEAD and see if the symlink
84 ## is regenerated properly.
85 svntest.actions.run_and_verify_svn(None, None, [],
86 'up', '-r', '1', wc_dir)
88 # Is the symlink gone?
89 if os.path.isfile(newfile_path) or os.path.islink(newfile_path):
90 raise svntest.Failure
92 svntest.actions.run_and_verify_svn(None, None, [],
93 'up', '-r', '2', wc_dir)
95 # Is the symlink back?
96 new_target = os.readlink(newfile_path)
97 if new_target != 'linktarget':
98 raise svntest.Failure
100 ## Now change the target of the symlink, verify that it is shown as
101 ## modified and that a commit succeeds.
102 os.remove(newfile_path)
103 os.symlink('A', newfile_path)
105 was_cwd = os.getcwd()
106 os.chdir(wc_dir)
107 svntest.actions.run_and_verify_svn(None, [ "M newfile\n" ], [], 'st')
109 os.chdir(was_cwd)
111 expected_output = svntest.wc.State(wc_dir, {
112 'newfile' : Item(verb='Sending'),
115 expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
116 expected_status.add({
117 'newfile' : Item(status=' ', wc_rev=3),
118 'linktarget' : Item(status=' ', wc_rev=2),
121 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
122 expected_status, None, wc_dir)
125 def replace_file_with_symlink(sbox):
126 "replace a normal file with a special file"
128 sbox.build()
129 wc_dir = sbox.wc_dir
131 # First replace a normal file with a symlink and make sure we get an
132 # error
133 iota_path = os.path.join(wc_dir, 'iota')
134 os.remove(iota_path)
135 os.symlink('A', iota_path)
137 # Does status show the obstruction?
138 was_cwd = os.getcwd()
139 os.chdir(wc_dir)
140 svntest.actions.run_and_verify_svn(None, [ "~ iota\n" ], [], 'st')
142 # And does a commit fail?
143 os.chdir(was_cwd)
144 exit_code, stdout_lines, stderr_lines = svntest.main.run_svn(1, 'ci', '-m',
145 'log msg',
146 wc_dir)
148 regex = 'svn: Commit failed'
149 for line in stderr_lines:
150 if re.match(regex, line):
151 break
152 else:
153 raise svntest.Failure
156 def import_export_symlink(sbox):
157 "import and export a symlink"
159 sbox.build()
160 wc_dir = sbox.wc_dir
162 # create a new symlink to import
163 new_path = os.path.join(wc_dir, 'new_file')
165 os.symlink('linktarget', new_path)
167 # import this symlink into the repository
168 url = sbox.repo_url + "/dirA/dirB/new_link"
169 exit_code, output, errput = svntest.actions.run_and_verify_svn(
170 'Import a symlink', None, [], 'import',
171 '-m', 'log msg', new_path, url)
173 regex = "(Committed|Imported) revision [0-9]+."
174 for line in output:
175 if re.match(regex, line):
176 break
177 else:
178 raise svntest.Failure
180 # remove the unversioned link
181 os.remove(new_path)
183 # run update and verify that the symlink is put back into place
184 svntest.actions.run_and_verify_svn(None, None, [],
185 'up', wc_dir)
187 # Is the symlink back?
188 link_path = wc_dir + "/dirA/dirB/new_link"
189 new_target = os.readlink(link_path)
190 if new_target != 'linktarget':
191 raise svntest.Failure
193 ## Now we will try exporting from both the working copy and the
194 ## repository directly, verifying that the symlink is created in
195 ## both cases.
197 for export_src, dest_dir in [(sbox.wc_dir, 'export-wc'),
198 (sbox.repo_url, 'export-url')]:
199 export_target = sbox.add_wc_path(dest_dir)
200 svntest.actions.run_and_verify_svn(None, None, [],
201 'export', export_src, export_target)
203 # is the link at the correct place?
204 link_path = os.path.join(export_target, "dirA/dirB/new_link")
205 new_target = os.readlink(link_path)
206 if new_target != 'linktarget':
207 raise svntest.Failure
210 #----------------------------------------------------------------------
211 # Regression test for issue 1986
213 def copy_tree_with_symlink(sbox):
214 "'svn cp dir1 dir2' which contains a symlink"
216 sbox.build()
217 wc_dir = sbox.wc_dir
219 # Create a versioned symlink within directory 'A/D/H'.
220 newfile_path = os.path.join(wc_dir, 'A', 'D', 'H', 'newfile')
221 linktarget_path = os.path.join(wc_dir, 'A', 'D', 'H', 'linktarget')
222 svntest.main.file_append(linktarget_path, 'this is just a link target')
223 os.symlink('linktarget', newfile_path)
224 svntest.main.run_svn(None, 'add', newfile_path, linktarget_path)
226 expected_output = svntest.wc.State(wc_dir, {
227 'A/D/H/newfile' : Item(verb='Adding'),
228 'A/D/H/linktarget' : Item(verb='Adding'),
231 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
232 expected_status.add({
233 'A/D/H/newfile' : Item(status=' ', wc_rev=2),
234 'A/D/H/linktarget' : Item(status=' ', wc_rev=2),
237 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
238 expected_status, None, wc_dir)
239 # Copy H to H2
240 H_path = os.path.join(wc_dir, 'A', 'D', 'H')
241 H2_path = os.path.join(wc_dir, 'A', 'D', 'H2')
242 svntest.actions.run_and_verify_svn(None, None, [], 'cp', H_path, H2_path)
244 # 'svn status' should show just "A/D/H2 A +". Nothing broken.
245 expected_status.add({
246 'A/D/H2' : Item(status='A ', copied='+', wc_rev='-'),
247 'A/D/H2/chi' : Item(status=' ', copied='+', wc_rev='-'),
248 'A/D/H2/omega' : Item(status=' ', copied='+', wc_rev='-'),
249 'A/D/H2/psi' : Item(status=' ', copied='+', wc_rev='-'),
250 'A/D/H2/linktarget' : Item(status=' ', copied='+', wc_rev='-'),
251 'A/D/H2/newfile' : Item(status=' ', copied='+', wc_rev='-'),
253 svntest.actions.run_and_verify_status(wc_dir, expected_status)
256 def replace_symlink_with_file(sbox):
257 "replace a special file with a non-special file"
259 sbox.build()
260 wc_dir = sbox.wc_dir
262 # Create a new special file and commit it.
263 newfile_path = os.path.join(wc_dir, 'newfile')
264 linktarget_path = os.path.join(wc_dir, 'linktarget')
265 svntest.main.file_append(linktarget_path, 'this is just a link target')
266 os.symlink('linktarget', newfile_path)
267 svntest.main.run_svn(None, 'add', newfile_path, linktarget_path)
269 expected_output = svntest.wc.State(wc_dir, {
270 'newfile' : Item(verb='Adding'),
271 'linktarget' : Item(verb='Adding'),
274 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
275 expected_status.add({
276 'newfile' : Item(status=' ', wc_rev=2),
277 'linktarget' : Item(status=' ', wc_rev=2),
280 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
281 expected_status, None, wc_dir)
284 # Now replace the symlink with a normal file and try to commit, we
285 # should get an error
286 os.remove(newfile_path);
287 svntest.main.file_append(newfile_path, "text of actual file");
289 # Does status show the obstruction?
290 was_cwd = os.getcwd()
291 os.chdir(wc_dir)
292 svntest.actions.run_and_verify_svn(None, [ "~ newfile\n" ], [], 'st')
294 # And does a commit fail?
295 os.chdir(was_cwd)
296 exit_code, stdout_lines, stderr_lines = svntest.main.run_svn(1, 'ci', '-m',
297 'log msg',
298 wc_dir)
300 regex = 'svn: Commit failed'
301 for line in stderr_lines:
302 if re.match(regex, line):
303 break
304 else:
305 raise svntest.Failure
308 def remove_symlink(sbox):
309 "remove a symlink"
311 sbox.build()
312 wc_dir = sbox.wc_dir
314 # Commit a symlink
315 newfile_path = os.path.join(wc_dir, 'newfile')
316 linktarget_path = os.path.join(wc_dir, 'linktarget')
317 svntest.main.file_append(linktarget_path, 'this is just a link target')
318 os.symlink('linktarget', newfile_path)
319 svntest.main.run_svn(None, 'add', newfile_path, linktarget_path)
321 expected_output = svntest.wc.State(wc_dir, {
322 'newfile' : Item(verb='Adding'),
323 'linktarget' : Item(verb='Adding'),
326 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
327 expected_status.add({
328 'newfile' : Item(status=' ', wc_rev=2),
329 'linktarget' : Item(status=' ', wc_rev=2),
332 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
333 expected_status, None, wc_dir)
335 # Now remove it
336 svntest.actions.run_and_verify_svn(None, None, [], 'rm', newfile_path)
338 # Commit and verify that it worked
339 expected_output = svntest.wc.State(wc_dir, {
340 'newfile' : Item(verb='Deleting'),
343 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
344 expected_status.add({
345 'linktarget' : Item(status=' ', wc_rev=2),
348 svntest.actions.run_and_verify_commit(wc_dir, expected_output,
349 expected_status, None, wc_dir)
351 def merge_symlink_into_file(sbox):
352 "merge symlink into file"
354 sbox.build()
355 wc_dir = sbox.wc_dir
356 d_url = sbox.repo_url + '/A/D'
357 dprime_url = sbox.repo_url + '/A/Dprime'
359 gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma')
360 gamma_prime_path = os.path.join(wc_dir, 'A', 'Dprime', 'gamma')
362 # create a copy of the D directory to play with
363 svntest.main.run_svn(None,
364 'copy', d_url, dprime_url, '-m', 'copy')
365 svntest.main.run_svn(None,
366 'update', sbox.wc_dir)
368 # remove A/Dprime/gamma
369 svntest.main.run_svn(None, 'delete', gamma_prime_path)
371 expected_output = svntest.wc.State(wc_dir, {
372 'A/Dprime/gamma' : Item(verb='Deleting'),
375 svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None,
376 wc_dir)
378 # Commit a symlink in its place
379 linktarget_path = os.path.join(wc_dir, 'linktarget')
380 svntest.main.file_append(linktarget_path, 'this is just a link target')
381 os.symlink('linktarget', gamma_prime_path)
382 svntest.main.run_svn(None, 'add', gamma_prime_path)
384 expected_output = svntest.wc.State(wc_dir, {
385 'A/Dprime/gamma' : Item(verb='Adding'),
388 svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None,
389 wc_dir)
391 # merge the creation of the symlink into the original directory
392 svntest.main.run_svn(None,
393 'merge', '-r', '2:4', dprime_url,
394 os.path.join(wc_dir, 'A', 'D'))
396 # now revert, and we'll get a strange error
397 svntest.main.run_svn(None, 'revert', '-R', wc_dir)
399 # assuming we got past the revert because someone fixed that bug, lets
400 # try the merge and a commit, since that apparently used to throw us for
401 # a loop, see issue 2530
402 svntest.main.run_svn(None,
403 'merge', '-r', '2:4', dprime_url,
404 os.path.join(wc_dir, 'A', 'D'))
406 expected_output = svntest.wc.State(wc_dir, {
407 'A/D' : Item(verb='Sending'),
408 'A/D/gamma' : Item(verb='Replacing'),
411 svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None,
412 wc_dir)
416 def merge_file_into_symlink(sbox):
417 "merge file into symlink"
419 sbox.build()
420 wc_dir = sbox.wc_dir
421 d_url = sbox.repo_url + '/A/D'
422 dprime_url = sbox.repo_url + '/A/Dprime'
424 gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma')
425 gamma_prime_path = os.path.join(wc_dir, 'A', 'Dprime', 'gamma')
427 # create a copy of the D directory to play with
428 svntest.main.run_svn(None,
429 'copy', d_url, dprime_url, '-m', 'copy')
430 svntest.main.run_svn(None,
431 'update', sbox.wc_dir)
433 # remove A/Dprime/gamma
434 svntest.main.run_svn(None, 'delete', gamma_prime_path)
436 expected_output = svntest.wc.State(wc_dir, {
437 'A/Dprime/gamma' : Item(verb='Deleting'),
440 svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None,
441 wc_dir)
443 # Commit a symlink in its place
444 linktarget_path = os.path.join(wc_dir, 'linktarget')
445 svntest.main.file_append(linktarget_path, 'this is just a link target')
446 os.symlink('linktarget', gamma_prime_path)
447 svntest.main.run_svn(None, 'add', gamma_prime_path)
449 expected_output = svntest.wc.State(wc_dir, {
450 'A/Dprime/gamma' : Item(verb='Adding'),
453 svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None,
454 wc_dir)
456 svntest.main.file_write(gamma_path, 'changed file', 'w+')
458 expected_output = svntest.wc.State(wc_dir, {
459 'A/D/gamma' : Item(verb='Sending'),
462 svntest.actions.run_and_verify_commit(wc_dir, expected_output, None, None,
463 wc_dir)
465 # ok, now merge the change to the file into the symlink we created, this
466 # gives us a weird error
467 svntest.main.run_svn(None,
468 'merge', '-r', '4:5', d_url,
469 os.path.join(wc_dir, 'A', 'Dprime'))
471 # Issue 2701: Tests to see repository with symlinks can be checked out on all
472 # platforms.
473 def checkout_repo_with_symlinks(sbox):
474 "checkout a repository containing symlinks"
476 svntest.actions.load_repo(sbox, os.path.join(os.path.dirname(sys.argv[0]),
477 'special_tests_data',
478 'symlink.dump'))
480 expected_output = svntest.wc.State(sbox.wc_dir, {
481 'from': Item(status='A '),
482 'to': Item(status='A '),
485 if svntest.main.is_os_windows():
486 expected_link_contents = 'link to'
487 else:
488 expected_link_contents = ''
490 expected_wc = svntest.wc.State('', {
491 'from' : Item(contents=expected_link_contents),
492 'to' : Item(contents=''),
494 svntest.actions.run_and_verify_checkout(sbox.repo_url,
495 sbox.wc_dir,
496 expected_output,
497 expected_wc)
499 # Issue 2716: 'svn diff' against a symlink to a directory within the wc
500 def diff_symlink_to_dir(sbox):
501 "diff a symlink to a directory"
503 sbox.build(read_only = True)
504 wc_dir = sbox.wc_dir
506 # Create a symlink to A/D/.
507 d_path = os.path.join('A', 'D')
508 link_path = os.path.join(wc_dir, 'link')
509 os.symlink(d_path, link_path)
511 # Add the symlink.
512 svntest.main.run_svn(None, 'add', link_path)
514 # Now diff the wc itself and check the results.
515 expected_output = [
516 "Index: svn-test-work/working_copies/special_tests-10/link\n",
517 "===================================================================\n",
518 "--- svn-test-work/working_copies/special_tests-10/link\t(revision 0)\n",
519 "+++ svn-test-work/working_copies/special_tests-10/link\t(revision 0)\n",
520 "@@ -0,0 +1 @@\n",
521 "+link " + d_path + "\n",
522 "\ No newline at end of file\n",
523 "\n",
524 "Property changes on: svn-test-work/working_copies/special_tests-10/link\n",
525 "___________________________________________________________________\n",
526 "Added: svn:special\n",
527 " + *\n",
528 "\n" ]
529 svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
530 wc_dir)
531 # We should get the same output if we the diff the symlink itself.
532 svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
533 link_path)
535 # Issue 2692 (part of): Check that the client can check out a repository
536 # that contains an unknown special file type.
537 def checkout_repo_with_unknown_special_type(sbox):
538 "checkout repository with unknown special file type"
540 svntest.actions.load_repo(sbox, os.path.join(os.path.dirname(sys.argv[0]),
541 'special_tests_data',
542 'bad-special-type.dump'))
544 expected_output = svntest.wc.State(sbox.wc_dir, {
545 'special': Item(status='A '),
547 expected_wc = svntest.wc.State('', {
548 'special' : Item(contents='gimble wabe'),
550 svntest.actions.run_and_verify_checkout(sbox.repo_url,
551 sbox.wc_dir,
552 expected_output,
553 expected_wc)
555 def replace_symlink_with_dir(sbox):
556 "replace a special file with a directory"
558 svntest.actions.load_repo(sbox, os.path.join(os.path.dirname(sys.argv[0]),
559 'special_tests_data',
560 'symlink.dump'))
562 wc_dir = sbox.wc_dir
563 from_path = os.path.join(wc_dir, 'from')
565 # Now replace the symlink with a directory and try to commit, we
566 # should get an error
567 os.remove(from_path);
568 os.mkdir(from_path);
570 # Does status show the obstruction?
571 was_cwd = os.getcwd()
572 os.chdir(wc_dir)
573 svntest.actions.run_and_verify_svn(None, [ "~ from\n" ], [], 'st')
575 # The commit shouldn't do anything.
576 # I'd expect a failed commit here, but replacing a file locally with a
577 # directory seems to make svn think the file is unchanged.
578 os.chdir(was_cwd)
579 exit_code, stdout_lines, stderr_lines = svntest.main.run_svn(1, 'ci', '-m',
580 'log msg',
581 wc_dir)
582 if not (stdout_lines == [] or stderr_lines == []):
583 raise svntest.Failure
585 # test for issue #1808: svn up deletes local symlink that obstructs
586 # versioned file
587 def update_obstructing_symlink(sbox):
588 "symlink obstructs incoming delete"
590 sbox.build()
591 wc_dir = sbox.wc_dir
592 mu_path = os.path.join(wc_dir, 'A', 'mu')
593 mu_url = sbox.repo_url + '/A/mu'
594 iota_path = os.path.join(wc_dir, 'iota')
596 # delete A/mu and replace it with a symlink
597 svntest.main.run_svn(None, 'rm', mu_path)
598 os.symlink(iota_path, mu_path)
600 svntest.main.run_svn(None, 'rm', mu_url,
601 '-m', 'log msg')
603 svntest.main.run_svn(None,
604 'up', wc_dir)
606 # check that the symlink is still there
607 target = os.readlink(mu_path)
608 if target != iota_path:
609 raise svntest.Failure
612 def warn_on_reserved_name(sbox):
613 "warn when attempt operation on a reserved name"
614 sbox.build()
615 wc_dir = sbox.wc_dir
616 if os.path.exists(os.path.join(wc_dir, ".svn")):
617 reserved_path = os.path.join(wc_dir, ".svn")
618 elif os.path.exists(os.path.join(wc_dir, "_svn")):
619 reserved_path = os.path.join(wc_dir, "_svn")
620 else:
621 # We don't know how to test this, but have no reason to believe
622 # it would fail. (TODO: any way to return 'Skip', though?)
623 return
624 svntest.actions.run_and_verify_svn(
625 "Locking a file with a reserved name failed to result in an error",
626 None,
627 ".*Skipping argument: '.+' ends in a reserved name.*",
628 'lock', reserved_path)
631 ########################################################################
632 # Run the tests
635 # list all tests here, starting with None:
636 test_list = [ None,
637 SkipUnless(general_symlink, svntest.main.is_posix_os),
638 SkipUnless(replace_file_with_symlink, svntest.main.is_posix_os),
639 SkipUnless(import_export_symlink, svntest.main.is_posix_os),
640 SkipUnless(copy_tree_with_symlink, svntest.main.is_posix_os),
641 SkipUnless(replace_symlink_with_file, svntest.main.is_posix_os),
642 SkipUnless(remove_symlink, svntest.main.is_posix_os),
643 SkipUnless(SkipUnless(merge_symlink_into_file,
644 svntest.main.is_posix_os),
645 server_has_mergeinfo),
646 SkipUnless(merge_file_into_symlink, svntest.main.is_posix_os),
647 checkout_repo_with_symlinks,
648 XFail(SkipUnless(diff_symlink_to_dir, svntest.main.is_posix_os)),
649 checkout_repo_with_unknown_special_type,
650 replace_symlink_with_dir,
651 SkipUnless(update_obstructing_symlink, svntest.main.is_posix_os),
652 warn_on_reserved_name,
655 if __name__ == '__main__':
656 svntest.main.run_tests(test_list)
657 # NOTREACHED
660 ### End of file.