~svn/ubuntu/oneiric/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/tests/libsvn_fs_base/fs-test.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-12-05 01:26:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051205012614-qom4xfypgtsqc2xq
Tags: 1.2.3dfsg1-3ubuntu1
Merge with the final Debian release of 1.2.3dfsg1-3, bringing in
fixes to the clean target, better documentation of the libdb4.3
upgrade and build fixes to work with swig1.3_1.3.27.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* fs-test.c --- tests for the filesystem
 
2
 *
 
3
 * ====================================================================
 
4
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
5
 *
 
6
 * This software is licensed as described in the file COPYING, which
 
7
 * you should have received as part of this distribution.  The terms
 
8
 * are also available at http://subversion.tigris.org/license-1.html.
 
9
 * If newer versions of this license are posted there, you may use a
 
10
 * newer version instead, at your option.
 
11
 *
 
12
 * This software consists of voluntary contributions made by many
 
13
 * individuals.  For exact contribution history, see the revision
 
14
 * history and logs, available at http://subversion.tigris.org/.
 
15
 * ====================================================================
 
16
 */
 
17
 
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
#include <apr_pools.h>
 
21
 
 
22
#include "svn_pools.h"
 
23
#include "svn_time.h"
 
24
#include "svn_string.h"
 
25
#include "svn_test.h"
 
26
#include "svn_fs.h"
 
27
#include "svn_md5.h"
 
28
 
 
29
#include "../fs-helpers.h"
 
30
 
 
31
#include "../../libsvn_fs_base/trail.h"
 
32
 
 
33
#include "../../libsvn_fs_base/bdb/txn-table.h"
 
34
#include "../../libsvn_fs_base/bdb/nodes-table.h"
 
35
 
 
36
#include "../../libsvn_delta/delta.h"
 
37
 
 
38
#define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))
 
39
 
 
40
 
 
41
/*-----------------------------------------------------------------*/
 
42
 
 
43
/** The actual fs-tests called by `make check` **/
 
44
 
 
45
/* Create a filesystem.  */
 
46
static svn_error_t *
 
47
create_berkeley_filesystem (const char **msg,
 
48
                            svn_boolean_t msg_only,
 
49
                            svn_test_opts_t *opts,
 
50
                            apr_pool_t *pool)
 
51
{
 
52
  svn_fs_t *fs;
 
53
 
 
54
  *msg = "svn_fs_create_berkeley";
 
55
 
 
56
  if (msg_only)
 
57
    return SVN_NO_ERROR;
 
58
 
 
59
  /* Create and close a repository. */
 
60
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-berkeley",
 
61
                                "bdb", pool));
 
62
  
 
63
  return SVN_NO_ERROR;
 
64
}
 
65
 
 
66
 
 
67
/* Generic Berkeley DB error handler function. */
 
68
static void
 
69
berkeley_error_handler (const char *errpfx, char *msg)
 
70
{
 
71
  fprintf (stderr, "%s%s\n", errpfx ? errpfx : "", msg);
 
72
}
 
73
 
 
74
 
 
75
/* Helper:  commit TXN, expecting either success or failure:
 
76
 *
 
77
 * If EXPECTED_CONFLICT is null, then the commit is expected to
 
78
 * succeed.  If it does succeed, set *NEW_REV to the new revision;
 
79
 * else return error.
 
80
 *
 
81
 * If EXPECTED_CONFLICT is non-null, it is either the empty string or
 
82
 * the expected path of the conflict.  If it is the empty string, any
 
83
 * conflict is acceptable.  If it is a non-empty string, the commit
 
84
 * must fail due to conflict, and the conflict path must match
 
85
 * EXPECTED_CONFLICT.  If they don't match, return error.
 
86
 *
 
87
 * If a conflict is expected but the commit succeeds anyway, return
 
88
 * error.
 
89
 */
 
90
static svn_error_t *
 
91
test_commit_txn (svn_revnum_t *new_rev,
 
92
                 svn_fs_txn_t *txn,
 
93
                 const char *expected_conflict,
 
94
                 apr_pool_t *pool)
 
95
{
 
96
  const char *conflict;
 
97
  svn_error_t *err;
 
98
 
 
99
  err = svn_fs_commit_txn (&conflict, new_rev, txn, pool);
 
100
 
 
101
  if (err && (err->apr_err == SVN_ERR_FS_CONFLICT))
 
102
    {
 
103
      svn_error_clear (err);
 
104
      if (! expected_conflict)
 
105
        {
 
106
          return svn_error_createf
 
107
            (SVN_ERR_FS_CONFLICT, NULL,
 
108
             "commit conflicted at '%s', but no conflict expected",
 
109
             conflict ? conflict : "(missing conflict info!)");
 
110
        }
 
111
      else if (conflict == NULL)
 
112
        {
 
113
          return svn_error_createf
 
114
            (SVN_ERR_FS_CONFLICT, NULL,
 
115
             "commit conflicted as expected, "
 
116
             "but no conflict path was returned ('%s' expected)",
 
117
             expected_conflict);
 
118
        }
 
119
      else if ((strcmp (expected_conflict, "") != 0)
 
120
               && (strcmp (conflict, expected_conflict) != 0))
 
121
        {
 
122
          return svn_error_createf
 
123
            (SVN_ERR_FS_CONFLICT, NULL,
 
124
             "commit conflicted at '%s', but expected conflict at '%s')",
 
125
             conflict, expected_conflict);
 
126
        }
 
127
    }
 
128
  else if (err)   /* commit failed, but not due to conflict */
 
129
    {
 
130
      return svn_error_quick_wrap 
 
131
        (err, "commit failed due to something other than a conflict");
 
132
    }
 
133
  else            /* err == NULL, so commit succeeded */
 
134
    {
 
135
      if (expected_conflict)
 
136
        {
 
137
          return svn_error_createf
 
138
            (SVN_ERR_FS_GENERAL, NULL,
 
139
             "commit succeeded that was expected to fail at '%s'",
 
140
             expected_conflict);
 
141
        }
 
142
    }
 
143
 
 
144
  return SVN_NO_ERROR;
 
145
}
 
146
 
 
147
 
 
148
 
 
149
/* Open an existing filesystem.  */
 
150
static svn_error_t *
 
151
open_berkeley_filesystem (const char **msg,
 
152
                          svn_boolean_t msg_only,
 
153
                          svn_test_opts_t *opts,
 
154
                          apr_pool_t *pool)
 
155
{
 
156
  svn_fs_t *fs, *fs2;
 
157
 
 
158
  *msg = "open an existing Berkeley DB filesystem";
 
159
 
 
160
  if (msg_only)
 
161
    return SVN_NO_ERROR;
 
162
 
 
163
  /* Create and close a repository (using fs). */
 
164
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-open-berkeley",
 
165
                                "bdb", pool));
 
166
 
 
167
  /* Create a different fs object, and use it to re-open the
 
168
     repository again.  */
 
169
  SVN_ERR (svn_test__fs_new (&fs2, pool));
 
170
  SVN_ERR (svn_fs_open_berkeley (fs2, "test-repo-open-berkeley"));
 
171
 
 
172
  /* Provide a handler for Berkeley DB error messages.  */
 
173
  SVN_ERR (svn_fs_set_berkeley_errcall (fs2, berkeley_error_handler));
 
174
 
 
175
  return SVN_NO_ERROR;
 
176
}
 
177
 
 
178
 
 
179
/* Begin a txn, check its name, then close it */
 
180
static svn_error_t *
 
181
trivial_transaction (const char **msg,
 
182
                     svn_boolean_t msg_only,
 
183
                     svn_test_opts_t *opts,
 
184
                     apr_pool_t *pool)
 
185
{
 
186
  svn_fs_t *fs;
 
187
  svn_fs_txn_t *txn;
 
188
  const char *txn_name;
 
189
 
 
190
  *msg = "begin a txn, check its name, then close it";
 
191
 
 
192
  if (msg_only)
 
193
    return SVN_NO_ERROR;
 
194
 
 
195
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-trivial-txn",
 
196
                                "bdb", pool));
 
197
 
 
198
  /* Begin a new transaction that is based on revision 0.  */
 
199
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
200
      
 
201
  /* Test that the txn name is non-null. */
 
202
  SVN_ERR (svn_fs_txn_name (&txn_name, txn, pool));
 
203
  
 
204
  if (! txn_name)
 
205
    return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
 
206
                             "Got a NULL txn name.");
 
207
 
 
208
  return SVN_NO_ERROR;
 
209
}
 
210
 
 
211
 
 
212
 
 
213
/* Open an existing transaction by name. */
 
214
static svn_error_t *
 
215
reopen_trivial_transaction (const char **msg,
 
216
                            svn_boolean_t msg_only,
 
217
                            svn_test_opts_t *opts,
 
218
                            apr_pool_t *pool)
 
219
{
 
220
  svn_fs_t *fs;
 
221
  svn_fs_txn_t *txn;
 
222
  const char *txn_name;
 
223
  apr_pool_t *subpool = svn_pool_create (pool);
 
224
 
 
225
  *msg = "open an existing transaction by name";
 
226
 
 
227
  if (msg_only)
 
228
    return SVN_NO_ERROR;
 
229
 
 
230
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-reopen-trivial-txn",
 
231
                                "bdb", pool));
 
232
 
 
233
  /* Begin a new transaction that is based on revision 0.  */
 
234
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
 
235
 
 
236
  /* Don't use the subpool, txn_name must persist beyond the current txn */
 
237
  SVN_ERR (svn_fs_txn_name (&txn_name, txn, pool));
 
238
 
 
239
  /* Close the transaction. */
 
240
  svn_pool_clear (subpool);
 
241
 
 
242
  /* Reopen the transaction by name */
 
243
  SVN_ERR (svn_fs_open_txn (&txn, fs, txn_name, subpool));
 
244
 
 
245
  /* Close the transaction ... again. */
 
246
  svn_pool_destroy (subpool);
 
247
 
 
248
  return SVN_NO_ERROR;
 
249
}
 
250
 
 
251
 
 
252
 
 
253
/* Create a file! */
 
254
static svn_error_t *
 
255
create_file_transaction (const char **msg,
 
256
                         svn_boolean_t msg_only,
 
257
                         svn_test_opts_t *opts,
 
258
                         apr_pool_t *pool)
 
259
{
 
260
  svn_fs_t *fs;
 
261
  svn_fs_txn_t *txn;
 
262
  svn_fs_root_t *txn_root;
 
263
 
 
264
  *msg = "begin a txn, get the txn root, and add a file";
 
265
 
 
266
  if (msg_only)
 
267
    return SVN_NO_ERROR;
 
268
 
 
269
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-file-txn",
 
270
                                "bdb", pool));
 
271
 
 
272
  /* Begin a new transaction that is based on revision 0.  */
 
273
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
274
 
 
275
  /* Get the txn root */
 
276
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
277
  
 
278
  /* Create a new file in the root directory. */
 
279
  SVN_ERR (svn_fs_make_file (txn_root, "beer.txt", pool));
 
280
 
 
281
  return SVN_NO_ERROR;
 
282
}
 
283
 
 
284
 
 
285
/* Make sure we get txn lists correctly. */
 
286
static svn_error_t *
 
287
verify_txn_list (const char **msg,
 
288
                 svn_boolean_t msg_only,
 
289
                 svn_test_opts_t *opts,
 
290
                 apr_pool_t *pool)
 
291
{
 
292
  svn_fs_t *fs;
 
293
  apr_pool_t *subpool;
 
294
  svn_fs_txn_t *txn1, *txn2;
 
295
  const char *name1, *name2;
 
296
  apr_array_header_t *txn_list;
 
297
 
 
298
  *msg = "create 2 txns, list them, and verify the list";
 
299
 
 
300
  if (msg_only)
 
301
    return SVN_NO_ERROR;
 
302
 
 
303
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-verify-txn-list",
 
304
                                "bdb", pool));
 
305
 
 
306
  /* Begin a new transaction, get its name (in the top pool), close it.  */
 
307
  subpool = svn_pool_create (pool);
 
308
  SVN_ERR (svn_fs_begin_txn (&txn1, fs, 0, subpool));
 
309
  SVN_ERR (svn_fs_txn_name (&name1, txn1, pool));
 
310
  svn_pool_destroy (subpool);
 
311
 
 
312
  /* Begin *another* transaction, get its name (in the top pool), close it.  */
 
313
  subpool = svn_pool_create (pool);
 
314
  SVN_ERR (svn_fs_begin_txn (&txn2, fs, 0, subpool));
 
315
  SVN_ERR (svn_fs_txn_name (&name2, txn2, pool));
 
316
  svn_pool_destroy (subpool);
 
317
 
 
318
  /* Get the list of active transactions from the fs. */
 
319
  SVN_ERR (svn_fs_list_transactions (&txn_list, fs, pool));
 
320
 
 
321
  /* Check the list. It should have *exactly* two entries. */
 
322
  if (txn_list->nelts != 2)
 
323
    goto all_bad;
 
324
  
 
325
  /* We should be able to find our 2 txn names in the list, in some
 
326
     order. */
 
327
  if ((! strcmp (name1, APR_ARRAY_IDX (txn_list, 0, const char *)))
 
328
      && (! strcmp (name2, APR_ARRAY_IDX (txn_list, 1, const char *))))
 
329
    goto all_good;
 
330
  
 
331
  else if ((! strcmp (name2, APR_ARRAY_IDX (txn_list, 0, const char *)))
 
332
           && (! strcmp (name1, APR_ARRAY_IDX (txn_list, 1, const char *))))
 
333
    goto all_good;
 
334
  
 
335
 all_bad:
 
336
 
 
337
  return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
 
338
                           "Got a bogus txn list.");
 
339
 all_good:
 
340
  
 
341
  return SVN_NO_ERROR;
 
342
}
 
343
 
 
344
 
 
345
 
 
346
/* Test writing & reading a file's contents. */
 
347
static svn_error_t *
 
348
write_and_read_file (const char **msg,
 
349
                     svn_boolean_t msg_only,
 
350
                     svn_test_opts_t *opts,
 
351
                     apr_pool_t *pool)
 
352
{
 
353
  svn_fs_t *fs;
 
354
  svn_fs_txn_t *txn;
 
355
  svn_fs_root_t *txn_root;
 
356
  svn_stream_t *rstream;
 
357
  svn_stringbuf_t *rstring;
 
358
  svn_stringbuf_t *wstring;
 
359
 
 
360
  *msg = "write and read a file's contents";
 
361
 
 
362
  if (msg_only)
 
363
    return SVN_NO_ERROR;
 
364
 
 
365
  wstring = svn_stringbuf_create ("Wicki wild, wicki wicki wild.", pool);
 
366
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-read-and-write-file",
 
367
                                "bdb", pool));
 
368
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
369
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
370
  
 
371
  /* Add an empty file. */
 
372
  SVN_ERR (svn_fs_make_file (txn_root, "beer.txt", pool));
 
373
 
 
374
  /* And write some data into this file. */
 
375
  SVN_ERR (svn_test__set_file_contents (txn_root, "beer.txt", 
 
376
                                        wstring->data, pool));
 
377
  
 
378
  /* Now let's read the data back from the file. */
 
379
  SVN_ERR (svn_fs_file_contents (&rstream, txn_root, "beer.txt", pool));  
 
380
  SVN_ERR (svn_test__stream_to_string (&rstring, rstream, pool));
 
381
 
 
382
  /* Compare what was read to what was written. */
 
383
  if (! svn_stringbuf_compare (rstring, wstring))
 
384
    return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
 
385
                             "data read != data written.");    
 
386
 
 
387
  return SVN_NO_ERROR;
 
388
}
 
389
 
 
390
 
 
391
 
 
392
/* Create a file, a directory, and a file in that directory! */
 
393
static svn_error_t *
 
394
create_mini_tree_transaction (const char **msg,
 
395
                              svn_boolean_t msg_only,
 
396
                              svn_test_opts_t *opts,
 
397
                              apr_pool_t *pool)
 
398
{
 
399
  svn_fs_t *fs;
 
400
  svn_fs_txn_t *txn;
 
401
  svn_fs_root_t *txn_root;
 
402
 
 
403
  *msg = "test basic file and subdirectory creation";
 
404
 
 
405
  if (msg_only)
 
406
    return SVN_NO_ERROR;
 
407
 
 
408
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-mini-tree-txn",
 
409
                                "bdb", pool));
 
410
 
 
411
  /* Begin a new transaction that is based on revision 0.  */
 
412
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
413
 
 
414
  /* Get the txn root */
 
415
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
416
  
 
417
  /* Create a new file in the root directory. */
 
418
  SVN_ERR (svn_fs_make_file (txn_root, "wine.txt", pool));
 
419
 
 
420
  /* Create a new directory in the root directory. */
 
421
  SVN_ERR (svn_fs_make_dir (txn_root, "keg", pool));
 
422
 
 
423
  /* Now, create a file in our new directory. */
 
424
  SVN_ERR (svn_fs_make_file (txn_root, "keg/beer.txt", pool));
 
425
 
 
426
  return SVN_NO_ERROR;
 
427
}
 
428
 
 
429
 
 
430
/* Create a file, a directory, and a file in that directory! */
 
431
static svn_error_t *
 
432
create_greek_tree_transaction (const char **msg,
 
433
                               svn_boolean_t msg_only,
 
434
                               svn_test_opts_t *opts,
 
435
                               apr_pool_t *pool)
 
436
{
 
437
  svn_fs_t *fs;
 
438
  svn_fs_txn_t *txn;
 
439
  svn_fs_root_t *txn_root;
 
440
 
 
441
  *msg = "make The Official Subversion Test Tree";
 
442
 
 
443
  if (msg_only)
 
444
    return SVN_NO_ERROR;
 
445
 
 
446
  /* Prepare a txn to receive the greek tree. */
 
447
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-greek-tree-txn",
 
448
                                "bdb", pool));
 
449
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
450
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
451
 
 
452
  /* Create and verify the greek tree. */
 
453
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
454
 
 
455
  return SVN_NO_ERROR;
 
456
}
 
457
 
 
458
 
 
459
/* Verify that entry KEY is present in ENTRIES, and that its value is
 
460
   an svn_fs_dirent_t whose name and id are not null. */
 
461
static svn_error_t *
 
462
verify_entry (apr_hash_t *entries, const char *key)
 
463
{
 
464
  svn_fs_dirent_t *ent = apr_hash_get (entries, key, 
 
465
                                       APR_HASH_KEY_STRING);
 
466
 
 
467
  if (ent == NULL)
 
468
    return svn_error_createf
 
469
      (SVN_ERR_FS_GENERAL, NULL,
 
470
       "didn't find dir entry for \"%s\"", key);
 
471
 
 
472
  if ((ent->name == NULL) && (ent->id == NULL))
 
473
    return svn_error_createf
 
474
      (SVN_ERR_FS_GENERAL, NULL,
 
475
       "dir entry for \"%s\" has null name and null id", key);
 
476
  
 
477
  if (ent->name == NULL)
 
478
    return svn_error_createf
 
479
      (SVN_ERR_FS_GENERAL, NULL,
 
480
       "dir entry for \"%s\" has null name", key);
 
481
  
 
482
  if (ent->id == NULL)
 
483
    return svn_error_createf
 
484
      (SVN_ERR_FS_GENERAL, NULL,
 
485
       "dir entry for \"%s\" has null id", key);
 
486
  
 
487
  if (strcmp (ent->name, key) != 0)
 
488
     return svn_error_createf
 
489
     (SVN_ERR_FS_GENERAL, NULL,
 
490
      "dir entry for \"%s\" contains wrong name (\"%s\")", key, ent->name);
 
491
        
 
492
  return SVN_NO_ERROR;
 
493
}
 
494
 
 
495
 
 
496
static svn_error_t *
 
497
list_directory (const char **msg,
 
498
                svn_boolean_t msg_only,
 
499
                svn_test_opts_t *opts,
 
500
                apr_pool_t *pool)
 
501
{
 
502
  svn_fs_t *fs;
 
503
  svn_fs_txn_t *txn;
 
504
  svn_fs_root_t *txn_root;
 
505
  apr_hash_t *entries;
 
506
 
 
507
  *msg = "fill a directory, then list it";
 
508
 
 
509
  if (msg_only)
 
510
    return SVN_NO_ERROR;
 
511
 
 
512
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-list-dir",
 
513
                                "bdb", pool));
 
514
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
515
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
516
  
 
517
  /* We create this tree
 
518
   *
 
519
   *         /q
 
520
   *         /A/x
 
521
   *         /A/y
 
522
   *         /A/z
 
523
   *         /B/m
 
524
   *         /B/n
 
525
   *         /B/o
 
526
   *
 
527
   * then list dir A.  It should have 3 files: "x", "y", and "z", no
 
528
   * more, no less.
 
529
   */
 
530
 
 
531
  /* Create the tree. */
 
532
  SVN_ERR (svn_fs_make_file (txn_root, "q", pool));
 
533
  SVN_ERR (svn_fs_make_dir  (txn_root, "A", pool));
 
534
  SVN_ERR (svn_fs_make_file (txn_root, "A/x", pool));
 
535
  SVN_ERR (svn_fs_make_file (txn_root, "A/y", pool));
 
536
  SVN_ERR (svn_fs_make_file (txn_root, "A/z", pool));
 
537
  SVN_ERR (svn_fs_make_dir  (txn_root, "B", pool));
 
538
  SVN_ERR (svn_fs_make_file (txn_root, "B/m", pool));
 
539
  SVN_ERR (svn_fs_make_file (txn_root, "B/n", pool));
 
540
  SVN_ERR (svn_fs_make_file (txn_root, "B/o", pool));
 
541
 
 
542
  /* Get A's entries. */
 
543
  SVN_ERR (svn_fs_dir_entries (&entries, txn_root, "A", pool));
 
544
 
 
545
  /* Make sure exactly the right set of entries is present. */
 
546
  if (apr_hash_count (entries) != 3)
 
547
    {
 
548
      return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
 
549
                               "unexpected number of entries in dir");
 
550
    }
 
551
  else
 
552
    {
 
553
      SVN_ERR (verify_entry (entries, "x"));
 
554
      SVN_ERR (verify_entry (entries, "y"));
 
555
      SVN_ERR (verify_entry (entries, "z"));
 
556
    }
 
557
 
 
558
  return SVN_NO_ERROR;
 
559
}
 
560
 
 
561
 
 
562
static svn_error_t *
 
563
revision_props (const char **msg,
 
564
                svn_boolean_t msg_only,
 
565
                svn_test_opts_t *opts,
 
566
                apr_pool_t *pool)
 
567
{
 
568
  svn_fs_t *fs;
 
569
  apr_hash_t *proplist;
 
570
  svn_string_t *value;
 
571
  int i;
 
572
  svn_string_t s1;
 
573
 
 
574
  const char *initial_props[4][2] = { 
 
575
    { "color", "red" },
 
576
    { "size", "XXL" },
 
577
    { "favorite saturday morning cartoon", "looney tunes" },
 
578
    { "auto", "Green 1997 Saturn SL1" }
 
579
    };
 
580
 
 
581
  const char *final_props[4][2] = { 
 
582
    { "color", "violet" },
 
583
    { "flower", "violet" },
 
584
    { "favorite saturday morning cartoon", "looney tunes" },
 
585
    { "auto", "Red 2000 Chevrolet Blazer" }
 
586
    };
 
587
 
 
588
  *msg = "set and get some revision properties";
 
589
 
 
590
  if (msg_only)
 
591
    return SVN_NO_ERROR;
 
592
 
 
593
  /* Open the fs */
 
594
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-rev-props",
 
595
                                "bdb", pool));
 
596
 
 
597
  /* Set some properties on the revision. */
 
598
  for (i = 0; i < 4; i++)
 
599
    {
 
600
      SET_STR (&s1, initial_props[i][1]);
 
601
      SVN_ERR (svn_fs_change_rev_prop (fs, 0, initial_props[i][0], &s1, pool));
 
602
    }
 
603
 
 
604
  /* Change some of the above properties. */
 
605
  SET_STR (&s1, "violet");
 
606
  SVN_ERR (svn_fs_change_rev_prop (fs, 0, "color", &s1, pool));
 
607
 
 
608
  SET_STR (&s1, "Red 2000 Chevrolet Blazer");
 
609
  SVN_ERR (svn_fs_change_rev_prop (fs, 0, "auto", &s1, pool));
 
610
 
 
611
  /* Remove a property altogether */
 
612
  SVN_ERR (svn_fs_change_rev_prop (fs, 0, "size", NULL, pool));
 
613
 
 
614
  /* Copy a property's value into a new property. */
 
615
  SVN_ERR (svn_fs_revision_prop (&value, fs, 0, "color", pool));
 
616
 
 
617
  s1.data = value->data;
 
618
  s1.len = value->len;
 
619
  SVN_ERR (svn_fs_change_rev_prop (fs, 0, "flower", &s1, pool));
 
620
 
 
621
  /* Obtain a list of all current properties, and make sure it matches
 
622
     the expected values. */
 
623
  SVN_ERR (svn_fs_revision_proplist (&proplist, fs, 0, pool));
 
624
  {
 
625
    svn_string_t *prop_value;
 
626
 
 
627
    if (apr_hash_count (proplist) < 4 )
 
628
      return svn_error_createf
 
629
        (SVN_ERR_FS_GENERAL, NULL,
 
630
         "too few revision properties found");
 
631
 
 
632
    /* Loop through our list of expected revision property name/value
 
633
       pairs. */
 
634
    for (i = 0; i < 4; i++)
 
635
      {
 
636
        /* For each expected property: */
 
637
 
 
638
        /* Step 1.  Find it by name in the hash of all rev. props
 
639
           returned to us by svn_fs_revision_proplist.  If it can't be
 
640
           found, return an error. */
 
641
        prop_value = apr_hash_get (proplist, 
 
642
                                   final_props[i][0],
 
643
                                   APR_HASH_KEY_STRING);
 
644
        if (! prop_value)
 
645
          return svn_error_createf
 
646
            (SVN_ERR_FS_GENERAL, NULL,
 
647
             "unable to find expected revision property");
 
648
 
 
649
        /* Step 2.  Make sure the value associated with it is the same
 
650
           as what was expected, else return an error. */
 
651
        if (strcmp (prop_value->data, final_props[i][1]))
 
652
          return svn_error_createf
 
653
            (SVN_ERR_FS_GENERAL, NULL,
 
654
             "revision property had an unexpected value");
 
655
      }
 
656
  }
 
657
 
 
658
  return SVN_NO_ERROR;
 
659
}
 
660
 
 
661
 
 
662
static svn_error_t *
 
663
transaction_props (const char **msg,
 
664
                   svn_boolean_t msg_only,
 
665
                   svn_test_opts_t *opts,
 
666
                   apr_pool_t *pool)
 
667
{
 
668
  svn_fs_t *fs;
 
669
  svn_fs_txn_t *txn;
 
670
  apr_hash_t *proplist;
 
671
  svn_string_t *value;
 
672
  svn_revnum_t after_rev;
 
673
  int i;
 
674
  svn_string_t s1;
 
675
 
 
676
  const char *initial_props[4][2] = { 
 
677
    { "color", "red" },
 
678
    { "size", "XXL" },
 
679
    { "favorite saturday morning cartoon", "looney tunes" },
 
680
    { "auto", "Green 1997 Saturn SL1" }
 
681
    };
 
682
 
 
683
  const char *final_props[5][2] = { 
 
684
    { "color", "violet" },
 
685
    { "flower", "violet" },
 
686
    { "favorite saturday morning cartoon", "looney tunes" },
 
687
    { "auto", "Red 2000 Chevrolet Blazer" },
 
688
    { SVN_PROP_REVISION_DATE, "<some datestamp value>" }
 
689
    };
 
690
 
 
691
  *msg = "set/get txn props, commit, validate new rev props";
 
692
 
 
693
  if (msg_only)
 
694
    return SVN_NO_ERROR;
 
695
 
 
696
  /* Open the fs */
 
697
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-txn-props",
 
698
                                "bdb", pool));
 
699
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
700
 
 
701
  /* Set some properties on the revision. */
 
702
  for (i = 0; i < 4; i++)
 
703
    {
 
704
      SET_STR (&s1, initial_props[i][1]);
 
705
      SVN_ERR (svn_fs_change_txn_prop (txn, initial_props[i][0], &s1, pool));
 
706
    }
 
707
 
 
708
  /* Change some of the above properties. */
 
709
  SET_STR (&s1, "violet");
 
710
  SVN_ERR (svn_fs_change_txn_prop (txn, "color", &s1, pool));
 
711
 
 
712
  SET_STR (&s1, "Red 2000 Chevrolet Blazer");
 
713
  SVN_ERR (svn_fs_change_txn_prop (txn, "auto", &s1, pool));
 
714
 
 
715
  /* Remove a property altogether */
 
716
  SVN_ERR (svn_fs_change_txn_prop (txn, "size", NULL, pool));
 
717
 
 
718
  /* Copy a property's value into a new property. */
 
719
  SVN_ERR (svn_fs_txn_prop (&value, txn, "color", pool));
 
720
 
 
721
  s1.data = value->data;
 
722
  s1.len = value->len;
 
723
  SVN_ERR (svn_fs_change_txn_prop (txn, "flower", &s1, pool));
 
724
 
 
725
  /* Obtain a list of all current properties, and make sure it matches
 
726
     the expected values. */
 
727
  SVN_ERR (svn_fs_txn_proplist (&proplist, txn, pool));
 
728
  {
 
729
    svn_string_t *prop_value;
 
730
 
 
731
    /* All transactions get a datestamp property at their inception,
 
732
       so we expect *5*, not 4 properties. */
 
733
    if (apr_hash_count (proplist) != 5 )
 
734
      return svn_error_createf
 
735
        (SVN_ERR_FS_GENERAL, NULL,
 
736
         "unexpected number of transaction properties were found");
 
737
 
 
738
    /* Loop through our list of expected revision property name/value
 
739
       pairs. */
 
740
    for (i = 0; i < 5; i++)
 
741
      {
 
742
        /* For each expected property: */
 
743
 
 
744
        /* Step 1.  Find it by name in the hash of all rev. props
 
745
           returned to us by svn_fs_revision_proplist.  If it can't be
 
746
           found, return an error. */
 
747
        prop_value = apr_hash_get (proplist, 
 
748
                                   final_props[i][0],
 
749
                                   APR_HASH_KEY_STRING);
 
750
        if (! prop_value)
 
751
          return svn_error_createf
 
752
            (SVN_ERR_FS_GENERAL, NULL,
 
753
             "unable to find expected transaction property");
 
754
 
 
755
        /* Step 2.  Make sure the value associated with it is the same
 
756
           as what was expected, else return an error. */
 
757
        if (strcmp (final_props[i][0], SVN_PROP_REVISION_DATE))
 
758
          if (strcmp (prop_value->data, final_props[i][1]))
 
759
            return svn_error_createf
 
760
              (SVN_ERR_FS_GENERAL, NULL,
 
761
               "transaction property had an unexpected value");
 
762
      }
 
763
  }
 
