2092
2227
run_and_verify_svn(None, verify.AnyOutput, [], 'update', wc_dir)
2095
def make_deep_trees(base):
2096
"""Helper function for deep trees conflicts. Create a set of trees,
2097
each in its own "container" dir. Any conflicts can be tested separately
2101
# Create the container dirs.
2106
DDF = j(base, 'DDF')
2107
DDD = j(base, 'DDD')
2109
os.makedirs(j(D, 'D1'))
2110
os.makedirs(j(DF, 'D1'))
2111
os.makedirs(j(DD, 'D1', 'D2'))
2112
os.makedirs(j(DDF, 'D1', 'D2'))
2113
os.makedirs(j(DDD, 'D1', 'D2', 'D3'))
2115
# Create their files.
2116
alpha = j(F, 'alpha')
2117
beta = j(DF, 'D1', 'beta')
2118
gamma = j(DDF, 'D1', 'D2', 'gamma')
2119
main.file_append(alpha, "This is the file 'alpha'.\n")
2120
main.file_append(beta, "This is the file 'beta'.\n")
2121
main.file_append(gamma, "This is the file 'gamma'.\n")
2124
def add_deep_trees(sbox, base_dir_name):
2125
"""Prepare a "deep_trees" within a given directory.
2127
The directory <sbox.wc_dir>/<base_dir_name> is created and a deep_tree
2128
is created within. The items are only added, a commit has to be
2129
called separately, if needed.
2131
<base_dir_name> will thus be a container for the set of containers
2132
mentioned in make_deep_trees().
2135
base = j(sbox.wc_dir, base_dir_name)
2136
make_deep_trees(base)
2137
main.run_svn(None, 'add', base)
2142
# initial deep trees state
2143
deep_trees_virginal_state = wc.State('', {
2145
'F/alpha' : Item("This is the file 'alpha'.\n"),
2150
'DF/D1/beta' : Item("This is the file 'beta'.\n"),
2153
'DD/D1/D2' : Item(),
2156
'DDF/D1/D2' : Item(),
2157
'DDF/D1/D2/gamma' : Item("This is the file 'gamma'.\n"),
2160
'DDD/D1/D2' : Item(),
2161
'DDD/D1/D2/D3' : Item(),
2165
# Many actions on deep trees and their resulting states...
2167
def deep_trees_leaf_edit(base):
2168
"""Helper function for deep trees test cases. Append text to files,
2169
create new files in empty directories, and change leaf node properties."""
2171
F = j(base, 'F', 'alpha')
2172
DF = j(base, 'DF', 'D1', 'beta')
2173
DDF = j(base, 'DDF', 'D1', 'D2', 'gamma')
2174
main.file_append(F, "More text for file alpha.\n")
2175
main.file_append(DF, "More text for file beta.\n")
2176
main.file_append(DDF, "More text for file gamma.\n")
2177
run_and_verify_svn(None, verify.AnyOutput, [],
2178
'propset', 'prop1', '1', F, DF, DDF)
2180
D = j(base, 'D', 'D1')
2181
DD = j(base, 'DD', 'D1', 'D2')
2182
DDD = j(base, 'DDD', 'D1', 'D2', 'D3')
2183
run_and_verify_svn(None, verify.AnyOutput, [],
2184
'propset', 'prop1', '1', D, DD, DDD)
2185
D = j(base, 'D', 'D1', 'delta')
2186
DD = j(base, 'DD', 'D1', 'D2', 'epsilon')
2187
DDD = j(base, 'DDD', 'D1', 'D2', 'D3', 'zeta')
2188
main.file_append(D, "This is the file 'delta'.\n")
2189
main.file_append(DD, "This is the file 'epsilon'.\n")
2190
main.file_append(DDD, "This is the file 'zeta'.\n")
2191
run_and_verify_svn(None, verify.AnyOutput, [],
2194
# deep trees state after a call to deep_trees_leaf_edit
2195
deep_trees_after_leaf_edit = wc.State('', {
2197
'F/alpha' : Item("This is the file 'alpha'.\nMore text for file alpha.\n"),
2200
'D/D1/delta' : Item("This is the file 'delta'.\n"),
2203
'DF/D1/beta' : Item("This is the file 'beta'.\nMore text for file beta.\n"),
2206
'DD/D1/D2' : Item(),
2207
'DD/D1/D2/epsilon' : Item("This is the file 'epsilon'.\n"),
2210
'DDF/D1/D2' : Item(),
2211
'DDF/D1/D2/gamma' : Item("This is the file 'gamma'.\nMore text for file gamma.\n"),
2214
'DDD/D1/D2' : Item(),
2215
'DDD/D1/D2/D3' : Item(),
2216
'DDD/D1/D2/D3/zeta' : Item("This is the file 'zeta'.\n"),
2220
def deep_trees_leaf_del(base):
2221
"""Helper function for deep trees test cases. Delete files and empty
2224
F = j(base, 'F', 'alpha')
2225
D = j(base, 'D', 'D1')
2226
DF = j(base, 'DF', 'D1', 'beta')
2227
DD = j(base, 'DD', 'D1', 'D2')
2228
DDF = j(base, 'DDF', 'D1', 'D2', 'gamma')
2229
DDD = j(base, 'DDD', 'D1', 'D2', 'D3')
2230
main.run_svn(None, 'rm', F, D, DF, DD, DDF, DDD)
2232
# deep trees state after a call to deep_trees_leaf_del
2233
deep_trees_after_leaf_del = wc.State('', {
2242
'DDF/D1/D2' : Item(),
2245
'DDD/D1/D2' : Item(),
2248
# deep trees state after a call to deep_trees_leaf_del with no commit
2249
def deep_trees_after_leaf_del_no_ci(wc_dir):
2250
if svntest.main.wc_is_singledb(wc_dir):
2251
return deep_trees_after_leaf_del
2253
return deep_trees_empty_dirs
2256
def deep_trees_tree_del(base):
2257
"""Helper function for deep trees test cases. Delete top-level dirs."""
2259
F = j(base, 'F', 'alpha')
2260
D = j(base, 'D', 'D1')
2261
DF = j(base, 'DF', 'D1')
2262
DD = j(base, 'DD', 'D1')
2263
DDF = j(base, 'DDF', 'D1')
2264
DDD = j(base, 'DDD', 'D1')
2265
main.run_svn(None, 'rm', F, D, DF, DD, DDF, DDD)
2267
def deep_trees_rmtree(base):
2268
"""Helper function for deep trees test cases. Delete top-level dirs
2269
with rmtree instead of svn del."""
2271
F = j(base, 'F', 'alpha')
2272
D = j(base, 'D', 'D1')
2273
DF = j(base, 'DF', 'D1')
2274
DD = j(base, 'DD', 'D1')
2275
DDF = j(base, 'DDF', 'D1')
2276
DDD = j(base, 'DDD', 'D1')
2279
main.safe_rmtree(DF)
2280
main.safe_rmtree(DD)
2281
main.safe_rmtree(DDF)
2282
main.safe_rmtree(DDD)
2284
# deep trees state after a call to deep_trees_tree_del
2285
deep_trees_after_tree_del = wc.State('', {
2294
# deep trees state without any files
2295
deep_trees_empty_dirs = wc.State('', {
2303
'DD/D1/D2' : Item(),
2306
'DDF/D1/D2' : Item(),
2309
'DDD/D1/D2' : Item(),
2310
'DDD/D1/D2/D3' : Item(),
2313
# deep trees state after a call to deep_trees_tree_del with no commit
2314
def deep_trees_after_tree_del_no_ci(wc_dir):
2315
if svntest.main.wc_is_singledb(wc_dir):
2316
return deep_trees_after_tree_del
2318
return deep_trees_empty_dirs
2320
def deep_trees_tree_del_repos(base):
2321
"""Helper function for deep trees test cases. Delete top-level dirs,
2322
directly in the repository."""
2324
F = j([base, 'F', 'alpha'])
2325
D = j([base, 'D', 'D1'])
2326
DF = j([base, 'DF', 'D1'])
2327
DD = j([base, 'DD', 'D1'])
2328
DDF = j([base, 'DDF', 'D1'])
2329
DDD = j([base, 'DDD', 'D1'])
2330
main.run_svn(None, 'mkdir', '-m', '', F, D, DF, DD, DDF, DDD)
2332
# Expected merge/update/switch output.
2334
deep_trees_conflict_output = wc.State('', {
2335
'F/alpha' : Item(status=' ', treeconflict='C'),
2336
'D/D1' : Item(status=' ', treeconflict='C'),
2337
'DF/D1' : Item(status=' ', treeconflict='C'),
2338
'DD/D1' : Item(status=' ', treeconflict='C'),
2339
'DDF/D1' : Item(status=' ', treeconflict='C'),
2340
'DDD/D1' : Item(status=' ', treeconflict='C'),
2343
deep_trees_conflict_output_skipped = wc.State('', {
2344
'D/D1' : Item(verb='Skipped'),
2345
'F/alpha' : Item(verb='Skipped'),
2346
'DD/D1' : Item(verb='Skipped'),
2347
'DF/D1' : Item(verb='Skipped'),
2348
'DDD/D1' : Item(verb='Skipped'),
2349
'DDF/D1' : Item(verb='Skipped'),
2352
# Expected status output after merge/update/switch.
2354
deep_trees_status_local_tree_del = wc.State('', {
2355
'' : Item(status=' ', wc_rev=3),
2356
'D' : Item(status=' ', wc_rev=3),
2357
'D/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
2358
'DD' : Item(status=' ', wc_rev=3),
2359
'DD/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
2360
'DD/D1/D2' : Item(status='D ', wc_rev=2),
2361
'DDD' : Item(status=' ', wc_rev=3),
2362
'DDD/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
2363
'DDD/D1/D2' : Item(status='D ', wc_rev=2),
2364
'DDD/D1/D2/D3' : Item(status='D ', wc_rev=2),
2365
'DDF' : Item(status=' ', wc_rev=3),
2366
'DDF/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
2367
'DDF/D1/D2' : Item(status='D ', wc_rev=2),
2368
'DDF/D1/D2/gamma' : Item(status='D ', wc_rev=2),
2369
'DF' : Item(status=' ', wc_rev=3),
2370
'DF/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
2371
'DF/D1/beta' : Item(status='D ', wc_rev=2),
2372
'F' : Item(status=' ', wc_rev=3),
2373
'F/alpha' : Item(status='D ', wc_rev=2, treeconflict='C'),
2376
deep_trees_status_local_leaf_edit = wc.State('', {
2377
'' : Item(status=' ', wc_rev=3),
2378
'D' : Item(status=' ', wc_rev=3),
2379
'D/D1' : Item(status=' M', wc_rev=2, treeconflict='C'),
2380
'D/D1/delta' : Item(status='A ', wc_rev=0),
2381
'DD' : Item(status=' ', wc_rev=3),
2382
'DD/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
2383
'DD/D1/D2' : Item(status=' M', wc_rev=2),
2384
'DD/D1/D2/epsilon' : Item(status='A ', wc_rev=0),
2385
'DDD' : Item(status=' ', wc_rev=3),
2386
'DDD/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
2387
'DDD/D1/D2' : Item(status=' ', wc_rev=2),
2388
'DDD/D1/D2/D3' : Item(status=' M', wc_rev=2),
2389
'DDD/D1/D2/D3/zeta' : Item(status='A ', wc_rev=0),
2390
'DDF' : Item(status=' ', wc_rev=3),
2391
'DDF/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
2392
'DDF/D1/D2' : Item(status=' ', wc_rev=2),
2393
'DDF/D1/D2/gamma' : Item(status='MM', wc_rev=2),
2394
'DF' : Item(status=' ', wc_rev=3),
2395
'DF/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
2396
'DF/D1/beta' : Item(status='MM', wc_rev=2),
2397
'F' : Item(status=' ', wc_rev=3),
2398
'F/alpha' : Item(status='MM', wc_rev=2, treeconflict='C'),
2402
class DeepTreesTestCase:
2403
"""Describes one tree-conflicts test case.
2404
See deep_trees_run_tests_scheme_for_update(), ..._switch(), ..._merge().
2406
The name field is the subdirectory name in which the test should be run.
2408
The local_action and incoming_action are the functions to run
2409
to construct the local changes and incoming changes, respectively.
2410
See deep_trees_leaf_edit, deep_trees_tree_del, etc.
2412
The expected_* and error_re_string arguments are described in functions
2413
run_and_verify_[update|switch|merge]
2414
except expected_info, which is a dict that has path keys with values
2415
that are dicts as passed to run_and_verify_info():
2420
'^local delete, incoming edit upon update'
2421
+ ' Source left: .file.*/F/alpha@2'
2422
+ ' Source right: .file.*/F/alpha@3$',
2426
'^local delete, incoming edit upon update'
2427
+ ' Source left: .dir.*/DF/D1@2'
2428
+ ' Source right: .dir.*/DF/D1@3$',
2433
Note: expected_skip is only used in merge, i.e. using
2434
deep_trees_run_tests_scheme_for_merge.
2437
def __init__(self, name, local_action, incoming_action,
2438
expected_output = None, expected_disk = None,
2439
expected_status = None, expected_skip = None,
2440
error_re_string = None,
2441
commit_block_string = ".*remains in conflict.*",
2442
expected_info = None):
2444
self.local_action = local_action
2445
self.incoming_action = incoming_action
2446
self.expected_output = expected_output
2447
self.expected_disk = expected_disk
2448
self.expected_status = expected_status
2449
self.expected_skip = expected_skip
2450
self.error_re_string = error_re_string
2451
self.commit_block_string = commit_block_string
2452
self.expected_info = expected_info
2456
def deep_trees_run_tests_scheme_for_update(sbox, greater_scheme):
2458
Runs a given list of tests for conflicts occuring at an update operation.
2460
This function wants to save time and perform a number of different
2461
test cases using just a single repository and performing just one commit
2462
for all test cases instead of one for each test case.
2464
1) Each test case is initialized in a separate subdir. Each subdir
2465
again contains one set of "deep_trees", being separate container
2466
dirs for different depths of trees (F, D, DF, DD, DDF, DDD).
2468
2) A commit is performed across all test cases and depths.
2469
(our initial state, -r2)
2471
3) In each test case subdir (e.g. "local_tree_del_incoming_leaf_edit"),
2472
its *incoming* action is performed (e.g. "deep_trees_leaf_edit"), in
2473
each of the different depth trees (F, D, DF, ... DDD).
2475
4) A commit is performed across all test cases and depths:
2476
our "incoming" state is "stored away in the repository for now",
2479
5) All test case dirs and contained deep_trees are time-warped
2480
(updated) back to -r2, the initial state containing deep_trees.
2482
6) In each test case subdir (e.g. "local_tree_del_incoming_leaf_edit"),
2483
its *local* action is performed (e.g. "deep_trees_leaf_del"), in
2484
each of the different depth trees (F, D, DF, ... DDD).
2486
7) An update to -r3 is performed across all test cases and depths.
2487
This causes tree-conflicts between the "local" state in the working
2488
copy and the "incoming" state from the repository, -r3.
2490
8) A commit is performed in each separate container, to verify
2491
that each tree-conflict indeed blocks a commit.
2493
The sbox parameter is just the sbox passed to a test function. No need
2494
to call sbox.build(), since it is called (once) within this function.
2496
The "table" greater_scheme models all of the different test cases
2497
that should be run using a single repository.
2499
greater_scheme is a list of DeepTreesTestCase items, which define complete
2500
test setups, so that they can be performed as described above.
2505
if not sbox.is_built():
2507
wc_dir = sbox.wc_dir
2510
# 1) create directories
2512
for test_case in greater_scheme:
2514
add_deep_trees(sbox, test_case.name)
2516
print("ERROR IN: Tests scheme for update: "
2517
+ "while setting up deep trees in '%s'" % test_case.name)
2521
# 2) commit initial state
2523
main.run_svn(None, 'commit', '-m', 'initial state', wc_dir)
2526
# 3) apply incoming changes
2528
for test_case in greater_scheme:
2530
test_case.incoming_action(j(sbox.wc_dir, test_case.name))
2532
print("ERROR IN: Tests scheme for update: "
2533
+ "while performing incoming action in '%s'" % test_case.name)
2537
# 4) commit incoming changes
2539
main.run_svn(None, 'commit', '-m', 'incoming changes', wc_dir)
2542
# 5) time-warp back to -r2
2544
main.run_svn(None, 'update', '-r2', wc_dir)
2547
# 6) apply local changes
2549
for test_case in greater_scheme:
2551
test_case.local_action(j(wc_dir, test_case.name))
2553
print("ERROR IN: Tests scheme for update: "
2554
+ "while performing local action in '%s'" % test_case.name)
2558
# 7) update to -r3, conflicting with incoming changes.
2559
# A lot of different things are expected.
2560
# Do separate update operations for each test case.
2562
for test_case in greater_scheme:
2564
base = j(wc_dir, test_case.name)
2566
x_out = test_case.expected_output
2568
x_out = x_out.copy()
2571
x_disk = test_case.expected_disk
2573
x_status = test_case.expected_status
2574
if x_status != None:
2576
x_status.wc_dir = base
2578
run_and_verify_update(base, x_out, x_disk, None,
2579
error_re_string = test_case.error_re_string)
2581
run_and_verify_unquiet_status(base, x_status)
2583
x_info = test_case.expected_info or {}
2585
run_and_verify_info([x_info[path]], j(base, path))
2588
print("ERROR IN: Tests scheme for update: "
2589
+ "while verifying in '%s'" % test_case.name)
2593
# 8) Verify that commit fails.
2595
for test_case in greater_scheme:
2597
base = j(wc_dir, test_case.name)
2599
x_status = test_case.expected_status
2600
if x_status != None:
2602
x_status.wc_dir = base
2604
run_and_verify_commit(base, None, x_status,
2605
test_case.commit_block_string,
2608
print("ERROR IN: Tests scheme for update: "
2609
+ "while checking commit-blocking in '%s'" % test_case.name)
2614
def deep_trees_skipping_on_update(sbox, test_case, skip_paths,
2617
Create tree conflicts, then update again, expecting the existing tree
2618
conflicts to be skipped.
2619
SKIP_PATHS is a list of paths, relative to the "base dir", for which
2620
"update" on the "base dir" should report as skipped.
2621
CHDIR_SKIP_PATHS is a list of (target-path, skipped-path) pairs for which
2622
an update of "target-path" (relative to the "base dir") should result in
2623
"skipped-path" (relative to "target-path") being reported as skipped.
2626
"""FURTHER_ACTION is a function that will make a further modification to
2627
each target, this being the modification that we expect to be skipped. The
2628
function takes the "base dir" (the WC path to the test case directory) as
2629
its only argument."""
2630
further_action = deep_trees_tree_del_repos
2633
wc_dir = sbox.wc_dir
2634
base = j(wc_dir, test_case.name)
2636
# Initialize: generate conflicts. (We do not check anything here.)
2637
setup_case = DeepTreesTestCase(test_case.name,
2638
test_case.local_action,
2639
test_case.incoming_action,
2643
deep_trees_run_tests_scheme_for_update(sbox, [setup_case])
2645
# Make a further change to each target in the repository so there is a new
2646
# revision to update to. (This is r4.)
2647
further_action(sbox.repo_url + '/' + test_case.name)
2649
# Update whole working copy, expecting the nodes still in conflict to be
2652
x_out = test_case.expected_output
2654
x_out = x_out.copy()
2657
x_disk = test_case.expected_disk
2659
x_status = test_case.expected_status
2660
if x_status != None:
2661
x_status = x_status.copy()
2662
x_status.wc_dir = base
2663
# Account for nodes that were updated by further_action
2664
x_status.tweak('', 'D', 'F', 'DD', 'DF', 'DDD', 'DDF', wc_rev=4)
2666
run_and_verify_update(base, x_out, x_disk, None,
2667
error_re_string = test_case.error_re_string)
2669
run_and_verify_unquiet_status(base, x_status)
2671
# Try to update each in-conflict subtree. Expect a 'Skipped' output for
2672
# each, and the WC status to be unchanged.
2673
for path in skip_paths:
2674
run_and_verify_update(j(base, path),
2675
wc.State(base, {path : Item(verb='Skipped')}),
2678
run_and_verify_unquiet_status(base, x_status)
2680
# Try to update each in-conflict subtree. Expect a 'Skipped' output for
2681
# each, and the WC status to be unchanged.
2682
# This time, cd to the subdir before updating it.
2683
was_cwd = os.getcwd()
2684
for path, skipped in chdir_skip_paths:
2685
if isinstance(skipped, list):
2688
expected_skip[p] = Item(verb='Skipped')
2690
expected_skip = {skipped : Item(verb='Skipped')}
2692
run_and_verify_update(p,
2693
wc.State(p, expected_skip),
2697
run_and_verify_unquiet_status(base, x_status)
2699
# Verify that commit still fails.
2700
for path, skipped in chdir_skip_paths:
2702
run_and_verify_commit(j(base, path), None, None,
2703
test_case.commit_block_string,
2706
run_and_verify_unquiet_status(base, x_status)
2709
def deep_trees_run_tests_scheme_for_switch(sbox, greater_scheme):
2711
Runs a given list of tests for conflicts occuring at a switch operation.
2713
This function wants to save time and perform a number of different
2714
test cases using just a single repository and performing just one commit
2715
for all test cases instead of one for each test case.
2717
1) Each test case is initialized in a separate subdir. Each subdir
2718
again contains two subdirs: one "local" and one "incoming" for
2719
the switch operation. These contain a set of deep_trees each.
2721
2) A commit is performed across all test cases and depths.
2722
(our initial state, -r2)
2724
3) In each test case subdir's incoming subdir, the
2725
incoming actions are performed.
2727
4) A commit is performed across all test cases and depths. (-r3)
2729
5) In each test case subdir's local subdir, the local actions are
2730
performed. They remain uncommitted in the working copy.
2732
6) In each test case subdir's local dir, a switch is performed to its
2733
corresponding incoming dir.
2734
This causes conflicts between the "local" state in the working
2735
copy and the "incoming" state from the incoming subdir (still -r3).
2737
7) A commit is performed in each separate container, to verify
2738
that each tree-conflict indeed blocks a commit.
2740
The sbox parameter is just the sbox passed to a test function. No need
2741
to call sbox.build(), since it is called (once) within this function.
2743
The "table" greater_scheme models all of the different test cases
2744
that should be run using a single repository.
2746
greater_scheme is a list of DeepTreesTestCase items, which define complete
2747
test setups, so that they can be performed as described above.
2752
if not sbox.is_built():
2754
wc_dir = sbox.wc_dir
2757
# 1) Create directories.
2759
for test_case in greater_scheme:
2761
base = j(sbox.wc_dir, test_case.name)
2763
make_deep_trees(j(base, "local"))
2764
make_deep_trees(j(base, "incoming"))
2765
main.run_svn(None, 'add', base)
2767
print("ERROR IN: Tests scheme for switch: "
2768
+ "while setting up deep trees in '%s'" % test_case.name)
2772
# 2) Commit initial state (-r2).
2774
main.run_svn(None, 'commit', '-m', 'initial state', wc_dir)
2777
# 3) Apply incoming changes
2779
for test_case in greater_scheme:
2781
test_case.incoming_action(j(sbox.wc_dir, test_case.name, "incoming"))
2783
print("ERROR IN: Tests scheme for switch: "
2784
+ "while performing incoming action in '%s'" % test_case.name)
2788
# 4) Commit all changes (-r3).
2790
main.run_svn(None, 'commit', '-m', 'incoming changes', wc_dir)
2793
# 5) Apply local changes in their according subdirs.
2795
for test_case in greater_scheme:
2797
test_case.local_action(j(sbox.wc_dir, test_case.name, "local"))
2799
print("ERROR IN: Tests scheme for switch: "
2800
+ "while performing local action in '%s'" % test_case.name)
2804
# 6) switch the local dir to the incoming url, conflicting with incoming
2805
# changes. A lot of different things are expected.
2806
# Do separate switch operations for each test case.
2808
for test_case in greater_scheme:
2810
local = j(wc_dir, test_case.name, "local")
2811
incoming = sbox.repo_url + "/" + test_case.name + "/incoming"
2813
x_out = test_case.expected_output
2815
x_out = x_out.copy()
2816
x_out.wc_dir = local
2818
x_disk = test_case.expected_disk
2820
x_status = test_case.expected_status
2821
if x_status != None:
2823
x_status.wc_dir = local
2825
run_and_verify_switch(local, local, incoming, x_out, x_disk, None,
2826
test_case.error_re_string, None, None, None,
2827
None, False, '--ignore-ancestry')
2828
run_and_verify_unquiet_status(local, x_status)
2830
x_info = test_case.expected_info or {}
2832
run_and_verify_info([x_info[path]], j(local, path))
2834
print("ERROR IN: Tests scheme for switch: "
2835
+ "while verifying in '%s'" % test_case.name)
2839
# 7) Verify that commit fails.
2841
for test_case in greater_scheme:
2843
local = j(wc_dir, test_case.name, 'local')
2845
x_status = test_case.expected_status
2846
if x_status != None:
2848
x_status.wc_dir = local
2850
run_and_verify_commit(local, None, x_status,
2851
test_case.commit_block_string,
2854
print("ERROR IN: Tests scheme for switch: "
2855
+ "while checking commit-blocking in '%s'" % test_case.name)
2859
def deep_trees_run_tests_scheme_for_merge(sbox, greater_scheme,
2860
do_commit_local_changes,
2861
do_commit_conflicts=True,
2862
ignore_ancestry=False):
2864
Runs a given list of tests for conflicts occuring at a merge operation.
2866
This function wants to save time and perform a number of different
2867
test cases using just a single repository and performing just one commit
2868
for all test cases instead of one for each test case.
2870
1) Each test case is initialized in a separate subdir. Each subdir
2871
initially contains another subdir, called "incoming", which
2872
contains a set of deep_trees.
2874
2) A commit is performed across all test cases and depths.
2875
(a pre-initial state)
2877
3) In each test case subdir, the "incoming" subdir is copied to "local",
2878
via the `svn copy' command. Each test case's subdir now has two sub-
2879
dirs: "local" and "incoming", initial states for the merge operation.
2881
4) An update is performed across all test cases and depths, so that the
2882
copies made in 3) are pulled into the wc.
2884
5) In each test case's "incoming" subdir, the incoming action is
2887
6) A commit is performed across all test cases and depths, to commit
2888
the incoming changes.
2889
If do_commit_local_changes is True, this becomes step 7 (swap steps).
2891
7) In each test case's "local" subdir, the local_action is performed.
2892
If do_commit_local_changes is True, this becomes step 6 (swap steps).
2893
Then, in effect, the local changes are committed as well.
2895
8) In each test case subdir, the "incoming" subdir is merged into the
2896
"local" subdir. If ignore_ancestry is True, then the merge is done
2897
with the --ignore-ancestry option, so mergeinfo is neither considered
2898
nor recorded. This causes conflicts between the "local" state in the
2899
working copy and the "incoming" state from the incoming subdir.
2901
9) If do_commit_conflicts is True, then a commit is performed in each
2902
separate container, to verify that each tree-conflict indeed blocks
2905
The sbox parameter is just the sbox passed to a test function. No need
2906
to call sbox.build(), since it is called (once) within this function.
2908
The "table" greater_scheme models all of the different test cases
2909
that should be run using a single repository.
2911
greater_scheme is a list of DeepTreesTestCase items, which define complete
2912
test setups, so that they can be performed as described above.
2917
if not sbox.is_built():
2919
wc_dir = sbox.wc_dir
2921
# 1) Create directories.
2922
for test_case in greater_scheme:
2924
base = j(sbox.wc_dir, test_case.name)
2926
make_deep_trees(j(base, "incoming"))
2927
main.run_svn(None, 'add', base)
2929
print("ERROR IN: Tests scheme for merge: "
2930
+ "while setting up deep trees in '%s'" % test_case.name)
2934
# 2) Commit pre-initial state (-r2).
2936
main.run_svn(None, 'commit', '-m', 'pre-initial state', wc_dir)
2939
# 3) Copy "incoming" to "local".
2941
for test_case in greater_scheme:
2943
base_url = sbox.repo_url + "/" + test_case.name
2944
incoming_url = base_url + "/incoming"
2945
local_url = base_url + "/local"
2946
main.run_svn(None, 'cp', incoming_url, local_url, '-m',
2947
'copy incoming to local')
2949
print("ERROR IN: Tests scheme for merge: "
2950
+ "while copying deep trees in '%s'" % test_case.name)
2953
# 4) Update to load all of the "/local" subdirs into the working copies.
2956
main.run_svn(None, 'up', sbox.wc_dir)
2958
print("ERROR IN: Tests scheme for merge: "
2959
+ "while updating local subdirs")
2963
# 5) Perform incoming actions
2965
for test_case in greater_scheme:
2967
test_case.incoming_action(j(sbox.wc_dir, test_case.name, "incoming"))
2969
print("ERROR IN: Tests scheme for merge: "
2970
+ "while performing incoming action in '%s'" % test_case.name)
2974
# 6) or 7) Commit all incoming actions
2976
if not do_commit_local_changes:
2978
main.run_svn(None, 'ci', '-m', 'Committing incoming actions',
2981
print("ERROR IN: Tests scheme for merge: "
2982
+ "while committing incoming actions")
2986
# 7) or 6) Perform all local actions.
2988
for test_case in greater_scheme:
2990
test_case.local_action(j(sbox.wc_dir, test_case.name, "local"))
2992
print("ERROR IN: Tests scheme for merge: "
2993
+ "while performing local action in '%s'" % test_case.name)
2997
# 6) or 7) Commit all incoming actions
2999
if do_commit_local_changes:
3001
main.run_svn(None, 'ci', '-m', 'Committing incoming and local actions',
3004
print("ERROR IN: Tests scheme for merge: "
3005
+ "while committing incoming and local actions")
3009
# 8) Merge all "incoming" subdirs to their respective "local" subdirs.
3010
# This creates conflicts between the local changes in the "local" wc
3011
# subdirs and the incoming states committed in the "incoming" subdirs.
3013
for test_case in greater_scheme:
3015
local = j(sbox.wc_dir, test_case.name, "local")
3016
incoming = sbox.repo_url + "/" + test_case.name + "/incoming"
3018
x_out = test_case.expected_output
3020
x_out = x_out.copy()
3021
x_out.wc_dir = local
3023
x_disk = test_case.expected_disk
3025
x_status = test_case.expected_status
3026
if x_status != None:
3028
x_status.wc_dir = local
3030
x_skip = test_case.expected_skip
3033
x_skip.wc_dir = local
3037
varargs = varargs + ('--ignore-ancestry',)
3039
run_and_verify_merge(local, None, None, incoming, None,
3040
x_out, None, None, x_disk, None, x_skip,
3041
test_case.error_re_string,
3042
None, None, None, None,
3043
False, False, *varargs)
3044
run_and_verify_unquiet_status(local, x_status)
3046
print("ERROR IN: Tests scheme for merge: "
3047
+ "while verifying in '%s'" % test_case.name)
3051
# 9) Verify that commit fails.
3053
if do_commit_conflicts:
3054
for test_case in greater_scheme:
3056
local = j(wc_dir, test_case.name, 'local')
3058
x_status = test_case.expected_status
3059
if x_status != None:
3061
x_status.wc_dir = local
3063
run_and_verify_commit(local, None, x_status,
3064
test_case.commit_block_string,
3067
print("ERROR IN: Tests scheme for merge: "
3068
+ "while checking commit-blocking in '%s'" % test_case.name)