1#!/usr/bin/env python 2# 3# resolve_tests.py: testing 'svn resolve' 4# 5# Subversion is a tool for revision control. 6# See http://subversion.apache.org for more information. 7# 8# ==================================================================== 9# Licensed to the Apache Software Foundation (ASF) under one 10# or more contributor license agreements. See the NOTICE file 11# distributed with this work for additional information 12# regarding copyright ownership. The ASF licenses this file 13# to you under the Apache License, Version 2.0 (the 14# "License"); you may not use this file except in compliance 15# with the License. You may obtain a copy of the License at 16# 17# http://www.apache.org/licenses/LICENSE-2.0 18# 19# Unless required by applicable law or agreed to in writing, 20# software distributed under the License is distributed on an 21# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 22# KIND, either express or implied. See the License for the 23# specific language governing permissions and limitations 24# under the License. 25###################################################################### 26 27# General modules 28import shutil, sys, re, os, stat 29import time 30 31# Our testing module 32import svntest 33from svntest import wc 34 35# (abbreviation) 36Item = wc.StateItem 37Skip = svntest.testcase.Skip_deco 38SkipUnless = svntest.testcase.SkipUnless_deco 39XFail = svntest.testcase.XFail_deco 40Issues = svntest.testcase.Issues_deco 41Issue = svntest.testcase.Issue_deco 42Wimp = svntest.testcase.Wimp_deco 43 44from svntest.mergetrees import set_up_branch 45from svntest.mergetrees import expected_merge_output 46 47 48###################################################################### 49# Tests 50# 51# Each test must return on success or raise on failure. 52 53#---------------------------------------------------------------------- 54# 'svn resolve --accept [ base | mine-full | theirs-full ]' was segfaulting 55# on 1.6.x. Prior to this test, the bug was only caught by the Ruby binding 56# tests, see http://svn.haxx.se/dev/archive-2010-01/0088.shtml. 57def automatic_conflict_resolution(sbox): 58 "resolve -R --accept [base | mf | tf]" 59 60 sbox.build() 61 wc_dir = sbox.wc_dir 62 63 # Some paths we'll care about 64 A_COPY_path = os.path.join(wc_dir, "A_COPY") 65 psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi") 66 67 # Branch A to A_COPY in r2, then make some changes under 'A' in r3-6. 68 wc_disk, wc_status = set_up_branch(sbox) 69 70 # Make a change on the A_COPY branch such that a subsequent merge 71 # conflicts. 72 svntest.main.file_write(psi_COPY_path, "Branch content.\n") 73 svntest.actions.run_and_verify_svn(None, [], 74 'commit', '-m', 'log msg', wc_dir) 75 def do_text_conflicting_merge(): 76 svntest.actions.run_and_verify_svn(None, [], 77 'revert', '--recursive', A_COPY_path) 78 svntest.actions.run_and_verify_svn( 79 expected_merge_output([[3]], [ 80 "C %s\n" % psi_COPY_path, 81 " U %s\n" % A_COPY_path], 82 target=A_COPY_path, text_conflicts=1), 83 [], 'merge', '-c3', '--allow-mixed-revisions', 84 sbox.repo_url + '/A', 85 A_COPY_path) 86 87 # Test 'svn resolve -R --accept base' 88 do_text_conflicting_merge() 89 svntest.actions.run_and_verify_resolve([psi_COPY_path], 90 '-R', '--accept', 'base', 91 A_COPY_path) 92 wc_disk.tweak('A_COPY/D/H/psi', contents="This is the file 'psi'.\n") 93 svntest.actions.verify_disk(wc_dir, wc_disk) 94 95 # Test 'svn resolve -R --accept mine-full' 96 do_text_conflicting_merge() 97 svntest.actions.run_and_verify_resolve([psi_COPY_path], 98 '-R', '--accept', 'mine-full', 99 A_COPY_path) 100 wc_disk.tweak('A_COPY/D/H/psi', contents="Branch content.\n") 101 svntest.actions.verify_disk(wc_dir, wc_disk) 102 103 # Test 'svn resolve -R --accept theirs-full' 104 do_text_conflicting_merge() 105 svntest.actions.run_and_verify_resolve([psi_COPY_path], 106 '-R', '--accept', 'tf', 107 A_COPY_path) 108 wc_disk.tweak('A_COPY/D/H/psi', contents="New content") 109 svntest.actions.verify_disk(wc_dir, wc_disk) 110 111#---------------------------------------------------------------------- 112# Test for issue #3707 'property conflicts not handled correctly by 113# svn resolve'. 114@Issue(3707) 115def prop_conflict_resolution(sbox): 116 "resolving prop conflicts" 117 118 sbox.build() 119 wc_dir = sbox.wc_dir 120 121 # Some paths we'll care about 122 iota_path = os.path.join(wc_dir, "iota") 123 mu_path = os.path.join(wc_dir, "A", "mu") 124 gamma_path = os.path.join(wc_dir, "A", "D", "gamma") 125 psi_path = os.path.join(wc_dir, "A", "D", "H", "psi") 126 127 # r2 - Set property 'propname:propval' on iota, A/mu, and A/D/gamma. 128 svntest.actions.run_and_verify_svn(None, [], 129 'ps', 'propname', 'propval', 130 iota_path, mu_path, gamma_path) 131 svntest.actions.run_and_verify_svn(None, [], 'commit', 132 '-m', 'create some new properties', 133 wc_dir) 134 135 # r3 - Make some changes to the props from r2: 136 # 137 # iota : Delete property 'propname' 138 # A/mu : Change property 'propname' to 'incoming-conflict' 139 # A/D/gamma : Change property 'propname' to 'incoming-no-conflict' 140 svntest.actions.run_and_verify_svn(None, [], 141 'pd', 'propname', iota_path) 142 svntest.actions.run_and_verify_svn(None, [], 143 'ps', 'propname', 'incoming-conflict', 144 mu_path) 145 svntest.actions.run_and_verify_svn(None, [], 146 'ps', 'propname', 'incoming-no-conflict', 147 gamma_path) 148 svntest.actions.run_and_verify_svn(None, [], 149 'commit', '-m', 'delete a property', 150 wc_dir) 151 152 def do_prop_conflicting_up_and_resolve(resolve_accept, 153 resolved_deleted_prop_val_output, 154 resolved_edited_prop_val_output): 155 156 """Revert the WC, update it to r2, and set the following properties: 157 158 iota : 'propname' = 'local_edit' 159 'newprop' = 'new-val-no-incoming' 160 A/mu : 'propname' = 'local_edit' 161 A/D/gamma : 'propname' = 'incoming-no-conflict' 162 A/D/H/psi : 'newprop' = 'new-val-no-incoming' 163 164 Update the WC, postponing conflicts, then run svn resolve -R 165 --accept=RESOLVE_ACCEPT. 166 167 Using svn propget, check that the resolution results in the following 168 properties: 169 170 iota : 'propname' = RESOLVED_DELETED_PROP_VAL_OUTPUT 171 'newprop' = 'new-val-no-incoming' 172 A/mu : 'propname' = RESOLVED_EDITED_PROP_VAL_OUTPUT 173 A/D/gamma : 'propname' = 'incoming-no-conflict' 174 A/D/H/psi : 'newprop' = 'new-val-no-incoming' 175 176 RESOLVED_DELETED_PROP_VAL_OUTPUT and RESOLVED_EDITED_PROP_VAL_OUTPUT 177 both follow the rules for the expected_stdout arg to 178 run_and_verify_svn2()""" 179 180 svntest.actions.run_and_verify_svn(None, [], 181 'revert', '--recursive', wc_dir) 182 svntest.actions.run_and_verify_svn(None, [], 'up', '-r2', wc_dir) 183 184 # Set some properties that will conflict when we update. 185 svntest.actions.run_and_verify_svn(None, [], 'ps', 186 'propname', 'local_edit', 187 iota_path, mu_path) 188 189 # Set a property that should always merge cleanly with the update. 190 svntest.actions.run_and_verify_svn(None, [], 'ps', 191 'propname', 'incoming-no-conflict', 192 gamma_path) 193 194 # Set a property that has no update coming. 195 svntest.actions.run_and_verify_svn(None, [], 'ps', 196 'newprop', 'new-val-no-incoming', 197 psi_path, 198 iota_path) 199 200 # Update, postponing all conflict resolution. 201 svntest.actions.run_and_verify_svn(None, [], 'up', 202 '--accept=postpone', wc_dir) 203 svntest.actions.run_and_verify_resolve([iota_path, mu_path], '-R', 204 '--accept', resolve_accept, wc_dir) 205 if resolved_deleted_prop_val_output: 206 expected_deleted_stderr = [] 207 else: 208 expected_deleted_stderr = '.*W200017: Property.*not found' 209 210 svntest.actions.run_and_verify_svn( 211 resolved_deleted_prop_val_output, expected_deleted_stderr, 212 'pg', 'propname', iota_path) 213 svntest.actions.run_and_verify_svn( 214 ['new-val-no-incoming\n'], [], 'pg', 'newprop', iota_path) 215 svntest.actions.run_and_verify_svn( 216 resolved_edited_prop_val_output, [], 'pg', 'propname', mu_path) 217 svntest.actions.run_and_verify_svn( 218 ['incoming-no-conflict\n'], [], 'pg', 'propname', gamma_path) 219 svntest.actions.run_and_verify_svn( 220 ['new-val-no-incoming\n'], [], 'pg', 'newprop', psi_path) 221 222 # Test how svn resolve deals with prop conflicts and other local 223 # prop changes: 224 # 225 # 1) 'iota' - An incoming prop delete on a local prop modification. 226 # 2) 'A/mu' - An incoming prop edit on a local prop modification. 227 # 3) 'A/D/gamma' - An local, non-conflicted prop edit 228 # 229 # Previously this failed because svn resolve --accept=[theirs-conflict | 230 # theirs-full] removed the conflicts, but didn't install 'their' version 231 # of the conflicted properties. 232 do_prop_conflicting_up_and_resolve('mine-full', 233 ['local_edit\n'], 234 ['local_edit\n']) 235 do_prop_conflicting_up_and_resolve('mine-conflict', 236 ['local_edit\n'], 237 ['local_edit\n']) 238 do_prop_conflicting_up_and_resolve('working', 239 ['local_edit\n'], 240 ['local_edit\n']) 241 do_prop_conflicting_up_and_resolve('theirs-conflict', 242 [], # Prop deleted 243 ['incoming-conflict\n']) 244 do_prop_conflicting_up_and_resolve('theirs-full', 245 [], # Prop deleted 246 ['incoming-conflict\n']) 247 248#---------------------------------------------------------------------- 249@SkipUnless(svntest.main.is_posix_os) 250def auto_resolve_executable_file(sbox): 251 "resolve file with executable bit set" 252 sbox.build() 253 wc_dir = sbox.wc_dir 254 255 # Mark iota as executable 256 sbox.simple_propset("svn:executable", '*', 'iota') 257 sbox.simple_commit() # r2 258 259 # Make a change to iota in r3 260 svntest.main.file_write(sbox.ospath('iota'), "boo\n") 261 sbox.simple_commit() # r3 262 263 # Update back to r2, and tweak iota to provoke a text conflict 264 sbox.simple_update(revision=2) 265 svntest.main.file_write(sbox.ospath('iota'), "bzzt\n") 266 267 # Get permission bits of iota 268 mode = os.stat(sbox.ospath('iota'))[stat.ST_MODE] 269 270 # Update back to r3, and auto-resolve the text conflict. 271 svntest.main.run_svn(False, 'update', wc_dir, '--accept', 'theirs-full') 272 273 # permission bits of iota should be unaffected 274 if mode != os.stat(sbox.ospath('iota'))[stat.ST_MODE]: 275 raise svntest.Failure 276 277#---------------------------------------------------------------------- 278def resolved_on_wc_root(sbox): 279 "resolved on working copy root" 280 281 sbox.build() 282 wc = sbox.wc_dir 283 284 i = os.path.join(wc, 'iota') 285 B = os.path.join(wc, 'A', 'B') 286 g = os.path.join(wc, 'A', 'D', 'gamma') 287 288 # Create some conflicts... 289 # Commit mods 290 svntest.main.file_append(i, "changed iota.\n") 291 svntest.main.file_append(g, "changed gamma.\n") 292 svntest.actions.run_and_verify_svn(None, [], 293 'propset', 'foo', 'foo-val', B) 294 295 expected_output = svntest.wc.State(wc, { 296 'iota' : Item(verb='Sending'), 297 'A/B' : Item(verb='Sending'), 298 'A/D/gamma' : Item(verb='Sending'), 299 }) 300 301 expected_status = svntest.actions.get_virginal_state(wc, 1) 302 expected_status.tweak('iota', 'A/B', 'A/D/gamma', wc_rev = 2) 303 304 svntest.actions.run_and_verify_commit(wc, 305 expected_output, 306 expected_status) 307 308 # Go back to rev 1 309 expected_output = svntest.wc.State(wc, { 310 'iota' : Item(status='U '), 311 'A/B' : Item(status=' U'), 312 'A/D/gamma' : Item(status='U '), 313 }) 314 expected_status = svntest.actions.get_virginal_state(wc, 1) 315 expected_disk = svntest.main.greek_state.copy() 316 svntest.actions.run_and_verify_update(wc, 317 expected_output, 318 expected_disk, 319 expected_status, 320 [], False, 321 '-r1', wc) 322 323 # Deletions so that the item becomes unversioned and 324 # will have a tree-conflict upon update. 325 svntest.actions.run_and_verify_svn(None, [], 326 'rm', i, B, g) 327 328 # Update so that conflicts appear 329 expected_output = svntest.wc.State(wc, { 330 'iota' : Item(status=' ', treeconflict='C'), 331 'A/B' : Item(status=' ', treeconflict='C'), 332 'A/D/gamma' : Item(status=' ', treeconflict='C'), 333 }) 334 335 expected_disk = svntest.main.greek_state.copy() 336 expected_disk.remove('iota', 337 'A/B', 338 'A/B/lambda', 339 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 340 'A/B/F', 341 'A/D/gamma') 342 343 expected_status = svntest.actions.get_virginal_state(wc, 2) 344 expected_status.tweak('iota', 'A/B', 'A/D/gamma', 345 status='D ', treeconflict='C') 346 expected_status.tweak('A/B/lambda', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 347 'A/B/F', status='D ') 348 svntest.actions.run_and_verify_update(wc, 349 expected_output, 350 expected_disk, 351 None, 352 [], False, 353 wc) 354 svntest.actions.run_and_verify_unquiet_status(wc, expected_status) 355 356 # Resolve recursively 357 svntest.actions.run_and_verify_resolved([i, B, g], '--depth=infinity', wc) 358 359 expected_status.tweak('iota', 'A/B', 'A/D/gamma', treeconflict=None) 360 svntest.actions.run_and_verify_unquiet_status(wc, expected_status) 361 362#---------------------------------------------------------------------- 363@SkipUnless(svntest.main.server_has_mergeinfo) 364def resolved_on_deleted_item(sbox): 365 "resolved on deleted item" 366 367 sbox.build() 368 wc = sbox.wc_dir 369 370 A = os.path.join(wc, 'A',) 371 B = os.path.join(wc, 'A', 'B') 372 g = os.path.join(wc, 'A', 'D', 'gamma') 373 A2 = os.path.join(wc, 'A2') 374 B2 = os.path.join(A2, 'B') 375 g2 = os.path.join(A2, 'D', 'gamma') 376 377 A_url = sbox.repo_url + '/A' 378 A2_url = sbox.repo_url + '/A2' 379 380 # make a copy of A 381 svntest.actions.run_and_verify_svn(None, [], 382 'cp', A_url, A2_url, '-m', 'm') 383 384 expected_output = svntest.wc.State(wc, { 385 'A2' : Item(status='A '), 386 'A2/B' : Item(status='A '), 387 'A2/B/lambda' : Item(status='A '), 388 'A2/B/E' : Item(status='A '), 389 'A2/B/E/alpha' : Item(status='A '), 390 'A2/B/E/beta' : Item(status='A '), 391 'A2/B/F' : Item(status='A '), 392 'A2/mu' : Item(status='A '), 393 'A2/C' : Item(status='A '), 394 'A2/D' : Item(status='A '), 395 'A2/D/gamma' : Item(status='A '), 396 'A2/D/G' : Item(status='A '), 397 'A2/D/G/pi' : Item(status='A '), 398 'A2/D/G/rho' : Item(status='A '), 399 'A2/D/G/tau' : Item(status='A '), 400 'A2/D/H' : Item(status='A '), 401 'A2/D/H/chi' : Item(status='A '), 402 'A2/D/H/omega' : Item(status='A '), 403 'A2/D/H/psi' : Item(status='A '), 404 }) 405 406 expected_disk = svntest.main.greek_state.copy() 407 expected_disk.add({ 408 'A2/mu' : Item(contents="This is the file 'mu'.\n"), 409 'A2/D/gamma' : Item(contents="This is the file 'gamma'.\n"), 410 'A2/D/H/psi' : Item(contents="This is the file 'psi'.\n"), 411 'A2/D/H/omega' : Item(contents="This is the file 'omega'.\n"), 412 'A2/D/H/chi' : Item(contents="This is the file 'chi'.\n"), 413 'A2/D/G/rho' : Item(contents="This is the file 'rho'.\n"), 414 'A2/D/G/pi' : Item(contents="This is the file 'pi'.\n"), 415 'A2/D/G/tau' : Item(contents="This is the file 'tau'.\n"), 416 'A2/B/lambda' : Item(contents="This is the file 'lambda'.\n"), 417 'A2/B/F' : Item(), 418 'A2/B/E/beta' : Item(contents="This is the file 'beta'.\n"), 419 'A2/B/E/alpha' : Item(contents="This is the file 'alpha'.\n"), 420 'A2/C' : Item(), 421 }) 422 423 expected_status = svntest.actions.get_virginal_state(wc, 2) 424 expected_status.add({ 425 'A2' : Item(), 426 'A2/B' : Item(), 427 'A2/B/lambda' : Item(), 428 'A2/B/E' : Item(), 429 'A2/B/E/alpha' : Item(), 430 'A2/B/E/beta' : Item(), 431 'A2/B/F' : Item(), 432 'A2/mu' : Item(), 433 'A2/C' : Item(), 434 'A2/D' : Item(), 435 'A2/D/gamma' : Item(), 436 'A2/D/G' : Item(), 437 'A2/D/G/pi' : Item(), 438 'A2/D/G/rho' : Item(), 439 'A2/D/G/tau' : Item(), 440 'A2/D/H' : Item(), 441 'A2/D/H/chi' : Item(), 442 'A2/D/H/omega' : Item(), 443 'A2/D/H/psi' : Item(), 444 }) 445 expected_status.tweak(status=' ', wc_rev='2') 446 447 svntest.actions.run_and_verify_update(wc, 448 expected_output, 449 expected_disk, 450 expected_status, 451 [], False, 452 wc) 453 454 # Create some conflicts... 455 456 # Modify the paths in the one directory. 457 svntest.actions.run_and_verify_svn(None, [], 458 'propset', 'foo', 'foo-val', B) 459 svntest.main.file_append(g, "Modified gamma.\n") 460 461 expected_output = svntest.wc.State(wc, { 462 'A/B' : Item(verb='Sending'), 463 'A/D/gamma' : Item(verb='Sending'), 464 }) 465 466 expected_status.tweak('A/B', 'A/D/gamma', wc_rev='3') 467 468 svntest.actions.run_and_verify_commit(wc, 469 expected_output, 470 expected_status) 471 472 # Delete the paths in the second directory. 473 svntest.actions.run_and_verify_svn(None, [], 474 'rm', B2, g2) 475 476 expected_output = svntest.wc.State(wc, { 477 'A2/B' : Item(verb='Deleting'), 478 'A2/D/gamma' : Item(verb='Deleting'), 479 }) 480 481 expected_status.remove('A2/B', 'A2/B/lambda', 482 'A2/B/E', 'A2/B/E/alpha', 'A2/B/E/beta', 483 'A2/B/F', 484 'A2/D/gamma') 485 486 svntest.actions.run_and_verify_commit(wc, 487 expected_output, 488 expected_status, 489 [], 490 A2) 491 492 # Now merge A to A2, creating conflicts... 493 494 expected_output = svntest.wc.State(A2, { 495 'B' : Item(status=' ', treeconflict='C'), 496 'D/gamma' : Item(status=' ', treeconflict='C'), 497 }) 498 expected_mergeinfo_output = svntest.wc.State(A2, { 499 '' : Item(status=' U') 500 }) 501 expected_elision_output = svntest.wc.State(A2, { 502 }) 503 expected_disk = svntest.wc.State('', { 504 'mu' : Item(contents="This is the file 'mu'.\n"), 505 'D' : Item(), 506 'D/H' : Item(), 507 'D/H/psi' : Item(contents="This is the file 'psi'.\n"), 508 'D/H/omega' : Item(contents="This is the file 'omega'.\n"), 509 'D/H/chi' : Item(contents="This is the file 'chi'.\n"), 510 'D/G' : Item(), 511 'D/G/rho' : Item(contents="This is the file 'rho'.\n"), 512 'D/G/pi' : Item(contents="This is the file 'pi'.\n"), 513 'D/G/tau' : Item(contents="This is the file 'tau'.\n"), 514 'C' : Item(), 515 }) 516 517 expected_skip = svntest.wc.State(wc, { 518 }) 519 520 expected_status = svntest.wc.State(A2, { 521 '' : Item(status=' M', wc_rev='2'), 522 'D' : Item(status=' ', wc_rev='2'), 523 'D/gamma' : Item(status='! ', treeconflict='C'), 524 'D/G' : Item(status=' ', wc_rev='2'), 525 'D/G/pi' : Item(status=' ', wc_rev='2'), 526 'D/G/rho' : Item(status=' ', wc_rev='2'), 527 'D/G/tau' : Item(status=' ', wc_rev='2'), 528 'D/H' : Item(status=' ', wc_rev='2'), 529 'D/H/chi' : Item(status=' ', wc_rev='2'), 530 'D/H/omega' : Item(status=' ', wc_rev='2'), 531 'D/H/psi' : Item(status=' ', wc_rev='2'), 532 'B' : Item(status='! ', treeconflict='C'), 533 'mu' : Item(status=' ', wc_rev='2'), 534 'C' : Item(status=' ', wc_rev='2'), 535 }) 536 537 svntest.actions.run_and_verify_merge(A2, None, None, A_url, None, 538 expected_output, 539 expected_mergeinfo_output, 540 expected_elision_output, 541 expected_disk, None, expected_skip, 542 [], dry_run = False) 543 svntest.actions.run_and_verify_unquiet_status(A2, expected_status) 544 545 # Now resolve by recursing on the working copy root. 546 svntest.actions.run_and_verify_resolved([B2, g2], '--depth=infinity', wc) 547 548 expected_status.remove('B', 'D/gamma') 549 svntest.actions.run_and_verify_unquiet_status(A2, expected_status) 550 551#---------------------------------------------------------------------- 552 553def theirs_conflict_in_subdir(sbox): 554 "resolve to 'theirs-conflict' in sub-directory" 555 556 sbox.build() 557 wc = sbox.wc_dir 558 wc2 = sbox.add_wc_path('wc2') 559 svntest.actions.duplicate_dir(sbox.wc_dir, wc2) 560 561 alpha_path = os.path.join(wc, 'A', 'B', 'E', 'alpha') 562 alpha_path2 = os.path.join(wc2, 'A', 'B', 'E', 'alpha') 563 564 svntest.main.file_append(alpha_path, "Modified alpha.\n") 565 sbox.simple_commit(message='logmsg') 566 567 svntest.main.file_append(alpha_path2, "Modified alpha, too.\n") 568 svntest.main.run_svn(None, 'up', wc2) 569 570 svntest.actions.run_and_verify_resolve([alpha_path2], 571 '--accept=theirs-conflict', 572 alpha_path2) 573 574#---------------------------------------------------------------------- 575 576# Regression test for issue #4238 "merge -cA,B with --accept option aborts 577# if rA conflicts". 578@Issue(4238) 579def multi_range_merge_with_accept(sbox): 580 "multi range merge with --accept keeps going" 581 582 sbox.build() 583 os.chdir(sbox.wc_dir) 584 sbox.wc_dir = '' 585 586 # Commit some changes 587 for c in [2, 3, 4]: 588 svntest.main.file_append('iota', 'Change ' + str(c) + '\n') 589 sbox.simple_commit() 590 591 sbox.simple_update(revision=1) 592 593 # The bug: with a request to merge -c4 then -c3, it merges -c4 which 594 # conflicts then auto-resolves the conflict, then errors out with 595 # 'svn: E155035: Can't merge into conflicted node 'iota'. 596 # ### We need more checking of the result to make this test robust, since 597 # it may not always just error out. 598 svntest.main.run_svn(None, 'merge', '-c4,3', '^/iota', 'iota', 599 '--accept=theirs-conflict') 600 601#---------------------------------------------------------------------- 602 603# Test for issue #4647 'auto resolution mine-full fails on binary file' 604@Issue(4647) 605def automatic_binary_conflict_resolution(sbox): 606 "resolve -R --accept [base | mf | tf] binary file" 607 608 sbox.build() 609 wc_dir = sbox.wc_dir 610 611 # Some paths we'll care about 612 A_COPY_path = os.path.join(wc_dir, "A_COPY") 613 614 # Add a binary file to the project in revision 2. 615 theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read() 616 theta_path = sbox.ospath('A/theta') 617 svntest.main.file_write(theta_path, theta_contents, 'wb') 618 svntest.main.run_svn(None, 'add', theta_path) 619 svntest.main.run_svn(None, 'commit', '-m', 'log msg', wc_dir) 620 621 # Branch A to A_COPY in revision 3. 622 svntest.main.run_svn(None, 'copy', wc_dir + "/A", A_COPY_path) 623 svntest.main.run_svn(None, 'commit', '-m', 'log msg', wc_dir) 624 625 # Modify the binary file on trunk and in the branch, so that both versions 626 # differ. 627 theta_branch_path = sbox.ospath('A_COPY/theta') 628 svntest.main.file_append_binary(theta_path, theta_contents) 629 svntest.main.run_svn(None, 'commit', '-m', 'log msg', wc_dir) 630 svntest.main.file_append_binary(theta_branch_path, theta_contents) 631 svntest.main.file_append_binary(theta_branch_path, theta_contents) 632 svntest.main.run_svn(None, 'commit', '-m', 'log msg', wc_dir) 633 634 # Run an svn update now to prevent mixed-revision working copy [1:4] error. 635 svntest.main.run_svn(None, 'update', wc_dir) 636 637 638 def do_binary_conflicting_merge(): 639 svntest.actions.run_and_verify_svn(None, [], 640 'revert', '--recursive', A_COPY_path) 641 svntest.main.run_svn(None, 'merge', sbox.repo_url + "/A/theta", 642 wc_dir + "/A_COPY/theta") 643 644 # Test 'svn resolve -R --accept base' 645 # Regression until r1758160 646 do_binary_conflicting_merge() 647 svntest.actions.run_and_verify_resolve([theta_branch_path], 648 '-R', '--accept', 'base', 649 A_COPY_path) 650 651 # Test 'svn resolve -R --accept theirs-full' 652 do_binary_conflicting_merge() 653 svntest.actions.run_and_verify_resolve([theta_branch_path], 654 '-R', '--accept', 'tf', 655 A_COPY_path) 656 657 # Test 'svn resolve -R --accept working' 658 # Equivalent to 'svn resolved' 659 do_binary_conflicting_merge() 660 svntest.actions.run_and_verify_resolve([theta_branch_path], 661 '-R', '--accept', 'working', 662 A_COPY_path) 663 664 # Test 'svn resolve -R --accept mine-full' 665 # There is no '.mine' for binary file conflicts. Same handling as 'working' 666 do_binary_conflicting_merge() 667 svntest.actions.run_and_verify_resolve([theta_branch_path], 668 '-R', '--accept', 'mine-full', 669 A_COPY_path) 670 671######################################################################## 672# Run the tests 673 674# list all tests here, starting with None: 675test_list = [ None, 676 automatic_conflict_resolution, 677 prop_conflict_resolution, 678 auto_resolve_executable_file, 679 resolved_on_wc_root, 680 resolved_on_deleted_item, 681 theirs_conflict_in_subdir, 682 multi_range_merge_with_accept, 683 automatic_binary_conflict_resolution, 684 ] 685 686if __name__ == '__main__': 687 svntest.main.run_tests(test_list) 688 # NOTREACHED 689 690### End of file. 691