764
  
 
765
  /* Commit the transaction. */
 
766
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
767
  if (after_rev != 1)
 
768
    return svn_error_createf
 
769
      (SVN_ERR_FS_GENERAL, NULL,
 
770
       "committed transaction got wrong revision number");
 
771
 
 
772
  /* Obtain a list of all properties on the new revision, and make
 
773
     sure it matches the expected values.  If you're wondering, the
 
774
     expected values should be the exact same set of properties that
 
775
     existed on the transaction just prior to its being committed. */
 
776
  SVN_ERR (svn_fs_revision_proplist (&proplist, fs, after_rev, pool));
 
777
  {
 
778
    svn_string_t *prop_value;
 
779
 
 
780
    if (apr_hash_count (proplist) < 5 )
 
781
      return svn_error_createf
 
782
        (SVN_ERR_FS_GENERAL, NULL,
 
783
         "unexpected number of revision properties were found");
 
784
 
 
785
    /* Loop through our list of expected revision property name/value
 
786
       pairs. */
 
787
    for (i = 0; i < 5; i++)
 
788
      {
 
789
        /* For each expected property: */
 
790
 
 
791
        /* Step 1.  Find it by name in the hash of all rev. props
 
792
           returned to us by svn_fs_revision_proplist.  If it can't be
 
793
           found, return an error. */
 
794
        prop_value = apr_hash_get (proplist, 
 
795
                                   final_props[i][0],
 
796
                                   APR_HASH_KEY_STRING);
 
797
        if (! prop_value)
 
798
          return svn_error_createf
 
799
            (SVN_ERR_FS_GENERAL, NULL,
 
800
             "unable to find expected revision property");
 
801
 
 
802
        /* Step 2.  Make sure the value associated with it is the same
 
803
           as what was expected, else return an error. */
 
804
        if (strcmp (final_props[i][0], SVN_PROP_REVISION_DATE))
 
805
          if (strcmp (prop_value->data, final_props[i][1]))
 
806
            return svn_error_createf
 
807
              (SVN_ERR_FS_GENERAL, NULL,
 
808
               "revision property had an unexpected value");
 
809
      }
 
810
  }
 
811
 
 
812
  return SVN_NO_ERROR;
 
813
}
 
814
 
 
815
 
 
816
static svn_error_t *
 
817
node_props (const char **msg,
 
818
            svn_boolean_t msg_only,
 
819
            svn_test_opts_t *opts,
 
820
            apr_pool_t *pool)
 
821
{
 
822
  svn_fs_t *fs;
 
823
  svn_fs_txn_t *txn;
 
824
  svn_fs_root_t *txn_root;
 
825
  apr_hash_t *proplist;
 
826
  svn_string_t *value;
 
827
  int i;
 
828
  svn_string_t s1;
 
829
 
 
830
  const char *initial_props[4][2] = { 
 
831
    { "Best Rock Artist", "Creed" },
 
832
    { "Best Rap Artist", "Eminem" },
 
833
    { "Best Country Artist", "(null)" },
 
834
    { "Best Sound Designer", "Pluessman" }
 
835
    };
 
836
 
 
837
  const char *final_props[4][2] = { 
 
838
    { "Best Rock Artist", "P.O.D." },
 
839
    { "Best Rap Artist", "Busta Rhymes" },
 
840
    { "Best Sound Designer", "Pluessman" },
 
841
    { "Biggest Cakewalk Fanatic", "Pluessman" }
 
842
    };
 
843
 
 
844
  *msg = "set and get some node properties";
 
845
 
 
846
  if (msg_only)
 
847
    return SVN_NO_ERROR;
 
848
 
 
849
  /* Open the fs and transaction */
 
850
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-node-props",
 
851
                                "bdb", pool));
 
852
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
853
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
854
 
 
855
  /* Make a node to put some properties into */
 
856
  SVN_ERR (svn_fs_make_file (txn_root, "music.txt", pool));
 
857
 
 
858
  /* Set some properties on the nodes. */
 
859
  for (i = 0; i < 4; i++)
 
860
    {
 
861
      SET_STR (&s1, initial_props[i][1]);
 
862
      SVN_ERR (svn_fs_change_node_prop
 
863
               (txn_root, "music.txt", initial_props[i][0], &s1, pool));
 
864
    }
 
865
 
 
866
  /* Change some of the above properties. */
 
867
  SET_STR (&s1, "P.O.D.");
 
868
  SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt", "Best Rock Artist",
 
869
                                    &s1, pool));
 
870
 
 
871
  SET_STR (&s1, "Busta Rhymes");
 
872
  SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt", "Best Rap Artist",
 
873
                                    &s1, pool));
 
874
 
 
875
  /* Remove a property altogether */
 
876
  SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt",
 
877
                                    "Best Country Artist", NULL, pool));
 
878
 
 
879
  /* Copy a property's value into a new property. */
 
880
  SVN_ERR (svn_fs_node_prop (&value, txn_root, "music.txt",
 
881
                             "Best Sound Designer", pool));
 
882
 
 
883
  s1.data = value->data;
 
884
  s1.len = value->len;
 
885
  SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt",
 
886
                                    "Biggest Cakewalk Fanatic", &s1, pool));
 
887
 
 
888
  /* Obtain a list of all current properties, and make sure it matches
 
889
     the expected values. */
 
890
  SVN_ERR (svn_fs_node_proplist (&proplist, txn_root, "music.txt", pool));
 
891
  {
 
892
    svn_string_t *prop_value;
 
893
 
 
894
    if (apr_hash_count (proplist) != 4 )
 
895
      return svn_error_createf
 
896
        (SVN_ERR_FS_GENERAL, NULL,
 
897
         "unexpected number of node properties were found");
 
898
 
 
899
    /* Loop through our list of expected node property name/value
 
900
       pairs. */
 
901
    for (i = 0; i < 4; i++)
 
902
      {
 
903
        /* For each expected property: */
 
904
 
 
905
        /* Step 1.  Find it by name in the hash of all node props
 
906
           returned to us by svn_fs_node_proplist.  If it can't be
 
907
           found, return an error. */
 
908
        prop_value = apr_hash_get (proplist, 
 
909
                                   final_props[i][0],
 
910
                                   APR_HASH_KEY_STRING);
 
911
        if (! prop_value)
 
912
          return svn_error_createf
 
913
            (SVN_ERR_FS_GENERAL, NULL,
 
914
             "unable to find expected node property");
 
915
 
 
916
        /* Step 2.  Make sure the value associated with it is the same
 
917
           as what was expected, else return an error. */
 
918
        if (strcmp (prop_value->data, final_props[i][1]))
 
919
          return svn_error_createf
 
920
            (SVN_ERR_FS_GENERAL, NULL,
 
921
             "node property had an unexpected value");
 
922
      }
 
923
  }
 
924
  
 
925
  return SVN_NO_ERROR;
 
926
}
 
927
 
 
928
 
 
929
 
 
930
/* Set *PRESENT to true if entry NAME is present in directory PATH
 
931
   under ROOT, else set *PRESENT to false. */
 
932
static svn_error_t *
 
933
check_entry (svn_fs_root_t *root,
 
934
             const char *path,
 
935
             const char *name,
 
936
             svn_boolean_t *present,
 
937
             apr_pool_t *pool)
 
938
{
 
939
  apr_hash_t *entries;
 
940
  svn_fs_dirent_t *ent;
 
941
 
 
942
  SVN_ERR (svn_fs_dir_entries (&entries, root, path, pool));
 
943
  ent = apr_hash_get (entries, name, APR_HASH_KEY_STRING);
 
944
 
 
945
  if (ent)
 
946
    *present = TRUE;
 
947
  else
 
948
    *present = FALSE;
 
949
 
 
950
  return SVN_NO_ERROR;
 
951
}
 
952
 
 
953
 
 
954
/* Return an error if entry NAME is absent in directory PATH under ROOT. */
 
955
static svn_error_t *
 
956
check_entry_present (svn_fs_root_t *root, const char *path, 
 
957
                     const char *name, apr_pool_t *pool)
 
958
{
 
959
  svn_boolean_t present;
 
960
  SVN_ERR (check_entry (root, path, name, &present, pool));
 
961
 
 
962
  if (! present)
 
963
    return svn_error_createf
 
964
      (SVN_ERR_FS_GENERAL, NULL,
 
965
       "entry \"%s\" absent when it should be present", name);
 
966
 
 
967
  return SVN_NO_ERROR;
 
968
}
 
969
 
 
970
 
 
971
/* Return an error if entry NAME is present in directory PATH under ROOT. */
 
972
static svn_error_t *
 
973
check_entry_absent (svn_fs_root_t *root, const char *path, 
 
974
                    const char *name, apr_pool_t *pool)
 
975
{
 
976
  svn_boolean_t present;
 
977
  SVN_ERR (check_entry (root, path, name, &present, pool));
 
978
 
 
979
  if (present)
 
980
    return svn_error_createf
 
981
      (SVN_ERR_FS_GENERAL, NULL,
 
982
       "entry \"%s\" present when it should be absent", name);
 
983
 
 
984
  return SVN_NO_ERROR;
 
985
}
 
986
 
 
987
 
 
988
struct check_id_args
 
989
{
 
990
  svn_fs_t *fs;
 
991
  const svn_fs_id_t *id;
 
992
  svn_boolean_t present;
 
993
};
 
994
 
 
995
 
 
996
static svn_error_t *
 
997
txn_body_check_id (void *baton, trail_t *trail)
 
998
{
 
999
  struct check_id_args *args = baton;
 
1000
  node_revision_t *noderev;
 
1001
  svn_error_t *err;
 
1002
 
 
1003
  err = svn_fs_bdb__get_node_revision (&noderev, args->fs, args->id, 
 
1004
                                       trail, trail->pool);
 
1005
 
 
1006
  if (err && (err->apr_err == SVN_ERR_FS_ID_NOT_FOUND))
 
1007
    args->present = FALSE;
 
1008
  else if (! err)
 
1009
    args->present = TRUE;
 
1010
  else
 
1011
    {
 
1012
      svn_string_t *id_str = svn_fs_unparse_id (args->id, trail->pool);
 
1013
      return svn_error_createf
 
1014
        (SVN_ERR_FS_GENERAL, err,
 
1015
         "error looking for node revision id \"%s\"", id_str->data);
 
1016
    }
 
1017
  svn_error_clear (err);
 
1018
 
 
1019
  return SVN_NO_ERROR;
 
1020
}
 
1021
 
 
1022
 
 
1023
/* Set *PRESENT to true if node revision ID is present in filesystem
 
1024
   FS, else set *PRESENT to false. */
 
1025
static svn_error_t *
 
1026
check_id (svn_fs_t *fs, const svn_fs_id_t *id, svn_boolean_t *present,
 
1027
          apr_pool_t *pool)
 
1028
{
 
1029
  struct check_id_args args;
 
1030
 
 
1031
  args.id = id;
 
1032
  args.fs = fs;
 
1033
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_check_id, &args, pool));
 
1034
 
 
1035
  if (args.present)
 
1036
    *present = TRUE;
 
1037
  else
 
1038
    *present = FALSE;
 
1039
 
 
1040
  return SVN_NO_ERROR;
 
1041
}
 
1042
 
 
1043
 
 
1044
/* Return error if node revision ID is not present in FS. */
 
1045
static svn_error_t *
 
1046
check_id_present (svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool)
 
1047
{
 
1048
  svn_boolean_t present;
 
1049
  SVN_ERR (check_id (fs, id, &present, pool));
 
1050
 
 
1051
  if (! present)
 
1052
    {
 
1053
      svn_string_t *id_str = svn_fs_unparse_id (id, pool);
 
1054
      return svn_error_createf
 
1055
        (SVN_ERR_FS_GENERAL, NULL,
 
1056
         "node revision id \"%s\" absent when should be present",
 
1057
         id_str->data);
 
1058
    }
 
1059
 
 
1060
  return SVN_NO_ERROR;
 
1061
}
 
1062
 
 
1063
 
 
1064
/* Return error if node revision ID is present in FS. */
 
1065
static svn_error_t *
 
1066
check_id_absent (svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool)
 
1067
{
 
1068
  svn_boolean_t present;
 
1069
  SVN_ERR (check_id (fs, id, &present, pool));
 
1070
 
 
1071
  if (present)
 
1072
    {
 
1073
      svn_string_t *id_str = svn_fs_unparse_id (id, pool);
 
1074
      return svn_error_createf
 
1075
        (SVN_ERR_FS_GENERAL, NULL,
 
1076
         "node revision id \"%s\" present when should be absent",
 
1077
         id_str->data);
 
1078
    }
 
1079
 
 
1080
  return SVN_NO_ERROR;
 
1081
}
 
1082
 
 
1083
 
 
1084
/* Test that aborting a Subversion transaction works.
 
1085
 
 
1086
   NOTE: This function tests internal filesystem interfaces, not just
 
1087
   the public filesystem interface.  */
 
1088
static svn_error_t *
 
1089
abort_txn (const char **msg,
 
1090
           svn_boolean_t msg_only,
 
1091
           svn_test_opts_t *opts,
 
1092
           apr_pool_t *pool)
 
1093
{
 
1094
  svn_fs_t *fs;
 
1095
  svn_fs_txn_t *txn1, *txn2;
 
1096
  svn_fs_root_t *txn1_root, *txn2_root;
 
1097
  const char *txn1_name, *txn2_name;
 
1098
 
 
1099
  *msg = "abort a transaction";
 
1100
 
 
1101
  if (msg_only)
 
1102
    return SVN_NO_ERROR;
 
1103
 
 
1104
  /* Prepare two txns to receive the Greek tree. */
 
1105
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-abort-txn",
 
1106
                                "bdb", pool));
 
1107
  SVN_ERR (svn_fs_begin_txn (&txn1, fs, 0, pool));
 
1108
  SVN_ERR (svn_fs_begin_txn (&txn2, fs, 0, pool));
 
1109
  SVN_ERR (svn_fs_txn_root (&txn1_root, txn1, pool));
 
1110
  SVN_ERR (svn_fs_txn_root (&txn2_root, txn2, pool));
 
1111
 
 
1112
  /* Save their names for later. */
 
1113
  SVN_ERR (svn_fs_txn_name (&txn1_name, txn1, pool));
 
1114
  SVN_ERR (svn_fs_txn_name (&txn2_name, txn2, pool));
 
1115
  
 
1116
  /* Create greek trees in them. */
 
1117
  SVN_ERR (svn_test__create_greek_tree (txn1_root, pool));
 
1118
  SVN_ERR (svn_test__create_greek_tree (txn2_root, pool));
 
1119
 
 
1120
  /* The test is to abort txn2, while leaving txn1.
 
1121
   *
 
1122
   * After we abort txn2, we make sure that a) all of its nodes
 
1123
   * disappeared from the database, and b) none of txn1's nodes
 
1124
   * disappeared.
 
1125
   *
 
1126
   * Finally, we create a third txn, and check that the name it got is
 
1127
   * different from the names of txn1 and txn2.
 
1128
   */
 
1129
 
 
1130
  {
 
1131
    /* Yes, I really am this paranoid. */
 
1132
 
 
1133
    /* IDs for every file in the standard Greek Tree. */
 
1134
    const svn_fs_id_t
 
1135
      *t1_root_id,    *t2_root_id,
 
1136
      *t1_iota_id,    *t2_iota_id,
 
1137
      *t1_A_id,       *t2_A_id,
 
1138
      *t1_mu_id,      *t2_mu_id,
 
1139
      *t1_B_id,       *t2_B_id,
 
1140
      *t1_lambda_id,  *t2_lambda_id,
 
1141
      *t1_E_id,       *t2_E_id,
 
1142
      *t1_alpha_id,   *t2_alpha_id,
 
1143
      *t1_beta_id,    *t2_beta_id,
 
1144
      *t1_F_id,       *t2_F_id,
 
1145
      *t1_C_id,       *t2_C_id,
 
1146
      *t1_D_id,       *t2_D_id,
 
1147
      *t1_gamma_id,   *t2_gamma_id,
 
1148
      *t1_H_id,       *t2_H_id,
 
1149
      *t1_chi_id,     *t2_chi_id,
 
1150
      *t1_psi_id,     *t2_psi_id,
 
1151
      *t1_omega_id,   *t2_omega_id,
 
1152
      *t1_G_id,       *t2_G_id,
 
1153
      *t1_pi_id,      *t2_pi_id,
 
1154
      *t1_rho_id,     *t2_rho_id,
 
1155
      *t1_tau_id,     *t2_tau_id;
 
1156
    
 
1157
    SVN_ERR (svn_fs_node_id (&t1_root_id, txn1_root, "", pool));
 
1158
    SVN_ERR (svn_fs_node_id (&t2_root_id, txn2_root, "", pool));
 
1159
    SVN_ERR (svn_fs_node_id (&t1_iota_id, txn1_root, "iota", pool));
 
1160
    SVN_ERR (svn_fs_node_id (&t2_iota_id, txn2_root, "iota", pool));
 
1161
    SVN_ERR (svn_fs_node_id (&t1_A_id, txn1_root, "/A", pool));
 
1162
    SVN_ERR (svn_fs_node_id (&t2_A_id, txn2_root, "/A", pool));
 
1163
    SVN_ERR (svn_fs_node_id (&t1_mu_id, txn1_root, "/A/mu", pool));
 
1164
    SVN_ERR (svn_fs_node_id (&t2_mu_id, txn2_root, "/A/mu", pool));
 
1165
    SVN_ERR (svn_fs_node_id (&t1_B_id, txn1_root, "/A/B", pool));
 
1166
    SVN_ERR (svn_fs_node_id (&t2_B_id, txn2_root, "/A/B", pool));
 
1167
    SVN_ERR (svn_fs_node_id (&t1_lambda_id, txn1_root, "/A/B/lambda", pool));
 
1168
    SVN_ERR (svn_fs_node_id (&t2_lambda_id, txn2_root, "/A/B/lambda", pool));
 
1169
    SVN_ERR (svn_fs_node_id (&t1_E_id, txn1_root, "/A/B/E", pool));
 
1170
    SVN_ERR (svn_fs_node_id (&t2_E_id, txn2_root, "/A/B/E", pool));
 
1171
    SVN_ERR (svn_fs_node_id (&t1_alpha_id, txn1_root, "/A/B/E/alpha", pool));
 
1172
    SVN_ERR (svn_fs_node_id (&t2_alpha_id, txn2_root, "/A/B/E/alpha", pool));
 
1173
    SVN_ERR (svn_fs_node_id (&t1_beta_id, txn1_root, "/A/B/E/beta", pool));
 
1174
    SVN_ERR (svn_fs_node_id (&t2_beta_id, txn2_root, "/A/B/E/beta", pool));
 
1175
    SVN_ERR (svn_fs_node_id (&t1_F_id, txn1_root, "/A/B/F", pool));
 
1176
    SVN_ERR (svn_fs_node_id (&t2_F_id, txn2_root, "/A/B/F", pool));
 
1177
    SVN_ERR (svn_fs_node_id (&t1_C_id, txn1_root, "/A/C", pool));
 
1178
    SVN_ERR (svn_fs_node_id (&t2_C_id, txn2_root, "/A/C", pool));
 
1179
    SVN_ERR (svn_fs_node_id (&t1_D_id, txn1_root, "/A/D", pool));
 
1180
    SVN_ERR (svn_fs_node_id (&t2_D_id, txn2_root, "/A/D", pool));
 
1181
    SVN_ERR (svn_fs_node_id (&t1_gamma_id, txn1_root, "/A/D/gamma", pool));
 
1182
    SVN_ERR (svn_fs_node_id (&t2_gamma_id, txn2_root, "/A/D/gamma", pool));
 
1183
    SVN_ERR (svn_fs_node_id (&t1_H_id, txn1_root, "/A/D/H", pool));
 
1184
    SVN_ERR (svn_fs_node_id (&t2_H_id, txn2_root, "/A/D/H", pool));
 
1185
    SVN_ERR (svn_fs_node_id (&t1_chi_id, txn1_root, "/A/D/H/chi", pool));
 
1186
    SVN_ERR (svn_fs_node_id (&t2_chi_id, txn2_root, "/A/D/H/chi", pool));
 
1187
    SVN_ERR (svn_fs_node_id (&t1_psi_id, txn1_root, "/A/D/H/psi", pool));
 
1188
    SVN_ERR (svn_fs_node_id (&t2_psi_id, txn2_root, "/A/D/H/psi", pool));
 
1189
    SVN_ERR (svn_fs_node_id (&t1_omega_id, txn1_root, "/A/D/H/omega", pool));
 
1190
    SVN_ERR (svn_fs_node_id (&t2_omega_id, txn2_root, "/A/D/H/omega", pool));
 
1191
    SVN_ERR (svn_fs_node_id (&t1_G_id, txn1_root, "/A/D/G", pool));
 
1192
    SVN_ERR (svn_fs_node_id (&t2_G_id, txn2_root, "/A/D/G", pool));
 
1193
    SVN_ERR (svn_fs_node_id (&t1_pi_id, txn1_root, "/A/D/G/pi", pool));
 
1194
    SVN_ERR (svn_fs_node_id (&t2_pi_id, txn2_root, "/A/D/G/pi", pool));
 
1195
    SVN_ERR (svn_fs_node_id (&t1_rho_id, txn1_root, "/A/D/G/rho", pool));
 
1196
    SVN_ERR (svn_fs_node_id (&t2_rho_id, txn2_root, "/A/D/G/rho", pool));
 
1197
    SVN_ERR (svn_fs_node_id (&t1_tau_id, txn1_root, "/A/D/G/tau", pool));
 
1198
    SVN_ERR (svn_fs_node_id (&t2_tau_id, txn2_root, "/A/D/G/tau", pool));
 
1199
 
 
1200
    /* Abort just txn2. */
 
1201
    SVN_ERR (svn_fs_abort_txn (txn2, pool));
 
1202
 
 
1203
    /* Now test that all the nodes in txn2 at the time of the abort
 
1204
     * are gone, but all of the ones in txn1 are still there. 
 
1205
     */
 
1206
 
 
1207
    /* Check that every node rev in t2 has vanished from the fs. */
 
1208
    SVN_ERR (check_id_absent (fs, t2_root_id, pool));
 
1209
    SVN_ERR (check_id_absent (fs, t2_iota_id, pool));
 
1210
    SVN_ERR (check_id_absent (fs, t2_A_id, pool));
 
1211
    SVN_ERR (check_id_absent (fs, t2_mu_id, pool));
 
1212
    SVN_ERR (check_id_absent (fs, t2_B_id, pool));
 
1213
    SVN_ERR (check_id_absent (fs, t2_lambda_id, pool));
 
1214
    SVN_ERR (check_id_absent (fs, t2_E_id, pool));
 
1215
    SVN_ERR (check_id_absent (fs, t2_alpha_id, pool));
 
1216
    SVN_ERR (check_id_absent (fs, t2_beta_id, pool));
 
1217
    SVN_ERR (check_id_absent (fs, t2_F_id, pool));
 
1218
    SVN_ERR (check_id_absent (fs, t2_C_id, pool));
 
1219
    SVN_ERR (check_id_absent (fs, t2_D_id, pool));
 
1220
    SVN_ERR (check_id_absent (fs, t2_gamma_id, pool));
 
1221
    SVN_ERR (check_id_absent (fs, t2_H_id, pool));
 
1222
    SVN_ERR (check_id_absent (fs, t2_chi_id, pool));
 
1223
    SVN_ERR (check_id_absent (fs, t2_psi_id, pool));
 
1224
    SVN_ERR (check_id_absent (fs, t2_omega_id, pool));
 
1225
    SVN_ERR (check_id_absent (fs, t2_G_id, pool));
 
1226
    SVN_ERR (check_id_absent (fs, t2_pi_id, pool));
 
1227
    SVN_ERR (check_id_absent (fs, t2_rho_id, pool));
 
1228
    SVN_ERR (check_id_absent (fs, t2_tau_id, pool));
 
1229
    
 
1230
    /* Check that every node rev in t1 is still in the fs. */
 
1231
    SVN_ERR (check_id_present (fs, t1_root_id, pool));
 
1232
    SVN_ERR (check_id_present (fs, t1_iota_id, pool));
 
1233
    SVN_ERR (check_id_present (fs, t1_A_id, pool));
 
1234
    SVN_ERR (check_id_present (fs, t1_mu_id, pool));
 
1235
    SVN_ERR (check_id_present (fs, t1_B_id, pool));
 
1236
    SVN_ERR (check_id_present (fs, t1_lambda_id, pool));
 
1237
    SVN_ERR (check_id_present (fs, t1_E_id, pool));
 
1238
    SVN_ERR (check_id_present (fs, t1_alpha_id, pool));
 
1239
    SVN_ERR (check_id_present (fs, t1_beta_id, pool));
 
1240
    SVN_ERR (check_id_present (fs, t1_F_id, pool));
 
1241
    SVN_ERR (check_id_present (fs, t1_C_id, pool));
 
1242
    SVN_ERR (check_id_present (fs, t1_D_id, pool));
 
1243
    SVN_ERR (check_id_present (fs, t1_gamma_id, pool));
 
1244
    SVN_ERR (check_id_present (fs, t1_H_id, pool));
 
1245
    SVN_ERR (check_id_present (fs, t1_chi_id, pool));
 
1246
    SVN_ERR (check_id_present (fs, t1_psi_id, pool));
 
1247
    SVN_ERR (check_id_present (fs, t1_omega_id, pool));
 
1248
    SVN_ERR (check_id_present (fs, t1_G_id, pool));
 
1249
    SVN_ERR (check_id_present (fs, t1_pi_id, pool));
 
1250
    SVN_ERR (check_id_present (fs, t1_rho_id, pool));
 
1251
    SVN_ERR (check_id_present (fs, t1_tau_id, pool));
 
1252
  }
 
1253
 
 
1254
  /* Test that txn2 itself is gone, by trying to open it. */
 
1255
  {
 
1256
    svn_fs_txn_t *txn2_again;
 
1257
    svn_error_t *err;
 
1258
 
 
1259
    err = svn_fs_open_txn (&txn2_again, fs, txn2_name, pool);
 
1260
    if (err && (err->apr_err != SVN_ERR_FS_NO_SUCH_TRANSACTION))
 
1261
      {
 
1262
        return svn_error_create
 
1263
          (SVN_ERR_FS_GENERAL, NULL,
 
1264
           "opening non-existent txn got wrong error");
 
1265
      }
 
1266
    else if (! err)
 
1267
      {
 
1268
        return svn_error_create
 
1269
          (SVN_ERR_FS_GENERAL, NULL,
 
1270
           "opening non-existent txn failed to get error");
 
1271
      }
 
1272
    svn_error_clear (err);
 
1273
  }
 
1274
 
 
1275
  /* Test that txn names are not recycled, by opening a new txn.  */
 
1276
  {
 
1277
    svn_fs_txn_t *txn3;
 
1278
    const char *txn3_name;
 
1279
 
 
1280
    SVN_ERR (svn_fs_begin_txn (&txn3, fs, 0, pool));
 
1281
    SVN_ERR (svn_fs_txn_name (&txn3_name, txn3, pool));
 
1282
 
 
1283
    if ((strcmp (txn3_name, txn2_name) == 0)
 
1284
        || (strcmp (txn3_name, txn1_name) == 0))
 
1285
      {
 
1286
        return svn_error_createf
 
1287
          (SVN_ERR_FS_GENERAL, NULL,
 
1288
           "txn name \"%s\" was recycled", txn3_name);
 
1289
      }
 
1290
  }
 
1291
 
 
1292
  /* Test that aborting a txn that's already committed fails. */
 
1293
  {
 
1294
    svn_fs_txn_t *txn4;
 
1295
    const char *txn4_name;
 
1296
    svn_revnum_t new_rev;
 
1297
    const char *conflict;
 
1298
    svn_error_t *err;
 
1299
 
 
1300
    SVN_ERR (svn_fs_begin_txn (&txn4, fs, 0, pool));
 
1301
    SVN_ERR (svn_fs_txn_name (&txn4_name, txn4, pool));
 
1302
    SVN_ERR (svn_fs_commit_txn (&conflict, &new_rev, txn4, pool));
 
1303
    err = svn_fs_abort_txn (txn4, pool);
 
1304
    if (! err)
 
1305
      return svn_error_create
 
1306
        (SVN_ERR_FS_GENERAL, NULL,
 
1307
         "expected error trying to abort a committed txn; got none");
 
1308
    else if (err->apr_err != SVN_ERR_FS_TRANSACTION_NOT_MUTABLE)
 
1309
      return svn_error_create
 
1310
        (SVN_ERR_FS_GENERAL, err,
 
1311
         "got an unexpected error trying to abort a committed txn");
 
1312
    else
 
1313
      svn_error_clear (err);
 
1314
  }
 
1315
  return SVN_NO_ERROR;
 
1316
}
 
1317
 
 
1318
 
 
1319
/* Fetch the youngest revision from a repos. */
 
1320
static svn_error_t *
 
1321
fetch_youngest_rev (const char **msg,
 
1322
                    svn_boolean_t msg_only,
 
1323
                    svn_test_opts_t *opts,
 
1324
                    apr_pool_t *pool)
 
1325
{
 
1326
  svn_fs_t *fs;
 
1327
  svn_fs_txn_t *txn;
 
1328
  svn_fs_root_t *txn_root;
 
1329
  svn_revnum_t new_rev;
 
1330
  svn_revnum_t youngest_rev, new_youngest_rev;
 
1331
 
 
1332
  *msg = "fetch the youngest revision from a filesystem";
 
1333
 
 
1334
  if (msg_only)
 
1335
    return SVN_NO_ERROR;
 
1336
 
 
1337
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-youngest-rev",
 
1338
                                "bdb", pool));
 
1339
 
 
1340
  /* Get youngest revision of brand spankin' new filesystem. */
 
