~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/tests/cmdline/svntest/actions.py

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
76
76
 
77
77
  # If there's no pristine repos, create one.
78
78
  if not os.path.exists(main.pristine_greek_repos_dir):
79
 
    main.create_repos(main.pristine_greek_repos_dir)
80
 
 
81
 
    # if this is dav, gives us access rights to import the greek tree.
82
 
    if main.is_ra_type_dav():
83
 
      authz_file = os.path.join(main.work_dir, "authz")
84
 
      main.file_write(authz_file, "[/]\n* = rw\n")
85
 
 
86
 
    # dump the greek tree to disk.
87
 
    main.greek_state.write_to_disk(main.greek_dump_dir)
88
 
 
89
 
    # import the greek tree, using l:foo/p:bar
90
 
    ### todo: svn should not be prompting for auth info when using
91
 
    ### repositories with no auth/auth requirements
92
 
    _, output, _ = main.run_svn(None, 'import', '-m',
93
 
                                'Log message for revision 1.',
94
 
                                main.greek_dump_dir,
95
 
                                main.pristine_greek_repos_url)
96
 
 
97
 
    # verify the printed output of 'svn import'.
98
 
    lastline = output.pop().strip()
99
 
    match = re.search("(Committed|Imported) revision [0-9]+.", lastline)
100
 
    if not match:
101
 
      logger.error("import did not succeed, while creating greek repos.")
102
 
      logger.error("The final line from 'svn import' was:")
103
 
      logger.error(lastline)
104
 
      sys.exit(1)
105
 
    output_tree = wc.State.from_commit(output)
106
 
 
107
 
    expected_output_tree = main.greek_state.copy(main.greek_dump_dir)
108
 
    expected_output_tree.tweak(verb='Adding',
109
 
                               contents=None)
110
 
 
111
 
    try:
112
 
      expected_output_tree.compare_and_display('output', output_tree)
113
 
    except tree.SVNTreeUnequal:
114
 
      verify.display_trees("ERROR:  output of import command is unexpected.",
115
 
                           "OUTPUT TREE",
116
 
                           expected_output_tree.old_tree(),
117
 
                           output_tree.old_tree())
118
 
      sys.exit(1)
 
79
    if main.options.fsfs_version is not None:
 
80
      main.unpack_greek_repos(main.pristine_greek_repos_dir)
 
81
    else:
 
82
      main.create_repos(main.pristine_greek_repos_dir)
 
83
 
 
84
      # if this is dav, gives us access rights to import the greek tree.
 
85
      if main.is_ra_type_dav():
 
86
        authz_file = os.path.join(main.work_dir, "authz")
 
87
        main.file_write(authz_file, "[/]\n* = rw\n")
 
88
 
 
89
      # dump the greek tree to disk.
 
90
      main.greek_state.write_to_disk(main.greek_dump_dir)
 
91
 
 
92
      # import the greek tree, using l:foo/p:bar
 
93
      ### todo: svn should not be prompting for auth info when using
 
94
      ### repositories with no auth/auth requirements
 
95
      _, output, _ = main.run_svn(None, 'import', '-m',
 
96
                                  'Log message for revision 1.',
 
97
                                  main.greek_dump_dir,
 
98
                                  main.pristine_greek_repos_url)
 
99
 
 
100
      # verify the printed output of 'svn import'.
 
101
      lastline = output.pop().strip()
 
102
      match = re.search("(Committed|Imported) revision [0-9]+.", lastline)
 
103
      if not match:
 
104
        logger.error("import did not succeed, while creating greek repos.")
 
105
        logger.error("The final line from 'svn import' was:")
 
106
        logger.error(lastline)
 
107
        sys.exit(1)
 
108
      output_tree = wc.State.from_commit(output)
 
109
 
 
110
      expected_output_tree = main.greek_state.copy(main.greek_dump_dir)
 
111
      expected_output_tree.tweak(verb='Adding',
 
112
                                 contents=None)
 
113
 
 
114
      try:
 
115
        expected_output_tree.compare_and_display('output', output_tree)
 
116
      except tree.SVNTreeUnequal:
 
117
        verify.display_trees("ERROR:  output of import command is unexpected.",
 
118
                             "OUTPUT TREE",
 
119
                             expected_output_tree.old_tree(),
 
120
                             output_tree.old_tree())
 
121
        sys.exit(1)
119
122
 
120
123
    # Finally, disallow any changes to the "pristine" repos.
121
124
    error_msg = "Don't modify the pristine repository"
126
129
 
127
130
######################################################################
128
131
 
129
 
def guarantee_empty_repository(path):
 
132
def guarantee_empty_repository(path, minor_version):
130
133
  """Guarantee that a local svn repository exists at PATH, containing
131
134
  nothing."""
132
135
 
136
139
 
137
140
  # create an empty repository at PATH.
138
141
  main.safe_rmtree(path)
139
 
  main.create_repos(path)
 
142
  main.create_repos(path, minor_version)
140
143
 
141
144
# Used by every test, so that they can run independently of  one
142
145
# another. Every time this routine is called, it recursively copies
153
156
 
154
157
  # copy the pristine repository to PATH.
155
158
  main.safe_rmtree(path)
156
 
  if main.copy_repos(main.pristine_greek_repos_dir, path, 1, 1, minor_version):
 
159
  if (main.options.fsfs_version is not None):
 
160
    failed = main.unpack_greek_repos(path)
 
161
  else:
 
162
    failed = main.copy_repos(main.pristine_greek_repos_dir,
 
163
                             path, 1, 1, minor_version)
 
164
  if failed:
157
165
    logger.error("copying repository failed.")
158
166
    sys.exit(1)
159
167
 
160
168
  # make the repos world-writeable, for mod_dav_svn's sake.
161
169
  main.chmod_tree(path, 0666, 0666)
162
170
 
 
171
  # give the repository a unique UUID
 
172
  run_and_verify_svnadmin([], [], 'setuuid', path)
163
173
 
164
 
