Add a little more to the svn_rangelist_intersect test to test the
[svn.git] / subversion / tests / cmdline / externals_tests.py
blobd09e088b25234a6e545bdf836bd604ed413ddd44
1 #!/usr/bin/env python
3 # module_tests.py: testing modules / external sources.
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 os
21 import warnings
23 # Our testing module
24 import svntest
26 # (abbreviation)
27 Skip = svntest.testcase.Skip
28 XFail = svntest.testcase.XFail
29 Item = svntest.wc.StateItem
32 ######################################################################
33 # Tests
35 # Each test must return on success or raise on failure.
38 #----------------------------------------------------------------------
40 ### todo: it's inefficient to keep calling externals_test_setup() for
41 ### every test. It's slow. But it's very safe -- we're guaranteed to
42 ### have a clean repository, built from the latest Subversion, with
43 ### the svn:externals properties preset in a known way. Right now I
44 ### can't think of any other way to achieve that guarantee, so the
45 ### result is that each individual test is slow.
47 def externals_test_setup(sbox):
48 """Set up a repository in which some directories have the externals property,
49 and set up another repository, referred to by some of those externals.
50 Both repositories contain greek trees with five revisions worth of
51 random changes, then in the sixth revision the first repository --
52 and only the first -- has some externals properties set. ### Later,
53 test putting externals on the second repository. ###
55 The arrangement of the externals in the first repository is:
57 /A/C/ ==> exdir_G <scheme>:///<other_repos>/A/D/G
58 ../../../<other_repos_basename>/A/D/H -r 1 exdir_H
60 /A/D/ ==> ^/../<other_repos_basename>/A exdir_A
61 //<other_repos>/A/D/G/ exdir_A/G/
62 exdir_A/H -r 1 <scheme>:///<other_repos>/A/D/H
63 /<some_paths>/A/B x/y/z/blah
65 A dictionary is returned keyed by the directory created by the
66 external whose value is the URL of the external.
67 """
69 # The test itself will create a working copy
70 sbox.build(create_wc = False)
72 svntest.main.safe_rmtree(sbox.wc_dir)
74 wc_init_dir = sbox.add_wc_path('init') # just for setting up props
75 repo_dir = sbox.repo_dir
76 repo_url = sbox.repo_url
77 other_repo_dir, other_repo_url = sbox.add_repo_path('other')
78 other_repo_basename = os.path.basename(other_repo_dir)
80 # Get a scheme relative URL to the other repository.
81 scheme_relative_other_repo_url = other_repo_url[other_repo_url.find(':')+1:]
83 # Get a server root relative URL to the other repository by trimming
84 # off the first three /'s.
85 server_relative_other_repo_url = other_repo_url
86 for i in range(3):
87 j = server_relative_other_repo_url.find('/') + 1
88 server_relative_other_repo_url = server_relative_other_repo_url[j:]
89 server_relative_other_repo_url = '/' + server_relative_other_repo_url
91 # These files will get changed in revisions 2 through 5.
92 mu_path = os.path.join(wc_init_dir, "A/mu")
93 pi_path = os.path.join(wc_init_dir, "A/D/G/pi")
94 lambda_path = os.path.join(wc_init_dir, "A/B/lambda")
95 omega_path = os.path.join(wc_init_dir, "A/D/H/omega")
97 # These are the directories on which `svn:externals' will be set, in
98 # revision 6 on the first repo.
99 C_path = os.path.join(wc_init_dir, "A/C")
100 D_path = os.path.join(wc_init_dir, "A/D")
102 # Create a working copy.
103 svntest.actions.run_and_verify_svn(None, None, [],
104 'checkout',
105 repo_url, wc_init_dir)
107 # Make revisions 2 through 5, but don't bother with pre- and
108 # post-commit status checks.
110 svntest.main.file_append(mu_path, "Added to mu in revision 2.\n")
111 svntest.actions.run_and_verify_svn(None, None, [],
112 'ci', '-m', 'log msg',
113 '--quiet', wc_init_dir)
115 svntest.main.file_append(pi_path, "Added to pi in revision 3.\n")
116 svntest.actions.run_and_verify_svn(None, None, [],
117 'ci', '-m', 'log msg',
118 '--quiet', wc_init_dir)
120 svntest.main.file_append(lambda_path, "Added to lambda in revision 4.\n")
121 svntest.actions.run_and_verify_svn(None, None, [],
122 'ci', '-m', 'log msg',
123 '--quiet', wc_init_dir)
125 svntest.main.file_append(omega_path, "Added to omega in revision 5.\n")
126 svntest.actions.run_and_verify_svn(None, None, [],
127 'ci', '-m', 'log msg',
128 '--quiet', wc_init_dir)
130 # Get the whole working copy to revision 5.
131 svntest.actions.run_and_verify_svn(None, None, [],
132 'up', wc_init_dir)
134 # Now copy the initial repository to create the "other" repository,
135 # the one to which the first repository's `svn:externals' properties
136 # will refer. After this, both repositories have five revisions
137 # of random stuff, with no svn:externals props set yet.
138 svntest.main.copy_repos(repo_dir, other_repo_dir, 5)
140 # This is the returned dictionary.
141 external_url_for = { }
143 external_url_for["A/C/exdir_G"] = other_repo_url + "/A/D/G"
144 external_url_for["A/C/exdir_H"] = "../../../" + \
145 other_repo_basename + \
146 "/A/D/H"
148 # Set up the externals properties on A/B/ and A/D/.
149 externals_desc = \
150 "exdir_G " + external_url_for["A/C/exdir_G"] + "\n" + \
151 external_url_for["A/C/exdir_H"] + " -r 1 exdir_H\n"
153 tmp_f = os.tempnam(wc_init_dir, 'tmp')
154 svntest.main.file_append(tmp_f, externals_desc)
155 svntest.actions.run_and_verify_svn(None, None, [],
156 'pset',
157 '-F', tmp_f, 'svn:externals', C_path)
159 os.remove(tmp_f)
161 external_url_for["A/D/exdir_A"] = "^/../" + other_repo_basename + "/A"
162 external_url_for["A/D/exdir_A/G/"] = scheme_relative_other_repo_url + \
163 "/A/D/G/"
164 external_url_for["A/D/exdir_A/H"] = other_repo_url + "/A/D/H"
165 external_url_for["A/D/x/y/z/blah"] = server_relative_other_repo_url + "/A/B"
167 externals_desc = \
168 external_url_for["A/D/exdir_A"] + " exdir_A" + \
169 "\n" + \
170 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G/" + \
171 "\n" + \
172 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
173 "\n" + \
174 external_url_for["A/D/x/y/z/blah"] + " x/y/z/blah" + \
175 "\n"
177 svntest.main.file_append(tmp_f, externals_desc)
178 svntest.actions.run_and_verify_svn(None, None, [], 'pset',
179 '-F', tmp_f, 'svn:externals', D_path)
181 os.remove(tmp_f)
183 # Commit the property changes.
185 expected_output = svntest.wc.State(wc_init_dir, {
186 'A/C' : Item(verb='Sending'),
187 'A/D' : Item(verb='Sending'),
190 expected_status = svntest.actions.get_virginal_state(wc_init_dir, 5)
191 expected_status.tweak('A/C', 'A/D', wc_rev=6, status=' ')
193 svntest.actions.run_and_verify_commit(wc_init_dir,
194 expected_output,
195 expected_status,
196 None, wc_init_dir)
198 return external_url_for
200 def change_external(path, new_val):
201 """Change the value of the externals property on PATH to NEW_VAL,
202 and commit the change."""
203 tmp_f = os.tempnam(svntest.main.temp_dir, 'tmp')
204 svntest.main.file_append(tmp_f, new_val)
205 svntest.actions.run_and_verify_svn(None, None, [], 'pset',
206 '-F', tmp_f, 'svn:externals', path)
207 svntest.actions.run_and_verify_svn(None, None, [], 'ci',
208 '-m', 'log msg', '--quiet', path)
209 os.remove(tmp_f)
212 def probe_paths_exist(paths):
213 """ Probe each one of PATHS to see if it exists, otherwise throw a
214 Failure exception. """
216 for path in paths:
217 if not os.path.exists(path):
218 raise svntest.Failure("Probing for " + path + " failed.")
221 def probe_paths_missing(paths):
222 """ Probe each one of PATHS to see if does not exist, otherwise throw a
223 Failure exception. """
225 for path in paths:
226 if os.path.exists(path):
227 raise svntest.Failure(path + " unexpectedly still exists.")
230 #----------------------------------------------------------------------
233 ### todo: It would be great if everything used the new wc.py system to
234 ### check output/status. In fact, it would be great to do more output
235 ### and status checking period! But must first see how well the
236 ### output checkers deal with multiple summary lines. With external
237 ### modules, you can get the first "Updated to revision X" line, and
238 ### then there will be more "Updated to..." and "Checked out..." lines
239 ### following it, one line for each new or changed external.
242 #----------------------------------------------------------------------
244 def checkout_with_externals(sbox):
245 "test checkouts with externals"
247 externals_test_setup(sbox)
249 wc_dir = sbox.wc_dir
250 repo_url = sbox.repo_url
252 # Create a working copy.
253 svntest.actions.run_and_verify_svn(None, None, [],
254 'checkout',
255 repo_url, wc_dir)
257 # Probe the working copy a bit, see if it's as expected.
258 expected_existing_paths = [
259 os.path.join(wc_dir, "A", "C", "exdir_G"),
260 os.path.join(wc_dir, "A", "C", "exdir_G", "pi"),
261 os.path.join(wc_dir, "A", "C", "exdir_H"),
262 os.path.join(wc_dir, "A", "C", "exdir_H", "omega"),
263 os.path.join(wc_dir, "A", "D", "x"),
264 os.path.join(wc_dir, "A", "D", "x", "y"),
265 os.path.join(wc_dir, "A", "D", "x", "y", "z"),
266 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah"),
267 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "alpha"),
268 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "beta"),
270 probe_paths_exist(expected_existing_paths)
272 # Pick a file at random, make sure it has the expected contents.
273 exdir_H_omega_path = os.path.join(wc_dir, "A", "C", "exdir_H", "omega")
274 fp = open(exdir_H_omega_path, 'r')
275 lines = fp.readlines()
276 if not ((len(lines) == 1) and (lines[0] == "This is the file 'omega'.\n")):
277 raise svntest.Failure("Unexpected contents for rev 1 of " +
278 exdir_H_omega_path)
280 #----------------------------------------------------------------------
282 def update_receive_new_external(sbox):
283 "update to receive a new external module"
285 external_url_for = externals_test_setup(sbox)
286 wc_dir = sbox.wc_dir
288 other_wc_dir = sbox.add_wc_path('other')
289 repo_url = sbox.repo_url
290 other_repo_url = repo_url + ".other"
292 # Checkout two working copies.
293 svntest.actions.run_and_verify_svn(None, None, [],
294 'checkout',
295 repo_url, wc_dir)
297 svntest.actions.run_and_verify_svn(None, None, [],
298 'checkout',
299 repo_url, other_wc_dir)
301 # Add one new external item to the property on A/D. The new item is
302 # "exdir_E", deliberately added in the middle not at the end.
303 new_externals_desc = \
304 external_url_for["A/D/exdir_A"] + " exdir_A" + \
305 "\n" + \
306 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G/" + \
307 "\n" + \
308 "exdir_E " + other_repo_url + "/A/B/E" + \
309 "\n" + \
310 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
311 "\n" + \
312 external_url_for["A/D/x/y/z/blah"] + " x/y/z/blah" + \
313 "\n"
315 # Set and commit the property
316 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
318 # Update the other working copy, see if we get the new item.
319 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
321 probe_paths_exist([os.path.join(other_wc_dir, "A", "D", "exdir_E")])
323 #----------------------------------------------------------------------
325 def update_lose_external(sbox):
326 "update to lose an external module"
328 external_url_for = externals_test_setup(sbox)
329 wc_dir = sbox.wc_dir
331 other_wc_dir = sbox.add_wc_path('other')
332 repo_url = sbox.repo_url
334 # Checkout two working copies.
335 svntest.actions.run_and_verify_svn(None, None, [],
336 'checkout',
337 repo_url, wc_dir)
339 svntest.actions.run_and_verify_svn(None, None, [],
340 'checkout',
341 repo_url, other_wc_dir)
343 # Lose one new external item from A/D. The lost item is
344 # "exdir_A", chosen because there are two other externals underneath
345 # it (G and H) which are not being removed. We expect them to
346 # remain -- in other words:
348 # BEFORE AFTER
349 # ------------ ------------
350 # A/D/exdir_A A/D/exdir_A
351 # A/D/exdir_A/.svn/... <GONE>
352 # A/D/exdir_A/mu <GONE>
353 # A/D/exdir_A/B/... <GONE>
354 # A/D/exdir_A/C/... <GONE>
355 # A/D/exdir_A/D/... <GONE>
356 # A/D/exdir_A/G/... A/D/exdir_A/G/...
357 # A/D/exdir_A/H/... A/D/exdir_A/H/...
359 new_externals_desc = \
360 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G" + \
361 "\n" + \
362 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
363 "\n" + \
364 external_url_for["A/D/x/y/z/blah"] + " x/y/z/blah" + \
365 "\n"
367 # Set and commit the property
368 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
370 # Update other working copy, see if lose & preserve things appropriately
371 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
373 expected_existing_paths = [
374 os.path.join(other_wc_dir, "A", "D", "exdir_A"),
375 os.path.join(other_wc_dir, "A", "D", "exdir_A", "G"),
376 os.path.join(other_wc_dir, "A", "D", "exdir_A", "H"),
378 probe_paths_exist(expected_existing_paths)
380 expected_missing_paths = [
381 os.path.join(other_wc_dir, "A", "D", "exdir_A", "mu"),
382 os.path.join(other_wc_dir, "A", "D", "exdir_A", "B"),
383 os.path.join(other_wc_dir, "A", "D", "exdir_A", "C"),
384 os.path.join(other_wc_dir, "A", "D", "exdir_A", "D"),
386 probe_paths_missing(expected_missing_paths)
388 #----------------------------------------------------------------------
390 def update_change_pristine_external(sbox):
391 "update change to an unmodified external module"
393 external_url_for = externals_test_setup(sbox)
394 wc_dir = sbox.wc_dir
396 other_wc_dir = sbox.add_wc_path('other')
397 repo_url = sbox.repo_url
398 other_repo_url = repo_url + ".other"
400 # Checkout two working copies.
401 svntest.actions.run_and_verify_svn(None, None, [],
402 'checkout',
403 repo_url, wc_dir)
405 svntest.actions.run_and_verify_svn(None, None, [],
406 'checkout',
407 repo_url, other_wc_dir)
409 # Change the "x/y/z/blah" external on A/D to point to a different
410 # URL. Since no changes were made to the old checked-out external,
411 # we should get a clean replace.
412 new_externals_desc = \
413 external_url_for["A/D/exdir_A"] + " exdir_A" + \
414 "\n" + \
415 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G" + \
416 "\n" + \
417 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
418 "\n" + \
419 "x/y/z/blah " + other_repo_url + "/A/B/F" + \
420 "\n"
422 # Set and commit the property
423 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
425 # Update other working copy, see if get the right change.
426 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
428 xyzb_path = os.path.join(other_wc_dir, "x", "y", "z", "blah")
430 expected_missing_paths = [
431 os.path.join(xyzb_path, "alpha"),
432 os.path.join(xyzb_path, "beta"),
434 probe_paths_missing(expected_missing_paths)
436 def update_change_modified_external(sbox):
437 "update changes to a modified external module"
439 external_url_for = externals_test_setup(sbox)
440 wc_dir = sbox.wc_dir
442 other_wc_dir = sbox.add_wc_path('other')
443 repo_url = sbox.repo_url
444 other_repo_url = repo_url + ".other"
446 # Checkout two working copies.
447 svntest.actions.run_and_verify_svn(None, None, [],
448 'checkout',
449 repo_url, wc_dir)
451 svntest.actions.run_and_verify_svn(None, None, [],
452 'checkout',
453 repo_url, other_wc_dir)
455 # Make a couple of mods in the "x/y/z/blah/" external.
456 alpha_path = os.path.join(other_wc_dir, "A", "D",
457 "x", "y", "z", "blah", "alpha")
458 svntest.main.file_append(alpha_path, "Some new text in alpha.\n")
459 new_file = os.path.join(other_wc_dir, "A", "D",
460 "x", "y", "z", "blah", "fish.txt")
461 svntest.main.file_append(new_file, "This is an unversioned file.\n")
463 # Change the "x/y/z/blah" external on A/D to point to a different
464 # URL. There are some local mods under the old checked-out external,
465 # so the old dir should be saved under a new name.
466 new_externals_desc = \
467 external_url_for["A/D/exdir_A"] + " exdir_A" + \
468 "\n" + \
469 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G/" + \
470 "\n" + \
471 "exdir_A/H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
472 "\n" + \
473 "x/y/z/blah " + other_repo_url + "/A/B/F" + \
474 "\n"
476 # Set and commit the property
477 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
479 # Update other working copy, see if get the right change.
480 svntest.actions.run_and_verify_svn(None, None, [], 'up', other_wc_dir)
482 xyzb_path = os.path.join(other_wc_dir, "x", "y", "z", "blah")
484 expected_missing_paths = [
485 os.path.join(xyzb_path, "alpha"),
486 os.path.join(xyzb_path, "beta"),
488 probe_paths_missing(expected_missing_paths)
490 def update_receive_change_under_external(sbox):
491 "update changes under an external module"
493 externals_test_setup(sbox)
494 wc_dir = sbox.wc_dir
496 other_wc_dir = sbox.add_wc_path('other')
497 repo_url = sbox.repo_url
498 other_repo_url = repo_url + ".other"
500 # Checkout two working copies.
501 svntest.actions.run_and_verify_svn(None, None, [],
502 'checkout',
503 repo_url, wc_dir)
505 svntest.actions.run_and_verify_svn(None, None, [],
506 'checkout',
507 other_repo_url, other_wc_dir)
509 # Commit some modifications from the other_wc.
510 other_gamma_path = os.path.join(other_wc_dir, 'A', 'D', 'gamma')
511 svntest.main.file_append(other_gamma_path, "New text in other gamma.\n")
513 expected_output = svntest.wc.State(other_wc_dir, {
514 'A/D/gamma' : Item(verb='Sending'),
516 expected_status = svntest.actions.get_virginal_state(other_wc_dir, 5)
517 expected_status.tweak('A/D/gamma', wc_rev=6)
518 svntest.actions.run_and_verify_commit(other_wc_dir,
519 expected_output,
520 expected_status,
521 None, other_wc_dir)
523 # Now update the regular wc to see if we get the change. Note that
524 # none of the module *properties* in this wc have been changed; only
525 # the source repository of the modules has received a change, and
526 # we're verifying that an update here pulls that change.
528 # The output's going to be all screwy because of the module
529 # notifications, so don't bother parsing it, just run update
530 # directly.
531 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
533 external_gamma_path = os.path.join(wc_dir, 'A', 'D', 'exdir_A', 'D', 'gamma')
534 fp = open(external_gamma_path, 'r')
535 lines = fp.readlines()
536 if not ((len(lines) == 2)
537 and (lines[0] == "This is the file 'gamma'.\n")
538 and (lines[1] == "New text in other gamma.\n")):
539 raise svntest.Failure("Unexpected contents for externally modified " +
540 external_gamma_path)
541 fp.close()
543 # Commit more modifications
544 other_rho_path = os.path.join(other_wc_dir, 'A', 'D', 'G', 'rho')
545 svntest.main.file_append(other_rho_path, "New text in other rho.\n")
547 expected_output = svntest.wc.State(other_wc_dir, {
548 'A/D/G/rho' : Item(verb='Sending'),
550 expected_status = svntest.actions.get_virginal_state(other_wc_dir, 5)
551 expected_status.tweak('A/D/gamma', wc_rev=6)
552 expected_status.tweak('A/D/G/rho', wc_rev=7)
553 svntest.actions.run_and_verify_commit(other_wc_dir,
554 expected_output,
555 expected_status,
556 None, other_wc_dir)
558 svntest.actions.run_and_verify_svn(None, None, [],
559 'up', os.path.join(wc_dir, "A", "C"))
561 external_rho_path = os.path.join(wc_dir, 'A', 'C', 'exdir_G', 'rho')
562 fp = open(external_rho_path, 'r')
563 lines = fp.readlines()
564 if not ((len(lines) == 2)
565 and (lines[0] == "This is the file 'rho'.\n")
566 and (lines[1] == "New text in other rho.\n")):
567 raise svntest.Failure("Unexpected contents for externally modified " +
568 external_rho_path)
569 fp.close()
571 #----------------------------------------------------------------------
573 def modify_and_update_receive_new_external(sbox):
574 "commit and update additional externals"
576 external_url_for = externals_test_setup(sbox)
577 wc_dir = sbox.wc_dir
578 repo_url = sbox.repo_url
580 # Checkout a working copy
581 svntest.actions.run_and_verify_svn(None, None, [],
582 'checkout',
583 repo_url, wc_dir)
585 # Add one more external item
586 B_path = os.path.join(wc_dir, "A/B")
587 externals_desc = \
588 external_url_for["A/D/exdir_A/G/"] + " exdir_G" + \
589 "\n" + \
590 "exdir_H -r 1 " + external_url_for["A/D/exdir_A/H"] + \
591 "\n" + \
592 "exdir_Z " + external_url_for["A/D/exdir_A/H"] + \
593 "\n"
595 tmp_f = os.tempnam()
596 svntest.main.file_append(tmp_f, externals_desc)
597 svntest.actions.run_and_verify_svn(None, None, [],
598 'pset', '-F', tmp_f,
599 'svn:externals', B_path)
600 os.remove(tmp_f)
602 # Now cd into A/B and try updating
603 was_cwd = os.getcwd()
604 os.chdir(B_path)
606 # Once upon a time there was a core-dump here
608 svntest.actions.run_and_verify_svn("update failed",
609 svntest.verify.AnyOutput, [], 'up' )
611 os.chdir(was_cwd)
613 probe_paths_exist([os.path.join(B_path, "exdir_Z")])
615 #----------------------------------------------------------------------
617 def disallow_dot_or_dotdot_directory_reference(sbox):
618 "error if external target dir involves '.' or '..'"
620 external_url_for = externals_test_setup(sbox)
621 wc_dir = sbox.wc_dir
623 # Try to set illegal externals in the original WC.
624 def set_externals_for_path_expect_error(path, val):
625 tmp_f = os.tempnam()
626 svntest.main.file_append(tmp_f, val)
627 svntest.actions.run_and_verify_svn(None, None, svntest.verify.AnyOutput,
628 'pset', '-F', tmp_f,
629 'svn:externals', path)
630 os.remove(tmp_f)
632 B_path = os.path.join(wc_dir, 'A', 'B')
633 G_path = os.path.join(wc_dir, 'A', 'D', 'G')
634 H_path = os.path.join(wc_dir, 'A', 'D', 'H')
635 C_path = os.path.join(wc_dir, 'A', 'C')
636 F_path = os.path.join(wc_dir, 'A', 'C', 'F')
638 external_urls = external_url_for.values()
640 externals_value_1 = "../foo" + " " + external_urls.pop() + "\n"
641 if not external_urls: external_urls = external_url_for.values()
642 externals_value_2 = "foo/bar/../baz" + " " + external_urls.pop() + "\n"
643 if not external_urls: external_urls = external_url_for.values()
644 externals_value_3 = "foo/.." + " " + external_urls.pop() + "\n"
645 if not external_urls: external_urls = external_url_for.values()
646 externals_value_4 = "." + " " + external_urls.pop() + "\n"
647 if not external_urls: external_urls = external_url_for.values()
648 externals_value_5 = "./" + " " + external_urls.pop() + "\n"
649 if not external_urls: external_urls = external_url_for.values()
650 externals_value_6 = ".." + " " + external_urls.pop() + "\n"
651 if not external_urls: external_urls = external_url_for.values()
652 externals_value_7 = "././/.///." + " " + external_urls.pop() + "\n"
653 if not external_urls: external_urls = external_url_for.values()
654 externals_value_8 = "/foo" + " " + external_urls.pop() + "\n"
655 if not external_urls: external_urls = external_url_for.values()
657 set_externals_for_path_expect_error(B_path, externals_value_1)
658 set_externals_for_path_expect_error(G_path, externals_value_2)
659 set_externals_for_path_expect_error(H_path, externals_value_3)
660 set_externals_for_path_expect_error(C_path, externals_value_4)
661 set_externals_for_path_expect_error(F_path, externals_value_5)
662 set_externals_for_path_expect_error(B_path, externals_value_6)
663 set_externals_for_path_expect_error(G_path, externals_value_7)
664 set_externals_for_path_expect_error(H_path, externals_value_8)
667 #----------------------------------------------------------------------
669 def export_with_externals(sbox):
670 "test exports with externals"
672 externals_test_setup(sbox)
674 wc_dir = sbox.wc_dir
675 repo_url = sbox.repo_url
677 # Create a working copy.
678 svntest.actions.run_and_verify_svn(None, None, [],
679 'export',
680 repo_url, wc_dir)
682 # Probe the working copy a bit, see if it's as expected.
683 expected_existing_paths = [
684 os.path.join(wc_dir, "A", "C", "exdir_G"),
685 os.path.join(wc_dir, "A", "C", "exdir_G", "pi"),
686 os.path.join(wc_dir, "A", "C", "exdir_H"),
687 os.path.join(wc_dir, "A", "C", "exdir_H", "omega"),
688 os.path.join(wc_dir, "A", "D", "x"),
689 os.path.join(wc_dir, "A", "D", "x", "y"),
690 os.path.join(wc_dir, "A", "D", "x", "y", "z"),
691 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah"),
692 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "alpha"),
693 os.path.join(wc_dir, "A", "D", "x", "y", "z", "blah", "E", "beta"),
695 probe_paths_exist(expected_existing_paths)
697 # Pick some files, make sure their contents are as expected.
698 exdir_G_pi_path = os.path.join(wc_dir, "A", "C", "exdir_G", "pi")
699 fp = open(exdir_G_pi_path, 'r')
700 lines = fp.readlines()
701 if not ((len(lines) == 2) \
702 and (lines[0] == "This is the file 'pi'.\n") \
703 and (lines[1] == "Added to pi in revision 3.\n")):
704 raise svntest.Failure("Unexpected contents for rev 1 of " +
705 exdir_G_pi_path)
707 exdir_H_omega_path = os.path.join(wc_dir, "A", "C", "exdir_H", "omega")
708 fp = open(exdir_H_omega_path, 'r')
709 lines = fp.readlines()
710 if not ((len(lines) == 1) and (lines[0] == "This is the file 'omega'.\n")):
711 raise svntest.Failure("Unexpected contents for rev 1 of " +
712 exdir_H_omega_path)
714 #----------------------------------------------------------------------
716 # Test for issue #2429
717 def export_wc_with_externals(sbox):
718 "test exports from working copies with externals"
720 externals_test_setup(sbox)
722 wc_dir = sbox.wc_dir
723 repo_url = sbox.repo_url
724 export_target = sbox.add_wc_path('export')
726 # Create a working copy.
727 svntest.actions.run_and_verify_svn(None, None, [],
728 'checkout',
729 repo_url, wc_dir)
730 # Export the working copy.
731 svntest.actions.run_and_verify_svn(None, None, [],
732 'export', wc_dir, export_target)
734 paths = [
735 os.path.join(export_target, "A", "C", "exdir_G"),
736 os.path.join(export_target, "A", "C", "exdir_G", "pi"),
737 os.path.join(export_target, "A", "C", "exdir_H"),
738 os.path.join(export_target, "A", "C", "exdir_H", "omega"),
739 os.path.join(export_target, "A", "D", "x"),
740 os.path.join(export_target, "A", "D", "x", "y"),
741 os.path.join(export_target, "A", "D", "x", "y", "z"),
742 os.path.join(export_target, "A", "D", "x", "y", "z", "blah"),
743 os.path.join(export_target, "A", "D", "x", "y", "z", "blah", "E", "alpha"),
744 os.path.join(export_target, "A", "D", "x", "y", "z", "blah", "E", "beta"),
746 probe_paths_exist(paths)
748 svntest.main.safe_rmtree(export_target)
750 # Export it again, without externals.
751 svntest.actions.run_and_verify_svn(None, None, [],
752 'export', '--ignore-externals',
753 wc_dir, export_target)
754 probe_paths_missing(paths)
756 #----------------------------------------------------------------------
758 def external_with_peg_and_op_revision(sbox):
759 "use a peg revision to specify an external module"
761 external_url_for = externals_test_setup(sbox)
762 wc_dir = sbox.wc_dir
763 repo_url = sbox.repo_url
765 # Checkout a working copy.
766 svntest.actions.run_and_verify_svn(None, None, [],
767 'checkout',
768 repo_url, wc_dir)
770 # remove A/D/H in the other repo
771 svntest.actions.run_and_verify_svn(None, None, [],
772 'rm',
773 external_url_for["A/D/exdir_A/H"],
774 '-m', 'remove original A/D/H')
776 # Set an external property using peg revision syntax.
777 new_externals_desc = \
778 external_url_for["A/D/exdir_A/H"] + "@4 exdir_A/H" + \
779 "\n" + \
780 external_url_for["A/D/exdir_A/G/"] + " exdir_A/G" + \
781 "\n"
783 # Set and commit the property.
784 change_external(os.path.join(wc_dir, "A/D"), new_externals_desc)
786 # Update other working copy, see if we get the right change.
787 svntest.actions.run_and_verify_svn(None, None, [],
788 'up', wc_dir)
790 external_chi_path = os.path.join(wc_dir, 'A', 'D', 'exdir_A', 'H', 'chi')
791 fp = open(external_chi_path, 'r')
792 lines = fp.readlines()
793 if not ((len(lines) == 1)
794 and (lines[0] == "This is the file 'chi'.\n")):
795 raise svntest.Failure("Unexpected contents for externally modified " +
796 external_chi_path)
797 fp.close()
799 #----------------------------------------------------------------------
801 def new_style_externals(sbox):
802 "check the new '-rN URL PATH' syntax"
804 external_url_for = externals_test_setup(sbox)
805 wc_dir = sbox.wc_dir
806 repo_url = sbox.repo_url
808 # Checkout a working copy.
809 svntest.actions.run_and_verify_svn(None, None, [],
810 'checkout',
811 repo_url, wc_dir)
813 # Set an external property using the new '-rN URL PATH' syntax.
814 new_externals_desc = \
815 external_url_for["A/C/exdir_G"] + " exdir_G" + \
816 "\n" + \
817 "-r 1 " + external_url_for["A/C/exdir_H"] + " exdir_H" + \
818 "\n" + \
819 "-r1 " + external_url_for["A/C/exdir_H"] + " exdir_I" + \
820 "\n"
822 # Set and commit the property.
823 change_external(os.path.join(wc_dir, "A/C"), new_externals_desc)
825 # Update other working copy.
826 svntest.actions.run_and_verify_svn(None, None, [],
827 'up', wc_dir)
829 for dir_name in ["exdir_H", "exdir_I"]:
830 exdir_X_omega_path = os.path.join(wc_dir, "A", "C", dir_name, "omega")
831 fp = open(exdir_X_omega_path, 'r')
832 lines = fp.readlines()
833 if not ((len(lines) == 1) and (lines[0] == "This is the file 'omega'.\n")):
834 raise svntest.Failure("Unexpected contents for rev 1 of " +
835 exdir_X_omega_path)
837 #----------------------------------------------------------------------
839 def disallow_propset_invalid_formatted_externals(sbox):
840 "error if propset'ing external with invalid format"
842 # Bootstrap
843 sbox.build()
844 wc_dir = sbox.wc_dir
846 A_path = os.path.join(wc_dir, 'A')
848 expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
849 svntest.actions.run_and_verify_status(wc_dir, expected_status)
851 # It should not be possible to set these external properties on a
852 # directory.
853 for ext in [ 'arg1',
854 'arg1 arg2 arg3',
855 'arg1 arg2 arg3 arg4',
856 'arg1 arg2 arg3 arg4 arg5',
857 '-r',
858 '-r1',
859 '-r 1',
860 '-r1 arg1',
861 '-r 1 arg1',
862 'arg1 -r',
863 'arg1 -r1',
864 'arg1 -r 1',
866 tmp_f = os.tempnam()
867 svntest.main.file_append(tmp_f, ext)
868 svntest.actions.run_and_verify_svn("No error for externals '%s'" % ext,
869 None,
870 '.*Error parsing svn:externals.*',
871 'propset',
872 '-F',
873 tmp_f,
874 'svn:externals',
875 A_path)
876 os.remove(tmp_f)
878 for ext in [ '-r abc arg1 arg2',
879 '-rabc arg1 arg2',
880 'arg1 -r abc arg2',
881 'arg1 -rabc arg2',
883 tmp_f = os.tempnam()
884 svntest.main.file_append(tmp_f, ext)
885 svntest.actions.run_and_verify_svn("No error for externals '%s'" % ext,
886 None,
887 '.*Invalid revision number found.*',
888 'propset',
889 '-F',
890 tmp_f,
891 'svn:externals',
892 A_path)
893 os.remove(tmp_f)
895 #----------------------------------------------------------------------
897 def old_style_externals_ignore_peg_reg(sbox):
898 "old 'PATH URL' format should ignore peg revisions"
900 external_url_for = externals_test_setup(sbox)
901 wc_dir = sbox.wc_dir
902 repo_url = sbox.repo_url
904 # Checkout a working copy.
905 svntest.actions.run_and_verify_svn(None, None, [],
906 'checkout',
907 repo_url, wc_dir)
909 # Update the working copy.
910 svntest.actions.run_and_verify_svn(None, None, [],
911 'up', wc_dir)
913 # Set an external property using the old 'PATH URL' syntax with
914 # @HEAD in the URL.
915 ext = "exdir_G " + external_url_for["A/C/exdir_G"] + "@HEAD\n"
917 # Set and commit the property.
918 change_external(os.path.join(wc_dir, "A"), ext)
920 # Update the working copy. This should fail because the URL with
921 # '@HEAD' does not exist.
922 svntest.actions.run_and_verify_svn("External '%s' used pegs" % ext.strip(),
923 None,
924 ".*URL '.*/A/D/G@HEAD' doesn't exist",
925 'up',
926 wc_dir)
929 ########################################################################
930 # Run the tests
933 # list all tests here, starting with None:
934 test_list = [ None,
935 checkout_with_externals,
936 update_receive_new_external,
937 update_lose_external,
938 update_change_pristine_external,
939 update_change_modified_external,
940 update_receive_change_under_external,
941 modify_and_update_receive_new_external,
942 disallow_dot_or_dotdot_directory_reference,
943 export_with_externals,
944 export_wc_with_externals,
945 external_with_peg_and_op_revision,
946 new_style_externals,
947 disallow_propset_invalid_formatted_externals,
948 old_style_externals_ignore_peg_reg
951 if __name__ == '__main__':
952 warnings.filterwarnings('ignore', 'tempnam', RuntimeWarning)
953 svntest.main.run_tests(test_list)
954 # NOTREACHED
957 ### End of file.