1341
  SVN_ERR (svn_fs_youngest_rev (&youngest_rev, fs, pool));
 
1342
 
 
1343
  /* Prepare a txn to receive the greek tree. */
 
1344
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-commit-txn",
 
1345
                                "bdb", pool));
 
1346
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
1347
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1348
 
 
1349
  /* Create the greek tree. */
 
1350
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
1351
 
 
1352
  /* Commit it. */
 
1353
  SVN_ERR (test_commit_txn (&new_rev, txn, NULL, pool));
 
1354
 
 
1355
  /* Get the new youngest revision. */
 
1356
  SVN_ERR (svn_fs_youngest_rev (&new_youngest_rev, fs, pool));
 
1357
 
 
1358
  if (youngest_rev == new_rev)
 
1359
    return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
 
1360
                             "commit didn't bump up revision number");
 
1361
 
 
1362
  if (new_youngest_rev != new_rev)
 
1363
    return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
 
1364
                             "couldn't fetch youngest revision");
 
1365
 
 
1366
  return SVN_NO_ERROR;
 
1367
}
 
1368
 
 
1369
 
 
1370
/* Test committing against an empty repository.
 
1371
   todo: also test committing against youngest? */
 
1372
static svn_error_t *
 
1373
basic_commit (const char **msg,
 
1374
              svn_boolean_t msg_only,
 
1375
              svn_test_opts_t *opts,
 
1376
              apr_pool_t *pool)
 
1377
{
 
1378
  svn_fs_t *fs;
 
1379
  svn_fs_txn_t *txn;
 
1380
  svn_fs_root_t *txn_root, *revision_root;
 
1381
  svn_revnum_t before_rev, after_rev;
 
1382
  const char *conflict;
 
1383
 
 
1384
  *msg = "basic commit";
 
1385
 
 
1386
  if (msg_only)
 
1387
    return SVN_NO_ERROR;
 
1388
 
 
1389
  /* Prepare a filesystem. */
 
1390
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-basic-commit",
 
1391
                                "bdb", pool));
 
1392
 
 
1393
  /* Save the current youngest revision. */
 
1394
  SVN_ERR (svn_fs_youngest_rev (&before_rev, fs, pool));
 
1395
 
 
1396
  /* Prepare a txn to receive the greek tree. */
 
1397
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
1398
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1399
 
 
1400
  /* Paranoidly check that the current youngest rev is unchanged. */
 
1401
  SVN_ERR (svn_fs_youngest_rev (&after_rev, fs, pool));
 
1402
  if (after_rev != before_rev)
 
1403
    return svn_error_create
 
1404
      (SVN_ERR_FS_GENERAL, NULL,
 
1405
       "youngest revision changed unexpectedly");
 
1406
 
 
1407
  /* Create the greek tree. */
 
1408
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
1409
 
 
1410
  /* Commit it. */
 
1411
  SVN_ERR (svn_fs_commit_txn (&conflict, &after_rev, txn, pool));
 
1412
 
 
1413
  /* Make sure it's a different revision than before. */
 
1414
  if (after_rev == before_rev)
 
1415
    return svn_error_create
 
1416
      (SVN_ERR_FS_GENERAL, NULL,
 
1417
       "youngest revision failed to change");
 
1418
 
 
1419
  /* Get root of the revision */
 
1420
  SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
 
1421
 
 
1422
  /* Check the tree. */
 
1423
  SVN_ERR (svn_test__check_greek_tree (revision_root, pool));
 
1424
 
 
1425
  return SVN_NO_ERROR;
 
1426
}
 
1427
 
 
1428
 
 
1429
 
 
1430
static svn_error_t *
 
1431
test_tree_node_validation (const char **msg,
 
1432
                           svn_boolean_t msg_only,
 
1433
                           svn_test_opts_t *opts,
 
1434
                           apr_pool_t *pool)
 
1435
{
 
1436
  svn_fs_t *fs;
 
1437
  svn_fs_txn_t *txn;
 
1438
  svn_fs_root_t *txn_root, *revision_root;
 
1439
  svn_revnum_t after_rev;
 
1440
  const char *conflict;
 
1441
  apr_pool_t *subpool;
 
1442
 
 
1443
  *msg = "testing tree validation helper";
 
1444
 
 
1445
  if (msg_only)
 
1446
    return SVN_NO_ERROR;
 
1447
 
 
1448
  /* Prepare a filesystem. */
 
1449
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-validate-tree-entries",
 
1450
                                "bdb", pool));
 
1451
 
 
1452
  /* In a txn, create the greek tree. */
 
1453
  subpool = svn_pool_create (pool);
 
1454
  {
 
1455
    static svn_test__tree_entry_t expected_entries[] = {
 
1456
      /* path, contents (0 = dir) */
 
1457
      { "iota",        "This is the file 'iota'.\n" },
 
1458
      { "A",           0 },
 
1459
      { "A/mu",        "This is the file 'mu'.\n" },
 
1460
      { "A/B",         0 },
 
1461
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
1462
      { "A/B/E",       0 },
 
1463
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
1464
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
1465
      { "A/B/F",       0 },
 
1466
      { "A/C",         0 },
 
1467
      { "A/D",         0 },
 
1468
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
1469
      { "A/D/G",       0 },
 
1470
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
1471
      { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
1472
      { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
1473
      { "A/D/H",       0 },
 
1474
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
1475
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
1476
      { "A/D/H/omega", "This is the file 'omega'.\n" }
 
1477
    };
 
1478
    SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
 
1479
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
1480
    SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
 
1481
 
 
1482
    /* Carefully validate that tree in the transaction. */
 
1483
    SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 20, 
 
1484
                                      subpool));
 
1485
 
 
1486
    /* Go ahead and commit the tree, and destroy the txn object.  */
 
1487
    SVN_ERR (svn_fs_commit_txn (&conflict, &after_rev, txn, subpool));
 
1488
 
 
1489
    /* Carefully validate that tree in the new revision, now. */
 
1490
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, subpool));
 
1491
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 20, 
 
1492
                                      subpool));
 
1493
  }
 
1494
  svn_pool_destroy (subpool);
 
1495
 
 
1496
  /* In a new txn, modify the greek tree. */
 
1497
  subpool = svn_pool_create (pool);
 
1498
  {
 
1499
    static svn_test__tree_entry_t expected_entries[] = {
 
1500
      /* path, contents (0 = dir) */
 
1501
      { "iota",          "This is a new version of 'iota'.\n" },
 
1502
      { "A",             0 },
 
1503
      { "A/B",           0 },
 
1504
      { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1505
      { "A/B/E",         0 },
 
1506
      { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1507
      { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1508
      { "A/B/F",         0 },
 
1509
      { "A/C",           0 },
 
1510
      { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1511
      { "A/D",           0 },
 
1512
      { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
1513
      { "A/D/H",         0 },
 
1514
      { "A/D/H/chi",     "This is the file 'chi'.\n" },
 
1515
      { "A/D/H/psi",     "This is the file 'psi'.\n" },
 
1516
      { "A/D/H/omega",   "This is the file 'omega'.\n" },
 
1517
      { "A/D/I",         0 },
 
1518
      { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
1519
      { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
1520
    };
 
1521
 
 
1522
    SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, subpool));
 
1523
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
1524
    SVN_ERR (svn_test__set_file_contents 
 
1525
             (txn_root, "iota", "This is a new version of 'iota'.\n", 
 
1526
              subpool));
 
1527
    SVN_ERR (svn_fs_delete (txn_root, "A/mu", subpool));            
 
1528
    SVN_ERR (svn_fs_delete (txn_root, "A/D/G", subpool));            
 
1529
    SVN_ERR (svn_fs_make_dir (txn_root, "A/D/I", subpool));
 
1530
    SVN_ERR (svn_fs_make_file (txn_root, "A/D/I/delta", subpool));
 
1531
    SVN_ERR (svn_test__set_file_contents 
 
1532
             (txn_root, "A/D/I/delta", "This is the file 'delta'.\n", 
 
1533
              subpool));
 
1534
    SVN_ERR (svn_fs_make_file (txn_root, "A/D/I/epsilon", subpool));
 
1535
    SVN_ERR (svn_test__set_file_contents 
 
1536
             (txn_root, "A/D/I/epsilon", "This is the file 'epsilon'.\n", 
 
1537
              subpool));
 
1538
    SVN_ERR (svn_fs_make_file (txn_root, "A/C/kappa", subpool));
 
1539
    SVN_ERR (svn_test__set_file_contents 
 
1540
             (txn_root, "A/C/kappa", "This is the file 'kappa'.\n", 
 
1541
              subpool));
 
1542
 
 
1543
    /* Carefully validate that tree in the transaction. */
 
1544
    SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 19, 
 
1545
                                      subpool));
 
1546
    
 
1547
    /* Go ahead and commit the tree, and destroy the txn object.  */
 
1548
    SVN_ERR (svn_fs_commit_txn (&conflict, &after_rev, txn, subpool));
 
1549
 
 
1550
    /* Carefully validate that tree in the new revision, now. */
 
1551
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, subpool));
 
1552
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
 
1553
                                      19, subpool));
 
1554
  }
 
1555
  svn_pool_destroy (subpool);
 
1556
 
 
1557
  return SVN_NO_ERROR;
 
1558
}
 
1559
 
 
1560
 
 
1561
/* Commit with merging (committing against non-youngest). */ 
 
1562
static svn_error_t *
 
1563
merging_commit (const char **msg,
 
1564
                svn_boolean_t msg_only,
 
1565
                svn_test_opts_t *opts,
 
1566
                apr_pool_t *pool)
 
1567
{
 
1568
  svn_fs_t *fs;
 
1569
  svn_fs_txn_t *txn;
 
1570
  svn_fs_root_t *txn_root, *revision_root;
 
1571
  svn_revnum_t after_rev;
 
1572
  svn_revnum_t revisions[24];
 
1573
  apr_size_t i;
 
1574
  svn_revnum_t revision_count;
 
1575
 
 
1576
  *msg = "merging commit";
 
1577
 
 
1578
  if (msg_only)
 
1579
    return SVN_NO_ERROR;
 
1580
 
 
1581
  /* Initialize our revision number stuffs. */
 
1582
  for (i = 0;
 
1583
       i < ((sizeof (revisions)) / (sizeof (svn_revnum_t)));
 
1584
       i++)
 
1585
    revisions[i] = SVN_INVALID_REVNUM;
 
1586
  revision_count = 0;
 
1587
 
 
1588
  /* Prepare a filesystem. */
 
1589
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-merging-commit",
 
1590
                                "bdb", pool));
 
1591
  revisions[revision_count++] = 0; /* the brand spankin' new revision */
 
1592
 
 
1593
  /***********************************************************************/
 
1594
  /* REVISION 0 */
 
1595
  /***********************************************************************/
 
1596
 
 
1597
  /* In one txn, create and commit the greek tree. */
 
1598
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
1599
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1600
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
1601
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1602
 
 
1603
  /***********************************************************************/
 
1604
  /* REVISION 1 */
 
1605
  /***********************************************************************/
 
1606
  {
 
1607
    static svn_test__tree_entry_t expected_entries[] = {
 
1608
      /* path, contents (0 = dir) */
 
1609
      { "iota",        "This is the file 'iota'.\n" },
 
1610
      { "A",           0 },
 
1611
      { "A/mu",        "This is the file 'mu'.\n" },
 
1612
      { "A/B",         0 },
 
1613
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
1614
      { "A/B/E",       0 },
 
1615
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
1616
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
1617
      { "A/B/F",       0 },
 
1618
      { "A/C",         0 },
 
1619
      { "A/D",         0 },
 
1620
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
1621
      { "A/D/G",       0 },
 
1622
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
1623
      { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
1624
      { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
1625
      { "A/D/H",       0 },
 
1626
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
1627
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
1628
      { "A/D/H/omega", "This is the file 'omega'.\n" }
 
1629
    };
 
1630
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
1631
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 
 
1632
                                      20, pool));
 
1633
  }
 
1634
  revisions[revision_count++] = after_rev;
 
1635
 
 
1636
  /* Let's add a directory and some files to the tree, and delete 
 
1637
     'iota' */
 
1638
  SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[revision_count-1], pool));
 
1639
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1640
  SVN_ERR (svn_fs_make_dir (txn_root, "A/D/I", pool));
 
1641
  SVN_ERR (svn_fs_make_file (txn_root, "A/D/I/delta", pool));
 
1642
  SVN_ERR (svn_test__set_file_contents 
 
1643
           (txn_root, "A/D/I/delta", "This is the file 'delta'.\n", pool));
 
1644
  SVN_ERR (svn_fs_make_file (txn_root, "A/D/I/epsilon", pool));
 
1645
  SVN_ERR (svn_test__set_file_contents 
 
1646
           (txn_root, "A/D/I/epsilon", "This is the file 'epsilon'.\n", pool));
 
1647
  SVN_ERR (svn_fs_make_file (txn_root, "A/C/kappa", pool));
 
1648
  SVN_ERR (svn_test__set_file_contents 
 
1649
           (txn_root, "A/C/kappa", "This is the file 'kappa'.\n", pool));
 
1650
  SVN_ERR (svn_fs_delete (txn_root, "iota", pool));
 
1651
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1652
 
 
1653
  /***********************************************************************/
 
1654
  /* REVISION 2 */
 
1655
  /***********************************************************************/
 