def run_and_verify_atomic_ra_revprop_change(message,
165
 
                                            expected_stdout,
 
174
def run_and_verify_atomic_ra_revprop_change(expected_stdout,
166
175
                                            expected_stderr,
167
176
                                            expected_exit,
168
177
                                            url, revision, propname,
192
201
                                                          want_error)
193
202
  verify.verify_outputs("Unexpected output", out, err,
194
203
                        expected_stdout, expected_stderr)
195
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
204
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
196
205
  return exit_code, out, err
197
206
 
198
207
 
199
 
def run_and_verify_svnlook(message, expected_stdout,
 
208
def run_and_verify_svnlook(expected_stdout,
200
209
                           expected_stderr, *varargs):
201
210
  """Like run_and_verify_svnlook2, but the expected exit code is
202
211
  assumed to be 0 if no output is expected on stderr, and 1 otherwise."""
204
213
  expected_exit = 0
205
214
  if expected_stderr is not None and expected_stderr != []:
206
215
    expected_exit = 1
207
 
  return run_and_verify_svnlook2(message, expected_stdout, expected_stderr,
 
216
  return run_and_verify_svnlook2(expected_stdout, expected_stderr,
208
217
                                 expected_exit, *varargs)
209
218
 
210
 
def run_and_verify_svnlook2(message, expected_stdout, expected_stderr,
 
219
def run_and_verify_svnlook2(expected_stdout, expected_stderr,
211
220
                            expected_exit, *varargs):
212
221
  """Run svnlook command and check its output and exit code."""
213
222
 
214
223
  exit_code, out, err = main.run_svnlook(*varargs)
215
224
  verify.verify_outputs("Unexpected output", out, err,
216
225
                        expected_stdout, expected_stderr)
217
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
226
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
218
227
  return exit_code, out, err
219
228
 
220
229
 
221
 
def run_and_verify_svnadmin(message, expected_stdout,
 
230
def run_and_verify_svnadmin(expected_stdout,
222
231
                            expected_stderr, *varargs):
223
232
  """Like run_and_verify_svnadmin2, but the expected exit code is
224
233
  assumed to be 0 if no output is expected on stderr, and 1 otherwise."""
226
235
  expected_exit = 0
227
236
  if expected_stderr is not None and expected_stderr != []:
228
237
    expected_exit = 1
229
 
  return run_and_verify_svnadmin2(message, expected_stdout, expected_stderr,
 
238
  return run_and_verify_svnadmin2(expected_stdout, expected_stderr,
230
239
                                  expected_exit, *varargs)
231
240
 
232
 
def run_and_verify_svnadmin2(message, expected_stdout, expected_stderr,
 
241
def run_and_verify_svnadmin2(expected_stdout, expected_stderr,
233
242
                             expected_exit, *varargs):
234
243
  """Run svnadmin command and check its output and exit code."""
235
244
 
236
245
  exit_code, out, err = main.run_svnadmin(*varargs)
237
246
  verify.verify_outputs("Unexpected output", out, err,
238
247
                        expected_stdout, expected_stderr)
239
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
248
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
240
249
  return exit_code, out, err
241
250
 
242
251
 
243
 
def run_and_verify_svnversion(message, wc_dir, trail_url,
 
252
def run_and_verify_svnversion(wc_dir, trail_url,
244
253
                              expected_stdout, expected_stderr, *varargs):
245
254
  """like run_and_verify_svnversion2, but the expected exit code is
246
255
  assumed to be 0 if no output is expected on stderr, and 1 otherwise."""
248
257
  expected_exit = 0
249
258
  if expected_stderr is not None and expected_stderr != []:
250
259
    expected_exit = 1
251
 
  return run_and_verify_svnversion2(message, wc_dir, trail_url,
 
260
  return run_and_verify_svnversion2(wc_dir, trail_url,
252
261
                                    expected_stdout, expected_stderr,
253
262
                                    expected_exit, *varargs)
254
263
 
255
 
def run_and_verify_svnversion2(message, wc_dir, trail_url,
 
264
def run_and_verify_svnversion2(wc_dir, trail_url,
256
265
                               expected_stdout, expected_stderr,
257
266
                               expected_exit, *varargs):
258
267
  """Run svnversion command and check its output and exit code."""
264
273
 
265
274
  verify.verify_outputs("Unexpected output", out, err,
266
275
                        expected_stdout, expected_stderr)
267
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
276
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
268
277
  return exit_code, out, err
269
278
 
270
 
def run_and_verify_svn(message, expected_stdout, expected_stderr, *varargs):
 
279
def run_and_verify_svn(expected_stdout, expected_stderr, *varargs):
271
280
  """like run_and_verify_svn2, but the expected exit code is assumed to
272
281
  be 0 if no output is expected on stderr, and 1 otherwise."""
273
282
 
278
287
        expected_exit = 1
279
288
    elif expected_stderr != []:
280
289
      expected_exit = 1
281
 
  return run_and_verify_svn2(message, expected_stdout, expected_stderr,
 
290
  return run_and_verify_svn2(expected_stdout, expected_stderr,
282
291
                             expected_exit, *varargs)
283
292
 
284
 
def run_and_verify_svn2(message, expected_stdout, expected_stderr,
 
293
def run_and_verify_svn2(expected_stdout, expected_stderr,
285
294
                        expected_exit, *varargs):
286
295
  """Invoke main.run_svn() with *VARARGS. Return exit code as int; stdout,
287
296
  stderr as lists of lines (including line terminators).  For both
296
305
     - If it is already an instance of ExpectedOutput
297
306
       (e.g. UnorderedOutput), leave it alone.
298
307
 
299
 
  ...and invoke compare_and_display_lines() on MESSAGE, a label based
 
308
  ...and invoke compare_and_display_lines() on a label based
300
309
  on the name of the stream being compared (e.g. STDOUT), the
301
310
  ExpectedOutput instance, and the actual output.
302
311
 
318
327
    want_err = True
319
328
 
320
329
  exit_code, out, err = main.run_svn(want_err, *varargs)
321
 
  verify.verify_outputs(message, out, err, expected_stdout, expected_stderr)
322
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
330
  verify.verify_outputs("Unexpected output", out, err,
 
331
                        expected_stdout, expected_stderr)
 
332
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
323
333
  return exit_code, out, err
324
334
 
325
335
def run_and_verify_load(repo_dir, dump_file_content,
328
338
  if not isinstance(dump_file_content, list):
329
339
    raise TypeError("dump_file_content argument should have list type")
330
340
  expected_stderr = []
 
341
  args = ()
331
342
  if bypass_prop_validation:
332
 
    exit_code, output, errput = main.run_command_stdin(
333
 
      main.svnadmin_binary, expected_stderr, 0, True, dump_file_content,
334
 
      'load', '--force-uuid', '--quiet', '--bypass-prop-validation', repo_dir)
335
 
  else:
336
 
    exit_code, output, errput = main.run_command_stdin(
337
 
      main.svnadmin_binary, expected_stderr, 0, True, dump_file_content,
338
 
      'load', '--force-uuid', '--quiet', repo_dir)
339
 
 
340
 
  verify.verify_outputs("Unexpected stderr output", None, errput,
341
 
                        None, expected_stderr)
 
343
    args += ('--bypass-prop-validation',)
 
344
  main.run_command_stdin(
 
345
    main.svnadmin_binary, expected_stderr, 0, True, dump_file_content,
 
346
    'load', '--force-uuid', '--quiet', repo_dir, *args)
342
347
 
343
348
 
344
349
def run_and_verify_dump(repo_dir, deltas=False):
345
350
  "Runs 'svnadmin dump' and reports any errors, returning the dump content."
 
351
  args = ()
346
352
  if deltas:
347
 
    exit_code, output, errput = main.run_svnadmin('dump', '--deltas',
348
 
                                                  repo_dir)
349
 
  else:
350
 
    exit_code, output, errput = main.run_svnadmin('dump', repo_dir)
351
 
  verify.verify_outputs("Missing expected output(s)", output, errput,
352
 
                        verify.AnyOutput, verify.AnyOutput)
 
353
    args += ('--deltas',)
 
354
  exit_code, output, errput = run_and_verify_svnadmin(
 
355
                                verify.AnyOutput, [],
 
356
                                'dump', '--quiet', repo_dir, *args)
353
357
  return output
354
358
 
355
359
 
364
368
  if sys.platform == 'win32':
365
369
    err = map(lambda x : x.replace('\r\n', '\n'), err)
366
370
 
 
371
  # Ignore "consider upgrade" warnings to allow regression tests to pass
 
372
  # when run against a 1.6 mod_dav_svn.
367
373
  for index, line in enumerate(err[:]):
368
374
    if re.search("warning: W200007", line):
369
375
      del err[index]
374
380
  return output
375
381
 
376
382
 
377
 
def run_and_verify_svnmucc(message, expected_stdout, expected_stderr,
 
383
def run_and_verify_svnmucc(expected_stdout, expected_stderr,
378
384
                           *varargs):
379
385
  """Run svnmucc command and check its output"""
380
386
 
381
387
  expected_exit = 0
382
388
  if expected_stderr is not None and expected_stderr != []:
383
389
    expected_exit = 1
384
 
  return run_and_verify_svnmucc2(message, expected_stdout, expected_stderr,
 
390
  return run_and_verify_svnmucc2(expected_stdout, expected_stderr,
385
391
                                 expected_exit, *varargs)
386
392
 
387
 
def run_and_verify_svnmucc2(message, expected_stdout, expected_stderr,
 
393
def run_and_verify_svnmucc2(expected_stdout, expected_stderr,
388
394
                            expected_exit, *varargs):
389
395
  """Run svnmucc command and check its output and exit code."""
390
396
 
391
397
  exit_code, out, err = main.run_svnmucc(*varargs)
392
398
  verify.verify_outputs("Unexpected output", out, err,
393
399
                        expected_stdout, expected_stderr)
394
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
400
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
 
401
  return exit_code, out, err
 
402
 
 
403
 
 
404
def run_and_verify_svnsync(expected_stdout, expected_stderr,
 
405
                           *varargs):
 
406
  """Run svnsync command and check its output"""
 
407
 
 
408
  expected_exit = 0
 
409
  if expected_stderr is not None and expected_stderr != []:
 
410
    expected_exit = 1
 
411
  return run_and_verify_svnsync2(expected_stdout, expected_stderr,
 
412
                                 expected_exit, *varargs)
 
413
 
 
414
def run_and_verify_svnsync2(expected_stdout, expected_stderr,
 
415
                            expected_exit, *varargs):
 
416
  """Run svnmucc command and check its output and exit code."""
 
417
 
 
418
  exit_code, out, err = main.run_svnsync(*varargs)
 
419
 
 
420
  # Ignore "consider upgrade" warnings to allow regression tests to pass
 
421
  # when run against a 1.6 mod_dav_svn.
 
422
  for index, line in enumerate(err[:]):
 
423
    if re.search("warning: W200007", line):
 
424
      del err[index]
 
425
 
 
426
  verify.verify_outputs("Unexpected output", out, err,
 
427
                        expected_stdout, expected_stderr)
 
428
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
395
429
  return exit_code, out, err
396
430
 
397
431
 
398
432
def load_repo(sbox, dumpfile_path = None, dump_str = None,
399
 
              bypass_prop_validation = False):
 
433
              bypass_prop_validation = False,create_wc=True):
400
434
  "Loads the dumpfile into sbox"
401
435
  if not dump_str:
402
436
    dump_str = open(dumpfile_path, "rb").read()
409
443
  # Load the mergetracking dumpfile into the repos, and check it out the repo
410
444
  run_and_verify_load(sbox.repo_dir, dump_str.splitlines(True),
411
445
                      bypass_prop_validation)
412
 
  run_and_verify_svn(None, None, [], "co", sbox.repo_url, sbox.wc_dir)
 
446
  if create_wc:
 
447
    run_and_verify_svn(None, [], "co", sbox.repo_url, sbox.wc_dir)
413
448
 
414
449
  return dump_str
415
450
 
421
456
                                     % (rev),
422
457
                                     "no-op update")
423
458
 
424
 
def run_and_verify_svnauthz(message, expected_stdout, expected_stderr,
 
459
def run_and_verify_svnauthz(expected_stdout, expected_stderr,
425
460
                            expected_exit, compat_mode, *varargs):
426
461
  """Run svnauthz command and check its output and exit code.
427
462
     If COMPAT_MODE is True then run the command in pre-1.8
434
469
 
435
470
  verify.verify_outputs("Unexpected output", out, err,
436
471
                        expected_stdout, expected_stderr)
437
 
  verify.verify_exit_code(message, exit_code, expected_exit)
 
472
  verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
438
473
  return exit_code, out, err
439
474
 
440
475
######################################################################
446
481
#
447
482
 
448
483
 
449
 
def run_and_verify_checkout2(do_remove,
450
 
                             URL, wc_dir_name, output_tree, disk_tree,
451
 
                             singleton_handler_a = None,
452
 
                             a_baton = None,
453
 
                             singleton_handler_b = None,
454
 
                             b_baton = None,
455
 
                             *args):
 
484
def run_and_verify_checkout(URL, wc_dir_name, output_tree, disk_tree,
 
485
                            expected_stderr=[],
 
486
                            *args, **kw):
456
487
  """Checkout the URL into a new directory WC_DIR_NAME. *ARGS are any
457
488
  extra optional args to the checkout subcommand.
458
489
 
469
500
  if isinstance(output_tree, wc.State):
470
501
    output_tree = output_tree.old_tree()
471
502
 
472
 
  # Remove dir if it's already there, unless this is a forced checkout.
473
 
  # In that case assume we want to test a forced checkout's toleration
474
 
  # of obstructing paths.
475
 
  if do_remove:
476
 
    main.safe_rmtree(wc_dir_name)
477
 
 
478
503
  # Checkout and make a tree of the output, using l:foo/p:bar
479
504
  ### todo: svn should not be prompting for auth info when using
480
505
  ### repositories with no auth/auth requirements
481
 
  exit_code, output, errput = main.run_svn(None, 'co',
482
 
                                           URL, wc_dir_name, *args)
 
506
  exit_code, output, errput = run_and_verify_svn(None, expected_stderr,
 
507
                                                 'co', URL, wc_dir_name,
 
508
                                                 *args)
483
509
  actual = tree.build_tree_from_checkout(output)
484
510
 
485
511
  # Verify actual output against expected output.
490
516
    raise
491
517
 
492
518
  if disk_tree:
493
 
    verify_disk(wc_dir_name, disk_tree, False,
494
 
                singleton_handler_a, a_baton,
495
 
                singleton_handler_b, b_baton)
496
 
 
497
 
def run_and_verify_checkout(URL, wc_dir_name, output_tree, disk_tree,
498
 
                            singleton_handler_a = None,
499
 
                            a_baton = None,
500
 
                            singleton_handler_b = None,
501
 
                            b_baton = None,
502
 
                            *args):
503
 
  """Same as run_and_verify_checkout2(), but without the DO_REMOVE arg.
504
 
  WC_DIR_NAME is deleted if present unless the '--force' option is passed
505
 
  in *ARGS."""
506
 
 
507
 
 
508
 
  # Remove dir if it's already there, unless this is a forced checkout.
509
 
  # In that case assume we want to test a forced checkout's toleration
510
 
  # of obstructing paths.
511
 
  return run_and_verify_checkout2(('--force' not in args),
512
 
                                  URL, wc_dir_name, output_tree, disk_tree,
513
 
                                  singleton_handler_a,
514
 
                                  a_baton,
515
 
                                  singleton_handler_b,
516
 
                                  b_baton,
517
 
                                  *args)
518
 
 
 
519
    verify_disk(wc_dir_name, disk_tree, False, **kw)
519
520
 
520
521
def run_and_verify_export(URL, export_dir_name, output_tree, disk_tree,
521
522
                          *args):
561
562
# run_and_verify_log_xml
562
563
 
563
564
class LogEntry:
564
 
  def __init__(self, revision, changed_paths=None, revprops=None):
 
565
  def __init__(self, revision, attributes=None,
 
566
               changed_paths=None, revprops=None):
565
567
    self.revision = revision
 
568
    if attributes == None:
 
569
      self.attributes = {}
 
570
    else:
 
571
      self.attributes = attributes
566
572
    if changed_paths == None:
567
573
      self.changed_paths = {}
568
574
    else:
572
578
    else:
573
579
      self.revprops = revprops
574
580
 
 
581
  def assert_log_attrs(self, attributes):
 
582
    """Assert that attributes is the same as this entry's attributes
 
583
    Raises svntest.Failure if not.
 
584
    """
 
585
    if self.attributes != attributes:
 
586
      raise Failure('\n' + '\n'.join(difflib.ndiff(
 
587
            pprint.pformat(attributes).splitlines(),
 
588
            pprint.pformat(self.attributes).splitlines())))
 
589
 
575
590
  def assert_changed_paths(self, changed_paths):
576
591
    """Assert that changed_paths is the same as this entry's changed_paths
577
592
    Raises svntest.Failure if not.
649
664
 
650
665
  # element handlers
651
666
  def logentry_start(self, attrs):
652
 
    self.entries.append(LogEntry(int(attrs['revision'])))
 
667
    self.entries.append(LogEntry(int(attrs['revision']), attrs))
653
668
  def author_end(self):
654
669
    self.svn_prop('author')
655
670
  def msg_end(self):
669
684
    self.entries[-1].changed_paths[self.use_cdata()] = [{'kind': self.kind,
670
685
                                                         'action': self.action}]
671
686
 
672
 
def run_and_verify_log_xml(message=None, expected_paths=None,
673
 
                           expected_revprops=None, expected_stdout=None,
674
 
                           expected_stderr=None, args=[]):
 
687
def run_and_verify_log_xml(expected_log_attrs=None,
 
688
                           expected_paths=None, expected_revprops=None,
 
689
                           expected_stdout=None, expected_stderr=None,
 
690
                           args=[]):
675
691
  """Call run_and_verify_svn with log --xml and args (optional) as command
676
 
  arguments, and pass along message, expected_stdout, and expected_stderr.
677
 
 
678
 
  If message is None, pass the svn log command as message.
 
692
  arguments, and pass along expected_stdout, and expected_stderr.
679
693
 
680
694
  expected_paths checking is not yet implemented.
681
695
 
 
696
  expected_log_attrs is an optional list of dicts, compared to each revisions's
 
697
  logentry attributes.  The list must be in the same order the log entries
 
698
  come in.
 
699
 
682
700
  expected_revprops is an optional list of dicts, compared to each
683
701
  revision's revprops.  The list must be in the same order the log entries
684
702
  come in.  Any svn:date revprops in the dicts must be '' in order to
687
705
  expected_paths and expected_revprops are ignored if expected_stdout or
688
706
  expected_stderr is specified.
689
707
  """
690
 
  if message == None:
691
 
    message = ' '.join(args)
 
708
  message = ' '.join(args)
692
709
 
693
710
  # We'll parse the output unless the caller specifies expected_stderr or
694
711
  # expected_stdout for run_and_verify_svn.
705
722
    log_args.append('-v')
706
723
 
707
724
  (exit_code, stdout, stderr) = run_and_verify_svn(
708
 
    message, expected_stdout, expected_stderr,
 
725
    expected_stdout, expected_stderr,
709
726
    'log', '--xml', *log_args)
710
727
  if not parse:
711
728
    return
717
734
      entry.assert_revprops(expected_revprops[index])
718
735
    if expected_paths != None:
719
736
      entry.assert_changed_paths(expected_paths[index])
 
737
    if expected_log_attrs != None:
 
738
      entry.assert_log_attrs(expected_log_attrs[index])
720
739
 
721
740
 
722
741
def verify_update(actual_output,
728
747
                  elision_output_tree,
729
748
                  disk_tree,
730
749
                  status_tree,
731
 
                  singleton_handler_a=None,
732
 
                  a_baton=None,
733
 
                  singleton_handler_b=None,
734
 
                  b_baton=None,
735
 
                  check_props=False):
 
750
                  check_props=False,
 
751
                  extra_files=None):
736
752
  """Verify update of WC_DIR_NAME.
737
753
 
738
754
  The subcommand output (found in ACTUAL_OUTPUT, ACTUAL_MERGEINFO_OUTPUT,
795
811
  # Create a tree by scanning the working copy, and verify it
796
812
  if disk_tree:
797
813
    verify_disk(wc_dir_name, disk_tree, check_props,
798
 
                singleton_handler_a, a_baton,
799
 
                singleton_handler_b, b_baton)
 
814
                extra_files=extra_files)
800
815
 
801
816
  # Verify via 'status' command too, if possible.
802
817
  if status_tree:
804
819
 
805
820
 
806
821
def verify_disk(wc_dir_name, disk_tree, check_props=False,
807
 
                singleton_handler_a = None, a_baton = None,
808
 
                singleton_handler_b = None, b_baton = None):
 
822
                extra_files=None):
809
823
  """Verify WC_DIR_NAME against DISK_TREE.  If CHECK_PROPS is set,
810
824
  the comparison will examin props.  Returns if successful, raises on
811
825
  failure."""
812
826
 
 
827
  singleton_handler_a = None
 
828
  a_baton = None,
 
829
  singleton_handler_b = None
 
830
  b_baton = None
 
831
  done_a = None
 
832
 
 
833
  if extra_files:
 
834
    singleton_handler_a = svntest.tree.detect_conflict_files
 
835
    done_a = svntest.tree.detect_conflict_files_done
 
836
    a_baton = extra_files
 
837
 
813
838
  if isinstance(disk_tree, wc.State):
814
839
    disk_tree = disk_tree.old_tree()
815
840
 
823
848
    _log_tree_state("ACTUAL DISK TREE:", actual_disk)
824
849
    raise
825
850
 
826
 
 
 
851
  if done_a:
 
852
    done_a(a_baton)
827
853
 
828
854
 
829
855
def run_and_verify_update(wc_dir_name,
830
856
                          output_tree, disk_tree, status_tree,
831
 
                          error_re_string = None,
832
 
                          singleton_handler_a = None,
833
 
                          a_baton = None,
834
 
                          singleton_handler_b = None,
835
 
                          b_baton = None,
 
857
                          expected_stderr=[],
836
858
                          check_props = False,
837
 
                          *args):
 
859
                          *args, **kw):
838
860
 
839
861
  """Update WC_DIR_NAME.  *ARGS are any extra optional args to the
840
862
  update subcommand.  NOTE: If *ARGS is specified at all, explicit
852
874
  None, the 'svn status' output will be verified against STATUS_TREE.
853
875
  (This is a good way to check that revision numbers were bumped.)
854
876
 
855
 
  For the DISK_TREE verification, SINGLETON_HANDLER_A and
856
 
  SINGLETON_HANDLER_B will be passed to tree.compare_trees -- see that
857
 
  function's doc string for more details.
858
 
 
859
877
  If CHECK_PROPS is set, then disk comparison will examine props.
860
878
 
861
879
  Return if successful, raise on failure."""
862
880
 
863
881
  # Update and make a tree of the output.
864
 
  if len(args):
865
 
    exit_code, output, errput = main.run_svn(error_re_string, 'up', *args)
866
 
  else:
867
 
    exit_code, output, errput = main.run_svn(error_re_string,
868
 
                                             'up', wc_dir_name,
869
 
                                             *args)
 
882
  if len(args) == 0:
 
883
    args = (wc_dir_name,)
870
884
 
871
 
  if error_re_string:
872
 
    rm = re.compile(error_re_string)
873
 
    match = None
874
 
    for line in errput:
875
 
      match = rm.search(line)
876
 
      if match:
877
 
        break
878
 
    if not match:
879
 
      raise main.SVNUnmatchedError
 
885
  exit_code, output, errput = run_and_verify_svn(None, expected_stderr, 'up', *args)
880
886
 
881
887
  actual = wc.State.from_checkout(output)
882
888
  verify_update(actual, None, None, wc_dir_name,
883
889
                output_tree, None, None, disk_tree, status_tree,
884
 
                singleton_handler_a, a_baton,
885
 
                singleton_handler_b, b_baton,
886
 
                check_props)
 
890
                check_props, **kw)
887
891
 
888
892
 
889
893
def run_and_parse_info(*args):
967
971
 
968
972
    for actual, expected in zip(actual_infos, expected_infos):
969
973
      # compare dicts
 
974
      path = actual['Path']
970
975
      for key, value in expected.items():
971
976
        assert ':' not in key # caller passed impossible expectations?
972
977
        if value is None and key in actual:
973
 
          raise main.SVNLineUnequal("Found unexpected key '%s' with value '%s'"
974
 
                                    % (key, actual[key]))
 
978
          raise main.SVNLineUnequal("On '%s': Found unexpected key '%s'\n  Value '%s'"
 
979
                                    % (path, key, actual[key]))
975
980
        if value is not None and key not in actual:
976
 
          raise main.SVNLineUnequal("Expected key '%s' (with value '%s') "
977
 
                                    "not found" % (key, value))
 
981
          raise main.SVNLineUnequal("On '%s': Expected key '%s' not found\n Expected value '%s'"
 
982
                                    % (path, key, value))
978
983
        if value is not None and not re.match(value, actual[key]):
979
 
          raise verify.SVNUnexpectedStdout("Values of key '%s' don't match:\n"
 
984
          raise verify.SVNUnexpectedStdout("On '%s': Values of key '%s' don't match:\n"
980
985
                                           "  Expected: '%s' (regex)\n"
981
986
                                           "  Found:    '%s' (string)\n"
982
 
                                           % (key, value, actual[key]))
 
987
                                           % (path, key, value, actual[key]))
983
988
 
984
989
  except:
985
990
    sys.stderr.write("Bad 'svn info' output:\n"
993
998
                         mergeinfo_output_tree,
994
999
                         elision_output_tree,
995
1000
                         disk_tree, status_tree, skip_tree,
996
 
                         error_re_string = None,
997
 
                         singleton_handler_a = None,
998
 
                         a_baton = None,
999
 
                         singleton_handler_b = None,
1000
 
                         b_baton = None,
 
1001
                         expected_stderr = [],
1001
1002
                         check_props = False,
1002
1003
                         dry_run = True,
1003
 
                         *args):
 
1004
                         *args, **kw):
1004
1005
  """Run 'svn merge URL1@REV1 URL2@REV2 DIR' if URL2 is not None
1005
1006
  (for a three-way merge between URLs and WC).
1006
1007
 
1007
1008
  If URL2 is None, run 'svn merge -rREV1:REV2 URL1 DIR'.  If both REV1
1008
1009
  and REV2 are None, leave off the '-r' argument.
1009
1010
 
1010
 
  If ERROR_RE_STRING, the merge must exit with error, and the error
1011
 
  message must match regular expression ERROR_RE_STRING.
1012
 
 
1013
 
  Else if ERROR_RE_STRING is None, then:
1014
 
 
1015
1011
  The subcommand output will be verified against OUTPUT_TREE.  Output
1016
1012
  related to mergeinfo notifications will be verified against
1017
1013
  MERGEINFO_OUTPUT_TREE if that is not None.  Output related to mergeinfo
1051
1047
    pre_disk = tree.build_tree_from_wc(dir)
1052
1048
    dry_run_command = merge_command + ('--dry-run',)
1053
1049
    dry_run_command = dry_run_command + args
1054
 
    exit_code, out_dry, err_dry = main.run_svn(error_re_string,
1055
 
                                               *dry_run_command)
 
1050
    exit_code, out_dry, err_dry = run_and_verify_svn(None, expected_stderr,
 
1051
                                                     *dry_run_command)
1056
1052
    post_disk = tree.build_tree_from_wc(dir)
1057
1053
    try:
1058
1054
      tree.compare_trees("disk", post_disk, pre_disk)
1065
1061
 
1066
1062
  # Update and make a tree of the output.
1067
1063
  merge_command = merge_command + args
1068
 
  exit_code, out, err = main.run_svn(error_re_string, *merge_command)
1069
 
 
1070
 
  if error_re_string:
1071
 
    if not error_re_string.startswith(".*"):
1072
 
      error_re_string = ".*(" + error_re_string + ")"
1073
 
    expected_err = verify.RegexOutput(error_re_string, match_all=False)
1074
 
    verify.verify_outputs(None, None, err, None, expected_err)
1075
 
    return
1076
 
  elif err:
1077
 
    raise verify.SVNUnexpectedStderr(err)
 
1064
  exit_code, out, err = run_and_verify_svn(None, expected_stderr, *merge_command)
1078
1065
 
1079
1066
  # Split the output into that related to application of the actual diff
1080
1067
  # and that related to the recording of mergeinfo describing the merge.
1163
1150
  verify_update(actual_diff, actual_mergeinfo, actual_elision, dir,
1164
1151
                output_tree, mergeinfo_output_tree, elision_output_tree,
1165
1152
                disk_tree, status_tree,
1166
 
                singleton_handler_a, a_baton,
1167
 
                singleton_handler_b, b_baton,
1168
 
                check_props)
 
1153
                check_props, **kw)
1169
1154
 
1170
1155
 
1171
1156
def run_and_verify_patch(dir, patch_path,
1173
1158
                         error_re_string=None,
1174
1159
                         check_props=False,
1175
1160
                         dry_run=True,
1176
 
                         *args):
 
1161
                         *args, **kw):
1177
1162
  """Run 'svn patch patch_path DIR'.
1178
1163
 
1179
1164
  If ERROR_RE_STRING, 'svn patch' must exit with error, and the error
1265
1250
 
1266
1251
  verify_update(mytree, None, None, dir,
1267
1252
                output_tree, None, None, disk_tree, status_tree,
1268
 
                check_props=check_props)
 
1253
                check_props=check_props, **kw)
1269
1254
 
1270
1255
 
1271
1256
def run_and_verify_mergeinfo(error_re_string = None,
1308
1293
                          wc_target,
1309
1294
                          switch_url,
1310
1295
                          output_tree, disk_tree, status_tree,
1311
 
                          error_re_string = None,
1312
 
                          singleton_handler_a = None,
1313
 
                          a_baton = None,
1314
 
                          singleton_handler_b = None,
1315
 
                          b_baton = None,
 
1296
                          expected_stderr = [],
1316
1297
                          check_props = False,
1317
 
                          *args):
 
1298
                          *args, **kw):
1318
1299
 
1319
1300
  """Switch WC_TARGET (in working copy dir WC_DIR_NAME) to SWITCH_URL.
1320
1301
 
1321
 
  If ERROR_RE_STRING, the switch must exit with error, and the error
1322
 
  message must match regular expression ERROR_RE_STRING.
1323
 
 
1324
 
  Else if ERROR_RE_STRING is None, then:
1325
 
 
1326
1302
  The subcommand output will be verified against OUTPUT_TREE, and the
1327
1303
  working copy itself will be verified against DISK_TREE.  If optional
1328
1304
  STATUS_TREE is given, then 'svn status' output will be
1329
1305
  compared.  (This is a good way to check that revision numbers were
1330
1306
  bumped.)
1331
1307
 
1332
 
  For the DISK_TREE verification, SINGLETON_HANDLER_A and
1333
 
  SINGLETON_HANDLER_B will be passed to tree.compare_trees -- see that
1334
 
  function's doc string for more details.
1335
 
 
1336
1308
  If CHECK_PROPS is set, then disk comparison will examine props.
1337
1309
 
1338
1310
  Return if successful, raise on failure."""
1339
1311
 
1340
1312
  # Update and make a tree of the output.
1341
 
  exit_code, output, errput = main.run_svn(error_re_string, 'switch',
1342
 
                                           switch_url, wc_target, *args)
1343
 
 
1344
 
  if error_re_string:
1345
 
    if not error_re_string.startswith(".*"):
1346
 
      error_re_string = ".*(" + error_re_string + ")"
1347
 
    expected_err = verify.RegexOutput(error_re_string, match_all=False)
1348
 
    verify.verify_outputs(None, None, errput, None, expected_err)
1349
 
  elif errput:
1350
 
    raise verify.SVNUnexpectedStderr(err)
1351
 
 
 
1313
  exit_code, output, errput = run_and_verify_svn(None, expected_stderr,
 
1314
                                                 'switch', switch_url,
 
1315
                                                 wc_target, *args)
1352
1316
  actual = wc.State.from_checkout(output)
1353
1317
 
1354
1318
  verify_update(actual, None, None, wc_dir_name,
1355
1319
                output_tree, None, None, disk_tree, status_tree,
1356
 
                singleton_handler_a, a_baton,
1357
 
                singleton_handler_b, b_baton,
1358
 
                check_props)
 
1320
                check_props, **kw)
1359
1321
 
1360
1322
def process_output_for_commit(output, error_re_string):
1361
1323
  """Helper for run_and_verify_commit(), also used in the factory."""
1403
1365
 
1404
1366
 
1405
1367
def run_and_verify_commit(wc_dir_name, output_tree, status_tree,
1406
 
                          error_re_string = None,
 
1368
                          expected_stderr=[],
1407
1369
                          *args):
1408
1370
  """Commit and verify results within working copy WC_DIR_NAME,
1409
1371
  sending ARGS to the commit subcommand.
1413
1375
  be compared.  (This is a good way to check that revision numbers
1414
1376
  were bumped.)
1415
1377
 
1416
 
  If ERROR_RE_STRING is None, the commit must not exit with error.  If
1417
 
  ERROR_RE_STRING is a string, the commit must exit with error, and
1418
 
  the error message must match regular expression ERROR_RE_STRING.
 
1378
  EXPECTED_STDERR is handled as in run_and_verify_svn()
1419
1379
 
1420
1380
  Return if successful, raise on failure."""
1421
1381
 
1423
1383
    output_tree = output_tree.old_tree()
1424
1384
 
1425
1385
  # Commit.
 
1386
  if len(args) == 0:
 
1387
    args = (wc_dir_name,)
1426
1388
  if '-m' not in args and '-F' not in args:
1427
1389
    args = list(args) + ['-m', 'log msg']
1428
 
  exit_code, output, errput = main.run_svn(error_re_string, 'ci',
1429
 
                                           *args)
1430
 
 
1431
 
  if error_re_string:
1432
 
    if not error_re_string.startswith(".*"):
1433
 
      error_re_string = ".*(" + error_re_string + ")"
1434
 
    expected_err = verify.RegexOutput(error_re_string, match_all=False)
1435
 
    verify.verify_outputs(None, None, errput, None, expected_err)
1436
 
 
1437
 
  # Else not expecting error:
 
1390
  exit_code, output, errput = run_and_verify_svn(None, expected_stderr,
 
1391
                                                 'ci', *args)
1438
1392
 
1439
1393
  # Convert the output into a tree.
1440
 
  output = process_output_for_commit(output, error_re_string)
 
1394
  output = process_output_for_commit(output, expected_stderr)
1441
1395
  actual = tree.build_tree_from_commit(output)
1442
1396
 
1443
1397
  # Verify actual output against expected output.
1457
1411
 
1458
1412
# This function always passes '-q' to the status command, which
1459
1413
# suppresses the printing of any unversioned or nonexistent items.
1460
 
def run_and_verify_status(wc_dir_name, status_tree,
1461
 
                          singleton_handler_a = None,
1462
 
                          a_baton = None,
1463
 
                          singleton_handler_b = None,
1464
 
                          b_baton = None):
 
1414
def run_and_verify_status(wc_dir_name, status_tree, no_entries=False):
1465
1415
  """Run 'status' on WC_DIR_NAME and compare it with the
1466
 
  expected STATUS_TREE.  SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will
1467
 
  be passed to tree.compare_trees - see that function's doc string for
1468
 
  more details.
 
1416
  expected STATUS_TREE.
1469
1417
  Returns on success, raises on failure."""
1470
1418
 
 
1419
  if not isinstance(status_tree, wc.State):
 
1420
    raise TypeError('wc.State tree expected')
 
1421
 
1471
1422
  exit_code, output, errput = main.run_svn(None, 'status', '-v', '-u', '-q',
1472
1423
                                           wc_dir_name)
1473
1424
 
1474
 
  actual_status = svntest.wc.State.from_status(output)
 
1425
  actual_status = svntest.wc.State.from_status(output, wc_dir=wc_dir_name)
1475
1426
 
1476
1427
  # Verify actual output against expected output.
1477
 
  if isinstance(status_tree, wc.State):
1478
 
    try:
1479
 
      status_tree.compare_and_display('status', actual_status)
1480
 
    except tree.SVNTreeError:
1481
 
      _log_tree_state("ACTUAL STATUS TREE:", actual_status.old_tree(),
1482
 
                                             wc_dir_name)
1483
 
      raise
1484
 
  else:
1485
 
    actual_status = actual_status.old_tree()
1486
 
    try:
1487
 
      tree.compare_trees("status", actual_status, status_tree,
1488
 
                         singleton_handler_a, a_baton,
1489
 
                         singleton_handler_b, b_baton)
1490
 
    except tree.SVNTreeError:
1491
 
      verify.display_trees(None, 'STATUS OUTPUT TREE', status_tree, actual_status)
1492
 
      _log_tree_state("ACTUAL STATUS TREE:", actual_status, wc_dir_name)
1493
 
      raise
 
1428
  try:
 
1429
    status_tree.compare_and_display('status', actual_status)
 
1430
  except tree.SVNTreeError:
 
1431
    _log_tree_state("ACTUAL STATUS TREE:", actual_status.old_tree(),
 
1432
                                           wc_dir_name)
 
1433
    raise
 
1434
 
 
1435
  if no_entries:
 
1436
    return
1494
1437
 
1495
1438
  # if we have an output State, and we can/are-allowed to create an
1496
1439
  # entries-based State, then compare the two.
1497
 
  if isinstance(status_tree, wc.State):
1498
 
    actual_entries = wc.State.from_entries(wc_dir_name)
1499
 
    if actual_entries:
1500
 
      tweaked = status_tree.copy()
1501
 
      tweaked.tweak_for_entries_compare()
1502
 
      try:
1503
 
        tweaked.compare_and_display('entries', actual_entries)
1504
 
      except tree.SVNTreeUnequal:
1505
 
        ### do something more
1506
 
        raise
 
1440
  actual_entries = wc.State.from_entries(wc_dir_name)
 
1441
  if actual_entries:
 
1442
    tweaked = status_tree.copy()
 
1443
    tweaked.tweak_for_entries_compare()
 
1444
    try:
 
1445
      tweaked.compare_and_display('entries', actual_entries)
 
1446
    except tree.SVNTreeUnequal:
 
1447
      ### do something more
 
1448
      _log_tree_state("ACTUAL ENTRY TREE:", actual_entries.old_tree(),
 
1449
                                           wc_dir_name)
 
1450
      raise
1507
1451
 
1508
1452
 
1509
1453
# A variant of previous func, but doesn't pass '-q'.  This allows us
1513
1457
  expected STATUS_TREE.
1514
1458
  Returns on success, raises on failure."""
1515
1459
 
 
1460
  if not isinstance(status_tree, wc.State):
 
1461
    raise TypeError('wc.State tree expected')
 
1462
 
1516
1463
  exit_code, output, errput = main.run_svn(None, 'status', '-v',
1517
1464
                                           '-u', wc_dir_name)
1518
1465
 
1519
 
  actual_status = svntest.wc.State.from_status(output)
 
1466
  actual_status = svntest.wc.State.from_status(output, wc_dir=wc_dir_name)
1520
1467
 
1521
1468
  # Verify actual output against expected output.
1522
 
  if isinstance(status_tree, wc.State):
1523
 
    try:
1524
 
      status_tree.compare_and_display('unquiet status', actual_status)
1525
 
    except tree.SVNTreeError:
1526
 
      _log_tree_state("ACTUAL STATUS TREE:",
1527
 
                      actual_status.normalize().old_tree(), wc_dir_name)
1528
 
      raise
1529
 
  else:
1530
 
    actual_status = actual_status.old_tree()
1531
 
    try:
1532
 
      tree.compare_trees("UNQUIET STATUS", actual_status, status_tree)
1533
 
    except tree.SVNTreeError:
1534
 
      _log_tree_state("ACTUAL UNQUIET STATUS TREE:", actual_status,
1535
 
                                                     wc_dir_name)
1536
 
      raise
 
1469
  try:
 
1470
    status_tree.compare_and_display('unquiet status', actual_status)
 
1471
  except tree.SVNTreeError:
 
1472
    _log_tree_state("ACTUAL STATUS TREE:",
 
1473
                    actual_status.normalize().old_tree(), wc_dir_name)
 
1474
    raise
1537
1475
 
1538
1476
def run_and_verify_status_xml(expected_entries = [],
1539
1477
                              *args):
1542
1480
  EXPECTED_ENTRIES.
1543
1481
  """
1544
1482
 
1545
 
  exit_code, output, errput = run_and_verify_svn(None, None, [],
 
1483
  exit_code, output, errput = run_and_verify_svn(None, [],
1546
1484
                                                 'status', '--xml', *args)
1547
1485
 
1548
1486
  if len(errput) > 0:
1614
1552
 
1615
1553
  if (propname):
1616
1554
    exit_code, output, errput = svntest.actions.run_and_verify_svn(
1617
 
      None, None, [], 'propget', propname, '--xml',
 
1555
      None, [], 'propget', propname, '--xml',
1618
1556
      '--show-inherited-props', path_or_url, *args)
1619
1557
  else:
1620
1558
    exit_code, output, errput = svntest.actions.run_and_verify_svn(
1621
 
      None, None, [], 'proplist', '-v', '--xml', '--show-inherited-props',
 
1559
      None, [], 'proplist', '-v', '--xml', '--show-inherited-props',
1622
1560
      path_or_url, *args)
1623
1561
 
1624
1562
  if len(errput) > 0:
1691
1629
  EXPECTED_PROPS and EXPECTED_KINDS. Returns on success, raises
1692
1630
  on failure."""
1693
1631
 
1694
 
  exit_code, output, errput = run_and_verify_svn(None, None, error_re_string,
 
1632
  exit_code, output, errput = run_and_verify_svn(None, error_re_string,
1695
1633
                                                 'diff', '--summarize',
1696
1634
                                                 '--xml', *args)
1697
1635
 
1775
1713
  comment = "Locking path:%s." % path
1776
1714
 
1777
1715
  # lock the path
1778
 
  run_and_verify_svn(None, ".*locked by user", [], 'lock',
 
1716
  run_and_verify_svn(".*locked by user", [], 'lock',
1779
1717
                     '--username', username,
1780
1718
                     '-m', comment, path)
1781
1719
 
1782
1720
  # Run info and check that we get the lock fields.
1783
 
  exit_code, output, err = run_and_verify_svn(None, None, [],
 
1721
  exit_code, output, err = run_and_verify_svn(None, [],
1784
1722
                                              'info','-R',
1785
1723
                                              path)
1786
1724
 
1818
1756
        expected_paths]),
1819
1757
    ],
1820
1758
    match_all=False)
1821
 
  run_and_verify_svn(None, expected_output, [],
 
1759
  run_and_verify_svn(expected_output, [],
1822
1760
                     cmd, *args)
1823
1761
 
1824
1762
def run_and_verify_resolve(expected_paths, *args):
1842
1780
  expected_output = verify.UnorderedOutput([
1843
1781
    "Reverted '" + path + "'\n" for path in
1844
1782
    expected_paths])
1845
 
  run_and_verify_svn(None, expected_output, [],
 
1783
  run_and_verify_svn(expected_output, [],
1846
1784
                     "revert", *args)
1847
1785
 
1848
1786
 
1851
1789
 
1852
1790
 
1853
1791
# This allows a test to *quickly* bootstrap itself.
1854
 
def make_repo_and_wc(sbox, create_wc = True, read_only = False,
1855
 
                     minor_version = None):
1856
 
  """Create a fresh 'Greek Tree' repository and check out a WC from it.
 
1792
def make_repo_and_wc(sbox, create_wc=True, read_only=False, empty=False,
 
1793
                     minor_version=None):
 
1794
  """Create a fresh repository and check out a WC from it.  If EMPTY is
 
1795
  True, the repository and WC will be empty and at revision 0,
 
1796
  otherwise they will contain the 'Greek Tree' at revision 1.
1857
1797
 
1858
1798
  If READ_ONLY is False, a dedicated repository will be created, at the path
1859
 
  SBOX.repo_dir.  If READ_ONLY is True, the pristine repository will be used.
 
1799
  SBOX.repo_dir.  If READ_ONLY is True, a shared pristine repository may be
 
1800
  used or a dedicated repository may be created.  (Currently we use a shared
 
1801
  pristine 'Greek tree' repo but we create a dedicated empty repo.)
1860
1802
  In either case, SBOX.repo_url is assumed to point to the repository that
1861
1803
  will be used.
1862
1804
 
1863
 
  If create_wc is True, a dedicated working copy will be checked out from
 
1805
  If CREATE_WC is True, a dedicated working copy will be checked out from
1864
1806
  the repository, at the path SBOX.wc_dir.
1865
1807
 
1866
1808
  Returns on success, raises on failure."""
1867
1809
 
1868
 
  # Create (or copy afresh) a new repos with a greek tree in it.
1869
 
  if not read_only:
1870
 
    guarantee_greek_repository(sbox.repo_dir, minor_version)
 
1810
  # Create or copy or reference the appropriate kind of repository:
 
1811
  # if we want a non-empty, Greek repo, refer to the shared one; else
 
1812
  # if we want an empty repo or a writable Greek repo, create one.
 
1813
  # (We could have a shared empty repo for read-only use, but we don't.)
 
1814
  if empty:
 
1815
    guarantee_empty_repository(sbox.repo_dir, minor_version)
 
1816
    expected_state = svntest.wc.State('', {})
 
1817
  else:
 
1818
    if not read_only:
 
1819
      guarantee_greek_repository(sbox.repo_dir, minor_version)
 
1820
    expected_state = main.greek_state
1871
1821
 
1872
1822
  if create_wc:
1873
1823
    # Generate the expected output tree.
1874
 
    expected_output = main.greek_state.copy()
 
1824
    expected_output = expected_state.copy()
1875
1825
    expected_output.wc_dir = sbox.wc_dir
1876
1826
    expected_output.tweak(status='A ', contents=None)
1877
1827
 
1878
1828
    # Generate an expected wc tree.
1879
 
    expected_wc = main.greek_state
 
1829
    expected_wc = expected_state
1880
1830
 
1881
1831
    # Do a checkout, and verify the resulting output and disk contents.
1882
1832
    run_and_verify_checkout(sbox.repo_url,
1916
1866
  return state
1917
1867
 
1918
1868
# Cheap administrative directory locking
1919
 
def lock_admin_dir(wc_dir, recursive=False):
 
1869
def lock_admin_dir(wc_dir, recursive=False, work_queue=False):
1920
1870
  "Lock a SVN administrative directory"
1921
1871
  db, root_path, relpath = wc.open_wc_db(wc_dir)
1922
1872
 
1923
 
  svntest.main.run_wc_lock_tester(recursive, wc_dir)
 
1873
  svntest.main.run_wc_lock_tester(recursive, wc_dir, work_queue)
1924
1874
 
1925
1875
def set_incomplete(wc_dir, revision):
1926
1876
  "Make wc_dir incomplete at revision"
2101
2051
  if expected_status:
2102
2052
    expected_status.tweak(state_path, wc_rev=merged_rev)
2103
2053
  run_and_verify_commit(wc_dir, expected_output, expected_status,
2104
 
                        None, file_path)
 
2054
                        [], file_path)
2105
2055
 
2106
2056
  # Backdate the file.
2107
2057
  exit_code, output, errput = main.run_svn(None, "up", "-r", str(prev_rev),
2122
2072
  inject_conflict_into_expected_state(state_path,
2123
2073
                                      expected_disk, expected_status,
2124
2074
                                      conflicting_contents, contents,
2125
 
                                      merged_rev)
 
2075
                                      prev_rev, merged_rev)
2126
2076
  exit_code, output, errput = main.run_svn(None, "up", "-r", str(merged_rev),
2127
2077
                                           file_path)
2128
2078
  if expected_status:
2130
2080
 
2131
2081
def inject_conflict_into_expected_state(state_path,
2132
2082
                                        expected_disk, expected_status,
2133
 
                                        wc_text, merged_text, merged_rev):
 
2083
                                        wc_text, merged_text, prev_rev,
 
2084
                                        merged_rev):
2134
2085
  """Update the EXPECTED_DISK and EXPECTED_STATUS trees for the
2135
2086
  conflict at STATE_PATH (ignored if None).  WC_TEXT, MERGED_TEXT, and
2136
2087
  MERGED_REV are used to determine the contents of the conflict (the
2137
2088
  text parameters should be newline-terminated)."""
2138
2089
  if expected_disk:
2139
2090
    conflict_marker = make_conflict_marker_text(wc_text, merged_text,
2140
 
                                                merged_rev)
 
2091
                                                prev_rev, merged_rev)
2141
2092
    existing_text = expected_disk.desc[state_path].contents or ""
2142
2093
    expected_disk.tweak(state_path, contents=existing_text + conflict_marker)
2143
2094
 
2144
2095
  if expected_status:
2145
2096
    expected_status.tweak(state_path, status='C ')
2146
2097
 
2147
 
def make_conflict_marker_text(wc_text, merged_text, merged_rev):
 
2098
def make_conflict_marker_text(wc_text, merged_text, prev_rev, merged_rev,
 
2099
                              old_text=''):
2148
2100
  """Return the conflict marker text described by WC_TEXT (the current
2149
2101
  text in the working copy, MERGED_TEXT (the conflicting text merged
2150
2102
  in), and MERGED_REV (the revision from whence the conflicting text
2151
2103
  came)."""
2152
 
  return "<<<<<<< .working\n" + wc_text + "=======\n" + \
 
2104
  return "<<<<<<< .working\n" + wc_text + \
 
2105
         "||||||| .merge-left.r" + str(prev_rev) + '\n' + \
 
2106
         old_text + "=======\n" + \
2153
2107
         merged_text + ">>>>>>> .merge-right.r" + str(merged_rev) + "\n"
2154
2108
 
2155
2109
 
2201
2155
  expected_status = get_virginal_state(wc_dir, 1)
2202
2156
  expected_status.tweak('A/D/G/pi', wc_rev='2')
2203
2157
  expected_status.remove('A/D/G/rho', 'A/D/G/tau')
2204
 
  run_and_verify_commit(wc_dir, expected_output, expected_status, None,
 
2158
  run_and_verify_commit(wc_dir, expected_output, expected_status, [],
2205
2159
                        '-m', 'Incoming changes.', wc_dir )
2206
2160
 
2207
2161
  # Update back to the pristine state ("time-warp").
2213
2167
  expected_disk = main.greek_state
2214
2168
  expected_status = get_virginal_state(wc_dir, 1)
2215
2169
  run_and_verify_update(wc_dir, expected_output, expected_disk,
2216
 
                        expected_status, None, None, None, None, None, False,
 
2170
                        expected_status, [], False,
2217
2171
                        '-r', '1', wc_dir)
2218
2172
 
2219
2173
  # Make local changes
2224
2178
  # Update, receiving the incoming changes on top of the local changes,
2225
2179
  # causing tree conflicts.  Don't check for any particular result: that is
2226
2180
  # the job of other tests.
2227
 
  run_and_verify_svn(None, verify.AnyOutput, [], 'update', wc_dir)
 
2181
  run_and_verify_svn(verify.AnyOutput, [], 'update', wc_dir)
2228
2182
 
2229
2183