3
# svnsync_tests.py: Tests SVNSync's repository mirroring capabilities.
5
# Subversion is a tool for revision control.
6
# See http://subversion.tigris.org for more information.
8
# ====================================================================
9
# Copyright (c) 2005, 2006 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, re, os.path
25
from authz_tests import write_restrictive_svnserve_conf, \
26
skip_test_when_no_authz_available
29
Skip = svntest.testcase.Skip
30
XFail = svntest.testcase.XFail
31
Item = svntest.wc.StateItem
34
######################################################################
38
def build_repos(sbox):
39
"""Avoid the use sbox.build() because we're working with a repos
40
other than the Greek tree."""
41
# Cleanup after the last run by removing any left-over repository.
42
svntest.main.safe_rmtree(sbox.repo_dir)
44
# Create an empty repository.
45
svntest.main.create_repos(sbox.repo_dir)
46
svntest.main.set_repos_paths(sbox.repo_dir)
49
def run_sync(url, expected_error=None):
50
"Synchronize the mirror repository with the master"
51
output, errput = svntest.main.run_svnsync(
53
"--username", svntest.main.wc_author,
54
"--password", svntest.main.wc_passwd)
56
if expected_error is None:
57
raise svntest.actions.SVNUnexpectedStderr(errput)
59
svntest.actions.match_or_fail(None, "STDERR", expected_error, errput)
60
elif expected_error is not None:
61
raise svntest.actions.SVNExpectedStderr()
62
if not output and not expected_error:
63
# should be: ['Committed revision 1.\n', 'Committed revision 2.\n']
64
raise svntest.actions.SVNUnexpectedStdout("Missing stdout")
66
def run_init(dst_url, src_url):
67
"Initialize the mirror repository from the master"
68
output, errput = svntest.main.run_svnsync(
69
"initialize", dst_url, src_url,
70
"--username", svntest.main.wc_author,
71
"--password", svntest.main.wc_passwd)
72
if output != ['Copied properties for revision 0.\n']:
73
raise svntest.actions.SVNUnexpectedStdout(output)
75
raise svntest.actions.SVNUnexpectedStderr(errput)
78
def run_test(sbox, dump_file_name):
79
"Load a dump file, sync repositories, and compare contents."
81
# Create the empty master repository.
84
# This directory contains all the dump files
85
svnsync_tests_dir = os.path.join(os.path.dirname(sys.argv[0]),
87
# Load the specified dump file into the master repository.
88
master_dumpfile_contents = file(os.path.join(svnsync_tests_dir,
89
dump_file_name)).readlines()
90
svntest.actions.run_and_verify_load(sbox.repo_dir, master_dumpfile_contents)
92
# Create the empty destination repository.
93
dest_sbox = sbox.clone_dependent()
94
build_repos(dest_sbox)
96
# Setup the mirror repository. Feed it the UUID of the source repository.
97
output, errput = svntest.main.run_svnlook("uuid", sbox.repo_dir)
98
mirror_cfg = ["SVN-fs-dump-format-version: 2\n",
101
svntest.actions.run_and_verify_load(dest_sbox.repo_dir, mirror_cfg)
103
# Create the revprop-change hook for this test
104
svntest.actions.enable_revprop_changes(svntest.main.current_repo_dir)
106
run_init(dest_sbox.repo_url, sbox.repo_url)
108
run_sync(dest_sbox.repo_url)
110
# Remove some SVNSync-specific housekeeping properties from the
111
# mirror repository in preparation for the comparison dump.
112
for prop_name in ("svn:sync-from-url", "svn:sync-from-uuid",
113
"svn:sync-last-merged-rev"):
114
svntest.actions.run_and_verify_svn(
115
None, None, [], "propdel", "--username", svntest.main.wc_author,
116
"--password", svntest.main.wc_passwd, "--revprop", "-r", "0",
117
prop_name, dest_sbox.repo_url)
119
# Create a dump file from the mirror repository.
120
dest_dump = svntest.actions.run_and_verify_dump(dest_sbox.repo_dir)
122
# Compare the original dump file (used to create the master
123
# repository) with the dump produced by the mirror repository.
124
svntest.actions.compare_and_display_lines(
125
"Dump files", "DUMP", master_dumpfile_contents, dest_dump)
128
######################################################################
131
#----------------------------------------------------------------------
133
def copy_and_modify(sbox):
135
run_test(sbox, "copy-and-modify.dump")
137
#----------------------------------------------------------------------
139
def copy_from_previous_version_and_modify(sbox):
140
"copy from previous version and modify"
141
run_test(sbox, "copy-from-previous-version-and-modify.dump")
143
#----------------------------------------------------------------------
145
def copy_from_previous_version(sbox):
146
"copy from previous version"
147
run_test(sbox, "copy-from-previous-version.dump")
149
#----------------------------------------------------------------------
151
def modified_in_place(sbox):
153
run_test(sbox, "modified-in-place.dump")
155
#----------------------------------------------------------------------
157
def tag_empty_trunk(sbox):
159
run_test(sbox, "tag-empty-trunk.dump")
161
#----------------------------------------------------------------------
163
def tag_trunk_with_dir(sbox):
164
"tag trunk containing a sub-directory"
165
run_test(sbox, "tag-trunk-with-dir.dump")
167
#----------------------------------------------------------------------
169
def tag_trunk_with_file(sbox):
170
"tag trunk containing a file"
171
run_test(sbox, "tag-trunk-with-file.dump")
173
#----------------------------------------------------------------------
175
def tag_trunk_with_file2(sbox):
176
"tag trunk containing a file (#2)"
177
run_test(sbox, "tag-trunk-with-file2.dump")
179
#----------------------------------------------------------------------
181
def tag_with_modified_file(sbox):
182
"tag with a modified file"
183
run_test(sbox, "tag-with-modified-file.dump")
185
#----------------------------------------------------------------------
187
def dir_prop_change(sbox):
188
"directory property changes"
189
run_test(sbox, "dir_prop_change.dump")
191
#----------------------------------------------------------------------
193
def file_dir_file(sbox):
194
"files and dirs mixed together"
195
run_test(sbox, "file-dir-file.dump")
197
#----------------------------------------------------------------------
199
def copy_parent_modify_prop(sbox):
200
"copy parent and modify prop"
201
run_test(sbox, "copy-parent-modify-prop.dump")
203
#----------------------------------------------------------------------
205
def detect_meddling(sbox):
206
"detect non-svnsync commits in destination"
208
sbox.build("svnsync-meddling")
210
dest_sbox = sbox.clone_dependent()
211
build_repos(dest_sbox)
213
# Make our own destination checkout (have to do it ourself because
216
svntest.main.safe_rmtree(dest_sbox.wc_dir)
217
svntest.actions.run_and_verify_svn(None,
224
svntest.actions.enable_revprop_changes(svntest.main.current_repo_dir)
226
run_init(dest_sbox.repo_url, sbox.repo_url)
227
run_sync(dest_sbox.repo_url)
229
svntest.actions.run_and_verify_svn(None,
234
svntest.main.wc_author,
236
svntest.main.wc_passwd,
239
# Commit some change to the destination, which should be detected by svnsync
240
svntest.main.file_append(os.path.join(dest_sbox.wc_dir, 'A', 'B', 'lambda'),
242
svntest.actions.run_and_verify_svn(None,
248
svntest.main.wc_author,
250
svntest.main.wc_passwd,
253
run_sync(dest_sbox.repo_url,
254
".*Destination HEAD \\(2\\) is not the last merged revision \\(1\\).*")
256
#----------------------------------------------------------------------
258
def basic_authz(sbox):
259
"verify that unreadable content is not synced"
261
skip_test_when_no_authz_available()
263
sbox.build("svnsync-basic-authz")
265
write_restrictive_svnserve_conf(svntest.main.current_repo_dir)
267
dest_sbox = sbox.clone_dependent()
268
build_repos(dest_sbox)
270
svntest.actions.enable_revprop_changes(svntest.main.current_repo_dir)
272
run_init(dest_sbox.repo_url, sbox.repo_url)
274
fp = open(sbox.authz_file, 'w')
275
fp.write("[svnsync-basic-authz:/]\n" +
278
"[svnsync-basic-authz:/A/B]\n" +
281
"[svnsync-basic-authz-1:/]\n" +
285
run_sync(dest_sbox.repo_url)
287
lambda_url = dest_sbox.repo_url + '/A/B/lambda'
289
# this file should have been blocked by authz
290
svntest.actions.run_and_verify_svn(None,
292
svntest.SVNAnyOutput,
294
'--username', svntest.main.wc_author,
295
'--password', svntest.main.wc_passwd,
298
#----------------------------------------------------------------------
300
def copy_from_unreadable_dir(sbox):
301
"verify that copies from unreadable dirs work"
303
skip_test_when_no_authz_available()
305
sbox.build("svnsync-copy-from-unreadable-dir")
307
B_url = sbox.repo_url + '/A/B'
308
P_url = sbox.repo_url + '/A/P'
310
# Set a property on the directory we're going to copy, and a file in it, to
311
# confirm that they're transmitted when we later sync the copied directory
312
svntest.actions.run_and_verify_svn(None,
318
sbox.wc_dir + '/A/B/lambda')
320
svntest.actions.run_and_verify_svn(None,
326
sbox.wc_dir + '/A/B')
328
svntest.actions.run_and_verify_svn(None,
332
sbox.wc_dir + '/A/B',
335
# Now copy that directory so we'll see it in our synced copy
336
svntest.actions.run_and_verify_svn(None,
342
'--username', svntest.main.wc_author,
343
'--password', svntest.main.wc_passwd,
346
write_restrictive_svnserve_conf(svntest.main.current_repo_dir)
348
dest_sbox = sbox.clone_dependent()
349
build_repos(dest_sbox)
351
svntest.actions.enable_revprop_changes(svntest.main.current_repo_dir)
353
fp = open(sbox.authz_file, 'w')
355
# For mod_dav_svn's parent path setup we need per-repos permissions in
357
if sbox.repo_url.startswith('http'):
358
fp.write("[svnsync-copy-from-unreadable-dir:/]\n" +
361
"[svnsync-copy-from-unreadable-dir:/A/B]\n" +
364
"[svnsync-copy-from-unreadable-dir-1:/]\n" +
367
# Otherwise we can just go with the permissions needed for the source
377
run_init(dest_sbox.repo_url, sbox.repo_url)
379
run_sync(dest_sbox.repo_url)
381
lambda_url = dest_sbox.repo_url + '/A/B/lambda'
395
out, err = svntest.main.run_svn(None,
397
'--username', svntest.main.wc_author,
398
'--password', svntest.main.wc_passwd,
404
raise svntest.actions.SVNUnexpectedStderr(err)
406
svntest.actions.compare_and_display_lines(None,
411
svntest.actions.run_and_verify_svn(None,
416
dest_sbox.repo_url + '/A/P/lambda')
418
svntest.actions.run_and_verify_svn(None,
423
dest_sbox.repo_url + '/A/P')
425
def url_encoding(sbox):
426
"test url encoding issues"
427
run_test(sbox, "url-encoding-bug.dump")
430
# A test for copying revisions that lack a property that already exists
431
# on the destination rev as part of the commit (i.e. svn:author in this
432
# case, but svn:date would also work).
434
"test copying revs with no svn:author revprops"
435
run_test(sbox, "no-author.dump")
438
########################################################################
442
# list all tests here, starting with None:
445
copy_from_previous_version_and_modify,
446
copy_from_previous_version,
450
tag_trunk_with_file2,
452
tag_with_modified_file,
455
copy_parent_modify_prop,
458
copy_from_unreadable_dir,
463
if __name__ == '__main__':
464
svntest.main.run_tests(test_list)