1656
  {
 
1657
    static svn_test__tree_entry_t expected_entries[] = {
 
1658
      /* path, contents (0 = dir) */
 
1659
      { "A",             0 },
 
1660
      { "A/mu",          "This is the file 'mu'.\n" },
 
1661
      { "A/B",           0 },
 
1662
      { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1663
      { "A/B/E",         0 },
 
1664
      { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1665
      { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1666
      { "A/B/F",         0 },
 
1667
      { "A/C",           0 },
 
1668
      { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1669
      { "A/D",           0 },
 
1670
      { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
1671
      { "A/D/G",         0 },
 
1672
      { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
1673
      { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
1674
      { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
1675
      { "A/D/H",         0 },
 
1676
      { "A/D/H/chi",     "This is the file 'chi'.\n" },
 
1677
      { "A/D/H/psi",     "This is the file 'psi'.\n" },
 
1678
      { "A/D/H/omega",   "This is the file 'omega'.\n" },
 
1679
      { "A/D/I",         0 },
 
1680
      { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
1681
      { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
1682
    };
 
1683
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
1684
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 
 
1685
                                      23, pool));
 
1686
  }
 
1687
  revisions[revision_count++] = after_rev;
 
1688
 
 
1689
  /* We don't think the A/D/H directory is pulling its weight...let's
 
1690
     knock it off.  Oh, and let's re-add iota, too. */
 
1691
  SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[revision_count-1], pool));
 
1692
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1693
  SVN_ERR (svn_fs_delete (txn_root, "A/D/H", pool));
 
1694
  SVN_ERR (svn_fs_make_file (txn_root, "iota", pool));
 
1695
  SVN_ERR (svn_test__set_file_contents 
 
1696
           (txn_root, "iota", "This is the new file 'iota'.\n", pool));
 
1697
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1698
 
 
1699
  /***********************************************************************/
 
1700
  /* REVISION 3 */
 
1701
  /***********************************************************************/
 
1702
  {
 
1703
    static svn_test__tree_entry_t expected_entries[] = {
 
1704
      /* path, contents (0 = dir) */
 
1705
      { "iota",          "This is the new file 'iota'.\n" },
 
1706
      { "A",             0 },
 
1707
      { "A/mu",          "This is the file 'mu'.\n" },
 
1708
      { "A/B",           0 },
 
1709
      { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1710
      { "A/B/E",         0 },
 
1711
      { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1712
      { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1713
      { "A/B/F",         0 },
 
1714
      { "A/C",           0 },
 
1715
      { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1716
      { "A/D",           0 },
 
1717
      { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
1718
      { "A/D/G",         0 },
 
1719
      { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
1720
      { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
1721
      { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
1722
      { "A/D/I",         0 },
 
1723
      { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
1724
      { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
1725
    };
 
1726
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
1727
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 
 
1728
                                      20, pool));
 
1729
  }
 
1730
  revisions[revision_count++] = after_rev;
 
1731
 
 
1732
  /* Delete iota (yet again). */
 
1733
  SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[revision_count-1], pool));
 
1734
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1735
  SVN_ERR (svn_fs_delete (txn_root, "iota", pool)); 
 
1736
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1737
 
 
1738
  /***********************************************************************/
 
1739
  /* REVISION 4 */
 
1740
  /***********************************************************************/
 
1741
  {
 
1742
    static svn_test__tree_entry_t expected_entries[] = {
 
1743
      /* path, contents (0 = dir) */
 
1744
      { "A",             0 },
 
1745
      { "A/mu",          "This is the file 'mu'.\n" },
 
1746
      { "A/B",           0 },
 
1747
      { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1748
      { "A/B/E",         0 },
 
1749
      { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1750
      { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1751
      { "A/B/F",         0 },
 
1752
      { "A/C",           0 },
 
1753
      { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1754
      { "A/D",           0 },
 
1755
      { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
1756
      { "A/D/G",         0 },
 
1757
      { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
1758
      { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
1759
      { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
1760
      { "A/D/I",         0 },
 
1761
      { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
1762
      { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
1763
    };
 
1764
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
1765
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 
 
1766
                                      19, pool));
 
1767
  }
 
1768
  revisions[revision_count++] = after_rev;
 
1769
 
 
1770
  /***********************************************************************/
 
1771
  /* GIVEN:  A and B, with common ancestor ANCESTOR, where A and B
 
1772
     directories, and E, an entry in either A, B, or ANCESTOR.
 
1773
 
 
1774
     For every E, the following cases exist:
 
1775
      - E exists in neither ANCESTOR nor A.
 
1776
      - E doesn't exist in ANCESTOR, and has been added to A.
 
1777
      - E exists in ANCESTOR, but has been deleted from A.
 
1778
      - E exists in both ANCESTOR and A ...
 
1779
        - but refers to different node revisions.
 
1780
        - and refers to the same node revision.
 
1781
 
 
1782
     The same set of possible relationships with ANCESTOR holds for B,
 
1783
     so there are thirty-six combinations.  The matrix is symmetrical
 
1784
     with A and B reversed, so we only have to describe one triangular
 
1785
     half, including the diagonal --- 21 combinations.
 
1786
 
 
1787
     Our goal here is to test all the possible scenarios that can
 
1788
     occur given the above boolean logic table, and to make sure that
 
1789
     the results we get are as expected.  
 
1790
 
 
1791
     The test cases below have the following features:
 
1792
 
 
1793
     - They run straight through the scenarios as described in the
 
1794
       `structure' document at this time.
 
1795
 
 
1796
     - In each case, a txn is begun based on some revision (ANCESTOR),
 
1797
       is modified into a new tree (B), and then is attempted to be
 
1798
       committed (which happens against the head of the tree, A).
 
1799
 
 
1800
     - If the commit is successful (and is *expected* to be such),
 
1801
       that new revision (which exists now as a result of the
 
1802
       successful commit) is thoroughly tested for accuracy of tree
 
1803
       entries, and in the case of files, for their contents.  It is
 
1804
       important to realize that these successful commits are
 
1805
       advancing the head of the tree, and each one effective becomes
 
1806
       the new `A' described in further test cases.
 
1807
  */
 
1808
  /***********************************************************************/
 
1809
 
 
1810
  /* (6) E exists in neither ANCESTOR nor A. */
 
1811
  {
 
1812
    /* (1) E exists in neither ANCESTOR nor B.  Can't occur, by
 
1813
       assumption that E exists in either A, B, or ancestor. */
 
1814
 
 
1815
    /* (1) E has been added to B.  Add E in the merged result. */
 
1816
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[0], pool));
 
1817
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1818
    SVN_ERR (svn_fs_make_file (txn_root, "theta", pool));
 
1819
    SVN_ERR (svn_test__set_file_contents 
 
1820
             (txn_root, "theta", "This is the file 'theta'.\n", pool));
 
1821
    SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1822
 
 
1823
    /*********************************************************************/
 
1824
    /* REVISION 5 */
 
1825
    /*********************************************************************/
 
1826
    {
 
1827
      static svn_test__tree_entry_t expected_entries[] = {
 
1828
        /* path, contents (0 = dir) */
 
1829
        { "theta",         "This is the file 'theta'.\n" },
 
1830
        { "A",             0 },
 
1831
        { "A/mu",          "This is the file 'mu'.\n" },
 
1832
        { "A/B",           0 },
 
1833
        { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1834
        { "A/B/E",         0 },
 
1835
        { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1836
        { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1837
        { "A/B/F",         0 },
 
1838
        { "A/C",           0 },
 
1839
        { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1840
        { "A/D",           0 },
 
1841
        { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
1842
        { "A/D/G",         0 },
 
1843
        { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
1844
        { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
1845
        { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
1846
        { "A/D/I",         0 },
 
1847
        { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
1848
        { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
1849
      };
 
1850
      SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
1851
      SVN_ERR (svn_test__validate_tree (revision_root,
 
1852
                                        expected_entries, 
 
1853
                                        20, pool));
 
1854
    }
 
1855
    revisions[revision_count++] = after_rev;
 
1856
 
 
1857
    /* (1) E has been deleted from B.  Can't occur, by assumption that
 
1858
       E doesn't exist in ANCESTOR. */
 
1859
 
 
1860
    /* (3) E exists in both ANCESTOR and B.  Can't occur, by
 
1861
       assumption that E doesn't exist in ancestor. */
 
1862
  }
 
1863
 
 
1864
  /* (5) E doesn't exist in ANCESTOR, and has been added to A. */
 
1865
  {
 
1866
    /* (1) E doesn't exist in ANCESTOR, and has been added to B.
 
1867
       Conflict. */
 
1868
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[4], pool));
 
1869
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1870
    SVN_ERR (svn_fs_make_file (txn_root, "theta", pool));
 
1871
    SVN_ERR (svn_test__set_file_contents 
 
1872
             (txn_root, "theta", "This is another file 'theta'.\n", pool));
 
1873
    SVN_ERR (test_commit_txn (&after_rev, txn, "/theta", pool));
 
1874
    SVN_ERR (svn_fs_abort_txn (txn, pool));
 
1875
 
 
1876
    /* (1) E exists in ANCESTOR, but has been deleted from B.  Can't
 
1877
       occur, by assumption that E doesn't exist in ANCESTOR. */
 
1878
 
 
1879
    /* (3) E exists in both ANCESTOR and B.  Can't occur, by assumption
 
1880
       that E doesn't exist in ANCESTOR. */
 
1881
  }
 
1882
 
 
1883
  /* (4) E exists in ANCESTOR, but has been deleted from A */
 
1884
  {
 
1885
    /* (1) E exists in ANCESTOR, but has been deleted from B.  If
 
1886
       neither delete was a result of a rename, then omit E from the
 
1887
       merged tree.  Otherwise, conflict. */
 
1888
    /* ### cmpilato todo: the rename case isn't actually handled by
 
1889
       merge yet, so we know we won't get a conflict here. */
 
1890
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
1891
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1892
    SVN_ERR (svn_fs_delete (txn_root, "A/D/H", pool));
 
1893
    SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1894
    /*********************************************************************/
 
1895
    /* REVISION 6 */
 
1896
    /*********************************************************************/
 
1897
    {
 
1898
      static svn_test__tree_entry_t expected_entries[] = {
 
1899
        /* path, contents (0 = dir) */
 
1900
        { "theta",         "This is the file 'theta'.\n" },
 
1901
        { "A",             0 },
 
1902
        { "A/mu",          "This is the file 'mu'.\n" },
 
1903
        { "A/B",           0 },
 
1904
        { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1905
        { "A/B/E",         0 },
 
1906
        { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1907
        { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1908
        { "A/B/F",         0 },
 
1909
        { "A/C",           0 },
 
1910
        { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1911
        { "A/D",           0 },
 
1912
        { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
1913
        { "A/D/G",         0 },
 
1914
        { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
1915
        { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
1916
        { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
1917
        { "A/D/I",         0 },
 
1918
        { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
1919
        { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
1920
      };
 
1921
      SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
1922
      SVN_ERR (svn_test__validate_tree (revision_root,
 
1923
                                        expected_entries, 
 
1924
                                        20, pool));
 
1925
    }
 
1926
    revisions[revision_count++] = after_rev;
 
1927
 
 
1928
    /* Try deleting a file F inside a subtree S where S does not exist
 
1929
       in the most recent revision, but does exist in the ancestor
 
1930
       tree.  This should conflict. */
 
1931
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
1932
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1933
    SVN_ERR (svn_fs_delete (txn_root, "A/D/H/omega", pool));
 
1934
    SVN_ERR (test_commit_txn (&after_rev, txn, "/A/D/H", pool));
 
1935
    SVN_ERR (svn_fs_abort_txn (txn, pool));
 
1936
 
 
1937
    /* E exists in both ANCESTOR and B ... */
 
1938
    {
 
1939
      /* (1) but refers to different nodes.  Conflict. */
 
1940
      SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
1941
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1942
      SVN_ERR (svn_fs_delete (txn_root, "A/D/H", pool));
 
1943
      SVN_ERR (svn_fs_make_dir (txn_root, "A/D/H", pool));
 
1944
      SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1945
      revisions[revision_count++] = after_rev;
 
1946
 
 
1947
      /*********************************************************************/
 
1948
      /* REVISION 7 */
 
1949
      /*********************************************************************/
 
1950
      
 
1951
      /* Re-remove A/D/H because future tests expect it to be absent. */
 
1952
      {
 
1953
        SVN_ERR (svn_fs_begin_txn 
 
1954
                 (&txn, fs, revisions[revision_count - 1], pool));
 
1955
        SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1956
        SVN_ERR (svn_fs_delete (txn_root, "A/D/H", pool));
 
1957
        SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1958
        revisions[revision_count++] = after_rev;
 
1959
      }
 
1960
 
 
1961
      /*********************************************************************/
 
1962
      /* REVISION 8 (looks exactly like revision 6, we hope) */
 
1963
      /*********************************************************************/
 
1964
      
 
1965
      /* (1) but refers to different revisions of the same node.
 
1966
         Conflict. */
 
1967
      SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
1968
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1969
      SVN_ERR (svn_fs_make_file (txn_root, "A/D/H/zeta", pool));
 
1970
      SVN_ERR (test_commit_txn (&after_rev, txn, "/A/D/H", pool));
 
1971
      SVN_ERR (svn_fs_abort_txn (txn, pool));
 
1972
 
 
1973
      /* (1) and refers to the same node revision.  Omit E from the
 
1974
         merged tree.  This is already tested in Merge-Test 3
 
1975
         (A/D/H/chi, A/D/H/psi, e.g.), but we'll test it here again
 
1976
         anyway.  A little paranoia never hurt anyone.  */
 
1977
      SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
1978
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
1979
      SVN_ERR (svn_fs_delete (txn_root, "A/mu", pool)); /* unrelated change */
 
1980
      SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
1981
 
 
1982
      /*********************************************************************/
 
1983
      /* REVISION 9 */
 
1984
      /*********************************************************************/
 
1985
      {
 
1986
        static svn_test__tree_entry_t expected_entries[] = {
 
1987
          /* path, contents (0 = dir) */
 
1988
          { "theta",         "This is the file 'theta'.\n" },
 
1989
          { "A",             0 },
 
1990
          { "A/B",           0 },
 
1991
          { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
1992
          { "A/B/E",         0 },
 
1993
          { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
1994
          { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
1995
          { "A/B/F",         0 },
 
1996
          { "A/C",           0 },
 
1997
          { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
1998
          { "A/D",           0 },
 
1999
          { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
2000
          { "A/D/G",         0 },
 
2001
          { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
2002
          { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
2003
          { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
2004
          { "A/D/I",         0 },
 
2005
          { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
2006
          { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
2007
        };
 
2008
        SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
2009
        SVN_ERR (svn_test__validate_tree (revision_root,
 
2010
                                          expected_entries, 
 
2011
                                          19, pool));
 
2012
      }
 
2013
      revisions[revision_count++] = after_rev;
 
2014
    }
 
2015
  }
 
2016
 
 
2017
  /* Preparation for upcoming tests. 
 
2018
     We make a new head revision, with A/mu restored, but containing
 
2019
     slightly different contents than its first incarnation. */
 
2020
  SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[revision_count-1], pool));
 
2021
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2022
  SVN_ERR (svn_fs_make_file (txn_root, "A/mu", pool));
 
2023
  SVN_ERR (svn_test__set_file_contents 
 
2024
           (txn_root, "A/mu", "A new file 'mu'.\n", pool));
 
2025
  SVN_ERR (svn_fs_make_file (txn_root, "A/D/G/xi", pool));
 
2026
  SVN_ERR (svn_test__set_file_contents 
 
2027
           (txn_root, "A/D/G/xi", "This is the file 'xi'.\n", pool));
 
2028
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2029
  /*********************************************************************/
 
2030
  /* REVISION 10 */
 
2031
  /*********************************************************************/
 
2032
  {
 
2033
    static svn_test__tree_entry_t expected_entries[] = {
 
2034
      /* path, contents (0 = dir) */
 
2035
      { "theta",         "This is the file 'theta'.\n" },
 
2036
      { "A",             0 },
 
2037
      { "A/mu",          "A new file 'mu'.\n" },
 
2038
      { "A/B",           0 },
 
2039
      { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
2040
      { "A/B/E",         0 },
 
2041
      { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
2042
      { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
2043
      { "A/B/F",         0 },
 
2044
      { "A/C",           0 },
 
2045
      { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
2046
      { "A/D",           0 },
 
2047
      { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
2048
      { "A/D/G",         0 },
 
2049
      { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
2050
      { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
2051
      { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
2052
      { "A/D/G/xi",      "This is the file 'xi'.\n" },
 
2053
      { "A/D/I",         0 },
 
2054
      { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
2055
      { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
2056
    };
 
2057
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
2058
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 
 
2059
                                      21, pool));
 
2060
  }
 
2061
  revisions[revision_count++] = after_rev;
 
2062
  
 
2063
  /* (3) E exists in both ANCESTOR and A, but refers to different
 
2064
     nodes. */
 
2065
  {
 
2066
    /* (1) E exists in both ANCESTOR and B, but refers to different
 
2067
       nodes, and not all nodes are directories.  Conflict. */
 
2068
 
 
2069
    /* ### kff todo: A/mu's contents will be exactly the same.
 
2070
       If the fs ever starts optimizing this case, these tests may
 
2071
       start to fail. */
 
2072
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2073
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2074
    SVN_ERR (svn_fs_delete (txn_root, "A/mu", pool));
 
2075
    SVN_ERR (svn_fs_make_file (txn_root, "A/mu", pool));
 
2076
    SVN_ERR (svn_test__set_file_contents 
 
2077
             (txn_root, "A/mu", "This is the file 'mu'.\n", pool));
 
2078
    SVN_ERR (test_commit_txn (&after_rev, txn, "/A/mu", pool));
 
2079
    SVN_ERR (svn_fs_abort_txn (txn, pool));
 
2080
 
 
2081
    /* (1) E exists in both ANCESTOR and B, but refers to different
 
2082
       revisions of the same node.  Conflict. */
 
2083
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2084
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2085
    SVN_ERR (svn_test__set_file_contents 
 
2086
             (txn_root, "A/mu", "A change to file 'mu'.\n", pool));
 
2087
    SVN_ERR (test_commit_txn (&after_rev, txn, "/A/mu", pool));
 
2088
    SVN_ERR (svn_fs_abort_txn (txn, pool));
 
2089
 
 
2090
    /* (1) E exists in both ANCESTOR and B, and refers to the same
 
2091
       node revision.  Replace E with A's node revision.  */
 
2092
    {
 
2093
      svn_stringbuf_t *old_mu_contents;
 
2094
      SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2095
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2096
      SVN_ERR (svn_test__get_file_contents 
 
2097
               (txn_root, "A/mu", &old_mu_contents, pool)); 
 
2098
      if ((! old_mu_contents) || (strcmp (old_mu_contents->data,
 
2099
                                          "This is the file 'mu'.\n") != 0))
 
2100
        {
 
2101
          return svn_error_create
 
2102
            (SVN_ERR_FS_GENERAL, NULL,
 
2103
             "got wrong contents from an old revision tree");
 
2104
        }
 
2105
      SVN_ERR (svn_fs_make_file (txn_root, "A/sigma", pool));
 
2106
      SVN_ERR (svn_test__set_file_contents  /* unrelated change */ 
 
2107
               (txn_root, "A/sigma", "This is the file 'sigma'.\n", pool));
 
2108
      SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2109
      /*********************************************************************/
 
2110
      /* REVISION 11 */
 
2111
      /*********************************************************************/
 
2112
      {
 
2113
        static svn_test__tree_entry_t expected_entries[] = {
 
2114
          /* path, contents (0 = dir) */
 
2115
          { "theta",         "This is the file 'theta'.\n" },
 
2116
          { "A",             0 },
 
2117
          { "A/mu",          "A new file 'mu'.\n" },
 
2118
          { "A/sigma",       "This is the file 'sigma'.\n" },
 
2119
          { "A/B",           0 },
 
2120
          { "A/B/lambda",    "This is the file 'lambda'.\n" },
 
2121
          { "A/B/E",         0 },
 
2122
          { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
2123
          { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
2124
          { "A/B/F",         0 },
 
2125
          { "A/C",           0 },
 
2126
          { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
2127
          { "A/D",           0 },
 
2128
          { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
2129
          { "A/D/G",         0 },
 
2130
          { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
2131
          { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
2132
          { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
2133
          { "A/D/G/xi",      "This is the file 'xi'.\n" },
 
2134
          { "A/D/I",         0 },
 
2135
          { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
2136
          { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
2137
        };
 
2138
        SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
2139
        SVN_ERR (svn_test__validate_tree (revision_root,
 
2140
                                          expected_entries, 
 
2141
                                          22, pool));
 
2142
      }
 
2143
      revisions[revision_count++] = after_rev;
 
2144
    }
 
2145
  }
 
2146
 
 
2147
  /* Preparation for upcoming tests. 
 
2148
     We make a new head revision.  There are two changes in the new
 
2149
     revision: A/B/lambda has been modified.  We will also use the
 
2150
     recent addition of A/D/G/xi, treated as a modification to
 
2151
     A/D/G. */
 
2152
  SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[revision_count-1], pool));
 
2153
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2154
  SVN_ERR (svn_test__set_file_contents 
 
2155
           (txn_root, "A/B/lambda", "Change to file 'lambda'.\n", pool));
 
2156
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2157
  /*********************************************************************/
 
2158
  /* REVISION 12 */
 
2159
  /*********************************************************************/
 
2160
  {
 
2161
    static svn_test__tree_entry_t expected_entries[] = {
 
2162
      /* path, contents (0 = dir) */
 
2163
      { "theta",         "This is the file 'theta'.\n" },
 
2164
      { "A",             0 },
 
2165
      { "A/mu",          "A new file 'mu'.\n" },
 
2166
      { "A/sigma",       "This is the file 'sigma'.\n" },
 
2167
      { "A/B",           0 },
 
2168
      { "A/B/lambda",    "Change to file 'lambda'.\n" },
 
2169
      { "A/B/E",         0 },
 
2170
      { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
2171
      { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
2172
      { "A/B/F",         0 },
 
2173
      { "A/C",           0 },
 
2174
      { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
2175
      { "A/D",           0 },
 
2176
      { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
2177
      { "A/D/G",         0 },
 
2178
      { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
2179
      { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
2180
      { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
2181
      { "A/D/G/xi",      "This is the file 'xi'.\n" },
 
2182
      { "A/D/I",         0 },
 
2183
      { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
2184
      { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
2185
    };
 
2186
    SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
2187
    SVN_ERR (svn_test__validate_tree (revision_root, expected_entries, 
 
2188
                                      22, pool));
 
2189
  }
 
2190
  revisions[revision_count++] = after_rev;
 
2191
 
 
2192
  /* (2) E exists in both ANCESTOR and A, but refers to different 
 
2193
     revisions of the same node. */
 
2194
  {
 
2195
    /* (1a) E exists in both ANCESTOR and B, but refers to different
 
2196
       revisions of the same file node.  Conflict. */
 
2197
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2198
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2199
    SVN_ERR (svn_test__set_file_contents 
 
2200
             (txn_root, "A/B/lambda", "A different change to 'lambda'.\n", 
 
2201
              pool));
 
2202
    SVN_ERR (test_commit_txn (&after_rev, txn, "/A/B/lambda", pool));
 
2203
    SVN_ERR (svn_fs_abort_txn (txn, pool));
 
2204
 
 
2205
    /* (1b) E exists in both ANCESTOR and B, but refers to different
 
2206
       revisions of the same directory node.  Merge A/E and B/E,
 
2207
       recursively.  Succeed, because no conflict beneath E. */
 
2208
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2209
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2210
    SVN_ERR (svn_fs_make_file (txn_root, "A/D/G/nu", pool));
 
2211
    SVN_ERR (svn_test__set_file_contents 
 
2212
             (txn_root, "A/D/G/nu", "This is the file 'nu'.\n", pool));
 
2213
    SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2214
    /*********************************************************************/
 
2215
    /* REVISION 13 */
 
2216
    /*********************************************************************/
 
2217
    {
 
2218
      static svn_test__tree_entry_t expected_entries[] = {
 
2219
        /* path, contents (0 = dir) */
 
2220
        { "theta",         "This is the file 'theta'.\n" },
 
2221
        { "A",             0 },
 
2222
        { "A/mu",          "A new file 'mu'.\n" },
 
2223
        { "A/sigma",       "This is the file 'sigma'.\n" },
 
2224
        { "A/B",           0 },
 
2225
        { "A/B/lambda",    "Change to file 'lambda'.\n" },
 
2226
        { "A/B/E",         0 },
 
2227
        { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
2228
        { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
2229
        { "A/B/F",         0 },
 
2230
        { "A/C",           0 },
 
2231
        { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
2232
        { "A/D",           0 },
 
2233
        { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
2234
        { "A/D/G",         0 },
 
2235
        { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
2236
        { "A/D/G/rho",     "This is the file 'rho'.\n" },
 
2237
        { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
2238
        { "A/D/G/xi",      "This is the file 'xi'.\n" },
 
2239
        { "A/D/G/nu",      "This is the file 'nu'.\n" },
 
2240
        { "A/D/I",         0 },
 
2241
        { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
2242
        { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
2243
      };
 
2244
      SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
2245
      SVN_ERR (svn_test__validate_tree (revision_root,
 
2246
                                        expected_entries, 
 
2247
                                        23, pool));
 
2248
    }
 
2249
    revisions[revision_count++] = after_rev;
 
2250
 
 
2251
    /* (1c) E exists in both ANCESTOR and B, but refers to different
 
2252
       revisions of the same directory node.  Merge A/E and B/E,
 
2253
       recursively.  Fail, because conflict beneath E. */
 
2254
    SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2255
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2256
    SVN_ERR (svn_fs_make_file (txn_root, "A/D/G/xi", pool));
 
2257
    SVN_ERR (svn_test__set_file_contents 
 
2258
             (txn_root, "A/D/G/xi", "This is a different file 'xi'.\n", pool));
 
2259
    SVN_ERR (test_commit_txn (&after_rev, txn, "/A/D/G/xi", pool));
 
2260
    SVN_ERR (svn_fs_abort_txn (txn, pool));
 
2261
 
 
2262
    /* (1) E exists in both ANCESTOR and B, and refers to the same node
 
2263
       revision.  Replace E with A's node revision.  */
 
2264
    {
 
2265
      svn_stringbuf_t *old_lambda_ctnts;
 
2266
      SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2267
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2268
      SVN_ERR (svn_test__get_file_contents 
 
2269
               (txn_root, "A/B/lambda", &old_lambda_ctnts, pool));
 
2270
      if ((! old_lambda_ctnts)
 
2271
          || (strcmp (old_lambda_ctnts->data,
 
2272
                      "This is the file 'lambda'.\n") != 0))
 
2273
        {
 
2274
          return svn_error_create
 
2275
            (SVN_ERR_FS_GENERAL, NULL,
 
2276
             "got wrong contents from an old revision tree");
 
2277
        }
 
2278
      SVN_ERR (svn_test__set_file_contents 
 
2279
               (txn_root, "A/D/G/rho", 
 
2280
                "This is an irrelevant change to 'rho'.\n", pool));
 
2281
      SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2282
      /*********************************************************************/
 
2283
      /* REVISION 14 */
 
2284
      /*********************************************************************/
 
2285
      {
 
2286
        static svn_test__tree_entry_t expected_entries[] = {
 
2287
          /* path, contents (0 = dir) */
 
2288
          { "theta",         "This is the file 'theta'.\n" },
 
2289
          { "A",             0 },
 
2290
          { "A/mu",          "A new file 'mu'.\n" },
 
2291
          { "A/sigma",       "This is the file 'sigma'.\n" },
 
2292
          { "A/B",           0 },
 
2293
          { "A/B/lambda",    "Change to file 'lambda'.\n" },
 
2294
          { "A/B/E",         0 },
 
2295
          { "A/B/E/alpha",   "This is the file 'alpha'.\n" },
 
2296
          { "A/B/E/beta",    "This is the file 'beta'.\n" },
 
2297
          { "A/B/F",         0 },
 
2298
          { "A/C",           0 },
 
2299
          { "A/C/kappa",     "This is the file 'kappa'.\n" },
 
2300
          { "A/D",           0 },
 
2301
          { "A/D/gamma",     "This is the file 'gamma'.\n" },
 
2302
          { "A/D/G",         0 },
 
2303
          { "A/D/G/pi",      "This is the file 'pi'.\n" },
 
2304
          { "A/D/G/rho",     "This is an irrelevant change to 'rho'.\n" },
 
2305
          { "A/D/G/tau",     "This is the file 'tau'.\n" },
 
2306
          { "A/D/G/xi",      "This is the file 'xi'.\n" },
 
2307
          { "A/D/G/nu",      "This is the file 'nu'.\n"},
 
2308
          { "A/D/I",         0 },
 
2309
          { "A/D/I/delta",   "This is the file 'delta'.\n" },
 
2310
          { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
 
2311
        };
 
2312
        SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool)); 
 
2313
        SVN_ERR (svn_test__validate_tree (revision_root,
 
2314
                                          expected_entries, 
 
2315
                                          23, pool));
 
2316
      }
 
2317
      revisions[revision_count++] = after_rev;
 
2318
    }
 
2319
  }  
 
2320
 
 
2321
  /* (1) E exists in both ANCESTOR and A, and refers to the same node
 
2322
     revision. */
 
2323
  {
 
2324
    /* (1) E exists in both ANCESTOR and B, and refers to the same
 
2325
       node revision.  Nothing has happened to ANCESTOR/E, so no
 
2326
       change is necessary. */
 
2327
 
 
2328
    /* This has now been tested about fifty-four trillion times.  We
 
2329
       don't need to test it again here. */
 
2330
  }
 
2331
 
 
2332
  /* E exists in ANCESTOR, but has been deleted from A.  E exists in
 
2333
     both ANCESTOR and B but refers to different revisions of the same
 
2334
     node.  Conflict.  */
 
2335
  SVN_ERR (svn_fs_begin_txn (&txn, fs, revisions[1], pool));
 
2336
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2337
  SVN_ERR (svn_test__set_file_contents 
 
2338
           (txn_root, "iota", "New contents for 'iota'.\n", pool));
 
2339
  SVN_ERR (test_commit_txn (&after_rev, txn, "/iota", pool));
 
2340
  SVN_ERR (svn_fs_abort_txn (txn, pool));
 
2341
 
 
2342
  return SVN_NO_ERROR;
 
2343
}
 
2344
 
 
2345
 
 
2346
static svn_error_t *
 
2347
copy_test (const char **msg,
 
2348
           svn_boolean_t msg_only,
 
2349
           svn_test_opts_t *opts,
 
2350
           apr_pool_t *pool)
 
2351
{
 
2352
  svn_fs_t *fs;
 
2353
  svn_fs_txn_t *txn;
 
2354
  svn_fs_root_t *txn_root, *rev_root;
 
2355
  svn_revnum_t after_rev;
 
2356
 
 
2357
  *msg = "copying and tracking copy history";
 
2358
 
 
2359
  if (msg_only)
 
2360
    return SVN_NO_ERROR;
 
2361
 
 
2362
  /* Prepare a filesystem. */
 
2363
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-copy-test",
 
2364
                                "bdb", pool));
 
2365
 
 
2366
  /* In first txn, create and commit the greek tree. */
 
2367
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
2368
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2369
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
2370
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2371
 
 
2372
  /* In second txn, copy the file A/D/G/pi into the subtree A/D/H as
 
2373
     pi2.  Change that file's contents to state its new name.  Along
 
2374
     the way, test that the copy history was preserved both during the
 
2375
     transaction and after the commit. */
 
2376
 
 
2377
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2378
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2379
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2380
  SVN_ERR (svn_fs_copy (rev_root, "A/D/G/pi", 
 
2381
                        txn_root, "A/D/H/pi2",
 
2382
                        pool));
 
2383
  { /* Check that copy history was preserved. */
 
2384
    svn_revnum_t rev;
 
2385
    const char *path;
 
2386
    
 
2387
    SVN_ERR (svn_fs_copied_from (&rev, &path, txn_root, 
 
2388
                                 "A/D/H/pi2", pool));
 
2389
 
 
2390
    if (rev != after_rev)
 
2391
      return svn_error_create
 
2392
        (SVN_ERR_FS_GENERAL, NULL,
 
2393
         "pre-commit copy history not preserved (rev lost) for A/D/H/pi2");
 
2394
 
 
2395
    if (strcmp (path, "/A/D/G/pi") != 0)
 
2396
      return svn_error_create
 
2397
        (SVN_ERR_FS_GENERAL, NULL,
 
2398
         "pre-commit copy history not preserved (path lost) for A/D/H/pi2");
 
2399
  }
 
2400
  SVN_ERR (svn_test__set_file_contents 
 
2401
           (txn_root, "A/D/H/pi2", "This is the file 'pi2'.\n", pool));
 
2402
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2403
 
 
2404
  { /* Check that copy history is still preserved _after_ the commit. */
 
2405
    svn_fs_root_t *root;
 
2406
    svn_revnum_t rev;
 
2407
    const char *path;
 
2408
    
 
2409
    SVN_ERR (svn_fs_revision_root (&root, fs, after_rev, pool));
 
2410
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/D/H/pi2", pool));
 
2411
 
 
2412
    if (rev != (after_rev - 1))
 
2413
      return svn_error_create
 
2414
        (SVN_ERR_FS_GENERAL, NULL,
 
2415
         "post-commit copy history wrong (rev) for A/D/H/pi2");
 
2416
 
 
2417
    if (strcmp (path, "/A/D/G/pi") != 0)
 
2418
      return svn_error_create
 
2419
        (SVN_ERR_FS_GENERAL, NULL,
 
2420
         "post-commit copy history wrong (path) for A/D/H/pi2");
 
2421
  }
 
2422
 
 
2423
  /* Let's copy the copy we just made, to make sure copy history gets
 
2424
     chained correctly. */
 
2425
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2426
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2427
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2428
  SVN_ERR (svn_fs_copy (rev_root, "A/D/H/pi2", txn_root, "A/D/H/pi3", pool));
 
2429
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2430
  { /* Check the copy history. */
 
2431
    svn_fs_root_t *root;
 
2432
    svn_revnum_t rev;
 
2433
    const char *path;
 
2434
    
 
2435
    /* Check that the original copy still has its old history. */
 
2436
    SVN_ERR (svn_fs_revision_root (&root, fs, (after_rev - 1), pool));
 
2437
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/D/H/pi2", pool));
 
2438
 
 
2439
    if (rev != (after_rev - 2))
 
2440
      return svn_error_create
 
2441
        (SVN_ERR_FS_GENERAL, NULL,
 
2442
         "first copy history wrong (rev) for A/D/H/pi2");
 
2443
 
 
2444
    if (strcmp (path, "/A/D/G/pi") != 0)
 
2445
      return svn_error_create
 
2446
        (SVN_ERR_FS_GENERAL, NULL,
 
2447
         "first copy history wrong (path) for A/D/H/pi2");
 
2448
 
 
2449
    /* Check that the copy of the copy has the right history. */
 
2450
    SVN_ERR (svn_fs_revision_root (&root, fs, after_rev, pool));
 
2451
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/D/H/pi3", pool));
 
2452
 
 
2453
    if (rev != (after_rev - 1))
 
2454
      return svn_error_create
 
2455
        (SVN_ERR_FS_GENERAL, NULL,
 
2456
         "second copy history wrong (rev) for A/D/H/pi3");
 
2457
 
 
2458
    if (strcmp (path, "/A/D/H/pi2") != 0)
 
2459
      return svn_error_create
 
2460
        (SVN_ERR_FS_GENERAL, NULL,
 
2461
         "second copy history wrong (path) for A/D/H/pi3");
 
2462
  }
 
2463
 
 
2464
  /* Commit a regular change to a copy, make sure the copy history
 
2465
     isn't inherited. */
 
2466
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2467
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2468
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2469
  SVN_ERR (svn_test__set_file_contents 
 
2470
           (txn_root, "A/D/H/pi3", "This is the file 'pi3'.\n", pool));
 
2471
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2472
  { /* Check the copy history. */
 
2473
    svn_fs_root_t *root;
 
2474
    svn_revnum_t rev;
 
2475
    const char *path;
 
2476
    
 
2477
    /* Check that the copy still has its history. */
 
2478
    SVN_ERR (svn_fs_revision_root (&root, fs, (after_rev - 1), pool));
 
2479
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/D/H/pi3", pool));
 
2480
 
 
2481
    if (rev != (after_rev - 2))
 
2482
      return svn_error_create
 
2483
        (SVN_ERR_FS_GENERAL, NULL,
 
2484
         "copy history wrong (rev) for A/D/H/pi3");
 
2485
 
 
2486
    if (strcmp (path, "/A/D/H/pi2") != 0)
 
2487
      return svn_error_create
 
2488
        (SVN_ERR_FS_GENERAL, NULL,
 
2489
         "copy history wrong (path) for A/D/H/pi3");
 
2490
 
 
2491
    /* Check that the next revision after the copy has no copy history. */
 
2492
    SVN_ERR (svn_fs_revision_root (&root, fs, after_rev, pool));
 
2493
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/D/H/pi3", pool));
 
2494
 
 
2495
    if (rev != SVN_INVALID_REVNUM)
 
2496
      return svn_error_create
 
2497
        (SVN_ERR_FS_GENERAL, NULL,
 
2498
         "copy history wrong (rev) for A/D/H/pi3");
 
2499
 
 
2500
    if (path != NULL)
 
2501
      return svn_error_create
 
2502
        (SVN_ERR_FS_GENERAL, NULL,
 
2503
         "copy history wrong (path) for A/D/H/pi3");
 
2504
  }
 
2505
 
 
2506
  /* Then, as if that wasn't fun enough, copy the whole subtree A/D/H
 
2507
     into the root directory as H2! */
 
2508
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2509
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2510
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2511
  SVN_ERR (svn_fs_copy (rev_root, "A/D/H", txn_root, "H2", pool));
 
2512
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2513
  { /* Check the copy history. */
 
2514
    svn_fs_root_t *root;
 
2515
    svn_revnum_t rev;
 
2516
    const char *path;
 
2517
    
 
2518
    /* Check that the top of the copy has history. */
 
2519
    SVN_ERR (svn_fs_revision_root (&root, fs, after_rev, pool));
 
2520
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "H2", pool));
 
2521
 
 
2522
    if (rev != (after_rev - 1))
 
2523
      return svn_error_create
 
2524
        (SVN_ERR_FS_GENERAL, NULL,
 
2525
         "copy history wrong (rev) for H2");
 
2526
 
 
2527
    if (strcmp (path, "/A/D/H") != 0)
 
2528
      return svn_error_create
 
2529
        (SVN_ERR_FS_GENERAL, NULL,
 
2530
         "copy history wrong (path) for H2");
 
2531
 
 
2532
    /* Check that a random file under H2 reports no copy history. */
 
2533
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "H2/omega", pool));
 
2534
 
 
2535
    if (rev != SVN_INVALID_REVNUM)
 
2536
      return svn_error_create
 
2537
        (SVN_ERR_FS_GENERAL, NULL,
 
2538
         "copy history wrong (rev) for H2/omega");
 
2539
 
 
2540
    if (path != NULL)
 
2541
      return svn_error_create
 
2542
        (SVN_ERR_FS_GENERAL, NULL,
 
2543
         "copy history wrong (path) for H2/omega");
 
2544
 
 
2545
    /* Note that H2/pi2 still has copy history, though.  See the doc
 
2546
       string for svn_fs_copied_from() for more on this. */
 
2547
  }
 
2548
 
 
2549
  /* Let's live dangerously.  What happens if we copy a path into one
 
2550
     of its own children.  Looping filesystem?  Cyclic ancestry?
 
2551
     Another West Virginia family tree with no branches?  We certainly
 
2552
     hope that's not the case. */
 
2553
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2554
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2555
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2556
  SVN_ERR (svn_fs_copy (rev_root, "A/B", txn_root, "A/B/E/B", pool));
 
2557
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2558
  { /* Check the copy history. */
 
2559
    svn_fs_root_t *root;
 
2560
    svn_revnum_t rev;
 
2561
    const char *path;
 
2562
    
 
2563
    /* Check that the copy has history. */
 
2564
    SVN_ERR (svn_fs_revision_root (&root, fs, after_rev, pool));
 
2565
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/B/E/B", pool));
 
2566
 
 
2567
    if (rev != (after_rev - 1))
 
2568
      return svn_error_create
 
2569
        (SVN_ERR_FS_GENERAL, NULL,
 
2570
         "copy history wrong (rev) for A/B/E/B");
 
2571
 
 
2572
    if (strcmp (path, "/A/B") != 0)
 
2573
      return svn_error_create
 
2574
        (SVN_ERR_FS_GENERAL, NULL,
 
2575
         "copy history wrong (path) for A/B/E/B");
 
2576
 
 
2577
    /* Check that the original does not have copy history. */
 
2578
    SVN_ERR (svn_fs_revision_root (&root, fs, after_rev, pool));
 
2579
    SVN_ERR (svn_fs_copied_from (&rev, &path, root, "A/B", pool));
 
2580
 
 
2581
    if (rev != SVN_INVALID_REVNUM)
 
2582
      return svn_error_create
 
2583
        (SVN_ERR_FS_GENERAL, NULL,
 
2584
         "copy history wrong (rev) for A/B");
 
2585
 
 
2586
    if (path != NULL)
 
2587
      return svn_error_create
 
2588
        (SVN_ERR_FS_GENERAL, NULL,
 
2589
         "copy history wrong (path) for A/B");
 
2590
  }
 
2591
 
 
2592
  /* After all these changes, let's see if the filesystem looks as we
 
2593
     would expect it to. */
 
2594
  {
 
2595
    static svn_test__tree_entry_t expected_entries[] = {
 
2596
      /* path, contents (0 = dir) */
 
2597
      { "iota",        "This is the file 'iota'.\n" },
 
2598
      { "H2",          0 },
 
2599
      { "H2/chi",      "This is the file 'chi'.\n" },
 
2600
      { "H2/pi2",      "This is the file 'pi2'.\n" },
 
2601
      { "H2/pi3",      "This is the file 'pi3'.\n" },
 
2602
      { "H2/psi",      "This is the file 'psi'.\n" },
 
2603
      { "H2/omega",    "This is the file 'omega'.\n" },
 
2604
      { "A",           0 },
 
2605
      { "A/mu",        "This is the file 'mu'.\n" },
 
2606
      { "A/B",         0 },
 
2607
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
2608
      { "A/B/E",       0 },
 
2609
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
2610
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
2611
      { "A/B/E/B",         0 },
 
2612
      { "A/B/E/B/lambda",  "This is the file 'lambda'.\n" },
 
2613
      { "A/B/E/B/E",       0 },
 
2614
      { "A/B/E/B/E/alpha", "This is the file 'alpha'.\n" },
 
2615
      { "A/B/E/B/E/beta",  "This is the file 'beta'.\n" },
 
2616
      { "A/B/E/B/F",       0 },
 
2617
      { "A/B/F",       0 },
 
2618
      { "A/C",         0 },
 
2619
      { "A/D",         0 },
 
2620
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
2621
      { "A/D/G",       0 },
 
2622
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
2623
      { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
2624
      { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
2625
      { "A/D/H",       0 },
 
2626
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
2627
      { "A/D/H/pi2",   "This is the file 'pi2'.\n" },
 
2628
      { "A/D/H/pi3",   "This is the file 'pi3'.\n" },
 
2629
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
2630
      { "A/D/H/omega", "This is the file 'omega'.\n" }
 
2631
    };
 
2632
    SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2633
    SVN_ERR (svn_test__validate_tree (rev_root, expected_entries, 
 
2634
                                      34, pool));
 
2635
  }
 
2636
 
 
2637
  return SVN_NO_ERROR;
 
2638
}
 
2639
 
 
2640
 
 
2641
static svn_error_t *
 
2642
link_test (const char **msg,
 
2643
           svn_boolean_t msg_only,
 
2644
           svn_test_opts_t *opts,
 
2645
           apr_pool_t *pool)
 
2646
{
 
2647
  *msg = "linking, so no copy history";
 
2648
  if (msg_only)
 
2649
    return SVN_NO_ERROR;
 
2650
  return svn_error_create (SVN_ERR_TEST_FAILED, NULL, "XFAIL");
 
2651
 
 
2652
#if 0 /* ### todo: svn_fs_link() as we knew it no longer exists.  This
 
2653
         test should be rewritten as a test of svn_fs_revision_link()
 
2654
         or discarded. */
 
2655
  svn_fs_t *fs;
 
2656
  svn_fs_txn_t *txn;
 
2657
  svn_fs_root_t *txn_root, *rev_root;
 
2658
  svn_revnum_t after_rev;
 
2659
 
 
2660
  *msg = "linking, so no copy history";
 
2661
 
 
2662
  if (msg_only)
 
2663
    return SVN_NO_ERROR;
 
2664
 
 
2665
  /* Prepare a filesystem. */
 
2666
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-link-test",
 
2667
                                "bdb", pool));
 
2668
 
 
2669
  /* In first txn, create and commit the greek tree. */
 
2670
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
2671
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2672
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
2673
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2674
  SVN_ERR (svn_fs_close_txn (txn));
 
2675
 
 
2676
  /* In second txn, link the file A/D/G/pi into the subtree A/D/G as
 
2677
     pi2.  Change that file's contents to state its new name.  Along
 
2678
     the way, test that no copy history was preserved, and the ids are
 
2679
     the same. */
 
2680
 
 
2681
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2682
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2683
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2684
  SVN_ERR (svn_fs_link (rev_root, "A/D/G/pi", 
 
2685
                        txn_root, "A/D/G/pi2",
 
2686
                        pool));
 
2687
 
 
2688
  /* Check that no copy history was generated. */
 
2689
  {
 
2690
    svn_revnum_t rev;
 
2691
    const char *path;
 
2692
    
 
2693
    SVN_ERR (svn_fs_copied_from (&rev, &path, txn_root, "A/D/G/pi2", pool));
 
2694
 
 
2695
    if (SVN_IS_VALID_REVNUM (rev))
 
2696
      return svn_error_createf
 
2697
        (SVN_ERR_FS_GENERAL, NULL,
 
2698
         "link_test: copy rev present when should be absent on '%s'",
 
2699
         "A/D/G/pi2");
 
2700
 
 
2701
    if (path)
 
2702
      return svn_error_createf
 
2703
        (SVN_ERR_FS_GENERAL, NULL,
 
2704
         "link_test: copy path present when should be absent on '%s'",
 
2705
         "A/D/G/pi2");
 
2706
  }
 
2707
 
 
2708
  /* Test that the node id is the same on the two files in the txn. */
 
2709
  {
 
2710
    const svn_fs_id_t *orig_id, *link_id;
 
2711
 
 
2712
    SVN_ERR (svn_fs_node_id (&orig_id, txn_root, "A/D/G/pi", pool));
 
2713
    SVN_ERR (svn_fs_node_id (&link_id, txn_root, "A/D/G/pi2", pool));
 
2714
 
 
2715
    if (! svn_fs__id_eq (orig_id, link_id))
 
2716
      return svn_error_createf
 
2717
        (SVN_ERR_FS_GENERAL, NULL,
 
2718
         "link_test: orig id not same as link id ('%s', '%s')",
 
2719
         "A/D/G/pi", "A/D/G/pi2");
 
2720
  }
 
2721
 
 
2722
  /* Commit the file. */
 
2723
  SVN_ERR (svn_test__set_file_contents 
 
2724
           (txn_root, "A/D/G/pi2", "This is the file 'pi2'.\n", pool));
 
2725
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2726
  SVN_ERR (svn_fs_close_txn (txn));
 
2727
 
 
2728
  /* Get a revision root on the head. */
 
2729
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool)); 
 
2730
 
 
2731
  /* Check that there's _still_ no copy history. */
 
2732
  {
 
2733
    svn_revnum_t rev;
 
2734
    const char *path;
 
2735
    
 
2736
    SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool));
 
2737
    SVN_ERR (svn_fs_copied_from (&rev, &path, rev_root, "A/D/G/pi2", pool));
 
2738
 
 
2739
    if (SVN_IS_VALID_REVNUM (rev))
 
2740
      return svn_error_createf
 
2741
        (SVN_ERR_FS_GENERAL, NULL,
 
2742
         "link_test: copy rev wrongly present on committed '%s'",
 
2743
         "A/D/G/pi2");
 
2744
 
 
2745
    if (path)
 
2746
      return svn_error_createf
 
2747
        (SVN_ERR_FS_GENERAL, NULL,
 
2748
         "link_test: copy path wrongly present on committed '%s'",
 
2749
         "A/D/G/pi2");
 
2750
  }
 
2751
 
 
2752
  /* Test that the node id has changed now, since we changed the file. */
 
2753
  {
 
2754
    const svn_fs_id_t *orig_id, *link_id;
 
2755
 
 
2756
    SVN_ERR (svn_fs_node_id (&orig_id, rev_root, "A/D/G/pi", pool));
 
2757
    SVN_ERR (svn_fs_node_id (&link_id, rev_root, "A/D/G/pi2", pool));
 
2758
 
 
2759
    if (svn_fs__id_eq (orig_id, link_id))
 
2760
      return svn_error_createf
 
2761
        (SVN_ERR_FS_GENERAL, NULL,
 
2762
         "link_test: orig id same as newly committed link id ('%s', '%s')",
 
2763
         "A/D/G/pi", "A/D/G/pi2");
 
2764
  }
 
2765
 
 
2766
  /* Link the file A/D/G/pi2 to A/D/G/pi3 and commit, *without*
 
2767
     changing pi3.  */
 
2768
 
 
2769
  SVN_ERR (svn_fs_begin_txn (&txn, fs, after_rev, pool));
 
2770
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2771
  SVN_ERR (svn_fs_link (rev_root, "A/D/G/pi2", 
 
2772
                        txn_root, "A/D/G/pi3",
 
2773
                        pool));
 
2774
  SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
 
2775
  SVN_ERR (svn_fs_close_txn (txn));
 
2776
 
 
2777
  /* Test that the node id has changed now, since we changed the file. */
 
2778
  {
 
2779
    /* The node id's will be the same.  BAD.  See below:
 
2780
       
 
2781
       ### todo: this is, of course, scary, because there's a hard link
 
2782
       in the filesystem.  svn_fs_link() is dangerous, and we will have
 
2783
       to modify it to protect against hard links.  See issue #419.
 
2784
       if this clause in the test starts failing, it probably means
 
2785
       the issue has been fixed, so the test needs to be changed, not
 
2786
       Subversion. 
 
2787
    */
 
2788
    const svn_fs_id_t *orig_id, *link_id;
 
2789
 
 
2790
    SVN_ERR (svn_fs_node_id (&orig_id, rev_root, "A/D/G/pi", pool));
 
2791
    SVN_ERR (svn_fs_node_id (&link_id, rev_root, "A/D/G/pi2", pool));
 
2792
 
 
2793
    if (svn_fs__id_eq (orig_id, link_id))
 
2794
      return svn_error_createf
 
2795
        (SVN_ERR_FS_GENERAL, NULL,
 
2796
         "link_test: orig not same as unchanged committed link ('%s', '%s')",
 
2797
         "A/D/G/pi", "A/D/G/pi2");
 
2798
  }
 
2799
 
 
2800
  return SVN_NO_ERROR;
 
2801
#endif /* 0 */
 
2802
}
 
2803
 
 
2804
/* This tests deleting of mutable nodes.  We build a tree in a
 
2805
 * transaction, then try to delete various items in the tree.  We
 
2806
 * never commit the tree, so every entry being deleted points to a 
 
2807
 * mutable node. 
 
2808
 * 
 
2809
 * ### todo: this test was written before commits worked.  It might
 
2810
 * now be worthwhile to combine it with delete().
 
2811
 */
 
2812
static svn_error_t *
 
2813
delete_mutables (const char **msg,
 
2814
                 svn_boolean_t msg_only,
 
2815
                 svn_test_opts_t *opts,
 
2816
                 apr_pool_t *pool)
 
2817
{
 
2818
  svn_fs_t *fs;
 
2819
  svn_fs_txn_t *txn;
 
2820
  svn_fs_root_t *txn_root;
 
2821
  svn_error_t *err;
 
2822
 
 
2823
  *msg = "delete mutable nodes from directories";
 
2824
 
 
2825
  if (msg_only)
 
2826
    return SVN_NO_ERROR;
 
2827
 
 
2828
  /* Prepare a txn to receive the greek tree. */
 
2829
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-del-from-dir",
 
2830
                                "bdb", pool));
 
2831
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
2832
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
2833
  
 
2834
  /* Create the greek tree. */
 
2835
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
2836
 
 
2837
  /* Baby, it's time to test like you've never tested before.  We do
 
2838
   * the following, in this order:
 
2839
   *
 
2840
   *    1. Delete a single file somewhere, succeed.
 
2841
   *    2. Delete two files of three, then make sure the third remains.
 
2842
   *    3. Delete the third and last file.
 
2843
   *    4. Try again to delete the dir, succeed.
 
2844
   *    5. Delete one of the natively empty dirs, succeed.
 
2845
   *    6. Try to delete root, fail.
 
2846
   *    7. Try to delete a top-level file, succeed.
 
2847
   *
 
2848
   * Specifically, that's:
 
2849
   *
 
2850
   *    1. Delete A/D/gamma.
 
2851
   *    2. Delete A/D/G/pi, A/D/G/rho.
 
2852
   *    3. Delete A/D/G/tau.
 
2853
   *    4. Try again to delete A/D/G, succeed.
 
2854
   *    5. Delete A/C.
 
2855
   *    6. Try to delete /, fail.
 
2856
   *    7. Try to delete iota, succeed.
 
2857
   *
 
2858
   * Before and after each deletion or attempted deletion, we probe
 
2859
   * the affected directory, to make sure everything is as it should
 
2860
   * be.
 
2861
   */
 
2862
 
 
2863
  /* 1 */
 
2864
  {
 
2865
    const svn_fs_id_t *gamma_id;
 
2866
    SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "A/D/gamma", pool));
 
2867
 
 
2868
    SVN_ERR (check_entry_present (txn_root, "A/D", "gamma", pool));
 
2869
    SVN_ERR (check_id_present (fs, gamma_id, pool));
 
2870
 
 
2871
    SVN_ERR (svn_fs_delete (txn_root, "A/D/gamma", pool));
 
2872
 
 
2873
    SVN_ERR (check_entry_absent (txn_root, "A/D", "gamma", pool));
 
2874
    SVN_ERR (check_id_absent (fs, gamma_id, pool));
 
2875
  }
 
2876
 
 
2877
  /* 2 */
 
2878
  {
 
2879
    const svn_fs_id_t *pi_id, *rho_id, *tau_id;
 
2880
    SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "A/D/G/pi", pool));
 
2881
    SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "A/D/G/rho", pool));
 
2882
    SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "A/D/G/tau", pool));
 
2883
 
 
2884
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi", pool));
 
2885
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho", pool));
 
2886
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
2887
    SVN_ERR (check_id_present (fs, pi_id, pool));
 
2888
    SVN_ERR (check_id_present (fs, rho_id, pool));
 
2889
    SVN_ERR (check_id_present (fs, tau_id, pool));
 
2890
 
 
2891
    SVN_ERR (svn_fs_delete (txn_root, "A/D/G/pi", pool));
 
2892
 
 
2893
    SVN_ERR (check_entry_absent (txn_root, "A/D/G", "pi", pool));
 
2894
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho", pool));
 
2895
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
2896
    SVN_ERR (check_id_absent (fs, pi_id, pool));
 
2897
    SVN_ERR (check_id_present (fs, rho_id, pool));
 
2898
    SVN_ERR (check_id_present (fs, tau_id, pool));
 
2899
 
 
2900
    SVN_ERR (svn_fs_delete (txn_root, "A/D/G/rho", pool));
 
2901
 
 
2902
    SVN_ERR (check_entry_absent (txn_root, "A/D/G", "pi", pool));
 
2903
    SVN_ERR (check_entry_absent (txn_root, "A/D/G", "rho", pool));
 
2904
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
2905
    SVN_ERR (check_id_absent (fs, pi_id, pool));
 
2906
    SVN_ERR (check_id_absent (fs, rho_id, pool));
 
2907
    SVN_ERR (check_id_present (fs, tau_id, pool));
 
2908
  }
 
2909
 
 
2910
  /* 3 */
 
2911
  {
 
2912
    const svn_fs_id_t *tau_id;
 
2913
    SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "A/D/G/tau", pool));
 
2914
 
 
2915
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
2916
    SVN_ERR (check_id_present (fs, tau_id, pool));
 
2917
 
 
2918
    SVN_ERR (svn_fs_delete (txn_root, "A/D/G/tau", pool));
 
2919
 
 
2920
    SVN_ERR (check_entry_absent (txn_root, "A/D/G", "tau", pool));
 
2921
    SVN_ERR (check_id_absent (fs, tau_id, pool));
 
2922
  }
 
2923
 
 
2924
  /* 4 */
 
2925
  {
 
2926
    const svn_fs_id_t *G_id;
 
2927
    SVN_ERR (svn_fs_node_id (&G_id, txn_root, "A/D/G", pool));
 
2928
 
 
2929
    SVN_ERR (check_entry_present (txn_root, "A/D", "G", pool));
 
2930
    SVN_ERR (check_id_present (fs, G_id, pool));
 
2931
 
 
2932
    SVN_ERR (svn_fs_delete (txn_root, "A/D/G", pool));        /* succeed */
 
2933
 
 
2934
    SVN_ERR (check_entry_absent (txn_root, "A/D", "G", pool));
 
2935
    SVN_ERR (check_id_absent (fs, G_id, pool));
 
2936
  }
 
2937
 
 
2938
  /* 5 */
 
2939
  {
 
2940
    const svn_fs_id_t *C_id;
 
2941
    SVN_ERR (svn_fs_node_id (&C_id, txn_root, "A/C", pool));
 
2942
 
 
2943
    SVN_ERR (check_entry_present (txn_root, "A", "C", pool));
 
2944
    SVN_ERR (check_id_present (fs, C_id, pool));
 
2945
 
 
2946
    SVN_ERR (svn_fs_delete (txn_root, "A/C", pool));
 
2947
 
 
2948
    SVN_ERR (check_entry_absent (txn_root, "A", "C", pool));
 
2949
    SVN_ERR (check_id_absent (fs, C_id, pool));
 
2950
  }
 
2951
 
 
2952
  /* 6 */
 
2953
  {
 
2954
    const svn_fs_id_t *root_id;
 
2955
    SVN_ERR (svn_fs_node_id (&root_id, txn_root, "", pool));
 
2956
 
 
2957
    err = svn_fs_delete (txn_root, "", pool);
 
2958
 
 
2959
    if (err && (err->apr_err != SVN_ERR_FS_ROOT_DIR))
 
2960
      {
 
2961
        return svn_error_createf
 
2962
          (SVN_ERR_FS_GENERAL, NULL,
 
2963
           "deleting root directory got wrong error");
 
2964
      }
 
2965
    else if (! err)
 
2966
      {
 
2967
        return svn_error_createf
 
2968
          (SVN_ERR_FS_GENERAL, NULL,
 
2969
           "deleting root directory failed to get error");
 
2970
      }
 
2971
    svn_error_clear (err);
 
2972
 
 
2973
    SVN_ERR (check_id_present (fs, root_id, pool));
 
2974
  }
 
2975
 
 
2976
  /* 7 */
 
2977
  {
 
2978
    const svn_fs_id_t *iota_id;
 
2979
    SVN_ERR (svn_fs_node_id (&iota_id, txn_root, "iota", pool));
 
2980
 
 
2981
    SVN_ERR (check_entry_present (txn_root, "", "iota", pool));
 
2982
    SVN_ERR (check_id_present (fs, iota_id, pool));
 
2983
 
 
2984
    SVN_ERR (svn_fs_delete (txn_root, "iota", pool));
 
2985
 
 
2986
    SVN_ERR (check_entry_absent (txn_root, "", "iota", pool));
 
2987
    SVN_ERR (check_id_absent (fs, iota_id, pool));
 
2988
  }
 
2989
 
 
2990
  return SVN_NO_ERROR;
 
2991
}
 
2992
 
 
2993
 
 
2994
/* This tests deleting in general.
 
2995
 * 
 
2996
 * ### todo: this test was written after (and independently of)
 
2997
 * delete_mutables().  It might be worthwhile to combine them.
 
2998
 */
 
2999
static svn_error_t *
 
3000
delete (const char **msg,
 
3001
        svn_boolean_t msg_only,
 
3002
        svn_test_opts_t *opts,
 
3003
        apr_pool_t *pool)
 
3004
{
 
3005
  svn_fs_t *fs;
 
3006
  svn_fs_txn_t *txn;
 
3007
  svn_fs_root_t *txn_root;
 
3008
  svn_revnum_t new_rev;
 
3009
 
 
3010
  *msg = "delete nodes tree";
 
3011
 
 
3012
  if (msg_only)
 
3013
    return SVN_NO_ERROR;
 
3014
 
 
3015
  /* This function tests 5 cases:
 
3016
   *
 
3017
   * 1. Delete mutable file.
 
3018
   * 2. Delete mutable directory.
 
3019
   * 3. Delete mutable directory with immutable nodes.
 
3020
   * 4. Delete immutable file.
 
3021
   * 5. Delete immutable directory.
 
3022
   */
 
3023
 
 
3024
  /* Prepare a txn to receive the greek tree. */
 
3025
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-del-tree",
 
3026
                                "bdb", pool));
 
3027
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
3028
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3029
 
 
3030
  /* Create the greek tree. */
 
3031
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
3032
 
 
3033
  /* 1. Delete mutable file. */
 
3034
  {
 
3035
    const svn_fs_id_t *iota_id, *gamma_id;
 
3036
    static svn_test__tree_entry_t expected_entries[] = {
 
3037
      /* path, contents (0 = dir) */
 
3038
      { "A",           0 },
 
3039
      { "A/mu",        "This is the file 'mu'.\n" },
 
3040
      { "A/B",         0 },
 
3041
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3042
      { "A/B/E",       0 },
 
3043
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3044
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3045
      { "A/C",         0 },
 
3046
      { "A/B/F",       0 },
 
3047
      { "A/D",         0 },
 
3048
      { "A/D/G",       0 },
 
3049
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3050
      { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3051
      { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3052
      { "A/D/H",       0 },
 
3053
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3054
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3055
      { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3056
    };
 
3057
 
 
3058
    /* Check nodes revision ID is gone.  */
 
3059
    SVN_ERR (svn_fs_node_id (&iota_id, txn_root, "iota", pool));
 
3060
    SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "A/D/gamma", pool));
 
3061
 
 
3062
    SVN_ERR (check_entry_present (txn_root, "", "iota", pool));
 
3063
    SVN_ERR (check_id_present (fs, iota_id, pool));
 
3064
    SVN_ERR (check_id_present (fs, gamma_id, pool));
 
3065
 
 
3066
    /* Try deleting mutable files. */
 
3067
    SVN_ERR (svn_fs_delete (txn_root, "iota", pool));
 
3068
    SVN_ERR (svn_fs_delete (txn_root, "A/D/gamma", pool));
 
3069
    SVN_ERR (check_entry_absent (txn_root, "", "iota", pool));
 
3070
    SVN_ERR (check_entry_absent (txn_root, "A/D", "gamma", pool));
 
3071
    SVN_ERR (check_id_absent (fs, iota_id, pool));
 
3072
    SVN_ERR (check_id_absent (fs, gamma_id, pool));
 
3073
 
 
3074
    /* Validate the tree.  */
 
3075
    SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 18, pool));
 
3076
  }
 
3077
  /* Abort transaction.  */
 
3078
  SVN_ERR (svn_fs_abort_txn (txn, pool));
 
3079
 
 
3080
  /* 2. Delete mutable directory. */
 
3081
 
 
3082
  /* Prepare a txn to receive the greek tree. */
 
3083
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
3084
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3085
 
 
3086
  /* Create the greek tree. */
 
3087
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
3088
 
 
3089
  {
 
3090
    const svn_fs_id_t *A_id, *mu_id, *B_id, *lambda_id, *E_id, *alpha_id,
 
3091
      *beta_id, *F_id, *C_id, *D_id, *gamma_id, *H_id, *chi_id,
 
3092
      *psi_id, *omega_id, *G_id, *pi_id, *rho_id, *tau_id;
 
3093
 
 
3094
    /* Check nodes revision ID is gone.  */
 
3095
    SVN_ERR (svn_fs_node_id (&A_id, txn_root, "/A", pool));
 
3096
    SVN_ERR (check_entry_present (txn_root, "", "A", pool));
 
3097
    SVN_ERR (svn_fs_node_id (&mu_id, txn_root, "/A/mu", pool));
 
3098
    SVN_ERR (check_entry_present (txn_root, "A", "mu", pool));
 
3099
    SVN_ERR (svn_fs_node_id (&B_id, txn_root, "/A/B", pool));
 
3100
    SVN_ERR (check_entry_present (txn_root, "A", "B", pool));
 
3101
    SVN_ERR (svn_fs_node_id (&lambda_id, txn_root, "/A/B/lambda", pool));
 
3102
    SVN_ERR (check_entry_present (txn_root, "A/B", "lambda", pool));
 
3103
    SVN_ERR (svn_fs_node_id (&E_id, txn_root, "/A/B/E", pool));
 
3104
    SVN_ERR (check_entry_present (txn_root, "A/B", "E", pool));
 
3105
    SVN_ERR (svn_fs_node_id (&alpha_id, txn_root, "/A/B/E/alpha", pool));
 
3106
    SVN_ERR (check_entry_present (txn_root, "A/B/E", "alpha", pool));
 
3107
    SVN_ERR (svn_fs_node_id (&beta_id, txn_root, "/A/B/E/beta", pool));
 
3108
    SVN_ERR (check_entry_present (txn_root, "A/B/E", "beta", pool));
 
3109
    SVN_ERR (svn_fs_node_id (&F_id, txn_root, "/A/B/F", pool));
 
3110
    SVN_ERR (check_entry_present (txn_root, "A/B", "F", pool));
 
3111
    SVN_ERR (svn_fs_node_id (&C_id, txn_root, "/A/C", pool));
 
3112
    SVN_ERR (check_entry_present (txn_root, "A", "C", pool));
 
3113
    SVN_ERR (svn_fs_node_id (&D_id, txn_root, "/A/D", pool));
 
3114
    SVN_ERR (check_entry_present (txn_root, "A", "D", pool));
 
3115
    SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "/A/D/gamma", pool));
 
3116
    SVN_ERR (check_entry_present (txn_root, "A/D", "gamma", pool));
 
3117
    SVN_ERR (svn_fs_node_id (&H_id, txn_root, "/A/D/H", pool));
 
3118
    SVN_ERR (check_entry_present (txn_root, "A/D", "H", pool));
 
3119
    SVN_ERR (svn_fs_node_id (&chi_id, txn_root, "/A/D/H/chi", pool));
 
3120
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "chi", pool));
 
3121
    SVN_ERR (svn_fs_node_id (&psi_id, txn_root, "/A/D/H/psi", pool));
 
3122
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "psi", pool));
 
3123
    SVN_ERR (svn_fs_node_id (&omega_id, txn_root, "/A/D/H/omega", pool));
 
3124
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "omega", pool));
 
3125
    SVN_ERR (svn_fs_node_id (&G_id, txn_root, "/A/D/G", pool));
 
3126
    SVN_ERR (check_entry_present (txn_root, "A/D", "G", pool));
 
3127
    SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "/A/D/G/pi", pool));
 
3128
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi", pool));
 
3129
    SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "/A/D/G/rho", pool));
 
3130
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho", pool));
 
3131
    SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "/A/D/G/tau", pool));
 
3132
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
3133
 
 
3134
    /* Try deleting a mutable empty dir. */
 
3135
    SVN_ERR (svn_fs_delete (txn_root, "A/C", pool));
 
3136
    SVN_ERR (svn_fs_delete (txn_root, "A/B/F", pool));
 
3137
    SVN_ERR (check_entry_absent (txn_root, "A", "C", pool));
 
3138
    SVN_ERR (check_entry_absent (txn_root, "A/B", "F", pool));
 
3139
    SVN_ERR (check_id_absent (fs, C_id, pool));
 
3140
    SVN_ERR (check_id_absent (fs, F_id, pool));
 
3141
 
 
3142
    /* Now delete a mutable non-empty dir. */
 
3143
    SVN_ERR (svn_fs_delete (txn_root, "A", pool));
 
3144
    SVN_ERR (check_entry_absent (txn_root, "", "A", pool));
 
3145
    SVN_ERR (check_id_absent (fs, A_id, pool));
 
3146
    SVN_ERR (check_id_absent (fs, mu_id, pool));
 
3147
    SVN_ERR (check_id_absent (fs, B_id, pool));
 
3148
    SVN_ERR (check_id_absent (fs, lambda_id, pool));
 
3149
    SVN_ERR (check_id_absent (fs, E_id, pool));
 
3150
    SVN_ERR (check_id_absent (fs, alpha_id, pool));
 
3151
    SVN_ERR (check_id_absent (fs, beta_id, pool));
 
3152
    SVN_ERR (check_id_absent (fs, D_id, pool));
 
3153
    SVN_ERR (check_id_absent (fs, gamma_id, pool));
 
3154
    SVN_ERR (check_id_absent (fs, H_id, pool));
 
3155
    SVN_ERR (check_id_absent (fs, chi_id, pool));
 
3156
    SVN_ERR (check_id_absent (fs, psi_id, pool));
 
3157
    SVN_ERR (check_id_absent (fs, omega_id, pool));
 
3158
    SVN_ERR (check_id_absent (fs, G_id, pool));
 
3159
    SVN_ERR (check_id_absent (fs, pi_id, pool));
 
3160
    SVN_ERR (check_id_absent (fs, rho_id, pool));
 
3161
    SVN_ERR (check_id_absent (fs, tau_id, pool));
 
3162
 
 
3163
    /* Validate the tree.  */
 
3164
    {
 
3165
      static svn_test__tree_entry_t expected_entries[] = {
 
3166
        /* path, contents (0 = dir) */
 
3167
        { "iota",        "This is the file 'iota'.\n" } };
 
3168
      SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 1, pool));
 
3169
    }
 
3170
  }
 
3171
 
 
3172
  /* Abort transaction.  */
 
3173
  SVN_ERR (svn_fs_abort_txn (txn, pool));
 
3174
 
 
3175
  /* 3. Delete mutable directory with immutable nodes. */
 
3176
 
 
3177
  /* Prepare a txn to receive the greek tree. */
 
3178
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
3179
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3180
 
 
3181
  /* Create the greek tree. */
 
3182
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
3183
 
 
3184
  /* Commit the greek tree. */
 
3185
  SVN_ERR (svn_fs_commit_txn (NULL, &new_rev, txn, pool));
 
3186
 
 
3187
  /* Create new transaction. */
 
3188
  SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
 
3189
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3190
 
 
3191
  {
 
3192
    const svn_fs_id_t *A_id, *mu_id, *B_id, *lambda_id, *E_id, *alpha_id,
 
3193
      *beta_id, *F_id, *C_id, *D_id, *gamma_id, *H_id, *chi_id,
 
3194
      *psi_id, *omega_id, *G_id, *pi_id, *rho_id, *tau_id, *sigma_id;
 
3195
 
 
3196
    /* Create A/D/G/sigma.  This makes all components of A/D/G
 
3197
       mutable.  */
 
3198
    SVN_ERR (svn_fs_make_file (txn_root, "A/D/G/sigma", pool));
 
3199
    SVN_ERR (svn_test__set_file_contents (txn_root, "A/D/G/sigma",
 
3200
                                "This is another file 'sigma'.\n", pool));
 
3201
 
 
3202
    /* Check that mutable node-revision-IDs are removed and immutable
 
3203
       ones still exist.  */
 
3204
    SVN_ERR (svn_fs_node_id (&A_id, txn_root, "/A", pool));
 
3205
    SVN_ERR (check_entry_present (txn_root, "", "A", pool));
 
3206
    SVN_ERR (svn_fs_node_id (&mu_id, txn_root, "/A/mu", pool));
 
3207
    SVN_ERR (check_entry_present (txn_root, "A", "mu", pool));
 
3208
    SVN_ERR (svn_fs_node_id (&B_id, txn_root, "/A/B", pool));
 
3209
    SVN_ERR (check_entry_present (txn_root, "A", "B", pool));
 
3210
    SVN_ERR (svn_fs_node_id (&lambda_id, txn_root, "/A/B/lambda", pool));
 
3211
    SVN_ERR (check_entry_present (txn_root, "A/B", "lambda", pool));
 
3212
    SVN_ERR (svn_fs_node_id (&E_id, txn_root, "/A/B/E", pool));
 
3213
    SVN_ERR (check_entry_present (txn_root, "A/B", "E", pool));
 
3214
    SVN_ERR (svn_fs_node_id (&alpha_id, txn_root, "/A/B/E/alpha", pool));
 
3215
    SVN_ERR (check_entry_present (txn_root, "A/B/E", "alpha", pool));
 
3216
    SVN_ERR (svn_fs_node_id (&beta_id, txn_root, "/A/B/E/beta", pool));
 
3217
    SVN_ERR (check_entry_present (txn_root, "A/B/E", "beta", pool));
 
3218
    SVN_ERR (svn_fs_node_id (&F_id, txn_root, "/A/B/F", pool));
 
3219
    SVN_ERR (check_entry_present (txn_root, "A/B", "F", pool));
 
3220
    SVN_ERR (svn_fs_node_id (&C_id, txn_root, "/A/C", pool));
 
3221
    SVN_ERR (check_entry_present (txn_root, "A", "C", pool));
 
3222
    SVN_ERR (svn_fs_node_id (&D_id, txn_root, "/A/D", pool));
 
3223
    SVN_ERR (check_entry_present (txn_root, "A", "D", pool));
 
3224
    SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "/A/D/gamma", pool));
 
3225
    SVN_ERR (check_entry_present (txn_root, "A/D", "gamma", pool));
 
3226
    SVN_ERR (svn_fs_node_id (&H_id, txn_root, "/A/D/H", pool));
 
3227
    SVN_ERR (check_entry_present (txn_root, "A/D", "H", pool));
 
3228
    SVN_ERR (svn_fs_node_id (&chi_id, txn_root, "/A/D/H/chi", pool));
 
3229
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "chi", pool));
 
3230
    SVN_ERR (svn_fs_node_id (&psi_id, txn_root, "/A/D/H/psi", pool));
 
3231
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "psi", pool));
 
3232
    SVN_ERR (svn_fs_node_id (&omega_id, txn_root, "/A/D/H/omega", pool));
 
3233
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "omega", pool));
 
3234
    SVN_ERR (svn_fs_node_id (&G_id, txn_root, "/A/D/G", pool));
 
3235
    SVN_ERR (check_entry_present (txn_root, "A/D", "G", pool));
 
3236
    SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "/A/D/G/pi", pool));
 
3237
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi", pool));
 
3238
    SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "/A/D/G/rho", pool));
 
3239
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho", pool));
 
3240
    SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "/A/D/G/tau", pool));
 
3241
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
3242
    SVN_ERR (svn_fs_node_id (&sigma_id, txn_root, "/A/D/G/sigma", pool));
 
3243
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "sigma", pool));
 
3244
 
 
3245
    /* Delete "A" */
 
3246
    SVN_ERR (svn_fs_delete (txn_root, "A", pool));
 
3247
    SVN_ERR (check_entry_absent (txn_root, "", "A", pool));
 
3248
    SVN_ERR (check_id_absent (fs, A_id, pool));
 
3249
    SVN_ERR (check_id_present (fs, mu_id, pool));
 
3250
    SVN_ERR (check_id_present (fs, B_id, pool));
 
3251
    SVN_ERR (check_id_present (fs, lambda_id, pool));
 
3252
    SVN_ERR (check_id_present (fs, E_id, pool));
 
3253
    SVN_ERR (check_id_present (fs, alpha_id, pool));
 
3254
    SVN_ERR (check_id_present (fs, beta_id, pool));
 
3255
    SVN_ERR (check_id_present (fs, F_id, pool));
 
3256
    SVN_ERR (check_id_present (fs, C_id, pool));
 
3257
    SVN_ERR (check_id_absent (fs, D_id, pool));
 
3258
    SVN_ERR (check_id_present (fs, gamma_id, pool));
 
3259
    SVN_ERR (check_id_present (fs, H_id, pool));
 
3260
    SVN_ERR (check_id_present (fs, chi_id, pool));
 
3261
    SVN_ERR (check_id_present (fs, psi_id, pool));
 
3262
    SVN_ERR (check_id_present (fs, omega_id, pool));
 
3263
    SVN_ERR (check_id_absent (fs, G_id, pool));
 
3264
    SVN_ERR (check_id_present (fs, pi_id, pool));
 
3265
    SVN_ERR (check_id_present (fs, rho_id, pool));
 
3266
    SVN_ERR (check_id_present (fs, tau_id, pool));
 
3267
    SVN_ERR (check_id_absent (fs, sigma_id, pool));
 
3268
 
 
3269
    /* Validate the tree.  */
 
3270
    {
 
3271
      static svn_test__tree_entry_t expected_entries[] = {
 
3272
        /* path, contents (0 = dir) */
 
3273
        { "iota",        "This is the file 'iota'.\n" }
 
3274
      };
 
3275
      
 
3276
      SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 1, pool));
 
3277
    }
 
3278
  }
 
3279
 
 
3280
  /* Abort transaction.  */
 
3281
  SVN_ERR (svn_fs_abort_txn (txn, pool));
 
3282
 
 
3283
  /* 4. Delete immutable file. */
 
3284
 
 
3285
  /* Create new transaction. */
 
3286
  SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
 
3287
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3288
 
 
3289
  {
 
3290
    const svn_fs_id_t *iota_id, *gamma_id;
 
3291
 
 
3292
    /* Check nodes revision ID is present.  */
 
3293
    SVN_ERR (svn_fs_node_id (&iota_id, txn_root, "iota", pool));
 
3294
    SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "A/D/gamma", pool));
 
3295
    SVN_ERR (check_entry_present (txn_root, "", "iota", pool));
 
3296
    SVN_ERR (check_entry_present (txn_root, "A/D", "gamma", pool));
 
3297
    SVN_ERR (check_id_present (fs, iota_id, pool));
 
3298
    SVN_ERR (check_id_present (fs, gamma_id, pool));
 
3299
 
 
3300
    /* Delete some files. */
 
3301
    SVN_ERR (svn_fs_delete (txn_root, "iota", pool));
 
3302
    SVN_ERR (svn_fs_delete (txn_root, "A/D/gamma", pool));
 
3303
    SVN_ERR (check_entry_absent (txn_root, "", "iota", pool));
 
3304
    SVN_ERR (check_entry_absent (txn_root, "A/D", "iota", pool));
 
3305
    SVN_ERR (check_id_present (fs, iota_id, pool));
 
3306
    SVN_ERR (check_id_present (fs, gamma_id, pool));
 
3307
 
 
3308
    /* Validate the tree.  */
 
3309
    {
 
3310
      static svn_test__tree_entry_t expected_entries[] = {
 
3311
        /* path, contents (0 = dir) */
 
3312
        { "A",           0 },
 
3313
        { "A/mu",        "This is the file 'mu'.\n" },
 
3314
        { "A/B",         0 },
 
3315
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3316
        { "A/B/E",       0 },
 
3317
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3318
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3319
        { "A/B/F",       0 },
 
3320
        { "A/C",         0 },
 
3321
        { "A/D",         0 },
 
3322
        { "A/D/G",       0 },
 
3323
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3324
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3325
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3326
        { "A/D/H",       0 },
 
3327
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3328
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3329
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3330
      };
 
3331
      SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 18, pool));
 
3332
    }
 
3333
  }
 
3334
 
 
3335
  /* Abort transaction.  */
 
3336
  SVN_ERR (svn_fs_abort_txn (txn, pool));
 
3337
 
 
3338
  /* 5. Delete immutable directory. */
 
3339
 
 
3340
  /* Create new transaction. */
 
3341
  SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
 
3342
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3343
 
 
3344
  {
 
3345
    const svn_fs_id_t *A_id, *mu_id, *B_id, *lambda_id, *E_id, *alpha_id,
 
3346
      *beta_id, *F_id, *C_id, *D_id, *gamma_id, *H_id, *chi_id,
 
3347
      *psi_id, *omega_id, *G_id, *pi_id, *rho_id, *tau_id;
 
3348
 
 
3349
    /* Check nodes revision ID is present.  */
 
3350
    SVN_ERR (svn_fs_node_id (&A_id, txn_root, "/A", pool));
 
3351
    SVN_ERR (check_entry_present (txn_root, "", "A", pool));
 
3352
    SVN_ERR (svn_fs_node_id (&mu_id, txn_root, "/A/mu", pool));
 
3353
    SVN_ERR (check_entry_present (txn_root, "A", "mu", pool));
 
3354
    SVN_ERR (svn_fs_node_id (&B_id, txn_root, "/A/B", pool));
 
3355
    SVN_ERR (check_entry_present (txn_root, "A", "B", pool));
 
3356
    SVN_ERR (svn_fs_node_id (&lambda_id, txn_root, "/A/B/lambda", pool));
 
3357
    SVN_ERR (check_entry_present (txn_root, "A/B", "lambda", pool));
 
3358
    SVN_ERR (svn_fs_node_id (&E_id, txn_root, "/A/B/E", pool));
 
3359
    SVN_ERR (check_entry_present (txn_root, "A/B", "E", pool));
 
3360
    SVN_ERR (svn_fs_node_id (&alpha_id, txn_root, "/A/B/E/alpha", pool));
 
3361
    SVN_ERR (check_entry_present (txn_root, "A/B/E", "alpha", pool));
 
3362
    SVN_ERR (svn_fs_node_id (&beta_id, txn_root, "/A/B/E/beta", pool));
 
3363
    SVN_ERR (check_entry_present (txn_root, "A/B/E", "beta", pool));
 
3364
    SVN_ERR (svn_fs_node_id (&F_id, txn_root, "/A/B/F", pool));
 
3365
    SVN_ERR (check_entry_present (txn_root, "A/B", "F", pool));
 
3366
    SVN_ERR (svn_fs_node_id (&C_id, txn_root, "/A/C", pool));
 
3367
    SVN_ERR (check_entry_present (txn_root, "A", "C", pool));
 
3368
    SVN_ERR (svn_fs_node_id (&D_id, txn_root, "/A/D", pool));
 
3369
    SVN_ERR (check_entry_present (txn_root, "A", "D", pool));
 
3370
    SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "/A/D/gamma", pool));
 
3371
    SVN_ERR (check_entry_present (txn_root, "A/D", "gamma", pool));
 
3372
    SVN_ERR (svn_fs_node_id (&H_id, txn_root, "/A/D/H", pool));
 
3373
    SVN_ERR (check_entry_present (txn_root, "A/D", "H", pool));
 
3374
    SVN_ERR (svn_fs_node_id (&chi_id, txn_root, "/A/D/H/chi", pool));
 
3375
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "chi", pool));
 
3376
    SVN_ERR (svn_fs_node_id (&psi_id, txn_root, "/A/D/H/psi", pool));
 
3377
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "psi", pool));
 
3378
    SVN_ERR (svn_fs_node_id (&omega_id, txn_root, "/A/D/H/omega", pool));
 
3379
    SVN_ERR (check_entry_present (txn_root, "A/D/H", "omega", pool));
 
3380
    SVN_ERR (svn_fs_node_id (&G_id, txn_root, "/A/D/G", pool));
 
3381
    SVN_ERR (check_entry_present (txn_root, "A/D", "G", pool));
 
3382
    SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "/A/D/G/pi", pool));
 
3383
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi", pool));
 
3384
    SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "/A/D/G/rho", pool));
 
3385
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho", pool));
 
3386
    SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "/A/D/G/tau", pool));
 
3387
    SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
 
3388
 
 
3389
    /* Delete "A" */
 
3390
    SVN_ERR (svn_fs_delete (txn_root, "A", pool));
 
3391
    SVN_ERR (check_entry_absent (txn_root, "", "A", pool));
 
3392
    SVN_ERR (check_id_present (fs, A_id, pool));
 
3393
    SVN_ERR (check_id_present (fs, mu_id, pool));
 
3394
    SVN_ERR (check_id_present (fs, B_id, pool));
 
3395
    SVN_ERR (check_id_present (fs, lambda_id, pool));
 
3396
    SVN_ERR (check_id_present (fs, E_id, pool));
 
3397
    SVN_ERR (check_id_present (fs, alpha_id, pool));
 
3398
    SVN_ERR (check_id_present (fs, beta_id, pool));
 
3399
    SVN_ERR (check_id_present (fs, F_id, pool));
 
3400
    SVN_ERR (check_id_present (fs, C_id, pool));
 
3401
    SVN_ERR (check_id_present (fs, D_id, pool));
 
3402
    SVN_ERR (check_id_present (fs, gamma_id, pool));
 
3403
    SVN_ERR (check_id_present (fs, H_id, pool));
 
3404
    SVN_ERR (check_id_present (fs, chi_id, pool));
 
3405
    SVN_ERR (check_id_present (fs, psi_id, pool));
 
3406
    SVN_ERR (check_id_present (fs, omega_id, pool));
 
3407
    SVN_ERR (check_id_present (fs, G_id, pool));
 
3408
    SVN_ERR (check_id_present (fs, pi_id, pool));
 
3409
    SVN_ERR (check_id_present (fs, rho_id, pool));
 
3410
    SVN_ERR (check_id_present (fs, tau_id, pool));
 
3411
 
 
3412
    /* Validate the tree.  */
 
3413
    {
 
3414
      static svn_test__tree_entry_t expected_entries[] = {
 
3415
        /* path, contents (0 = dir) */
 
3416
        { "iota",        "This is the file 'iota'.\n" }
 
3417
      };
 
3418
      SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 1, pool));
 
3419
    }
 
3420
  }
 
3421
 
 
3422
  return SVN_NO_ERROR;
 
3423
}
 
3424
 
 
3425
 
 
3426
 
 
3427
/* Test the datestamps on commits. */
 
3428
static svn_error_t *
 
3429
commit_date (const char **msg,
 
3430
             svn_boolean_t msg_only,
 
3431
             svn_test_opts_t *opts,
 
3432
              apr_pool_t *pool)
 
3433
{
 
3434
  svn_fs_t *fs;
 
3435
  svn_fs_txn_t *txn;
 
3436
  svn_fs_root_t *txn_root;
 
3437
  svn_revnum_t rev;
 
3438
  svn_string_t *datestamp;
 
3439
  apr_time_t before_commit, at_commit, after_commit;
 
3440
 
 
3441
  *msg = "commit datestamps";
 
3442
 
 
3443
  if (msg_only)
 
3444
    return SVN_NO_ERROR;
 
3445
 
 
3446
  /* Prepare a filesystem. */
 
3447
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-commit-date",
 
3448
                                "bdb", pool));
 
3449
 
 
3450
  before_commit = apr_time_now ();
 
3451
 
 
3452
  /* Commit a greek tree. */
 
3453
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
3454
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
3455
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
3456
  SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, pool));
 
3457
 
 
3458
  after_commit = apr_time_now ();
 
3459
 
 
3460
  /* Get the datestamp of the commit. */
 
3461
  SVN_ERR (svn_fs_revision_prop (&datestamp, fs, rev, SVN_PROP_REVISION_DATE,
 
3462
                                 pool));
 
3463
 
 
3464
  if (datestamp == NULL)
 
3465
    return svn_error_create
 
3466
      (SVN_ERR_FS_GENERAL, NULL,
 
3467
       "failed to get datestamp of committed revision");
 
3468
 
 
3469
  SVN_ERR (svn_time_from_cstring (&at_commit, datestamp->data, pool));
 
3470
 
 
3471
  if (at_commit < before_commit)
 
3472
    return svn_error_create
 
3473
      (SVN_ERR_FS_GENERAL, NULL,
 
3474
       "datestamp too early");
 
3475
    
 
3476
  if (at_commit > after_commit)
 
3477
    return svn_error_create
 
3478
      (SVN_ERR_FS_GENERAL, NULL,
 
3479
       "datestamp too late");
 
3480
 
 
3481
  return SVN_NO_ERROR;
 
3482
}
 
3483
 
 
3484
 
 
3485
static svn_error_t *
 
3486
check_old_revisions (const char **msg,
 
3487
                     svn_boolean_t msg_only,
 
3488
                     svn_test_opts_t *opts,
 
3489
                     apr_pool_t *pool)
 
3490
{
 
3491
  svn_fs_t *fs;
 
3492
  svn_fs_txn_t *txn;
 
3493
  svn_fs_root_t *txn_root;
 
3494
  svn_revnum_t rev;
 
3495
  apr_pool_t *subpool = svn_pool_create (pool);
 
3496
 
 
3497
  *msg = "check old revisions";
 
3498
 
 
3499
  if (msg_only)
 
3500
    return SVN_NO_ERROR;
 
3501
 
 
3502
  /* Prepare a filesystem. */
 
3503
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-old-revisions",
 
3504
                                "bdb", pool));
 
3505
 
 
3506
  /* Commit a greek tree. */
 
3507
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
 
3508
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3509
  SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
 
3510
  SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3511
  svn_pool_clear (subpool);
 
3512
 
 
3513
  /* Modify and commit iota a few times, then test to see if we can
 
3514
     retrieve all the committed revisions. */
 
3515
  {
 
3516
    /* right-side numbers match revision numbers */
 
3517
#define iota_contents_1 "This is the file 'iota'.\n"
 
3518
 
 
3519
    /* Add a char to the front. */
 
3520
#define iota_contents_2 "XThis is the file 'iota'.\n"
 
3521
 
 
3522
    /* Add a char to the end. */
 
3523
#define iota_contents_3 "XThis is the file 'iota'.\nX"
 
3524
 
 
3525
    /* Add a couple of chars in the middle. */
 
3526
#define iota_contents_4 "XThis is the X file 'iota'.\nX"
 
3527
 
 
3528
    /* Randomly add and delete chars all over. */
 
3529
#define iota_contents_5 \
 
3530
    "XTYhQis is ACK, PHHHT! no longer 'ioZZZZZta'.blarf\nbye"
 
3531
 
 
3532
    /* Reassure iota that it will live for quite some time. */
 
3533
#define iota_contents_6 "Matthew 5:18 (Revised Standard Version) --\n\
 
3534
For truly, I say to you, till heaven and earth pass away, not an iota,\n\
 
3535
not a dot, will pass from the law until all is accomplished."
 
3536
 
 
3537
    /* Revert to the original contents. */
 
3538
#define iota_contents_7 "This is the file 'iota'.\n"
 
3539
 
 
3540
    /* Revision 2. */
 
3541
    SVN_ERR (svn_fs_begin_txn (&txn, fs, rev, subpool));
 
3542
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3543
    SVN_ERR (svn_test__set_file_contents
 
3544
             (txn_root, "iota", iota_contents_2, subpool));
 
3545
    SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3546
    svn_pool_clear (subpool);
 
3547
    
 
3548
    /* Revision 3. */
 
3549
    SVN_ERR (svn_fs_begin_txn (&txn, fs, rev, subpool));
 
3550
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3551
    SVN_ERR (svn_test__set_file_contents
 
3552
             (txn_root, "iota", iota_contents_3, subpool));
 
3553
    SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3554
    svn_pool_clear (subpool);
 
3555
    
 
3556
    /* Revision 4. */
 
3557
    SVN_ERR (svn_fs_begin_txn (&txn, fs, rev, subpool));
 
3558
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3559
    SVN_ERR (svn_test__set_file_contents
 
3560
             (txn_root, "iota", iota_contents_4, subpool));
 
3561
    SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3562
    svn_pool_clear (subpool);
 
3563
    
 
3564
    /* Revision 5. */
 
3565
    SVN_ERR (svn_fs_begin_txn (&txn, fs, rev, subpool));
 
3566
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3567
    SVN_ERR (svn_test__set_file_contents
 
3568
             (txn_root, "iota", iota_contents_5, subpool));
 
3569
    SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3570
    svn_pool_clear (subpool);
 
3571
    
 
3572
    /* Revision 6. */
 
3573
    SVN_ERR (svn_fs_begin_txn (&txn, fs, rev, subpool));
 
3574
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3575
    SVN_ERR (svn_test__set_file_contents
 
3576
             (txn_root, "iota", iota_contents_6, subpool));
 
3577
    SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3578
    svn_pool_clear (subpool);
 
3579
 
 
3580
    /* Revision 7. */
 
3581
    SVN_ERR (svn_fs_begin_txn (&txn, fs, rev, subpool));
 
3582
    SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3583
    SVN_ERR (svn_test__set_file_contents
 
3584
             (txn_root, "iota", iota_contents_7, subpool));
 
3585
    SVN_ERR (svn_fs_commit_txn (NULL, &rev, txn, subpool));
 
3586
    svn_pool_clear (subpool);
 
3587
 
 
3588
    /** Now check the full Greek Tree in all of those revisions,
 
3589
        adjusting `iota' for each one. ***/
 
3590
 
 
3591
    /* Validate revision 1.  */
 
3592
    {
 
3593
      svn_fs_root_t *root;
 
3594
      static svn_test__tree_entry_t expected_entries[] = {
 
3595
        /* path, contents (0 = dir) */
 
3596
        { "iota",        iota_contents_1 },
 
3597
        { "A",           0 },
 
3598
        { "A/mu",        "This is the file 'mu'.\n" },
 
3599
        { "A/B",         0 },
 
3600
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3601
        { "A/B/E",       0 },
 
3602
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3603
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3604
        { "A/B/F",       0 },
 
3605
        { "A/C",         0 },
 
3606
        { "A/D",         0 },
 
3607
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3608
        { "A/D/G",       0 },
 
3609
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3610
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3611
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3612
        { "A/D/H",       0 },
 
3613
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3614
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3615
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3616
      };
 
3617
 
 
3618
      SVN_ERR (svn_fs_revision_root (&root, fs, 1, pool));
 
3619
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3620
    }
 
3621
 
 
3622
    /* Validate revision 2.  */
 
3623
    {
 
3624
      svn_fs_root_t *root;
 
3625
      static svn_test__tree_entry_t expected_entries[] = {
 
3626
        /* path, contents (0 = dir) */
 
3627
        { "iota",        iota_contents_2 },
 
3628
        { "A",           0 },
 
3629
        { "A/mu",        "This is the file 'mu'.\n" },
 
3630
        { "A/B",         0 },
 
3631
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3632
        { "A/B/E",       0 },
 
3633
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3634
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3635
        { "A/B/F",       0 },
 
3636
        { "A/C",         0 },
 
3637
        { "A/D",         0 },
 
3638
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3639
        { "A/D/G",       0 },
 
3640
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3641
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3642
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3643
        { "A/D/H",       0 },
 
3644
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3645
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3646
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3647
      };
 
3648
 
 
3649
      SVN_ERR (svn_fs_revision_root (&root, fs, 2, pool));
 
3650
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3651
    }
 
3652
 
 
3653
    /* Validate revision 3.  */
 
3654
    {
 
3655
      svn_fs_root_t *root;
 
3656
      static svn_test__tree_entry_t expected_entries[] = {
 
3657
        /* path, contents (0 = dir) */
 
3658
        { "iota",        iota_contents_3 },
 
3659
        { "A",           0 },
 
3660
        { "A/mu",        "This is the file 'mu'.\n" },
 
3661
        { "A/B",         0 },
 
3662
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3663
        { "A/B/E",       0 },
 
3664
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3665
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3666
        { "A/B/F",       0 },
 
3667
        { "A/C",         0 },
 
3668
        { "A/D",         0 },
 
3669
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3670
        { "A/D/G",       0 },
 
3671
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3672
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3673
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3674
        { "A/D/H",       0 },
 
3675
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3676
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3677
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3678
      };
 
3679
 
 
3680
      SVN_ERR (svn_fs_revision_root (&root, fs, 3, pool));
 
3681
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3682
    }
 
3683
 
 
3684
    /* Validate revision 4.  */
 
3685
    {
 
3686
      svn_fs_root_t *root;
 
3687
      static svn_test__tree_entry_t expected_entries[] = {
 
3688
        /* path, contents (0 = dir) */
 
3689
        { "iota",        iota_contents_4 },
 
3690
        { "A",           0 },
 
3691
        { "A/mu",        "This is the file 'mu'.\n" },
 
3692
        { "A/B",         0 },
 
3693
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3694
        { "A/B/E",       0 },
 
3695
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3696
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3697
        { "A/B/F",       0 },
 
3698
        { "A/C",         0 },
 
3699
        { "A/D",         0 },
 
3700
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3701
        { "A/D/G",       0 },
 
3702
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3703
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3704
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3705
        { "A/D/H",       0 },
 
3706
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3707
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3708
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3709
      };
 
3710
 
 
3711
      SVN_ERR (svn_fs_revision_root (&root, fs, 4, pool));
 
3712
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3713
    }
 
3714
 
 
3715
    /* Validate revision 5.  */
 
3716
    {
 
3717
      svn_fs_root_t *root;
 
3718
      static svn_test__tree_entry_t expected_entries[] = {
 
3719
        /* path, contents (0 = dir) */
 
3720
        { "iota",        iota_contents_5 },
 
3721
        { "A",           0 },
 
3722
        { "A/mu",        "This is the file 'mu'.\n" },
 
3723
        { "A/B",         0 },
 
3724
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3725
        { "A/B/E",       0 },
 
3726
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3727
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3728
        { "A/B/F",       0 },
 
3729
        { "A/C",         0 },
 
3730
        { "A/D",         0 },
 
3731
        { "A/D/G",       0 },
 
3732
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3733
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3734
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3735
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3736
        { "A/D/H",       0 },
 
3737
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3738
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3739
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3740
      };
 
3741
 
 
3742
      SVN_ERR (svn_fs_revision_root (&root, fs, 5, pool));
 
3743
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3744
    }
 
3745
 
 
3746
    /* Validate revision 6.  */
 
3747
    {
 
3748
      svn_fs_root_t *root;
 
3749
      static svn_test__tree_entry_t expected_entries[] = {
 
3750
        /* path, contents (0 = dir) */
 
3751
        { "iota",        iota_contents_6 },
 
3752
        { "A",           0 },
 
3753
        { "A/mu",        "This is the file 'mu'.\n" },
 
3754
        { "A/B",         0 },
 
3755
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3756
        { "A/B/E",       0 },
 
3757
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3758
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3759
        { "A/B/F",       0 },
 
3760
        { "A/C",         0 },
 
3761
        { "A/D",         0 },
 
3762
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3763
        { "A/D/G",       0 },
 
3764
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3765
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3766
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3767
        { "A/D/H",       0 },
 
3768
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3769
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3770
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3771
      };
 
3772
 
 
3773
      SVN_ERR (svn_fs_revision_root (&root, fs, 6, pool));
 
3774
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3775
    }
 
3776
 
 
3777
    /* Validate revision 7.  */
 
3778
    {
 
3779
      svn_fs_root_t *root;
 
3780
      static svn_test__tree_entry_t expected_entries[] = {
 
3781
        /* path, contents (0 = dir) */
 
3782
        { "iota",        iota_contents_7 },
 
3783
        { "A",           0 },
 
3784
        { "A/mu",        "This is the file 'mu'.\n" },
 
3785
        { "A/B",         0 },
 
3786
        { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3787
        { "A/B/E",       0 },
 
3788
        { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3789
        { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3790
        { "A/B/F",       0 },
 
3791
        { "A/C",         0 },
 
3792
        { "A/D",         0 },
 
3793
        { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3794
        { "A/D/G",       0 },
 
3795
        { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3796
        { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3797
        { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3798
        { "A/D/H",       0 },
 
3799
        { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3800
        { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3801
        { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3802
      };
 
3803
 
 
3804
      SVN_ERR (svn_fs_revision_root (&root, fs, 7, pool));
 
3805
      SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
 
3806
    }
 
3807
  }
 
3808
 
 
3809
  svn_pool_destroy (subpool);
 
3810
  return SVN_NO_ERROR;
 
3811
}
 
3812
 
 
3813
 
 
3814
/* For each revision R in FS, from 0 to MAX_REV, check that it
 
3815
   matches the tree in EXPECTED_TREES[R].  Use POOL for any
 
3816
   allocations.  This is a helper function for check_all_revisions. */
 
3817
static svn_error_t *
 
3818
validate_revisions (svn_fs_t *fs,
 
3819
                    svn_test__tree_t *expected_trees,
 
3820
                    svn_revnum_t max_rev,
 
3821
                    apr_pool_t *pool)
 
3822
{
 
3823
  svn_fs_root_t *revision_root;
 
3824
  svn_revnum_t i;
 
3825
  svn_error_t *err;
 
3826
  apr_pool_t *subpool = svn_pool_create (pool);
 
3827
 
 
3828
  /* Validate all revisions up to the current one. */
 
3829
  for (i = 0; i <= max_rev; i++)
 
3830
    {
 
3831
      SVN_ERR (svn_fs_revision_root (&revision_root, fs, 
 
3832
                                     (svn_revnum_t)i, subpool)); 
 
3833
      err = svn_test__validate_tree (revision_root, 
 
3834
                                     expected_trees[i].entries,
 
3835
                                     expected_trees[i].num_entries, 
 
3836
                                     subpool);
 
3837
      if (err)
 
3838
        return svn_error_createf
 
3839
          (SVN_ERR_FS_GENERAL, err, 
 
3840
           "Error validating revision %ld (youngest is %ld)", i, max_rev);
 
3841
      svn_pool_clear (subpool);
 
3842
    }
 
3843
 
 
3844
  svn_pool_destroy (subpool);
 
3845
  return SVN_NO_ERROR;
 
3846
}
 
3847
 
 
3848
 
 
3849
static svn_error_t *
 
3850
check_all_revisions (const char **msg,
 
3851
                     svn_boolean_t msg_only,
 
3852
                     svn_test_opts_t *opts,
 
3853
                     apr_pool_t *pool)
 
3854
 
3855
  svn_fs_t *fs;
 
3856
  svn_fs_txn_t *txn;
 
3857
  svn_fs_root_t *txn_root;
 
3858
  svn_revnum_t youngest_rev;
 
3859
  svn_test__tree_t expected_trees[5]; /* one tree per commit, please */
 
3860
  svn_revnum_t revision_count = 0;
 
3861
  apr_pool_t *subpool = svn_pool_create (pool);
 
3862
 
 
3863
  *msg = "after each commit, check all revisions";
 
3864
 
 
3865
  if (msg_only)
 
3866
    return SVN_NO_ERROR;
 
3867
 
 
3868
  /* Create a filesystem and repository. */
 
3869
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-all-revisions",
 
3870
                                "bdb", pool));
 
3871
 
 
3872
  /***********************************************************************/
 
3873
  /* REVISION 0 */
 
3874
  /***********************************************************************/
 
3875
  {
 
3876
    expected_trees[revision_count].num_entries = 0;
 
3877
    expected_trees[revision_count].entries = 0;
 
3878
    SVN_ERR (validate_revisions (fs, expected_trees, revision_count, subpool));
 
3879
    revision_count++;
 
3880
  }
 
3881
  svn_pool_clear (subpool);
 
3882
 
 
3883
  /* Create and commit the greek tree. */
 
3884
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
 
3885
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3886
  SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
 
3887
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
3888
 
 
3889
  /***********************************************************************/
 
3890
  /* REVISION 1 */
 
3891
  /***********************************************************************/
 
3892
  {
 
3893
    static svn_test__tree_entry_t expected_entries[] = {
 
3894
      /* path, contents (0 = dir) */
 
3895
      { "iota",        "This is the file 'iota'.\n" },
 
3896
      { "A",           0 },
 
3897
      { "A/mu",        "This is the file 'mu'.\n" },
 
3898
      { "A/B",         0 },
 
3899
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3900
      { "A/B/E",       0 },
 
3901
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3902
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3903
      { "A/B/F",       0 },
 
3904
      { "A/C",         0 },
 
3905
      { "A/D",         0 },
 
3906
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3907
      { "A/D/G",       0 },
 
3908
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3909
      { "A/D/G/rho",   "This is the file 'rho'.\n" },
 
3910
      { "A/D/G/tau",   "This is the file 'tau'.\n" },
 
3911
      { "A/D/H",       0 },
 
3912
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3913
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
3914
      { "A/D/H/omega", "This is the file 'omega'.\n" }
 
3915
    };
 
3916
    expected_trees[revision_count].entries = expected_entries;
 
3917
    expected_trees[revision_count].num_entries = 20;
 
3918
    SVN_ERR (validate_revisions (fs, expected_trees, revision_count, subpool));
 
3919
    revision_count++;
 
3920
  }
 
3921
  svn_pool_clear (subpool);
 
3922
 
 
3923
  /* Make a new txn based on the youngest revision, make some changes,
 
3924
     and commit those changes (which makes a new youngest
 
3925
     revision). */
 
3926
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
3927
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3928
  {
 
3929
    static svn_test__txn_script_command_t script_entries[] = {
 
3930
      { 'a', "A/delta",     "This is the file 'delta'.\n" },
 
3931
      { 'a', "A/epsilon",   "This is the file 'epsilon'.\n" },
 
3932
      { 'a', "A/B/Z",       0 },
 
3933
      { 'a', "A/B/Z/zeta",  "This is the file 'zeta'.\n" },
 
3934
      { 'd', "A/C",         0 },
 
3935
      { 'd', "A/mu",        "" },
 
3936
      { 'd', "A/D/G/tau",   "" },
 
3937
      { 'd', "A/D/H/omega", "" },
 
3938
      { 'e', "iota",        "Changed file 'iota'.\n" },
 
3939
      { 'e', "A/D/G/rho",   "Changed file 'rho'.\n" }
 
3940
    };
 
3941
    SVN_ERR (svn_test__txn_script_exec (txn_root, script_entries, 10, 
 
3942
                                        subpool));
 
3943
  }
 
3944
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
3945
 
 
3946
  /***********************************************************************/
 
3947
  /* REVISION 2 */
 
3948
  /***********************************************************************/
 
3949
  {
 
3950
    static svn_test__tree_entry_t expected_entries[] = {
 
3951
      /* path, contents (0 = dir) */
 
3952
      { "iota",        "Changed file 'iota'.\n" },
 
3953
      { "A",           0 },
 
3954
      { "A/delta",     "This is the file 'delta'.\n" },
 
3955
      { "A/epsilon",   "This is the file 'epsilon'.\n" },
 
3956
      { "A/B",         0 },
 
3957
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
3958
      { "A/B/E",       0 },
 
3959
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
3960
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
3961
      { "A/B/F",       0 },
 
3962
      { "A/B/Z",       0 },
 
3963
      { "A/B/Z/zeta",  "This is the file 'zeta'.\n" },
 
3964
      { "A/D",         0 },
 
3965
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
3966
      { "A/D/G",       0 },
 
3967
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
3968
      { "A/D/G/rho",   "Changed file 'rho'.\n" },
 
3969
      { "A/D/H",       0 },
 
3970
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
3971
      { "A/D/H/psi",   "This is the file 'psi'.\n" }
 
3972
    };
 
3973
    expected_trees[revision_count].entries = expected_entries;
 
3974
    expected_trees[revision_count].num_entries = 20;
 
3975
    SVN_ERR (validate_revisions (fs, expected_trees, revision_count, subpool));
 
3976
    revision_count++;
 
3977
  } 
 
3978
  svn_pool_clear (subpool);
 
3979
 
 
3980
  /* Make a new txn based on the youngest revision, make some changes,
 
3981
     and commit those changes (which makes a new youngest
 
3982
     revision). */
 
3983
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
3984
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
3985
  {
 
3986
    static svn_test__txn_script_command_t script_entries[] = {
 
3987
      { 'a', "A/mu",        "Re-added file 'mu'.\n" },
 
3988
      { 'a', "A/D/H/omega", 0 }, /* re-add omega as directory! */
 
3989
      { 'd', "iota",        "" },
 
3990
      { 'e', "A/delta",     "This is the file 'delta'.\nLine 2.\n" }
 
3991
    };
 
3992
    SVN_ERR (svn_test__txn_script_exec (txn_root, script_entries, 4, 
 
3993
                                        subpool));
 
3994
  }
 
3995
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
3996
 
 
3997
  /***********************************************************************/
 
3998
  /* REVISION 3 */
 
3999
  /***********************************************************************/
 
4000
  {
 
4001
    static svn_test__tree_entry_t expected_entries[] = {
 
4002
      /* path, contents (0 = dir) */
 
4003
      { "A",           0 },
 
4004
      { "A/delta",     "This is the file 'delta'.\nLine 2.\n" },
 
4005
      { "A/epsilon",   "This is the file 'epsilon'.\n" },
 
4006
      { "A/mu",        "Re-added file 'mu'.\n" },
 
4007
      { "A/B",         0 },
 
4008
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
4009
      { "A/B/E",       0 },
 
4010
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
4011
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
4012
      { "A/B/F",       0 },
 
4013
      { "A/B/Z",       0 },
 
4014
      { "A/B/Z/zeta",  "This is the file 'zeta'.\n" },
 
4015
      { "A/D",         0 },
 
4016
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
4017
      { "A/D/G",       0 },
 
4018
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
4019
      { "A/D/G/rho",   "Changed file 'rho'.\n" },
 
4020
      { "A/D/H",       0 },
 
4021
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
4022
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
4023
      { "A/D/H/omega", 0 }
 
4024
    };
 
4025
    expected_trees[revision_count].entries = expected_entries;
 
4026
    expected_trees[revision_count].num_entries = 21;
 
4027
    SVN_ERR (validate_revisions (fs, expected_trees, revision_count, subpool));
 
4028
    revision_count++;
 
4029
  }
 
4030
  svn_pool_clear (subpool);
 
4031
 
 
4032
  /* Make a new txn based on the youngest revision, make some changes,
 
4033
     and commit those changes (which makes a new youngest
 
4034
     revision). */
 
4035
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4036
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4037
  {
 
4038
    static svn_test__txn_script_command_t script_entries[] = {
 
4039
      { 'c', "A/D/G",        "A/D/G2" },
 
4040
      { 'c', "A/epsilon",    "A/B/epsilon" },
 
4041
    };
 
4042
    SVN_ERR (svn_test__txn_script_exec (txn_root, script_entries, 2, subpool));
 
4043
  }
 
4044
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4045
 
 
4046
  /***********************************************************************/
 
4047
  /* REVISION 4 */
 
4048
  /***********************************************************************/
 
4049
  {
 
4050
    static svn_test__tree_entry_t expected_entries[] = {
 
4051
      /* path, contents (0 = dir) */
 
4052
      { "A",           0 },
 
4053
      { "A/delta",     "This is the file 'delta'.\nLine 2.\n" },
 
4054
      { "A/epsilon",   "This is the file 'epsilon'.\n" },
 
4055
      { "A/mu",        "Re-added file 'mu'.\n" },
 
4056
      { "A/B",         0 },
 
4057
      { "A/B/epsilon", "This is the file 'epsilon'.\n" },
 
4058
      { "A/B/lambda",  "This is the file 'lambda'.\n" },
 
4059
      { "A/B/E",       0 },
 
4060
      { "A/B/E/alpha", "This is the file 'alpha'.\n" },
 
4061
      { "A/B/E/beta",  "This is the file 'beta'.\n" },
 
4062
      { "A/B/F",       0 },
 
4063
      { "A/B/Z",       0 },
 
4064
      { "A/B/Z/zeta",  "This is the file 'zeta'.\n" },
 
4065
      { "A/D",         0 },
 
4066
      { "A/D/gamma",   "This is the file 'gamma'.\n" },
 
4067
      { "A/D/G",       0 },
 
4068
      { "A/D/G/pi",    "This is the file 'pi'.\n" },
 
4069
      { "A/D/G/rho",   "Changed file 'rho'.\n" },
 
4070
      { "A/D/G2",      0 },
 
4071
      { "A/D/G2/pi",   "This is the file 'pi'.\n" },
 
4072
      { "A/D/G2/rho",  "Changed file 'rho'.\n" },
 
4073
      { "A/D/H",       0 },
 
4074
      { "A/D/H/chi",   "This is the file 'chi'.\n" },
 
4075
      { "A/D/H/psi",   "This is the file 'psi'.\n" },
 
4076
      { "A/D/H/omega", 0 }
 
4077
    };
 
4078
    expected_trees[revision_count].entries = expected_entries;
 
4079
    expected_trees[revision_count].num_entries = 25;
 
4080
    SVN_ERR (validate_revisions (fs, expected_trees, revision_count, subpool));
 
4081
    revision_count++;
 
4082
  }
 
4083
  svn_pool_destroy (subpool);
 
4084
 
 
4085
  return SVN_NO_ERROR;
 
4086
}
 
4087
 
 
4088
 
 
4089
/* Helper function for large_file_integrity().  Given a ROOT and PATH
 
4090
   to a file, calculate and return the MD5 digest for the contents of
 
4091
   the file. */
 
4092
static svn_error_t *
 
4093
get_file_digest (unsigned char digest[APR_MD5_DIGESTSIZE],
 
4094
                 svn_fs_root_t *root,
 
4095
                 const char *path,
 
4096
                 apr_pool_t *pool)
 
4097
{
 
4098
  svn_stream_t *stream;
 
4099
  apr_size_t len;
 
4100
  const apr_size_t buf_size = 100000;
 
4101
  apr_md5_ctx_t context;
 
4102
 
 
4103
  /* ### todo:  Pool usage in svndiff is currently really, really
 
4104
     crappy.  We need to keep this buffer fairly large so we don't run
 
4105
     out of memory doing undeltification of large files into tiny
 
4106
     buffers.  Issue #465.  */
 
4107
  char *buf = apr_palloc (pool, buf_size);
 
4108
 
 
4109
  /* Get a stream for the file contents. */
 
4110
  SVN_ERR (svn_fs_file_contents (&stream, root, path, pool));  
 
4111
 
 
4112
  /* Initialize APR MD5 context. */
 
4113
  apr_md5_init (&context);
 
4114
 
 
4115
  do 
 
4116
    {
 
4117
      /* "please fill the buf with bytes" */
 
4118
      len = buf_size;
 
4119
      SVN_ERR (svn_stream_read (stream, buf, &len));
 
4120
      
 
4121
      /* Update the MD5 calculation with the data we just read.  */
 
4122
      apr_md5_update (&context, buf, len);
 
4123
      
 
4124
    } while (len == buf_size);  /* Continue until a short read. */
 
4125
 
 
4126
  /* Finalize MD5 calculation. */
 
4127
  apr_md5_final (digest, &context);
 
4128
 
 
4129
  return SVN_NO_ERROR;
 
4130
}
 
4131
 
 
4132
 
 
4133
/* Return a pseudo-random number in the range [0,SCALAR) i.e. return
 
4134
   a number N such that 0 <= N < SCALAR */
 
4135
static int my_rand (int scalar, apr_uint32_t *seed)
 
4136
{
 
4137
  static const apr_uint32_t TEST_RAND_MAX = 0xffffffffUL;
 
4138
  /* Assumes TEST_RAND_MAX+1 can be exactly represented in a double */
 
4139
  return (int)(((double)svn_test_rand(seed)
 
4140
                / ((double)TEST_RAND_MAX+1.0))
 
4141
               * (double)scalar);
 
4142
}
 
4143
 
 
4144
 
 
4145
/* Put pseudo-random bytes in buffer BUF (which is LEN bytes long).
 
4146
   If FULL is TRUE, simply replace every byte in BUF with a
 
4147
   pseudo-random byte, else, replace a pseudo-random collection of
 
4148
   bytes with pseudo-random data. */
 
4149
static void
 
4150
random_data_to_buffer (char *buf, 
 
4151
                       apr_size_t buf_len, 
 
4152
                       svn_boolean_t full,
 
4153
                       apr_uint32_t *seed)
 
4154
{
 
4155
  apr_size_t i;
 
4156
  apr_size_t num_bytes;
 
4157
  apr_size_t offset;
 
4158
 
 
4159
  int ds_off = 0;
 
4160
  const char *dataset = "0123456789";
 
4161
  int dataset_size = strlen (dataset);
 
4162
 
 
4163
  if (full)
 
4164
    {
 
4165
      for (i = 0; i < buf_len; i++)
 
4166
        {
 
4167
          ds_off = my_rand (dataset_size, seed);
 
4168
          buf[i] = dataset[ds_off];
 
4169
        }
 
4170
 
 
4171
      return;
 
4172
    }
 
4173
 
 
4174
  num_bytes = my_rand (buf_len / 100, seed) + 1;
 
4175
  for (i = 0; i < num_bytes; i++)
 
4176
    {
 
4177
      offset = my_rand (buf_len - 1, seed);
 
4178
      ds_off = my_rand (dataset_size, seed);
 
4179
      buf[offset] = dataset[ds_off];
 
4180
    }
 
4181
 
 
4182
  return;
 
4183
}
 
4184
 
 
4185
 
 
4186
static svn_error_t *
 
4187
file_integrity_helper (apr_size_t filesize, apr_uint32_t *seed,
 
4188
                       apr_pool_t *pool)
 
4189
 
4190
  svn_fs_t *fs;
 
4191
  svn_fs_txn_t *txn;
 
4192
  svn_fs_root_t *txn_root, *rev_root;
 
4193
  svn_revnum_t youngest_rev = 0;
 
4194
  apr_pool_t *subpool = svn_pool_create (pool);
 
4195
  svn_string_t contents;
 
4196
  char *content_buffer;
 
4197
  unsigned char digest[APR_MD5_DIGESTSIZE];
 
4198
  unsigned char digest_list[100][APR_MD5_DIGESTSIZE];
 
4199
  svn_txdelta_window_handler_t wh_func;
 
4200
  void *wh_baton;
 
4201
  svn_revnum_t j;
 
4202
 
 
4203
  /* Create a filesystem and repository. */
 
4204
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-large-file-integrity",
 
4205
                                "bdb", pool));
 
4206
 
 
4207
  /* Set up our file contents string buffer. */
 
4208
  content_buffer = apr_palloc (pool, filesize);
 
4209
 
 
4210
  contents.data = content_buffer;
 
4211
  contents.len = filesize;
 
4212
 
 
4213
  /* THE PLAN:
 
4214
 
 
4215
     The plan here is simple.  We have a very large file (FILESIZE
 
4216
     bytes) that we initialize with pseudo-random data and commit.
 
4217
     Then we make pseudo-random modifications to that file's contents,
 
4218
     committing after each mod.  Prior to each commit, we generate an
 
4219
     MD5 checksum for the contents of the file, storing each of those
 
4220
     checksums in an array.  After we've made a whole bunch of edits
 
4221
     and commits, we'll re-check that file's contents as of each
 
4222
     revision in the repository, recalculate a checksum for those
 
4223
     contents, and make sure the "before" and "after" checksums
 
4224
     match.  */
 
4225
 
 
4226
  /* Create a big, ugly, pseudo-random-filled file and commit it.  */
 
4227
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4228
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4229
  SVN_ERR (svn_fs_make_file (txn_root, "bigfile", subpool));
 
4230
  random_data_to_buffer (content_buffer, filesize, TRUE, seed);
 
4231
  apr_md5 (digest, contents.data, contents.len);
 
4232
  SVN_ERR (svn_fs_apply_textdelta 
 
4233
           (&wh_func, &wh_baton, txn_root, "bigfile", NULL, NULL, subpool));
 
4234
  SVN_ERR (svn_txdelta_send_string (&contents, wh_func, wh_baton, subpool));
 
4235
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4236
  SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
4237
  memcpy (digest_list[youngest_rev], digest, APR_MD5_DIGESTSIZE);
 
4238
  svn_pool_clear (subpool);
 
4239
 
 
4240
  /* Now, let's make some edits to the beginning of our file, and
 
4241
     commit those. */
 
4242
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4243
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4244
  random_data_to_buffer (content_buffer, 20, TRUE, seed);
 
4245
  apr_md5 (digest, contents.data, contents.len);
 
4246
  SVN_ERR (svn_fs_apply_textdelta 
 
4247
           (&wh_func, &wh_baton, txn_root, "bigfile", NULL, NULL, subpool));
 
4248
  SVN_ERR (svn_txdelta_send_string (&contents, wh_func, wh_baton, subpool));
 
4249
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4250
  SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
4251
  memcpy (digest_list[youngest_rev], digest, APR_MD5_DIGESTSIZE);
 
4252
  svn_pool_clear (subpool);
 
4253
 
 
4254
  /* Now, let's make some edits to the end of our file. */
 
4255
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4256
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4257
  random_data_to_buffer (content_buffer + (filesize - 20), 20, TRUE, seed);
 
4258
  apr_md5 (digest, contents.data, contents.len);
 
4259
  SVN_ERR (svn_fs_apply_textdelta 
 
4260
           (&wh_func, &wh_baton, txn_root, "bigfile", NULL, NULL, subpool));
 
4261
  SVN_ERR (svn_txdelta_send_string (&contents, wh_func, wh_baton, subpool));
 
4262
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4263
  SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
4264
  memcpy (digest_list[youngest_rev], digest, APR_MD5_DIGESTSIZE);
 
4265
  svn_pool_clear (subpool);
 
4266
 
 
4267
  /* How about some edits to both the beginning and the end of the
 
4268
     file? */
 
4269
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4270
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4271
  random_data_to_buffer (content_buffer, 20, TRUE, seed);
 
4272
  random_data_to_buffer (content_buffer + (filesize - 20), 20, TRUE, seed);
 
4273
  apr_md5 (digest, contents.data, contents.len);
 
4274
  SVN_ERR (svn_fs_apply_textdelta 
 
4275
           (&wh_func, &wh_baton, txn_root, "bigfile", NULL, NULL, subpool));
 
4276
  SVN_ERR (svn_txdelta_send_string (&contents, wh_func, wh_baton, subpool));
 
4277
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4278
  SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
4279
  memcpy (digest_list[youngest_rev], digest, APR_MD5_DIGESTSIZE);
 
4280
  svn_pool_clear (subpool);
 
4281
 
 
4282
  /* Alright, now we're just going to go crazy.  Let's make many more
 
4283
     edits -- pseudo-random numbers and offsets of bytes changed to
 
4284
     more pseudo-random values.  */
 
4285
  for (j = youngest_rev; j < 30; j = youngest_rev)
 
4286
    {
 
4287
      SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4288
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4289
      random_data_to_buffer (content_buffer, filesize, FALSE, seed);
 
4290
      apr_md5 (digest, contents.data, contents.len);
 
4291
      SVN_ERR (svn_fs_apply_textdelta (&wh_func, &wh_baton, txn_root,
 
4292
                                       "bigfile", NULL, NULL, subpool));
 
4293
      SVN_ERR (svn_txdelta_send_string 
 
4294
               (&contents, wh_func, wh_baton, subpool));
 
4295
      SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4296
      SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
4297
      memcpy (digest_list[youngest_rev], digest, APR_MD5_DIGESTSIZE);
 
4298
      svn_pool_clear (subpool);
 
4299
    }
 
4300
 
 
4301
  /* Now, calculate an MD5 digest for the contents of our big ugly
 
4302
     file in each revision currently in existence, and make the sure
 
4303
     the checksum matches the checksum of the data prior to its
 
4304
     commit. */
 
4305
  for (j = youngest_rev; j > 0; j--)
 
4306
    {
 
4307
      SVN_ERR (svn_fs_revision_root (&rev_root, fs, j, subpool));
 
4308
      SVN_ERR (get_file_digest (digest, rev_root, "bigfile", subpool));
 
4309
      if (memcmp (digest, digest_list[j], APR_MD5_DIGESTSIZE))
 
4310
        return svn_error_createf
 
4311
          (SVN_ERR_FS_GENERAL, NULL,
 
4312
           "MD5 checksum failure, revision %ld", j);
 
4313
      svn_pool_clear (subpool);
 
4314
    }
 
4315
 
 
4316
  svn_pool_destroy (subpool);
 
4317
  return SVN_NO_ERROR;
 
4318
}
 
4319
 
 
4320
 
 
4321
static svn_error_t *
 
4322
medium_file_integrity (const char **msg,
 
4323
                       svn_boolean_t msg_only,
 
4324
                       svn_test_opts_t *opts,
 
4325
                       apr_pool_t *pool)
 
4326
{
 
4327
  apr_uint32_t seed = (apr_uint32_t) apr_time_now();
 
4328
  *msg = apr_psprintf (pool,
 
4329
                       "create and modify medium file (seed=%lu)", 
 
4330
                       (unsigned long) seed);
 
4331
 
 
4332
  if (msg_only)
 
4333
    return SVN_NO_ERROR;
 
4334
 
 
4335
  /* Being no larger than the standard delta window size affects
 
4336
     deltification internally, so test that. */
 
4337
  return file_integrity_helper (SVN_DELTA_WINDOW_SIZE, &seed, pool);
 
4338
}
 
4339
 
 
4340
 
 
4341
static svn_error_t *
 
4342
large_file_integrity (const char **msg,
 
4343
                      svn_boolean_t msg_only,
 
4344
                      svn_test_opts_t *opts,
 
4345
                      apr_pool_t *pool)
 
4346
{
 
4347
  apr_uint32_t seed = (apr_uint32_t) apr_time_now();
 
4348
  *msg = apr_psprintf (pool,
 
4349
                       "create and modify large file (seed=%lu)", 
 
4350
                       (unsigned long) seed);
 
4351
 
 
4352
  if (msg_only)
 
4353
    return SVN_NO_ERROR;
 
4354
 
 
4355
  /* Being larger than the standard delta window size affects
 
4356
     deltification internally, so test that. */
 
4357
  return file_integrity_helper (SVN_DELTA_WINDOW_SIZE + 1, &seed, pool);
 
4358
}
 
4359
 
 
4360
 
 
4361
static svn_error_t *
 
4362
check_root_revision (const char **msg,
 
4363
                     svn_boolean_t msg_only,
 
4364
                     svn_test_opts_t *opts,
 
4365
                     apr_pool_t *pool)
 
4366
 
4367
  svn_fs_t *fs;
 
4368
  svn_fs_txn_t *txn;
 
4369
  svn_fs_root_t *txn_root, *rev_root;
 
4370
  svn_revnum_t youngest_rev, test_rev;
 
4371
  apr_pool_t *subpool = svn_pool_create (pool);
 
4372
  int i;
 
4373
 
 
4374
  *msg = "ensure accurate storage of root node";
 
4375
 
 
4376
  if (msg_only)
 
4377
    return SVN_NO_ERROR;
 
4378
 
 
4379
  /* Create a filesystem and repository. */
 
4380
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-root-revision",
 
4381
                                "bdb", pool));
 
4382
 
 
4383
  /* Create and commit the greek tree. */
 
4384
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
 
4385
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4386
  SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
 
4387
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4388
 
 
4389
  /* Root node's revision should be the same as YOUNGEST_REV. */
 
4390
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, subpool)); 
 
4391
  SVN_ERR (svn_fs_node_created_rev (&test_rev, rev_root, "", subpool));
 
4392
  if (test_rev != youngest_rev)
 
4393
    return svn_error_createf
 
4394
      (SVN_ERR_FS_GENERAL, NULL,
 
4395
       "Root node in revision %ld has unexpected stored revision %ld",
 
4396
       youngest_rev, test_rev);
 
4397
  svn_pool_clear (subpool);
 
4398
 
 
4399
  for (i = 0; i < 10; i++)
 
4400
    {
 
4401
      /* Create and commit the greek tree. */
 
4402
      SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4403
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4404
      SVN_ERR (svn_test__set_file_contents 
 
4405
               (txn_root, "iota", 
 
4406
                apr_psprintf (subpool, "iota version %d", i + 2), subpool));
 
4407
 
 
4408
      SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4409
 
 
4410
      /* Root node's revision should be the same as YOUNGEST_REV. */
 
4411
      SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, subpool)); 
 
4412
      SVN_ERR (svn_fs_node_created_rev (&test_rev, rev_root, "", subpool));
 
4413
      if (test_rev != youngest_rev)
 
4414
        return svn_error_createf
 
4415
          (SVN_ERR_FS_GENERAL, NULL,
 
4416
           "Root node in revision %ld has unexpected stored revision %ld",
 
4417
           youngest_rev, test_rev);
 
4418
      svn_pool_clear (subpool);
 
4419
    }
 
4420
 
 
4421
  svn_pool_destroy (subpool);
 
4422
  return SVN_NO_ERROR;
 
4423
}
 
4424
 
 
4425
 
 
4426
struct node_created_rev_args {
 
4427
  const char *path;
 
4428
  svn_revnum_t rev;
 
4429
};
 
4430
 
 
4431
 
 
4432
static svn_error_t *
 
4433
verify_path_revs (svn_fs_root_t *root,
 
4434
                  struct node_created_rev_args *args,
 
4435
                  int num_path_revs,
 
4436
                  apr_pool_t *pool)
 
4437
{
 
4438
  apr_pool_t *subpool = svn_pool_create (pool);
 
4439
  int i;
 
4440
  svn_revnum_t rev;
 
4441
 
 
4442
  for (i = 0; i < num_path_revs; i++)
 
4443
    {
 
4444
      svn_pool_clear (subpool);
 
4445
      SVN_ERR (svn_fs_node_created_rev (&rev, root, args[i].path, subpool));
 
4446
      if (rev != args[i].rev)
 
4447
        return svn_error_createf
 
4448
          (SVN_ERR_FS_GENERAL, NULL,
 
4449
           "verify_path_revs: '%s' has created rev '%ld' "
 
4450
           "(expected '%ld')", 
 
4451
           args[i].path, rev, args[i].rev);
 
4452
    }
 
4453
 
 
4454
  apr_pool_destroy (subpool);
 
4455
  return SVN_NO_ERROR;
 
4456
}
 
4457
 
 
4458
 
 
4459
static svn_error_t *
 
4460
test_node_created_rev (const char **msg,
 
4461
                       svn_boolean_t msg_only,
 
4462
                       svn_test_opts_t *opts,
 
4463
                       apr_pool_t *pool)
 
4464
 
4465
  apr_pool_t *subpool = svn_pool_create (pool);
 
4466
  svn_fs_t *fs;
 
4467
  svn_fs_txn_t *txn;
 
4468
  svn_fs_root_t *txn_root, *rev_root;
 
4469
  svn_revnum_t youngest_rev = 0;
 
4470
  int i;
 
4471
  struct node_created_rev_args path_revs[21];
 
4472
  const char *greek_paths[21] = { 
 
4473
    /*  0 */ "",
 
4474
    /*  1 */ "iota",
 
4475
    /*  2 */ "A",
 
4476
    /*  3 */ "A/mu",
 
4477
    /*  4 */ "A/B",
 
4478
    /*  5 */ "A/B/lambda",
 
4479
    /*  6 */ "A/B/E",
 
4480
    /*  7 */ "A/B/E/alpha",
 
4481
    /*  8 */ "A/B/E/beta",
 
4482
    /*  9 */ "A/B/F",
 
4483
    /* 10 */ "A/C",
 
4484
    /* 11 */ "A/D",
 
4485
    /* 12 */ "A/D/gamma",
 
4486
    /* 13 */ "A/D/G",
 
4487
    /* 14 */ "A/D/G/pi",
 
4488
    /* 15 */ "A/D/G/rho",
 
4489
    /* 16 */ "A/D/G/tau",
 
4490
    /* 17 */ "A/D/H",
 
4491
    /* 18 */ "A/D/H/chi",
 
4492
    /* 19 */ "A/D/H/psi",
 
4493
    /* 20 */ "A/D/H/omega",
 
4494
  };
 
4495
  
 
4496
  *msg = "svn_fs_node_created_rev test";
 
4497
 
 
4498
  if (msg_only)
 
4499
    return SVN_NO_ERROR;
 
4500
 
 
4501
  /* Initialize the paths in our args list. */
 
4502
  for (i = 0; i < 20; i++)
 
4503
    path_revs[i].path = greek_paths[i];
 
4504
 
 
4505
  /* Create a filesystem and repository. */
 
4506
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-node-created-rev",
 
4507
                                "bdb", pool));
 
4508
 
 
4509
  /* Created the greek tree in revision 1. */
 
4510
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4511
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4512
  SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
 
4513
 
 
4514
  /* Now, prior to committing, all these nodes should have an invalid
 
4515
     created rev.  After all, the rev has been created yet.  Verify
 
4516
     this. */
 
4517
  for (i = 0; i < 20; i++)
 
4518
    path_revs[i].rev = SVN_INVALID_REVNUM;
 
4519
  SVN_ERR (verify_path_revs (txn_root, path_revs, 20, subpool));
 
4520
 
 
4521
  /* Now commit the transaction. */
 
4522
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4523
 
 
4524
  /* Now, we have a new revision, and all paths in it should have a
 
4525
     created rev of 1.  Verify this. */
 
4526
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, subpool));
 
4527
  for (i = 0; i < 20; i++)
 
4528
    path_revs[i].rev = 1;
 
4529
  SVN_ERR (verify_path_revs (rev_root, path_revs, 20, subpool));
 
4530
 
 
4531
  /*** Let's make some changes/commits here and there, and make sure
 
4532
       we can keep this whole created rev thing in good standing.  The
 
4533
       general rule here is that prior to commit, mutable things have
 
4534
       an invalid created rev, immutable things have their original
 
4535
       created rev.  After the commit, those things which had invalid
 
4536
       created revs in the transaction now have the youngest revision
 
4537
       as their created rev.  
 
4538
 
 
4539
       ### NOTE: Bubble-up currently affect the created revisions for
 
4540
       directory nodes.  I'm not sure if this is the behavior we've
 
4541
       settled on as desired. 
 
4542
  */
 
4543
 
 
4544
  /*** clear the per-commit pool */
 
4545
  svn_pool_clear (subpool);
 
4546
  /* begin a new transaction */
 
4547
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4548
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4549
  /* make mods */
 
4550
  SVN_ERR (svn_test__set_file_contents
 
4551
           (txn_root, "iota", "pointless mod here", subpool));
 
4552
  /* verify created revs */
 
4553
  path_revs[0].rev = SVN_INVALID_REVNUM; /* (root) */
 
4554
  path_revs[1].rev = SVN_INVALID_REVNUM; /* iota */
 
4555
  SVN_ERR (verify_path_revs (txn_root, path_revs, 20, subpool));
 
4556
  /* commit transaction */
 
4557
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4558
  /* get a revision root for the new revision */
 
4559
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, subpool));
 
4560
  /* verify created revs */
 
4561
  path_revs[0].rev = 2; /* (root) */
 
4562
  path_revs[1].rev = 2; /* iota */
 
4563
  SVN_ERR (verify_path_revs (rev_root, path_revs, 20, subpool));
 
4564
 
 
4565
  /*** clear the per-commit pool */
 
4566
  svn_pool_clear (subpool);
 
4567
  /* begin a new transaction */
 
4568
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4569
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4570
  /* make mods */
 
4571
  SVN_ERR (svn_test__set_file_contents
 
4572
           (txn_root, "A/D/H/omega", "pointless mod here", subpool));
 
4573
  /* verify created revs */
 
4574
  path_revs[0].rev  = SVN_INVALID_REVNUM; /* (root) */
 
4575
  path_revs[2].rev  = SVN_INVALID_REVNUM; /* A */
 
4576
  path_revs[11].rev = SVN_INVALID_REVNUM; /* D */
 
4577
  path_revs[17].rev = SVN_INVALID_REVNUM; /* H */
 
4578
  path_revs[20].rev = SVN_INVALID_REVNUM; /* omega */
 
4579
  SVN_ERR (verify_path_revs (txn_root, path_revs, 20, subpool));
 
4580
  /* commit transaction */
 
4581
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4582
  /* get a revision root for the new revision */
 
4583
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, subpool));
 
4584
  /* verify created revs */
 
4585
  path_revs[0].rev  = 3; /* (root) */
 
4586
  path_revs[2].rev  = 3; /* A */
 
4587
  path_revs[11].rev = 3; /* D */
 
4588
  path_revs[17].rev = 3; /* H */
 
4589
  path_revs[20].rev = 3; /* omega */
 
4590
  SVN_ERR (verify_path_revs (rev_root, path_revs, 20, subpool));
 
4591
 
 
4592
  /* Destroy the per-commit subpool. */
 
4593
  svn_pool_destroy (subpool);
 
4594
 
 
4595
  return SVN_NO_ERROR;
 
4596
}
 
4597
 
 
4598
 
 
4599
static svn_error_t *
 
4600
check_related (const char **msg,
 
4601
               svn_boolean_t msg_only,
 
4602
               svn_test_opts_t *opts,
 
4603
               apr_pool_t *pool)
 
4604
 
4605
  apr_pool_t *subpool = svn_pool_create (pool);
 
4606
  svn_fs_t *fs;
 
4607
  svn_fs_txn_t *txn;
 
4608
  svn_fs_root_t *txn_root, *rev_root;
 
4609
  svn_revnum_t youngest_rev = 0;
 
4610
  
 
4611
  *msg = "test svn_fs_check_related";
 
4612
 
 
4613
  if (msg_only)
 
4614
    return SVN_NO_ERROR;
 
4615
 
 
4616
  /* Create a filesystem and repository. */
 
4617
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-related",
 
4618
                                "bdb", pool));
 
4619
 
 
4620
  /*** Step I: Build up some state in our repository through a series
 
4621
       of commits */
 
4622
 
 
4623
  /* Using files because bubble-up complicates the testing.  However,
 
4624
     the algorithm itself is ambivalent about what type of node is
 
4625
     being examined.
 
4626
 
 
4627
     - New files show up in this order (through time): A,B,C,D,E,F
 
4628
     - Number following filename is the revision.
 
4629
     - Vertical motion shows revision history
 
4630
     - Horizontal motion show copy history.
 
4631
 
 
4632
     A1---------C4         E7
 
4633
     |          |          |
 
4634
     A2         C5         E8---F9
 
4635
     |          |               |
 
4636
     A3---B4    C6              F10
 
4637
     |    |
 
4638
     A4   B5----------D6
 
4639
          |           |
 
4640
          B6          D7
 
4641
  */
 
4642
  /* Revision 1 */
 
4643
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4644
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4645
  SVN_ERR (svn_fs_make_file (txn_root, "A", subpool));
 
4646
  SVN_ERR (svn_test__set_file_contents (txn_root, "A", "1", subpool));
 
4647
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4648
  svn_pool_clear (subpool);
 
4649
  /* Revision 2 */
 
4650
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4651
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4652
  SVN_ERR (svn_test__set_file_contents (txn_root, "A", "2", subpool));
 
4653
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4654
  svn_pool_clear (subpool);
 
4655
  /* Revision 3 */
 
4656
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4657
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4658
  SVN_ERR (svn_test__set_file_contents (txn_root, "A", "3", subpool));
 
4659
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4660
  svn_pool_clear (subpool);
 
4661
  /* Revision 4 */
 
4662
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4663
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4664
  SVN_ERR (svn_test__set_file_contents (txn_root, "A", "4", subpool));
 
4665
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, 3, subpool));
 
4666
  SVN_ERR (svn_fs_copy (rev_root, "A", txn_root, "B", subpool));
 
4667
  SVN_ERR (svn_test__set_file_contents (txn_root, "B", "4", subpool));
 
4668
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, 1, subpool));
 
4669
  SVN_ERR (svn_fs_copy (rev_root, "A", txn_root, "C", subpool));
 
4670
  SVN_ERR (svn_test__set_file_contents (txn_root, "C", "4", subpool));
 
4671
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4672
  svn_pool_clear (subpool);
 
4673
  /* Revision 5 */
 
4674
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4675
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4676
  SVN_ERR (svn_test__set_file_contents (txn_root, "B", "5", subpool));
 
4677
  SVN_ERR (svn_test__set_file_contents (txn_root, "C", "5", subpool));
 
4678
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4679
  svn_pool_clear (subpool);
 
4680
  /* Revision 6 */
 
4681
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4682
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4683
  SVN_ERR (svn_test__set_file_contents (txn_root, "B", "6", subpool));
 
4684
  SVN_ERR (svn_test__set_file_contents (txn_root, "C", "6", subpool));
 
4685
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, 5, subpool));
 
4686
  SVN_ERR (svn_fs_copy (rev_root, "B", txn_root, "D", subpool));
 
4687
  SVN_ERR (svn_test__set_file_contents (txn_root, "D", "5", subpool));
 
4688
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4689
  svn_pool_clear (subpool);
 
4690
  /* Revision 7 */
 
4691
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4692
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4693
  SVN_ERR (svn_test__set_file_contents (txn_root, "D", "7", subpool));
 
4694
  SVN_ERR (svn_fs_make_file (txn_root, "E", subpool));
 
4695
  SVN_ERR (svn_test__set_file_contents (txn_root, "E", "7", subpool));
 
4696
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4697
  svn_pool_clear (subpool);
 
4698
  /* Revision 8 */
 
4699
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4700
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4701
  SVN_ERR (svn_test__set_file_contents (txn_root, "E", "8", subpool));
 
4702
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4703
  svn_pool_clear (subpool);
 
4704
  /* Revision 9 */
 
4705
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4706
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4707
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, 8, subpool));
 
4708
  SVN_ERR (svn_fs_copy (rev_root, "E", txn_root, "F", subpool));
 
4709
  SVN_ERR (svn_test__set_file_contents (txn_root, "F", "9", subpool));
 
4710
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4711
  svn_pool_clear (subpool);
 
4712
  /* Revision 10 */
 
4713
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
4714
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
4715
  SVN_ERR (svn_test__set_file_contents (txn_root, "F", "10", subpool));
 
4716
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
4717
  svn_pool_clear (subpool);
 
4718
  
 
4719
  /*** Step II: Exhaustively verify relationship between all nodes in
 
4720
       existence. */
 
4721
  {
 
4722
    int i, j;
 
4723
    
 
4724
    struct path_rev_t
 
4725
    {
 
4726
      const char *path;
 
4727
      svn_revnum_t rev;
 
4728
    };
 
4729
 
 
4730
    /* Our 16 existing files/revisions. */
 
4731
    struct path_rev_t path_revs[16] = {
 
4732
      { "A", 1 }, { "A", 2 }, { "A", 3 }, { "A", 4 },
 
4733
      { "B", 4 }, { "B", 5 }, { "B", 6 }, { "C", 4 },
 
4734
      { "C", 5 }, { "C", 6 }, { "D", 6 }, { "D", 7 },
 
4735
      { "E", 7 }, { "E", 8 }, { "F", 9 }, { "F", 10 }
 
4736
    };
 
4737
 
 
4738
    int related_matrix[16][16] = {
 
4739
      /* A1 ... F10 across the top here*/
 
4740
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* A1 */
 
4741
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* A2 */
 
4742
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* A3 */
 
4743
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* A4 */
 
4744
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* B4 */
 
4745
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* B5 */
 
4746
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* B6 */
 
4747
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* C4 */
 
4748
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* C5 */
 
4749
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* C6 */
 
4750
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* D6 */
 
4751
      { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, /* D7 */
 
4752
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, /* E7 */
 
4753
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, /* E8 */
 
4754
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, /* F9 */
 
4755
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }  /* F10 */
 
4756
    };
 
4757
 
 
4758
    /* Here's the fun part.  Running the tests. */
 
4759
    for (i = 0; i < 16; i++)
 
4760
      {
 
4761
        for (j = 0; j < 16; j++)
 
4762
          {
 
4763
            struct path_rev_t pr1 = path_revs[i];
 
4764
            struct path_rev_t pr2 = path_revs[j];
 
4765
            const svn_fs_id_t *id1, *id2;
 
4766
            int related = 0;
 
4767
 
 
4768
            /* Get the ID for the first path/revision combination. */
 
4769
            SVN_ERR (svn_fs_revision_root (&rev_root, fs, pr1.rev, pool));
 
4770
            SVN_ERR (svn_fs_node_id (&id1, rev_root, pr1.path, pool));
 
4771
          
 
4772
            /* Get the ID for the second path/revision combination. */
 
4773
            SVN_ERR (svn_fs_revision_root (&rev_root, fs, pr2.rev, pool));
 
4774
            SVN_ERR (svn_fs_node_id (&id2, rev_root, pr2.path, pool));
 
4775
            
 
4776
            /* <exciting> Now, run the relationship check! </exciting> */
 
4777
            related = svn_fs_check_related (id1, id2) ? 1 : 0;
 
4778
            if (related == related_matrix[i][j])
 
4779
              {
 
4780
                /* xlnt! */
 
4781
              }
 
4782
            else if (related && (! related_matrix[i][j]))
 
4783
              {
 
4784
                return svn_error_createf
 
4785
                  (SVN_ERR_TEST_FAILED, NULL,
 
4786
                   "expected '%s:%d' to be related to '%s:%d'; it was not",
 
4787
                   pr1.path, (int)pr1.rev, pr2.path, (int)pr2.rev);
 
4788
              }
 
4789
            else if ((! related) && related_matrix[i][j])
 
4790
              {
 
4791
                return svn_error_createf
 
4792
                  (SVN_ERR_TEST_FAILED, NULL,
 
4793
                   "expected '%s:%d' to not be related to '%s:%d'; it was",
 
4794
                   pr1.path, (int)pr1.rev, pr2.path, (int)pr2.rev);
 
4795
              }
 
4796
 
 
4797
            svn_pool_clear (subpool);
 
4798
          } /* for ... */
 
4799
      } /* for ... */
 
4800
  }
 
4801
 
 
4802
  /* Destroy the subpool. */
 
4803
  svn_pool_destroy (subpool);
 
4804
 
 
4805
  return SVN_NO_ERROR;
 
4806
}
 
4807
 
 
4808
 
 
4809
static svn_error_t *
 
4810
canonicalize_abspath (const char **msg,
 
4811
                      svn_boolean_t msg_only,
 
4812
                      svn_test_opts_t *opts,
 
4813
                      apr_pool_t *pool)
 
4814
 
4815
  apr_size_t i;
 
4816
  const char *paths[21][2] = 
 
4817
    /* in                      out */
 
4818
  { { NULL,                    NULL },
 
4819
    { "",                      "/" },
 
4820
    { "/",                     "/" },
 
4821
    { "//",                    "/" },
 
4822
    { "///",                   "/" },
 
4823
    { "foo",                   "/foo" },
 
4824
    { "foo/",                  "/foo" },
 
4825
    { "foo//",                 "/foo" },
 
4826
    { "/foo",                  "/foo" },
 
4827
    { "/foo/",                 "/foo" },
 
4828
    { "/foo//",                "/foo" },
 
4829
    { "//foo//",               "/foo" },
 
4830
    { "foo/bar",               "/foo/bar" },
 
4831
    { "foo/bar/",              "/foo/bar" },
 
4832
    { "foo/bar//",             "/foo/bar" },
 
4833
    { "foo//bar",              "/foo/bar" },
 
4834
    { "foo//bar/",             "/foo/bar" },
 
4835
    { "foo//bar//",            "/foo/bar" },
 
4836
    { "/foo//bar//",           "/foo/bar" },
 
4837
    { "//foo//bar//",          "/foo/bar" },
 
4838
    { "///foo///bar///baz///", "/foo/bar/baz" },
 
4839
  };
 
4840
 
 
4841
  *msg = "test svn_fs_base__canonicalize_abspath";
 
4842
 
 
4843
  if (msg_only)
 
4844
    return SVN_NO_ERROR;
 
4845
 
 
4846
  for (i = 0; i < (sizeof (paths) / 2 / sizeof (const char *)); i++)
 
4847
    {
 
4848
      const char *input = paths[i][0];
 
4849
      const char *output = paths[i][1];
 
4850
      const char *actual = svn_fs_base__canonicalize_abspath (input, pool);
 
4851
      
 
4852
      if ((! output) && (! actual))
 
4853
        continue;
 
4854
      if ((! output) && actual)
 
4855
        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
 
4856
                                  "expected NULL path; got '%s'", actual);
 
4857
      if (output && (! actual))
 
4858
        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
 
4859
                                  "expected '%s' path; got NULL", output);
 
4860
      if (strcmp (output, actual))
 
4861
        return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
 
4862
                                  "expected '%s' path; got '%s'",
 
4863
                                  output, actual);
 
4864
    }
 
4865
  return SVN_NO_ERROR;
 
4866
}
 
4867
 
 
4868
 
 
4869
static svn_error_t *
 
4870
branch_test (const char **msg,
 
4871
             svn_boolean_t msg_only,
 
4872
             svn_test_opts_t *opts,
 
4873
             apr_pool_t *pool)
 
4874
 
4875
  apr_pool_t *spool = svn_pool_create (pool);
 
4876
  svn_fs_t *fs;
 
4877
  svn_fs_txn_t *txn;
 
4878
  svn_fs_root_t *txn_root, *rev_root;
 
4879
  svn_revnum_t youngest_rev = 0;
 
4880
  
 
4881
  *msg = "test complex copies (branches)";
 
4882
 
 
4883
  if (msg_only)
 
4884
    return SVN_NO_ERROR;
 
4885
 
 
4886
  /* Create a filesystem and repository. */
 
4887
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-branch-test",
 
4888
                                "bdb", pool));
 
4889
 
 
4890
  /*** Revision 1:  Create the greek tree in revision.  ***/
 
4891
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
4892
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
4893
  SVN_ERR (svn_test__create_greek_tree (txn_root, spool));
 
4894
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
4895
  svn_pool_clear (spool);
 
4896
  
 
4897
  /*** Revision 2:  Copy A/D/G/rho to A/D/G/rho2.  ***/
 
4898
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
4899
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
4900
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
4901
  SVN_ERR (svn_fs_copy (rev_root, "A/D/G/rho", txn_root, "A/D/G/rho2", spool));
 
4902
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
4903
  svn_pool_clear (spool);
 
4904
 
 
4905
  /*** Revision 3:  Copy A/D/G to A/D/G2.  ***/
 
4906
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
4907
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
4908
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
4909
  SVN_ERR (svn_fs_copy (rev_root, "A/D/G", txn_root, "A/D/G2", spool));
 
4910
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
4911
  svn_pool_clear (spool);
 
4912
 
 
4913
  /*** Revision 4:  Copy A/D to A/D2.  ***/
 
4914
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
4915
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
4916
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
4917
  SVN_ERR (svn_fs_copy (rev_root, "A/D", txn_root, "A/D2", spool));
 
4918
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
4919
  svn_pool_clear (spool);
 
4920
 
 
4921
  /*** Revision 5:  Edit all the rho's! ***/
 
4922
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
4923
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
4924
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
4925
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D/G/rho", 
 
4926
                                        "Edited text.", spool));
 
4927
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D/G/rho2", 
 
4928
                                        "Edited text.", spool));
 
4929
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D/G2/rho", 
 
4930
                                        "Edited text.", spool));
 
4931
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D/G2/rho2", 
 
4932
                                        "Edited text.", spool));
 
4933
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D2/G/rho", 
 
4934
                                        "Edited text.", spool));
 
4935
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D2/G/rho2", 
 
4936
                                        "Edited text.", spool));
 
4937
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D2/G2/rho", 
 
4938
                                        "Edited text.", spool));
 
4939
  SVN_ERR (svn_test__set_file_contents (txn_root, "A/D2/G2/rho2", 
 
4940
                                        "Edited text.", spool));
 
4941
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
4942
 
 
4943
  svn_pool_destroy (spool);
 
4944
 
 
4945
  return SVN_NO_ERROR;
 
4946
}
 
4947
 
 
4948
 
 
4949
static svn_error_t *
 
4950
verify_checksum (const char **msg,
 
4951
                 svn_boolean_t msg_only,
 
4952
                 svn_test_opts_t *opts,
 
4953
                 apr_pool_t *pool)
 
4954
 
4955
  svn_fs_t *fs;
 
4956
  svn_fs_txn_t *txn;
 
4957
  svn_fs_root_t *txn_root;
 
4958
  svn_stringbuf_t *str;
 
4959
  unsigned char expected_digest[APR_MD5_DIGESTSIZE];
 
4960
  unsigned char actual_digest[APR_MD5_DIGESTSIZE];
 
4961
 
 
4962
  /* Write a file, compare the repository's idea of its checksum
 
4963
     against our idea of its checksum.  They should be the same. */
 
4964
 
 
4965
  *msg = "test checksums";
 
4966
 
 
4967
  if (msg_only)
 
4968
    return SVN_NO_ERROR;
 
4969
 
 
4970
  str = svn_stringbuf_create ("My text editor charges me rent.", pool);
 
4971
  apr_md5 (expected_digest, str->data, str->len);
 
4972
 
 
4973
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-verify-checksum",
 
4974
                                "bdb", pool));
 
4975
  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
 
4976
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
4977
  SVN_ERR (svn_fs_make_file (txn_root, "fact", pool));
 
4978
  SVN_ERR (svn_test__set_file_contents (txn_root, "fact", str->data, pool));
 
4979
  SVN_ERR (svn_fs_file_md5_checksum (actual_digest, txn_root, "fact", pool));
 
4980
 
 
4981
  if (memcmp (expected_digest, actual_digest, APR_MD5_DIGESTSIZE) != 0)
 
4982
    return svn_error_createf
 
4983
      (SVN_ERR_FS_GENERAL, NULL,
 
4984
       "verify-checksum: checksum mismatch:\n"
 
4985
       "   expected:  %s\n"
 
4986
       "     actual:  %s\n", 
 
4987
       svn_md5_digest_to_cstring (expected_digest, pool),
 
4988
       svn_md5_digest_to_cstring (actual_digest, pool));
 
4989
 
 
4990
  return SVN_NO_ERROR;
 
4991
}
 
4992
 
 
4993
static svn_error_t *
 
4994
create_within_copy (const char **msg,
 
4995
                    svn_boolean_t msg_only,
 
4996
                    svn_test_opts_t *opts,
 
4997
                    apr_pool_t *pool)
 
4998
 
4999
  apr_pool_t *spool = svn_pool_create (pool);
 
5000
  svn_fs_t *fs;
 
5001
  svn_fs_txn_t *txn;
 
5002
  svn_fs_root_t *txn_root, *rev_root;
 
5003
  svn_revnum_t youngest_rev = 0;
 
5004
  
 
5005
  *msg = "create new items within a copied directory";
 
5006
 
 
5007
  if (msg_only)
 
5008
    return SVN_NO_ERROR;
 
5009
 
 
5010
  /* Create a filesystem and repository. */
 
5011
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-within-copy",
 
5012
                                "bdb", pool));
 
5013
 
 
5014
  /*** Revision 1:  Create the greek tree in revision.  ***/
 
5015
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
5016
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
5017
  SVN_ERR (svn_test__create_greek_tree (txn_root, spool));
 
5018
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
5019
  svn_pool_clear (spool);
 
5020
 
 
5021
  /*** Revision 2:  Copy A/D to A/D3 ***/
 
5022
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
5023
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
5024
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
5025
  SVN_ERR (svn_fs_copy (rev_root, "A/D", txn_root, "A/D3", spool));
 
5026
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
5027
  svn_pool_clear (spool);
 
5028
 
 
5029
  /*** Revision 3:  Copy A/D/G to A/D/G2 ***/
 
5030
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
5031
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
5032
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
5033
  SVN_ERR (svn_fs_copy (rev_root, "A/D/G", txn_root, "A/D/G2", spool));
 
5034
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
5035
  svn_pool_clear (spool);
 
5036
 
 
5037
  /*** Revision 4: Copy A/D to A/D2 and create up and I in the existing
 
5038
   A/D/G2, in the new A/D2, and in the nested, new A/D2/G2 ***/
 
5039
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
5040
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
5041
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
5042
  SVN_ERR (svn_fs_copy (rev_root, "A/D", txn_root, "A/D2", spool));
 
5043
  SVN_ERR (svn_fs_make_dir (txn_root, "A/D/G2/I", spool));
 
5044
  SVN_ERR (svn_fs_make_file (txn_root, "A/D/G2/up", spool));
 
5045
  SVN_ERR (svn_fs_make_dir (txn_root, "A/D2/I", spool));
 
5046
  SVN_ERR (svn_fs_make_file (txn_root, "A/D2/up", spool));
 
5047
  SVN_ERR (svn_fs_make_dir (txn_root, "A/D2/G2/I", spool));
 
5048
  SVN_ERR (svn_fs_make_file (txn_root, "A/D2/G2/up", spool));
 
5049
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
5050
  svn_pool_clear (spool);
 
5051
 
 
5052
  /*** Revision 5:  Create A/D3/down and A/D3/J ***/
 
5053
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, spool));
 
5054
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, spool));
 
5055
  SVN_ERR (svn_fs_make_file (txn_root, "A/D3/down", spool));
 
5056
  SVN_ERR (svn_fs_make_dir (txn_root, "A/D3/J", spool));
 
5057
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, spool));
 
5058
  svn_pool_clear (spool);
 
5059
 
 
5060
  {
 
5061
    /* New items should have same CopyID as their parent */
 
5062
    struct {
 
5063
      const char *path;
 
5064
      const char *unparsed_id;
 
5065
    } new_nodes[] = {
 
5066
      { "A/D/G2",     "d.2.4" },
 
5067
      { "A/D/G2/I",   "l.2.4" },
 
5068
      { "A/D/G2/up",  "m.2.4" },
 
5069
      { "A/D2",       "b.3.4" },
 
5070
      { "A/D2/I",     "n.3.4" },
 
5071
      { "A/D2/up",    "o.3.4" },
 
5072
      { "A/D2/G2",    "d.4.4" },
 
5073
      { "A/D2/G2/I",  "p.4.4" },
 
5074
      { "A/D2/G2/up", "q.4.4" },
 
5075
      { "A/D3",       "b.1.5" },
 
5076
      { "A/D3/down",  "r.1.5" },
 
5077
      { "A/D3/J",     "s.1.5" },
 
5078
      { NULL, NULL }
 
5079
    }, *node = new_nodes; 
 
5080
 
 
5081
    SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
 
5082
    while (node->path)
 
5083
      {
 
5084
        const svn_fs_id_t *id;
 
5085
        svn_string_t *s;
 
5086
        SVN_ERR (svn_fs_node_id (&id, rev_root, node->path, spool));
 
5087
        s = svn_fs_unparse_id (id, spool);
 
5088
        if (strcmp (s->data, node->unparsed_id) != 0)
 
5089
          return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
 
5090
                                    "'%s' id: expected '%s'; got '%s'",
 
5091
                                    node->path, node->unparsed_id, s->data);
 
5092
        ++node;
 
5093
      }
 
5094
    svn_pool_clear (spool);
 
5095
  }
 
5096
 
 
5097
  svn_pool_destroy (spool);
 
5098
  return SVN_NO_ERROR;
 
5099
}
 
5100
 
 
5101
 
 
5102
/* Test the skip delta support by commiting so many changes to a file
 
5103
 * that some of its older revisions become reachable by skip deltas,
 
5104
 * then try retrieving those revisions.
 
5105
 */
 
5106
static svn_error_t *
 
5107
skip_deltas (const char **msg,
 
5108
             svn_boolean_t msg_only,
 
5109
             svn_test_opts_t *opts,
 
5110
             apr_pool_t *pool)
 
5111
 
5112
  svn_fs_t *fs;
 
5113
  svn_fs_txn_t *txn;
 
5114
  svn_fs_root_t *txn_root, *rev_root;
 
5115
  apr_pool_t *subpool = svn_pool_create (pool);
 
5116
  svn_revnum_t youngest_rev = 0;
 
5117
  const char *one_line = "This is a line in file 'f'.\n";
 
5118
  svn_stringbuf_t *f = svn_stringbuf_create (one_line, pool); 
 
5119
 
 
5120
  *msg = "test skip deltas";
 
5121
 
 
5122
  if (msg_only)
 
5123
    return SVN_NO_ERROR;
 
5124
 
 
5125
  /* Create a filesystem and repository. */
 
5126
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-skip-deltas",
 
5127
                                "bdb", pool));
 
5128
 
 
5129
  /* Create the file. */
 
5130
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
5131
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
5132
  SVN_ERR (svn_fs_make_file (txn_root, "f", subpool));
 
5133
  SVN_ERR (svn_test__set_file_contents (txn_root, "f", f->data, subpool));
 
5134
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
5135
  SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
5136
  svn_pool_clear (subpool);
 
5137
 
 
5138
  /* Now, commit changes to the file 128 times. */
 
5139
  while (youngest_rev <= 128)
 
5140
    {
 
5141
      /* Append another line to the ever-growing file contents. */
 
5142
      svn_stringbuf_appendcstr (f, one_line); 
 
5143
 
 
5144
      /* Commit the new contents. */
 
5145
      SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
 
5146
      SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
 
5147
      SVN_ERR (svn_test__set_file_contents (txn_root, "f", f->data, subpool));
 
5148
      SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
 
5149
      SVN_ERR (svn_fs_deltify_revision (fs, youngest_rev, subpool));
 
5150
      svn_pool_clear (subpool);
 
5151
    }
 
5152
 
 
5153
  /* Now go back and check revision 1. */
 
5154
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, 1, pool));
 
5155
  SVN_ERR (svn_test__get_file_contents (rev_root, "f", &f, pool));
 
5156
  if (strcmp (one_line, f->data) != 0)
 
5157
    return svn_error_createf
 
5158
      (SVN_ERR_TEST_FAILED, NULL, 
 
5159
       "Wrong contents.  Expected:\n   '%s'\nGot:\n   '%s'\n", 
 
5160
       one_line, f->data);
 
5161
 
 
5162
  svn_pool_destroy (subpool);
 
5163
  return SVN_NO_ERROR;
 
5164
}
 
5165
 
 
5166
 
 
5167
/* Trail-ish helpers for redundant_copy(). */
 
5168
struct get_txn_args
 
5169
{
 
5170
  transaction_t **txn;
 
5171
  const char *txn_name;
 
5172
  svn_fs_t *fs;
 
5173
};
 
5174
 
 
5175
static svn_error_t *
 
5176
txn_body_get_txn (void *baton, trail_t *trail)
 
5177
{
 
5178
  struct get_txn_args *args = baton;
 
5179
  return svn_fs_bdb__get_txn (args->txn, args->fs, args->txn_name, 
 
5180
                              trail, trail->pool);
 
5181
}
 
5182
 
 
5183
 
 
5184
static svn_error_t *
 
5185
redundant_copy (const char **msg,
 
5186
                svn_boolean_t msg_only,
 
5187
                svn_test_opts_t *opts,
 
5188
                apr_pool_t *pool)
 
5189
 
5190
  svn_fs_t *fs;
 
5191
  svn_fs_txn_t *txn;
 
5192
  const char *txn_name;
 
5193
  transaction_t *transaction;
 
5194
  svn_fs_root_t *txn_root, *rev_root;
 
5195
  const svn_fs_id_t *old_D_id, *new_D_id;
 
5196
  svn_revnum_t youngest_rev = 0;
 
5197
  struct get_txn_args args;
 
5198
  
 
5199
  *msg = "ensure no-op for redundant copies";
 
5200
 
 
5201
  if (msg_only)
 
5202
    return SVN_NO_ERROR;
 
5203
 
 
5204
  /* Create a filesystem and repository. */
 
5205
  SVN_ERR (svn_test__create_fs (&fs, "test-repo-redundant-copy",
 
5206
                                "bdb", pool));
 
5207
 
 
5208
  /* Create the greek tree in revision 1. */
 
5209
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, pool));
 
5210
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
5211
  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
 
5212
  SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, pool));
 
5213
 
 
5214
  /* In a transaction, copy A to Z. */
 
5215
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, pool));
 
5216
  SVN_ERR (svn_fs_txn_name (&txn_name, txn, pool));
 
5217
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
 
5218
  SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, pool));
 
5219
  SVN_ERR (svn_fs_copy (rev_root, "A", txn_root, "Z", pool));
 
5220
 
 
5221
  /* Now, examine the transaction.  There should have been only one
 
5222
     copy there. */
 
5223
  args.fs = fs;
 
5224
  args.txn_name = txn_name;
 
5225
  args.txn = &transaction;
 
5226
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_get_txn, &args, pool));
 
5227
  if (transaction->copies->nelts != 1)
 
5228
    return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
 
5229
                              "Expected 1 copy; got %d",
 
5230
                              transaction->copies->nelts);
 
5231
 
 
5232
  /* Get the node-rev-id for A/D (the reason will be clear a little later). */
 
5233
  SVN_ERR (svn_fs_node_id (&old_D_id, txn_root, "A/D", pool));
 
5234
 
 
5235
  /* Now copy A/D/G Z/D/G. */
 
5236
  SVN_ERR (svn_fs_copy (rev_root, "A/D/G", txn_root, "Z/D/G", pool));
 
5237
 
 
5238
  /* Now, examine the transaction.  There should still only have been
 
5239
     one copy operation that "took". */
 
5240
  SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_get_txn, &args, pool));
 
5241
  if (transaction->copies->nelts != 1)
 
5242
    return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
 
5243
                              "Expected only 1 copy; got %d",
 
5244
                              transaction->copies->nelts);
 
5245
 
 
5246
  /* Finally, check the node-rev-id for "Z/D" -- it should never have
 
5247
     been made mutable (since the second copy should not have taken
 
5248
     place). */
 
5249
  SVN_ERR (svn_fs_node_id (&new_D_id, txn_root, "A/D", pool));
 
5250
  if (! svn_string_compare (svn_fs_unparse_id (old_D_id, pool),
 
5251
                            svn_fs_unparse_id (new_D_id, pool)))
 
5252
    return svn_error_create 
 
5253
      (SVN_ERR_TEST_FAILED, NULL,
 
5254
       "Expected equivalent node-rev-ids; got differing ones");
 
5255
 
 
5256
  return SVN_NO_ERROR;
 
5257
}
 
5258
 
 
5259
 
 
5260
/* ------------------------------------------------------------------------ */
 
5261
 
 
5262
/* The test table.  */
 
5263
 
 
5264
struct svn_test_descriptor_t test_funcs[] =
 
5265
  {
 
5266
    SVN_TEST_NULL,
 
5267
    SVN_TEST_PASS (create_berkeley_filesystem),
 
5268
    SVN_TEST_PASS (open_berkeley_filesystem),
 
5269
    SVN_TEST_PASS (trivial_transaction),
 
5270
    SVN_TEST_PASS (reopen_trivial_transaction),
 
5271
    SVN_TEST_PASS (create_file_transaction),
 
5272
    SVN_TEST_PASS (verify_txn_list),
 
5273
    SVN_TEST_PASS (write_and_read_file),
 
5274
    SVN_TEST_PASS (create_mini_tree_transaction),
 
5275
    SVN_TEST_PASS (create_greek_tree_transaction),
 
5276
    SVN_TEST_PASS (list_directory),
 
5277
    SVN_TEST_PASS (revision_props),
 
5278
    SVN_TEST_PASS (transaction_props),
 
5279
    SVN_TEST_PASS (node_props),
 
5280
    SVN_TEST_PASS (delete_mutables),
 
5281
    SVN_TEST_PASS (delete),
 
5282
    SVN_TEST_PASS (abort_txn),
 
5283
    SVN_TEST_PASS (test_tree_node_validation),
 
5284
    SVN_TEST_PASS (fetch_youngest_rev),
 
5285
    SVN_TEST_PASS (basic_commit),
 
5286
    SVN_TEST_PASS (copy_test),
 
5287
    SVN_TEST_PASS (create_within_copy),
 
5288
    SVN_TEST_XFAIL (link_test),
 
5289
    SVN_TEST_PASS (merging_commit),
 
5290
    SVN_TEST_PASS (commit_date),
 
5291
    SVN_TEST_PASS (check_old_revisions),
 
5292
    SVN_TEST_PASS (check_all_revisions),
 
5293
    SVN_TEST_PASS (medium_file_integrity),
 
5294
    SVN_TEST_PASS (large_file_integrity),
 
5295
    SVN_TEST_PASS (check_root_revision),
 
5296
    SVN_TEST_PASS (test_node_created_rev),
 
5297
    SVN_TEST_PASS (check_related),
 
5298
    SVN_TEST_PASS (canonicalize_abspath),
 
5299
    SVN_TEST_PASS (branch_test),
 
5300
    SVN_TEST_PASS (verify_checksum),
 
5301
    SVN_TEST_PASS (skip_deltas),
 
5302
    SVN_TEST_PASS (redundant_copy),
 
5303
    SVN_TEST_NULL
 
5304
  };