1
/* fs-test.c --- tests for the filesystem
3
* ====================================================================
4
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
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.
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
* ====================================================================
20
#include <apr_pools.h>
22
#include "svn_pools.h"
24
#include "svn_string.h"
29
#include "../fs-helpers.h"
31
#include "../../libsvn_fs_base/trail.h"
33
#include "../../libsvn_fs_base/bdb/txn-table.h"
34
#include "../../libsvn_fs_base/bdb/nodes-table.h"
36
#include "../../libsvn_delta/delta.h"
38
#define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))
41
/*-----------------------------------------------------------------*/
43
/** The actual fs-tests called by `make check` **/
45
/* Create a filesystem. */
47
create_berkeley_filesystem (const char **msg,
48
svn_boolean_t msg_only,
49
svn_test_opts_t *opts,
54
*msg = "svn_fs_create_berkeley";
59
/* Create and close a repository. */
60
SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-berkeley",
67
/* Generic Berkeley DB error handler function. */
69
berkeley_error_handler (const char *errpfx, char *msg)
71
fprintf (stderr, "%s%s\n", errpfx ? errpfx : "", msg);
75
/* Helper: commit TXN, expecting either success or failure:
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;
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.
87
* If a conflict is expected but the commit succeeds anyway, return
91
test_commit_txn (svn_revnum_t *new_rev,
93
const char *expected_conflict,
99
err = svn_fs_commit_txn (&conflict, new_rev, txn, pool);
101
if (err && (err->apr_err == SVN_ERR_FS_CONFLICT))
103
svn_error_clear (err);
104
if (! expected_conflict)
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!)");
111
else if (conflict == NULL)
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)",
119
else if ((strcmp (expected_conflict, "") != 0)
120
&& (strcmp (conflict, expected_conflict) != 0))
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);
128
else if (err) /* commit failed, but not due to conflict */
130
return svn_error_quick_wrap
131
(err, "commit failed due to something other than a conflict");
133
else /* err == NULL, so commit succeeded */
135
if (expected_conflict)
137
return svn_error_createf
138
(SVN_ERR_FS_GENERAL, NULL,
139
"commit succeeded that was expected to fail at '%s'",
149
/* Open an existing filesystem. */
151
open_berkeley_filesystem (const char **msg,
152
svn_boolean_t msg_only,
153
svn_test_opts_t *opts,
158
*msg = "open an existing Berkeley DB filesystem";
163
/* Create and close a repository (using fs). */
164
SVN_ERR (svn_test__create_fs (&fs, "test-repo-open-berkeley",
167
/* Create a different fs object, and use it to re-open the
169
SVN_ERR (svn_test__fs_new (&fs2, pool));
170
SVN_ERR (svn_fs_open_berkeley (fs2, "test-repo-open-berkeley"));
172
/* Provide a handler for Berkeley DB error messages. */
173
SVN_ERR (svn_fs_set_berkeley_errcall (fs2, berkeley_error_handler));
179
/* Begin a txn, check its name, then close it */
181
trivial_transaction (const char **msg,
182
svn_boolean_t msg_only,
183
svn_test_opts_t *opts,
188
const char *txn_name;
190
*msg = "begin a txn, check its name, then close it";
195
SVN_ERR (svn_test__create_fs (&fs, "test-repo-trivial-txn",
198
/* Begin a new transaction that is based on revision 0. */
199
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
201
/* Test that the txn name is non-null. */
202
SVN_ERR (svn_fs_txn_name (&txn_name, txn, pool));
205
return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
206
"Got a NULL txn name.");
213
/* Open an existing transaction by name. */
215
reopen_trivial_transaction (const char **msg,
216
svn_boolean_t msg_only,
217
svn_test_opts_t *opts,
222
const char *txn_name;
223
apr_pool_t *subpool = svn_pool_create (pool);
225
*msg = "open an existing transaction by name";
230
SVN_ERR (svn_test__create_fs (&fs, "test-repo-reopen-trivial-txn",
233
/* Begin a new transaction that is based on revision 0. */
234
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
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));
239
/* Close the transaction. */
240
svn_pool_clear (subpool);
242
/* Reopen the transaction by name */
243
SVN_ERR (svn_fs_open_txn (&txn, fs, txn_name, subpool));
245
/* Close the transaction ... again. */
246
svn_pool_destroy (subpool);
255
create_file_transaction (const char **msg,
256
svn_boolean_t msg_only,
257
svn_test_opts_t *opts,
262
svn_fs_root_t *txn_root;
264
*msg = "begin a txn, get the txn root, and add a file";
269
SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-file-txn",
272
/* Begin a new transaction that is based on revision 0. */
273
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
275
/* Get the txn root */
276
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
278
/* Create a new file in the root directory. */
279
SVN_ERR (svn_fs_make_file (txn_root, "beer.txt", pool));
285
/* Make sure we get txn lists correctly. */
287
verify_txn_list (const char **msg,
288
svn_boolean_t msg_only,
289
svn_test_opts_t *opts,
294
svn_fs_txn_t *txn1, *txn2;
295
const char *name1, *name2;
296
apr_array_header_t *txn_list;
298
*msg = "create 2 txns, list them, and verify the list";
303
SVN_ERR (svn_test__create_fs (&fs, "test-repo-verify-txn-list",
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);
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);
318
/* Get the list of active transactions from the fs. */
319
SVN_ERR (svn_fs_list_transactions (&txn_list, fs, pool));
321
/* Check the list. It should have *exactly* two entries. */
322
if (txn_list->nelts != 2)
325
/* We should be able to find our 2 txn names in the list, in some
327
if ((! strcmp (name1, APR_ARRAY_IDX (txn_list, 0, const char *)))
328
&& (! strcmp (name2, APR_ARRAY_IDX (txn_list, 1, const char *))))
331
else if ((! strcmp (name2, APR_ARRAY_IDX (txn_list, 0, const char *)))
332
&& (! strcmp (name1, APR_ARRAY_IDX (txn_list, 1, const char *))))
337
return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
338
"Got a bogus txn list.");
346
/* Test writing & reading a file's contents. */
348
write_and_read_file (const char **msg,
349
svn_boolean_t msg_only,
350
svn_test_opts_t *opts,
355
svn_fs_root_t *txn_root;
356
svn_stream_t *rstream;
357
svn_stringbuf_t *rstring;
358
svn_stringbuf_t *wstring;
360
*msg = "write and read a file's contents";
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",
368
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
369
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
371
/* Add an empty file. */
372
SVN_ERR (svn_fs_make_file (txn_root, "beer.txt", pool));
374
/* And write some data into this file. */
375
SVN_ERR (svn_test__set_file_contents (txn_root, "beer.txt",
376
wstring->data, pool));
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));
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.");
392
/* Create a file, a directory, and a file in that directory! */
394
create_mini_tree_transaction (const char **msg,
395
svn_boolean_t msg_only,
396
svn_test_opts_t *opts,
401
svn_fs_root_t *txn_root;
403
*msg = "test basic file and subdirectory creation";
408
SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-mini-tree-txn",
411
/* Begin a new transaction that is based on revision 0. */
412
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
414
/* Get the txn root */
415
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
417
/* Create a new file in the root directory. */
418
SVN_ERR (svn_fs_make_file (txn_root, "wine.txt", pool));
420
/* Create a new directory in the root directory. */
421
SVN_ERR (svn_fs_make_dir (txn_root, "keg", pool));
423
/* Now, create a file in our new directory. */
424
SVN_ERR (svn_fs_make_file (txn_root, "keg/beer.txt", pool));
430
/* Create a file, a directory, and a file in that directory! */
432
create_greek_tree_transaction (const char **msg,
433
svn_boolean_t msg_only,
434
svn_test_opts_t *opts,
439
svn_fs_root_t *txn_root;
441
*msg = "make The Official Subversion Test Tree";
446
/* Prepare a txn to receive the greek tree. */
447
SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-greek-tree-txn",
449
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
450
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
452
/* Create and verify the greek tree. */
453
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
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. */
462
verify_entry (apr_hash_t *entries, const char *key)
464
svn_fs_dirent_t *ent = apr_hash_get (entries, key,
465
APR_HASH_KEY_STRING);
468
return svn_error_createf
469
(SVN_ERR_FS_GENERAL, NULL,
470
"didn't find dir entry for \"%s\"", key);
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);
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);
483
return svn_error_createf
484
(SVN_ERR_FS_GENERAL, NULL,
485
"dir entry for \"%s\" has null id", key);
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);
497
list_directory (const char **msg,
498
svn_boolean_t msg_only,
499
svn_test_opts_t *opts,
504
svn_fs_root_t *txn_root;
507
*msg = "fill a directory, then list it";
512
SVN_ERR (svn_test__create_fs (&fs, "test-repo-list-dir",
514
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
515
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
517
/* We create this tree
527
* then list dir A. It should have 3 files: "x", "y", and "z", no
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));
542
/* Get A's entries. */
543
SVN_ERR (svn_fs_dir_entries (&entries, txn_root, "A", pool));
545
/* Make sure exactly the right set of entries is present. */
546
if (apr_hash_count (entries) != 3)
548
return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
549
"unexpected number of entries in dir");
553
SVN_ERR (verify_entry (entries, "x"));
554
SVN_ERR (verify_entry (entries, "y"));
555
SVN_ERR (verify_entry (entries, "z"));
563
revision_props (const char **msg,
564
svn_boolean_t msg_only,
565
svn_test_opts_t *opts,
569
apr_hash_t *proplist;
574
const char *initial_props[4][2] = {
577
{ "favorite saturday morning cartoon", "looney tunes" },
578
{ "auto", "Green 1997 Saturn SL1" }
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" }
588
*msg = "set and get some revision properties";
594
SVN_ERR (svn_test__create_fs (&fs, "test-repo-rev-props",
597
/* Set some properties on the revision. */
598
for (i = 0; i < 4; i++)
600
SET_STR (&s1, initial_props[i][1]);
601
SVN_ERR (svn_fs_change_rev_prop (fs, 0, initial_props[i][0], &s1, pool));
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));
608
SET_STR (&s1, "Red 2000 Chevrolet Blazer");
609
SVN_ERR (svn_fs_change_rev_prop (fs, 0, "auto", &s1, pool));
611
/* Remove a property altogether */
612
SVN_ERR (svn_fs_change_rev_prop (fs, 0, "size", NULL, pool));
614
/* Copy a property's value into a new property. */
615
SVN_ERR (svn_fs_revision_prop (&value, fs, 0, "color", pool));
617
s1.data = value->data;
619
SVN_ERR (svn_fs_change_rev_prop (fs, 0, "flower", &s1, pool));
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));
625
svn_string_t *prop_value;
627
if (apr_hash_count (proplist) < 4 )
628
return svn_error_createf
629
(SVN_ERR_FS_GENERAL, NULL,
630
"too few revision properties found");
632
/* Loop through our list of expected revision property name/value
634
for (i = 0; i < 4; i++)
636
/* For each expected property: */
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,
643
APR_HASH_KEY_STRING);
645
return svn_error_createf
646
(SVN_ERR_FS_GENERAL, NULL,
647
"unable to find expected revision property");
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");
663
transaction_props (const char **msg,
664
svn_boolean_t msg_only,
665
svn_test_opts_t *opts,
670
apr_hash_t *proplist;
672
svn_revnum_t after_rev;
676
const char *initial_props[4][2] = {
679
{ "favorite saturday morning cartoon", "looney tunes" },
680
{ "auto", "Green 1997 Saturn SL1" }
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>" }
691
*msg = "set/get txn props, commit, validate new rev props";
697
SVN_ERR (svn_test__create_fs (&fs, "test-repo-txn-props",
699
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
701
/* Set some properties on the revision. */
702
for (i = 0; i < 4; i++)
704
SET_STR (&s1, initial_props[i][1]);
705
SVN_ERR (svn_fs_change_txn_prop (txn, initial_props[i][0], &s1, pool));
708
/* Change some of the above properties. */
709
SET_STR (&s1, "violet");
710
SVN_ERR (svn_fs_change_txn_prop (txn, "color", &s1, pool));
712
SET_STR (&s1, "Red 2000 Chevrolet Blazer");
713
SVN_ERR (svn_fs_change_txn_prop (txn, "auto", &s1, pool));
715
/* Remove a property altogether */
716
SVN_ERR (svn_fs_change_txn_prop (txn, "size", NULL, pool));
718
/* Copy a property's value into a new property. */
719
SVN_ERR (svn_fs_txn_prop (&value, txn, "color", pool));
721
s1.data = value->data;
723
SVN_ERR (svn_fs_change_txn_prop (txn, "flower", &s1, pool));
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));
729
svn_string_t *prop_value;
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");
738
/* Loop through our list of expected revision property name/value
740
for (i = 0; i < 5; i++)
742
/* For each expected property: */
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,
749
APR_HASH_KEY_STRING);
751
return svn_error_createf
752
(SVN_ERR_FS_GENERAL, NULL,
753
"unable to find expected transaction property");
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");
765
/* Commit the transaction. */
766
SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
768
return svn_error_createf
769
(SVN_ERR_FS_GENERAL, NULL,
770
"committed transaction got wrong revision number");
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));
778
svn_string_t *prop_value;
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");
785
/* Loop through our list of expected revision property name/value
787
for (i = 0; i < 5; i++)
789
/* For each expected property: */
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,
796
APR_HASH_KEY_STRING);
798
return svn_error_createf
799
(SVN_ERR_FS_GENERAL, NULL,
800
"unable to find expected revision property");
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");
817
node_props (const char **msg,
818
svn_boolean_t msg_only,
819
svn_test_opts_t *opts,
824
svn_fs_root_t *txn_root;
825
apr_hash_t *proplist;
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" }
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" }
844
*msg = "set and get some node properties";
849
/* Open the fs and transaction */
850
SVN_ERR (svn_test__create_fs (&fs, "test-repo-node-props",
852
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
853
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
855
/* Make a node to put some properties into */
856
SVN_ERR (svn_fs_make_file (txn_root, "music.txt", pool));
858
/* Set some properties on the nodes. */
859
for (i = 0; i < 4; i++)
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));
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",
871
SET_STR (&s1, "Busta Rhymes");
872
SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt", "Best Rap Artist",
875
/* Remove a property altogether */
876
SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt",
877
"Best Country Artist", NULL, pool));
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));
883
s1.data = value->data;
885
SVN_ERR (svn_fs_change_node_prop (txn_root, "music.txt",
886
"Biggest Cakewalk Fanatic", &s1, pool));
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));
892
svn_string_t *prop_value;
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");
899
/* Loop through our list of expected node property name/value
901
for (i = 0; i < 4; i++)
903
/* For each expected property: */
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,
910
APR_HASH_KEY_STRING);
912
return svn_error_createf
913
(SVN_ERR_FS_GENERAL, NULL,
914
"unable to find expected node property");
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");
930
/* Set *PRESENT to true if entry NAME is present in directory PATH
931
under ROOT, else set *PRESENT to false. */
933
check_entry (svn_fs_root_t *root,
936
svn_boolean_t *present,
940
svn_fs_dirent_t *ent;
942
SVN_ERR (svn_fs_dir_entries (&entries, root, path, pool));
943
ent = apr_hash_get (entries, name, APR_HASH_KEY_STRING);
954
/* Return an error if entry NAME is absent in directory PATH under ROOT. */
956
check_entry_present (svn_fs_root_t *root, const char *path,
957
const char *name, apr_pool_t *pool)
959
svn_boolean_t present;
960
SVN_ERR (check_entry (root, path, name, &present, pool));
963
return svn_error_createf
964
(SVN_ERR_FS_GENERAL, NULL,
965
"entry \"%s\" absent when it should be present", name);
971
/* Return an error if entry NAME is present in directory PATH under ROOT. */
973
check_entry_absent (svn_fs_root_t *root, const char *path,
974
const char *name, apr_pool_t *pool)
976
svn_boolean_t present;
977
SVN_ERR (check_entry (root, path, name, &present, pool));
980
return svn_error_createf
981
(SVN_ERR_FS_GENERAL, NULL,
982
"entry \"%s\" present when it should be absent", name);
991
const svn_fs_id_t *id;
992
svn_boolean_t present;
997
txn_body_check_id (void *baton, trail_t *trail)
999
struct check_id_args *args = baton;
1000
node_revision_t *noderev;
1003
err = svn_fs_bdb__get_node_revision (&noderev, args->fs, args->id,
1004
trail, trail->pool);
1006
if (err && (err->apr_err == SVN_ERR_FS_ID_NOT_FOUND))
1007
args->present = FALSE;
1009
args->present = TRUE;
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);
1017
svn_error_clear (err);
1019
return SVN_NO_ERROR;
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,
1029
struct check_id_args args;
1033
SVN_ERR (svn_fs_base__retry_txn (fs, txn_body_check_id, &args, pool));
1040
return SVN_NO_ERROR;
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)
1048
svn_boolean_t present;
1049
SVN_ERR (check_id (fs, id, &present, pool));
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",
1060
return SVN_NO_ERROR;
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)
1068
svn_boolean_t present;
1069
SVN_ERR (check_id (fs, id, &present, pool));
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",
1080
return SVN_NO_ERROR;
1084
/* Test that aborting a Subversion transaction works.
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,
1095
svn_fs_txn_t *txn1, *txn2;
1096
svn_fs_root_t *txn1_root, *txn2_root;
1097
const char *txn1_name, *txn2_name;
1099
*msg = "abort a transaction";
1102
return SVN_NO_ERROR;
1104
/* Prepare two txns to receive the Greek tree. */
1105
SVN_ERR (svn_test__create_fs (&fs, "test-repo-abort-txn",
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));
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));
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));
1120
/* The test is to abort txn2, while leaving txn1.
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
1126
* Finally, we create a third txn, and check that the name it got is
1127
* different from the names of txn1 and txn2.
1131
/* Yes, I really am this paranoid. */
1133
/* IDs for every file in the standard Greek Tree. */
1135
*t1_root_id, *t2_root_id,
1136
*t1_iota_id, *t2_iota_id,
1138
*t1_mu_id, *t2_mu_id,
1140
*t1_lambda_id, *t2_lambda_id,
1142
*t1_alpha_id, *t2_alpha_id,
1143
*t1_beta_id, *t2_beta_id,
1147
*t1_gamma_id, *t2_gamma_id,
1149
*t1_chi_id, *t2_chi_id,
1150
*t1_psi_id, *t2_psi_id,
1151
*t1_omega_id, *t2_omega_id,
1153
*t1_pi_id, *t2_pi_id,
1154
*t1_rho_id, *t2_rho_id,
1155
*t1_tau_id, *t2_tau_id;
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));
1200
/* Abort just txn2. */
1201
SVN_ERR (svn_fs_abort_txn (txn2, pool));
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.
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));
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));
1254
/* Test that txn2 itself is gone, by trying to open it. */
1256
svn_fs_txn_t *txn2_again;
1259
err = svn_fs_open_txn (&txn2_again, fs, txn2_name, pool);
1260
if (err && (err->apr_err != SVN_ERR_FS_NO_SUCH_TRANSACTION))
1262
return svn_error_create
1263
(SVN_ERR_FS_GENERAL, NULL,
1264
"opening non-existent txn got wrong error");
1268
return svn_error_create
1269
(SVN_ERR_FS_GENERAL, NULL,
1270
"opening non-existent txn failed to get error");
1272
svn_error_clear (err);
1275
/* Test that txn names are not recycled, by opening a new txn. */
1278
const char *txn3_name;
1280
SVN_ERR (svn_fs_begin_txn (&txn3, fs, 0, pool));
1281
SVN_ERR (svn_fs_txn_name (&txn3_name, txn3, pool));
1283
if ((strcmp (txn3_name, txn2_name) == 0)
1284
|| (strcmp (txn3_name, txn1_name) == 0))
1286
return svn_error_createf
1287
(SVN_ERR_FS_GENERAL, NULL,
1288
"txn name \"%s\" was recycled", txn3_name);
1292
/* Test that aborting a txn that's already committed fails. */
1295
const char *txn4_name;
1296
svn_revnum_t new_rev;
1297
const char *conflict;
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);
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");
1313
svn_error_clear (err);
1315
return SVN_NO_ERROR;
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,
1328
svn_fs_root_t *txn_root;
1329
svn_revnum_t new_rev;
1330
svn_revnum_t youngest_rev, new_youngest_rev;
1332
*msg = "fetch the youngest revision from a filesystem";
1335
return SVN_NO_ERROR;
1337
SVN_ERR (svn_test__create_fs (&fs, "test-repo-youngest-rev",
1340
/* Get youngest revision of brand spankin' new filesystem. */
1341
SVN_ERR (svn_fs_youngest_rev (&youngest_rev, fs, pool));
1343
/* Prepare a txn to receive the greek tree. */
1344
SVN_ERR (svn_test__create_fs (&fs, "test-repo-commit-txn",
1346
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
1347
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
1349
/* Create the greek tree. */
1350
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
1353
SVN_ERR (test_commit_txn (&new_rev, txn, NULL, pool));
1355
/* Get the new youngest revision. */
1356
SVN_ERR (svn_fs_youngest_rev (&new_youngest_rev, fs, pool));
1358
if (youngest_rev == new_rev)
1359
return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
1360
"commit didn't bump up revision number");
1362
if (new_youngest_rev != new_rev)
1363
return svn_error_create (SVN_ERR_FS_GENERAL, NULL,
1364
"couldn't fetch youngest revision");
1366
return SVN_NO_ERROR;
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,
1380
svn_fs_root_t *txn_root, *revision_root;
1381
svn_revnum_t before_rev, after_rev;
1382
const char *conflict;
1384
*msg = "basic commit";
1387
return SVN_NO_ERROR;
1389
/* Prepare a filesystem. */
1390
SVN_ERR (svn_test__create_fs (&fs, "test-repo-basic-commit",
1393
/* Save the current youngest revision. */
1394
SVN_ERR (svn_fs_youngest_rev (&before_rev, fs, pool));
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));
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");
1407
/* Create the greek tree. */
1408
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
1411
SVN_ERR (svn_fs_commit_txn (&conflict, &after_rev, txn, pool));
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");
1419
/* Get root of the revision */
1420
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1422
/* Check the tree. */
1423
SVN_ERR (svn_test__check_greek_tree (revision_root, pool));
1425
return SVN_NO_ERROR;
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,
1438
svn_fs_root_t *txn_root, *revision_root;
1439
svn_revnum_t after_rev;
1440
const char *conflict;
1441
apr_pool_t *subpool;
1443
*msg = "testing tree validation helper";
1446
return SVN_NO_ERROR;
1448
/* Prepare a filesystem. */
1449
SVN_ERR (svn_test__create_fs (&fs, "test-repo-validate-tree-entries",
1452
/* In a txn, create the greek tree. */
1453
subpool = svn_pool_create (pool);
1455
static svn_test__tree_entry_t expected_entries[] = {
1456
/* path, contents (0 = dir) */
1457
{ "iota", "This is the file 'iota'.\n" },
1459
{ "A/mu", "This is the file 'mu'.\n" },
1461
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1463
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1464
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1468
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
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));
1482
/* Carefully validate that tree in the transaction. */
1483
SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 20,
1486
/* Go ahead and commit the tree, and destroy the txn object. */
1487
SVN_ERR (svn_fs_commit_txn (&conflict, &after_rev, txn, subpool));
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,
1494
svn_pool_destroy (subpool);
1496
/* In a new txn, modify the greek tree. */
1497
subpool = svn_pool_create (pool);
1499
static svn_test__tree_entry_t expected_entries[] = {
1500
/* path, contents (0 = dir) */
1501
{ "iota", "This is a new version of 'iota'.\n" },
1504
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1506
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1507
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1510
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1512
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
1518
{ "A/D/I/delta", "This is the file 'delta'.\n" },
1519
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
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",
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",
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",
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",
1543
/* Carefully validate that tree in the transaction. */
1544
SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 19,
1547
/* Go ahead and commit the tree, and destroy the txn object. */
1548
SVN_ERR (svn_fs_commit_txn (&conflict, &after_rev, txn, subpool));
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,
1555
svn_pool_destroy (subpool);
1557
return SVN_NO_ERROR;
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,
1570
svn_fs_root_t *txn_root, *revision_root;
1571
svn_revnum_t after_rev;
1572
svn_revnum_t revisions[24];
1574
svn_revnum_t revision_count;
1576
*msg = "merging commit";
1579
return SVN_NO_ERROR;
1581
/* Initialize our revision number stuffs. */
1583
i < ((sizeof (revisions)) / (sizeof (svn_revnum_t)));
1585
revisions[i] = SVN_INVALID_REVNUM;
1588
/* Prepare a filesystem. */
1589
SVN_ERR (svn_test__create_fs (&fs, "test-repo-merging-commit",
1591
revisions[revision_count++] = 0; /* the brand spankin' new revision */
1593
/***********************************************************************/
1595
/***********************************************************************/
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));
1603
/***********************************************************************/
1605
/***********************************************************************/
1607
static svn_test__tree_entry_t expected_entries[] = {
1608
/* path, contents (0 = dir) */
1609
{ "iota", "This is the file 'iota'.\n" },
1611
{ "A/mu", "This is the file 'mu'.\n" },
1613
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1615
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1616
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1620
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
1630
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1631
SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
1634
revisions[revision_count++] = after_rev;
1636
/* Let's add a directory and some files to the tree, and delete
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));
1653
/***********************************************************************/
1655
/***********************************************************************/
1657
static svn_test__tree_entry_t expected_entries[] = {
1658
/* path, contents (0 = dir) */
1660
{ "A/mu", "This is the file 'mu'.\n" },
1662
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1664
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1665
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1668
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1670
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" },
1680
{ "A/D/I/delta", "This is the file 'delta'.\n" },
1681
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
1683
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1684
SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
1687
revisions[revision_count++] = after_rev;
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));
1699
/***********************************************************************/
1701
/***********************************************************************/
1703
static svn_test__tree_entry_t expected_entries[] = {
1704
/* path, contents (0 = dir) */
1705
{ "iota", "This is the new file 'iota'.\n" },
1707
{ "A/mu", "This is the file 'mu'.\n" },
1709
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1711
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1712
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1715
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1717
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
1723
{ "A/D/I/delta", "This is the file 'delta'.\n" },
1724
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
1726
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1727
SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
1730
revisions[revision_count++] = after_rev;
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));
1738
/***********************************************************************/
1740
/***********************************************************************/
1742
static svn_test__tree_entry_t expected_entries[] = {
1743
/* path, contents (0 = dir) */
1745
{ "A/mu", "This is the file 'mu'.\n" },
1747
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1749
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1750
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1753
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1755
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
1761
{ "A/D/I/delta", "This is the file 'delta'.\n" },
1762
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
1764
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1765
SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
1768
revisions[revision_count++] = after_rev;
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.
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.
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.
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.
1791
The test cases below have the following features:
1793
- They run straight through the scenarios as described in the
1794
`structure' document at this time.
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).
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.
1808
/***********************************************************************/
1810
/* (6) E exists in neither ANCESTOR nor A. */
1812
/* (1) E exists in neither ANCESTOR nor B. Can't occur, by
1813
assumption that E exists in either A, B, or ancestor. */
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));
1823
/*********************************************************************/
1825
/*********************************************************************/
1827
static svn_test__tree_entry_t expected_entries[] = {
1828
/* path, contents (0 = dir) */
1829
{ "theta", "This is the file 'theta'.\n" },
1831
{ "A/mu", "This is the file 'mu'.\n" },
1833
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1835
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1836
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1839
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1841
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
1847
{ "A/D/I/delta", "This is the file 'delta'.\n" },
1848
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
1850
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1851
SVN_ERR (svn_test__validate_tree (revision_root,
1855
revisions[revision_count++] = after_rev;
1857
/* (1) E has been deleted from B. Can't occur, by assumption that
1858
E doesn't exist in ANCESTOR. */
1860
/* (3) E exists in both ANCESTOR and B. Can't occur, by
1861
assumption that E doesn't exist in ancestor. */
1864
/* (5) E doesn't exist in ANCESTOR, and has been added to A. */
1866
/* (1) E doesn't exist in ANCESTOR, and has been added to B.
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));
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. */
1879
/* (3) E exists in both ANCESTOR and B. Can't occur, by assumption
1880
that E doesn't exist in ANCESTOR. */
1883
/* (4) E exists in ANCESTOR, but has been deleted from A */
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
/*********************************************************************/
1896
/*********************************************************************/
1898
static svn_test__tree_entry_t expected_entries[] = {
1899
/* path, contents (0 = dir) */
1900
{ "theta", "This is the file 'theta'.\n" },
1902
{ "A/mu", "This is the file 'mu'.\n" },
1904
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1906
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1907
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1910
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1912
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
1918
{ "A/D/I/delta", "This is the file 'delta'.\n" },
1919
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
1921
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
1922
SVN_ERR (svn_test__validate_tree (revision_root,
1926
revisions[revision_count++] = after_rev;
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));
1937
/* E exists in both ANCESTOR and B ... */
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;
1947
/*********************************************************************/
1949
/*********************************************************************/
1951
/* Re-remove A/D/H because future tests expect it to be absent. */
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;
1961
/*********************************************************************/
1962
/* REVISION 8 (looks exactly like revision 6, we hope) */
1963
/*********************************************************************/
1965
/* (1) but refers to different revisions of the same node.
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));
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));
1982
/*********************************************************************/
1984
/*********************************************************************/
1986
static svn_test__tree_entry_t expected_entries[] = {
1987
/* path, contents (0 = dir) */
1988
{ "theta", "This is the file 'theta'.\n" },
1991
{ "A/B/lambda", "This is the file 'lambda'.\n" },
1993
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
1994
{ "A/B/E/beta", "This is the file 'beta'.\n" },
1997
{ "A/C/kappa", "This is the file 'kappa'.\n" },
1999
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
2005
{ "A/D/I/delta", "This is the file 'delta'.\n" },
2006
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
2008
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
2009
SVN_ERR (svn_test__validate_tree (revision_root,
2013
revisions[revision_count++] = after_rev;
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
/*********************************************************************/
2031
/*********************************************************************/
2033
static svn_test__tree_entry_t expected_entries[] = {
2034
/* path, contents (0 = dir) */
2035
{ "theta", "This is the file 'theta'.\n" },
2037
{ "A/mu", "A new file 'mu'.\n" },
2039
{ "A/B/lambda", "This is the file 'lambda'.\n" },
2041
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
2042
{ "A/B/E/beta", "This is the file 'beta'.\n" },
2045
{ "A/C/kappa", "This is the file 'kappa'.\n" },
2047
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
2054
{ "A/D/I/delta", "This is the file 'delta'.\n" },
2055
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
2057
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
2058
SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
2061
revisions[revision_count++] = after_rev;
2063
/* (3) E exists in both ANCESTOR and A, but refers to different
2066
/* (1) E exists in both ANCESTOR and B, but refers to different
2067
nodes, and not all nodes are directories. Conflict. */
2069
/* ### kff todo: A/mu's contents will be exactly the same.
2070
If the fs ever starts optimizing this case, these tests may
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));
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));
2090
/* (1) E exists in both ANCESTOR and B, and refers to the same
2091
node revision. Replace E with A's node revision. */
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))
2101
return svn_error_create
2102
(SVN_ERR_FS_GENERAL, NULL,
2103
"got wrong contents from an old revision tree");
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
/*********************************************************************/
2111
/*********************************************************************/
2113
static svn_test__tree_entry_t expected_entries[] = {
2114
/* path, contents (0 = dir) */
2115
{ "theta", "This is the file 'theta'.\n" },
2117
{ "A/mu", "A new file 'mu'.\n" },
2118
{ "A/sigma", "This is the file 'sigma'.\n" },
2120
{ "A/B/lambda", "This is the file 'lambda'.\n" },
2122
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
2123
{ "A/B/E/beta", "This is the file 'beta'.\n" },
2126
{ "A/C/kappa", "This is the file 'kappa'.\n" },
2128
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
2135
{ "A/D/I/delta", "This is the file 'delta'.\n" },
2136
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
2138
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
2139
SVN_ERR (svn_test__validate_tree (revision_root,
2143
revisions[revision_count++] = after_rev;
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
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
/*********************************************************************/
2159
/*********************************************************************/
2161
static svn_test__tree_entry_t expected_entries[] = {
2162
/* path, contents (0 = dir) */
2163
{ "theta", "This is the file 'theta'.\n" },
2165
{ "A/mu", "A new file 'mu'.\n" },
2166
{ "A/sigma", "This is the file 'sigma'.\n" },
2168
{ "A/B/lambda", "Change to file 'lambda'.\n" },
2170
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
2171
{ "A/B/E/beta", "This is the file 'beta'.\n" },
2174
{ "A/C/kappa", "This is the file 'kappa'.\n" },
2176
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
2183
{ "A/D/I/delta", "This is the file 'delta'.\n" },
2184
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
2186
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
2187
SVN_ERR (svn_test__validate_tree (revision_root, expected_entries,
2190
revisions[revision_count++] = after_rev;
2192
/* (2) E exists in both ANCESTOR and A, but refers to different
2193
revisions of the same node. */
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",
2202
SVN_ERR (test_commit_txn (&after_rev, txn, "/A/B/lambda", pool));
2203
SVN_ERR (svn_fs_abort_txn (txn, pool));
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
/*********************************************************************/
2216
/*********************************************************************/
2218
static svn_test__tree_entry_t expected_entries[] = {
2219
/* path, contents (0 = dir) */
2220
{ "theta", "This is the file 'theta'.\n" },
2222
{ "A/mu", "A new file 'mu'.\n" },
2223
{ "A/sigma", "This is the file 'sigma'.\n" },
2225
{ "A/B/lambda", "Change to file 'lambda'.\n" },
2227
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
2228
{ "A/B/E/beta", "This is the file 'beta'.\n" },
2231
{ "A/C/kappa", "This is the file 'kappa'.\n" },
2233
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
2241
{ "A/D/I/delta", "This is the file 'delta'.\n" },
2242
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
2244
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
2245
SVN_ERR (svn_test__validate_tree (revision_root,
2249
revisions[revision_count++] = after_rev;
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));
2262
/* (1) E exists in both ANCESTOR and B, and refers to the same node
2263
revision. Replace E with A's node revision. */
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))
2274
return svn_error_create
2275
(SVN_ERR_FS_GENERAL, NULL,
2276
"got wrong contents from an old revision tree");
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
/*********************************************************************/
2284
/*********************************************************************/
2286
static svn_test__tree_entry_t expected_entries[] = {
2287
/* path, contents (0 = dir) */
2288
{ "theta", "This is the file 'theta'.\n" },
2290
{ "A/mu", "A new file 'mu'.\n" },
2291
{ "A/sigma", "This is the file 'sigma'.\n" },
2293
{ "A/B/lambda", "Change to file 'lambda'.\n" },
2295
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
2296
{ "A/B/E/beta", "This is the file 'beta'.\n" },
2299
{ "A/C/kappa", "This is the file 'kappa'.\n" },
2301
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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"},
2309
{ "A/D/I/delta", "This is the file 'delta'.\n" },
2310
{ "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
2312
SVN_ERR (svn_fs_revision_root (&revision_root, fs, after_rev, pool));
2313
SVN_ERR (svn_test__validate_tree (revision_root,
2317
revisions[revision_count++] = after_rev;
2321
/* (1) E exists in both ANCESTOR and A, and refers to the same node
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. */
2328
/* This has now been tested about fifty-four trillion times. We
2329
don't need to test it again here. */
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
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));
2342
return SVN_NO_ERROR;
2346
static svn_error_t *
2347
copy_test (const char **msg,
2348
svn_boolean_t msg_only,
2349
svn_test_opts_t *opts,
2354
svn_fs_root_t *txn_root, *rev_root;
2355
svn_revnum_t after_rev;
2357
*msg = "copying and tracking copy history";
2360
return SVN_NO_ERROR;
2362
/* Prepare a filesystem. */
2363
SVN_ERR (svn_test__create_fs (&fs, "test-repo-copy-test",
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));
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. */
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",
2383
{ /* Check that copy history was preserved. */
2387
SVN_ERR (svn_fs_copied_from (&rev, &path, txn_root,
2388
"A/D/H/pi2", pool));
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");
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");
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));
2404
{ /* Check that copy history is still preserved _after_ the commit. */
2405
svn_fs_root_t *root;
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));
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");
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");
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;
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));
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");
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");
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));
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");
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");
2464
/* Commit a regular change to a copy, make sure the copy history
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;
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));
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");
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");
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));
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");
2501
return svn_error_create
2502
(SVN_ERR_FS_GENERAL, NULL,
2503
"copy history wrong (path) for A/D/H/pi3");
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;
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));
2522
if (rev != (after_rev - 1))
2523
return svn_error_create
2524
(SVN_ERR_FS_GENERAL, NULL,
2525
"copy history wrong (rev) for H2");
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");
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));
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");
2541
return svn_error_create
2542
(SVN_ERR_FS_GENERAL, NULL,
2543
"copy history wrong (path) for H2/omega");
2545
/* Note that H2/pi2 still has copy history, though. See the doc
2546
string for svn_fs_copied_from() for more on this. */
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;
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));
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");
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");
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));
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");
2587
return svn_error_create
2588
(SVN_ERR_FS_GENERAL, NULL,
2589
"copy history wrong (path) for A/B");
2592
/* After all these changes, let's see if the filesystem looks as we
2593
would expect it to. */
2595
static svn_test__tree_entry_t expected_entries[] = {
2596
/* path, contents (0 = dir) */
2597
{ "iota", "This is the file 'iota'.\n" },
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" },
2605
{ "A/mu", "This is the file 'mu'.\n" },
2607
{ "A/B/lambda", "This is the file 'lambda'.\n" },
2609
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
2610
{ "A/B/E/beta", "This is the file 'beta'.\n" },
2612
{ "A/B/E/B/lambda", "This is the file 'lambda'.\n" },
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" },
2620
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
2632
SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool));
2633
SVN_ERR (svn_test__validate_tree (rev_root, expected_entries,
2637
return SVN_NO_ERROR;
2641
static svn_error_t *
2642
link_test (const char **msg,
2643
svn_boolean_t msg_only,
2644
svn_test_opts_t *opts,
2647
*msg = "linking, so no copy history";
2649
return SVN_NO_ERROR;
2650
return svn_error_create (SVN_ERR_TEST_FAILED, NULL, "XFAIL");
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()
2657
svn_fs_root_t *txn_root, *rev_root;
2658
svn_revnum_t after_rev;
2660
*msg = "linking, so no copy history";
2663
return SVN_NO_ERROR;
2665
/* Prepare a filesystem. */
2666
SVN_ERR (svn_test__create_fs (&fs, "test-repo-link-test",
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));
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
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",
2688
/* Check that no copy history was generated. */
2693
SVN_ERR (svn_fs_copied_from (&rev, &path, txn_root, "A/D/G/pi2", pool));
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'",
2702
return svn_error_createf
2703
(SVN_ERR_FS_GENERAL, NULL,
2704
"link_test: copy path present when should be absent on '%s'",
2708
/* Test that the node id is the same on the two files in the txn. */
2710
const svn_fs_id_t *orig_id, *link_id;
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));
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");
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));
2728
/* Get a revision root on the head. */
2729
SVN_ERR (svn_fs_revision_root (&rev_root, fs, after_rev, pool));
2731
/* Check that there's _still_ no copy history. */
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));
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'",
2746
return svn_error_createf
2747
(SVN_ERR_FS_GENERAL, NULL,
2748
"link_test: copy path wrongly present on committed '%s'",
2752
/* Test that the node id has changed now, since we changed the file. */
2754
const svn_fs_id_t *orig_id, *link_id;
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));
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");
2766
/* Link the file A/D/G/pi2 to A/D/G/pi3 and commit, *without*
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",
2774
SVN_ERR (test_commit_txn (&after_rev, txn, NULL, pool));
2775
SVN_ERR (svn_fs_close_txn (txn));
2777
/* Test that the node id has changed now, since we changed the file. */
2779
/* The node id's will be the same. BAD. See below:
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
2788
const svn_fs_id_t *orig_id, *link_id;
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));
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");
2800
return SVN_NO_ERROR;
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
2809
* ### todo: this test was written before commits worked. It might
2810
* now be worthwhile to combine it with delete().
2812
static svn_error_t *
2813
delete_mutables (const char **msg,
2814
svn_boolean_t msg_only,
2815
svn_test_opts_t *opts,
2820
svn_fs_root_t *txn_root;
2823
*msg = "delete mutable nodes from directories";
2826
return SVN_NO_ERROR;
2828
/* Prepare a txn to receive the greek tree. */
2829
SVN_ERR (svn_test__create_fs (&fs, "test-repo-del-from-dir",
2831
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
2832
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
2834
/* Create the greek tree. */
2835
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
2837
/* Baby, it's time to test like you've never tested before. We do
2838
* the following, in this order:
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.
2848
* Specifically, that's:
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.
2855
* 6. Try to delete /, fail.
2856
* 7. Try to delete iota, succeed.
2858
* Before and after each deletion or attempted deletion, we probe
2859
* the affected directory, to make sure everything is as it should
2865
const svn_fs_id_t *gamma_id;
2866
SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "A/D/gamma", pool));
2868
SVN_ERR (check_entry_present (txn_root, "A/D", "gamma", pool));
2869
SVN_ERR (check_id_present (fs, gamma_id, pool));
2871
SVN_ERR (svn_fs_delete (txn_root, "A/D/gamma", pool));
2873
SVN_ERR (check_entry_absent (txn_root, "A/D", "gamma", pool));
2874
SVN_ERR (check_id_absent (fs, gamma_id, pool));
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));
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));
2891
SVN_ERR (svn_fs_delete (txn_root, "A/D/G/pi", pool));
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));
2900
SVN_ERR (svn_fs_delete (txn_root, "A/D/G/rho", pool));
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));
2912
const svn_fs_id_t *tau_id;
2913
SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "A/D/G/tau", pool));
2915
SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau", pool));
2916
SVN_ERR (check_id_present (fs, tau_id, pool));
2918
SVN_ERR (svn_fs_delete (txn_root, "A/D/G/tau", pool));
2920
SVN_ERR (check_entry_absent (txn_root, "A/D/G", "tau", pool));
2921
SVN_ERR (check_id_absent (fs, tau_id, pool));
2926
const svn_fs_id_t *G_id;
2927
SVN_ERR (svn_fs_node_id (&G_id, txn_root, "A/D/G", pool));
2929
SVN_ERR (check_entry_present (txn_root, "A/D", "G", pool));
2930
SVN_ERR (check_id_present (fs, G_id, pool));
2932
SVN_ERR (svn_fs_delete (txn_root, "A/D/G", pool)); /* succeed */
2934
SVN_ERR (check_entry_absent (txn_root, "A/D", "G", pool));
2935
SVN_ERR (check_id_absent (fs, G_id, pool));
2940
const svn_fs_id_t *C_id;
2941
SVN_ERR (svn_fs_node_id (&C_id, txn_root, "A/C", pool));
2943
SVN_ERR (check_entry_present (txn_root, "A", "C", pool));
2944
SVN_ERR (check_id_present (fs, C_id, pool));
2946
SVN_ERR (svn_fs_delete (txn_root, "A/C", pool));
2948
SVN_ERR (check_entry_absent (txn_root, "A", "C", pool));
2949
SVN_ERR (check_id_absent (fs, C_id, pool));
2954
const svn_fs_id_t *root_id;
2955
SVN_ERR (svn_fs_node_id (&root_id, txn_root, "", pool));
2957
err = svn_fs_delete (txn_root, "", pool);
2959
if (err && (err->apr_err != SVN_ERR_FS_ROOT_DIR))
2961
return svn_error_createf
2962
(SVN_ERR_FS_GENERAL, NULL,
2963
"deleting root directory got wrong error");
2967
return svn_error_createf
2968
(SVN_ERR_FS_GENERAL, NULL,
2969
"deleting root directory failed to get error");
2971
svn_error_clear (err);
2973
SVN_ERR (check_id_present (fs, root_id, pool));
2978
const svn_fs_id_t *iota_id;
2979
SVN_ERR (svn_fs_node_id (&iota_id, txn_root, "iota", pool));
2981
SVN_ERR (check_entry_present (txn_root, "", "iota", pool));
2982
SVN_ERR (check_id_present (fs, iota_id, pool));
2984
SVN_ERR (svn_fs_delete (txn_root, "iota", pool));
2986
SVN_ERR (check_entry_absent (txn_root, "", "iota", pool));
2987
SVN_ERR (check_id_absent (fs, iota_id, pool));
2990
return SVN_NO_ERROR;
2994
/* This tests deleting in general.
2996
* ### todo: this test was written after (and independently of)
2997
* delete_mutables(). It might be worthwhile to combine them.
2999
static svn_error_t *
3000
delete (const char **msg,
3001
svn_boolean_t msg_only,
3002
svn_test_opts_t *opts,
3007
svn_fs_root_t *txn_root;
3008
svn_revnum_t new_rev;
3010
*msg = "delete nodes tree";
3013
return SVN_NO_ERROR;
3015
/* This function tests 5 cases:
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.
3024
/* Prepare a txn to receive the greek tree. */
3025
SVN_ERR (svn_test__create_fs (&fs, "test-repo-del-tree",
3027
SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
3028
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
3030
/* Create the greek tree. */
3031
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
3033
/* 1. Delete mutable file. */
3035
const svn_fs_id_t *iota_id, *gamma_id;
3036
static svn_test__tree_entry_t expected_entries[] = {
3037
/* path, contents (0 = dir) */
3039
{ "A/mu", "This is the file 'mu'.\n" },
3041
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3043
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3044
{ "A/B/E/beta", "This is the file 'beta'.\n" },
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" },
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" }
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));
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));
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));
3074
/* Validate the tree. */
3075
SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 18, pool));
3077
/* Abort transaction. */
3078
SVN_ERR (svn_fs_abort_txn (txn, pool));
3080
/* 2. Delete mutable directory. */
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));
3086
/* Create the greek tree. */
3087
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
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;
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));
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));
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));
3163
/* Validate the tree. */
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));
3172
/* Abort transaction. */
3173
SVN_ERR (svn_fs_abort_txn (txn, pool));
3175
/* 3. Delete mutable directory with immutable nodes. */
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));
3181
/* Create the greek tree. */
3182
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
3184
/* Commit the greek tree. */
3185
SVN_ERR (svn_fs_commit_txn (NULL, &new_rev, txn, pool));
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));
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;
3196
/* Create A/D/G/sigma. This makes all components of A/D/G
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));
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));
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));
3269
/* Validate the tree. */
3271
static svn_test__tree_entry_t expected_entries[] = {
3272
/* path, contents (0 = dir) */
3273
{ "iota", "This is the file 'iota'.\n" }
3276
SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 1, pool));
3280
/* Abort transaction. */
3281
SVN_ERR (svn_fs_abort_txn (txn, pool));
3283
/* 4. Delete immutable file. */
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));
3290
const svn_fs_id_t *iota_id, *gamma_id;
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));
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));
3308
/* Validate the tree. */
3310
static svn_test__tree_entry_t expected_entries[] = {
3311
/* path, contents (0 = dir) */
3313
{ "A/mu", "This is the file 'mu'.\n" },
3315
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3317
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3318
{ "A/B/E/beta", "This is the file 'beta'.\n" },
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" },
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" }
3331
SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 18, pool));
3335
/* Abort transaction. */
3336
SVN_ERR (svn_fs_abort_txn (txn, pool));
3338
/* 5. Delete immutable directory. */
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));
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;
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));
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));
3412
/* Validate the tree. */
3414
static svn_test__tree_entry_t expected_entries[] = {
3415
/* path, contents (0 = dir) */
3416
{ "iota", "This is the file 'iota'.\n" }
3418
SVN_ERR (svn_test__validate_tree (txn_root, expected_entries, 1, pool));
3422
return SVN_NO_ERROR;
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,
3436
svn_fs_root_t *txn_root;
3438
svn_string_t *datestamp;
3439
apr_time_t before_commit, at_commit, after_commit;
3441
*msg = "commit datestamps";
3444
return SVN_NO_ERROR;
3446
/* Prepare a filesystem. */
3447
SVN_ERR (svn_test__create_fs (&fs, "test-repo-commit-date",
3450
before_commit = apr_time_now ();
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));
3458
after_commit = apr_time_now ();
3460
/* Get the datestamp of the commit. */
3461
SVN_ERR (svn_fs_revision_prop (&datestamp, fs, rev, SVN_PROP_REVISION_DATE,
3464
if (datestamp == NULL)
3465
return svn_error_create
3466
(SVN_ERR_FS_GENERAL, NULL,
3467
"failed to get datestamp of committed revision");
3469
SVN_ERR (svn_time_from_cstring (&at_commit, datestamp->data, pool));
3471
if (at_commit < before_commit)
3472
return svn_error_create
3473
(SVN_ERR_FS_GENERAL, NULL,
3474
"datestamp too early");
3476
if (at_commit > after_commit)
3477
return svn_error_create
3478
(SVN_ERR_FS_GENERAL, NULL,
3479
"datestamp too late");
3481
return SVN_NO_ERROR;
3485
static svn_error_t *
3486
check_old_revisions (const char **msg,
3487
svn_boolean_t msg_only,
3488
svn_test_opts_t *opts,
3493
svn_fs_root_t *txn_root;
3495
apr_pool_t *subpool = svn_pool_create (pool);
3497
*msg = "check old revisions";
3500
return SVN_NO_ERROR;
3502
/* Prepare a filesystem. */
3503
SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-old-revisions",
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);
3513
/* Modify and commit iota a few times, then test to see if we can
3514
retrieve all the committed revisions. */
3516
/* right-side numbers match revision numbers */
3517
#define iota_contents_1 "This is the file 'iota'.\n"
3519
/* Add a char to the front. */
3520
#define iota_contents_2 "XThis is the file 'iota'.\n"
3522
/* Add a char to the end. */
3523
#define iota_contents_3 "XThis is the file 'iota'.\nX"
3525
/* Add a couple of chars in the middle. */
3526
#define iota_contents_4 "XThis is the X file 'iota'.\nX"
3528
/* Randomly add and delete chars all over. */
3529
#define iota_contents_5 \
3530
"XTYhQis is ACK, PHHHT! no longer 'ioZZZZZta'.blarf\nbye"
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."
3537
/* Revert to the original contents. */
3538
#define iota_contents_7 "This is the file 'iota'.\n"
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);
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);
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);
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);
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);
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);
3588
/** Now check the full Greek Tree in all of those revisions,
3589
adjusting `iota' for each one. ***/
3591
/* Validate revision 1. */
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 },
3598
{ "A/mu", "This is the file 'mu'.\n" },
3600
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3602
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3603
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3607
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
3618
SVN_ERR (svn_fs_revision_root (&root, fs, 1, pool));
3619
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3622
/* Validate revision 2. */
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 },
3629
{ "A/mu", "This is the file 'mu'.\n" },
3631
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3633
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3634
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3638
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
3649
SVN_ERR (svn_fs_revision_root (&root, fs, 2, pool));
3650
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3653
/* Validate revision 3. */
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 },
3660
{ "A/mu", "This is the file 'mu'.\n" },
3662
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3664
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3665
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3669
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
3680
SVN_ERR (svn_fs_revision_root (&root, fs, 3, pool));
3681
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3684
/* Validate revision 4. */
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 },
3691
{ "A/mu", "This is the file 'mu'.\n" },
3693
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3695
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3696
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3700
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
3711
SVN_ERR (svn_fs_revision_root (&root, fs, 4, pool));
3712
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3715
/* Validate revision 5. */
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 },
3722
{ "A/mu", "This is the file 'mu'.\n" },
3724
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3726
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3727
{ "A/B/E/beta", "This is the file 'beta'.\n" },
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" },
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" }
3742
SVN_ERR (svn_fs_revision_root (&root, fs, 5, pool));
3743
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3746
/* Validate revision 6. */
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 },
3753
{ "A/mu", "This is the file 'mu'.\n" },
3755
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3757
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3758
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3762
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
3773
SVN_ERR (svn_fs_revision_root (&root, fs, 6, pool));
3774
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3777
/* Validate revision 7. */
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 },
3784
{ "A/mu", "This is the file 'mu'.\n" },
3786
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3788
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3789
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3793
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
3804
SVN_ERR (svn_fs_revision_root (&root, fs, 7, pool));
3805
SVN_ERR (svn_test__validate_tree (root, expected_entries, 20, pool));
3809
svn_pool_destroy (subpool);
3810
return SVN_NO_ERROR;
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,
3823
svn_fs_root_t *revision_root;
3826
apr_pool_t *subpool = svn_pool_create (pool);
3828
/* Validate all revisions up to the current one. */
3829
for (i = 0; i <= max_rev; i++)
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,
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);
3844
svn_pool_destroy (subpool);
3845
return SVN_NO_ERROR;
3849
static svn_error_t *
3850
check_all_revisions (const char **msg,
3851
svn_boolean_t msg_only,
3852
svn_test_opts_t *opts,
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);
3863
*msg = "after each commit, check all revisions";
3866
return SVN_NO_ERROR;
3868
/* Create a filesystem and repository. */
3869
SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-all-revisions",
3872
/***********************************************************************/
3874
/***********************************************************************/
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));
3881
svn_pool_clear (subpool);
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));
3889
/***********************************************************************/
3891
/***********************************************************************/
3893
static svn_test__tree_entry_t expected_entries[] = {
3894
/* path, contents (0 = dir) */
3895
{ "iota", "This is the file 'iota'.\n" },
3897
{ "A/mu", "This is the file 'mu'.\n" },
3899
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3901
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3902
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3906
{ "A/D/gamma", "This is the file 'gamma'.\n" },
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" },
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" }
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));
3921
svn_pool_clear (subpool);
3923
/* Make a new txn based on the youngest revision, make some changes,
3924
and commit those changes (which makes a new youngest
3926
SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
3927
SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
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" },
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" }
3941
SVN_ERR (svn_test__txn_script_exec (txn_root, script_entries, 10,
3944
SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
3946
/***********************************************************************/
3948
/***********************************************************************/
3950
static svn_test__tree_entry_t expected_entries[] = {
3951
/* path, contents (0 = dir) */
3952
{ "iota", "Changed file 'iota'.\n" },
3954
{ "A/delta", "This is the file 'delta'.\n" },
3955
{ "A/epsilon", "This is the file 'epsilon'.\n" },
3957
{ "A/B/lambda", "This is the file 'lambda'.\n" },
3959
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
3960
{ "A/B/E/beta", "This is the file 'beta'.\n" },
3963
{ "A/B/Z/zeta", "This is the file 'zeta'.\n" },
3965
{ "A/D/gamma", "This is the file 'gamma'.\n" },
3967
{ "A/D/G/pi", "This is the file 'pi'.\n" },
3968
{ "A/D/G/rho", "Changed file 'rho'.\n" },
3970
{ "A/D/H/chi", "This is the file 'chi'.\n" },
3971
{ "A/D/H/psi", "This is the file 'psi'.\n" }
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));
3978
svn_pool_clear (subpool);
3980
/* Make a new txn based on the youngest revision, make some changes,
3981
and commit those changes (which makes a new youngest
3983
SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
3984
SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
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" }
3992
SVN_ERR (svn_test__txn_script_exec (txn_root, script_entries, 4,
3995
SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
3997
/***********************************************************************/
3999
/***********************************************************************/
4001
static svn_test__tree_entry_t expected_entries[] = {
4002
/* path, contents (0 = dir) */
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" },
4008
{ "A/B/lambda", "This is the file 'lambda'.\n" },
4010
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
4011
{ "A/B/E/beta", "This is the file 'beta'.\n" },
4014
{ "A/B/Z/zeta", "This is the file 'zeta'.\n" },
4016
{ "A/D/gamma", "This is the file 'gamma'.\n" },
4018
{ "A/D/G/pi", "This is the file 'pi'.\n" },
4019
{ "A/D/G/rho", "Changed file 'rho'.\n" },
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 }
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));
4030
svn_pool_clear (subpool);
4032
/* Make a new txn based on the youngest revision, make some changes,
4033
and commit those changes (which makes a new youngest
4035
SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, subpool));
4036
SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
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" },
4042
SVN_ERR (svn_test__txn_script_exec (txn_root, script_entries, 2, subpool));
4044
SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
4046
/***********************************************************************/
4048
/***********************************************************************/
4050
static svn_test__tree_entry_t expected_entries[] = {
4051
/* path, contents (0 = dir) */
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" },
4057
{ "A/B/epsilon", "This is the file 'epsilon'.\n" },
4058
{ "A/B/lambda", "This is the file 'lambda'.\n" },
4060
{ "A/B/E/alpha", "This is the file 'alpha'.\n" },
4061
{ "A/B/E/beta", "This is the file 'beta'.\n" },
4064
{ "A/B/Z/zeta", "This is the file 'zeta'.\n" },
4066
{ "A/D/gamma", "This is the file 'gamma'.\n" },
4068
{ "A/D/G/pi", "This is the file 'pi'.\n" },
4069
{ "A/D/G/rho", "Changed file 'rho'.\n" },
4071
{ "A/D/G2/pi", "This is the file 'pi'.\n" },
4072
{ "A/D/G2/rho", "Changed file 'rho'.\n" },
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 }
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));
4083
svn_pool_destroy (subpool);
4085
return SVN_NO_ERROR;
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
4092
static svn_error_t *
4093
get_file_digest (unsigned char digest[APR_MD5_DIGESTSIZE],
4094
svn_fs_root_t *root,
4098
svn_stream_t *stream;
4100
const apr_size_t buf_size = 100000;
4101
apr_md5_ctx_t context;
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);
4109
/* Get a stream for the file contents. */
4110
SVN_ERR (svn_fs_file_contents (&stream, root, path, pool));
4112
/* Initialize APR MD5 context. */
4113
apr_md5_init (&context);
4117
/* "please fill the buf with bytes" */
4119
SVN_ERR (svn_stream_read (stream, buf, &len));
4121
/* Update the MD5 calculation with the data we just read. */
4122
apr_md5_update (&context, buf, len);
4124
} while (len == buf_size); /* Continue until a short read. */
4126
/* Finalize MD5 calculation. */
4127
apr_md5_final (digest, &context);
4129
return SVN_NO_ERROR;
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)
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))
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. */
4150
random_data_to_buffer (char *buf,
4156
apr_size_t num_bytes;
4160
const char *dataset = "0123456789";
4161
int dataset_size = strlen (dataset);
4165
for (i = 0; i < buf_len; i++)
4167
ds_off = my_rand (dataset_size, seed);
4168
buf[i] = dataset[ds_off];
4174
num_bytes = my_rand (buf_len / 100, seed) + 1;
4175
for (i = 0; i < num_bytes; i++)
4177
offset = my_rand (buf_len - 1, seed);
4178
ds_off = my_rand (dataset_size, seed);
4179
buf[offset] = dataset[ds_off];
4186
static svn_error_t *
4187
file_integrity_helper (apr_size_t filesize, apr_uint32_t *seed,
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;
4203
/* Create a filesystem and repository. */
4204
SVN_ERR (svn_test__create_fs (&fs, "test-repo-large-file-integrity",
4207
/* Set up our file contents string buffer. */
4208
content_buffer = apr_palloc (pool, filesize);
4210
contents.data = content_buffer;
4211
contents.len = filesize;
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
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);
4240
/* Now, let's make some edits to the beginning of our file, and
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);
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);
4267
/* How about some edits to both the beginning and the end of the
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);
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)
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);
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
4305
for (j = youngest_rev; j > 0; j--)
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);
4316
svn_pool_destroy (subpool);
4317
return SVN_NO_ERROR;
4321
static svn_error_t *
4322
medium_file_integrity (const char **msg,
4323
svn_boolean_t msg_only,
4324
svn_test_opts_t *opts,
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);
4333
return SVN_NO_ERROR;
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);
4341
static svn_error_t *
4342
large_file_integrity (const char **msg,
4343
svn_boolean_t msg_only,
4344
svn_test_opts_t *opts,
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);
4353
return SVN_NO_ERROR;
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);
4361
static svn_error_t *
4362
check_root_revision (const char **msg,
4363
svn_boolean_t msg_only,
4364
svn_test_opts_t *opts,
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);
4374
*msg = "ensure accurate storage of root node";
4377
return SVN_NO_ERROR;
4379
/* Create a filesystem and repository. */
4380
SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-root-revision",
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));
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);
4399
for (i = 0; i < 10; i++)
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
4406
apr_psprintf (subpool, "iota version %d", i + 2), subpool));
4408
SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
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);
4421
svn_pool_destroy (subpool);
4422
return SVN_NO_ERROR;
4426
struct node_created_rev_args {
4432
static svn_error_t *
4433
verify_path_revs (svn_fs_root_t *root,
4434
struct node_created_rev_args *args,
4438
apr_pool_t *subpool = svn_pool_create (pool);
4442
for (i = 0; i < num_path_revs; i++)
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' "
4451
args[i].path, rev, args[i].rev);
4454
apr_pool_destroy (subpool);
4455
return SVN_NO_ERROR;
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,
4465
apr_pool_t *subpool = svn_pool_create (pool);
4468
svn_fs_root_t *txn_root, *rev_root;
4469
svn_revnum_t youngest_rev = 0;
4471
struct node_created_rev_args path_revs[21];
4472
const char *greek_paths[21] = {
4478
/* 5 */ "A/B/lambda",
4480
/* 7 */ "A/B/E/alpha",
4481
/* 8 */ "A/B/E/beta",
4485
/* 12 */ "A/D/gamma",
4487
/* 14 */ "A/D/G/pi",
4488
/* 15 */ "A/D/G/rho",
4489
/* 16 */ "A/D/G/tau",
4491
/* 18 */ "A/D/H/chi",
4492
/* 19 */ "A/D/H/psi",
4493
/* 20 */ "A/D/H/omega",
4496
*msg = "svn_fs_node_created_rev test";
4499
return SVN_NO_ERROR;
4501
/* Initialize the paths in our args list. */
4502
for (i = 0; i < 20; i++)
4503
path_revs[i].path = greek_paths[i];
4505
/* Create a filesystem and repository. */
4506
SVN_ERR (svn_test__create_fs (&fs, "test-repo-node-created-rev",
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));
4514
/* Now, prior to committing, all these nodes should have an invalid
4515
created rev. After all, the rev has been created yet. Verify
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));
4521
/* Now commit the transaction. */
4522
SVN_ERR (svn_fs_commit_txn (NULL, &youngest_rev, txn, subpool));
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));
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.
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.
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));
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));
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));
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));
4592
/* Destroy the per-commit subpool. */
4593
svn_pool_destroy (subpool);
4595
return SVN_NO_ERROR;
4599
static svn_error_t *
4600
check_related (const char **msg,
4601
svn_boolean_t msg_only,
4602
svn_test_opts_t *opts,
4605
apr_pool_t *subpool = svn_pool_create (pool);
4608
svn_fs_root_t *txn_root, *rev_root;
4609
svn_revnum_t youngest_rev = 0;
4611
*msg = "test svn_fs_check_related";
4614
return SVN_NO_ERROR;
4616
/* Create a filesystem and repository. */
4617
SVN_ERR (svn_test__create_fs (&fs, "test-repo-check-related",
4620
/*** Step I: Build up some state in our repository through a series
4623
/* Using files because bubble-up complicates the testing. However,
4624
the algorithm itself is ambivalent about what type of node is
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.
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
4719
/*** Step II: Exhaustively verify relationship between all nodes in
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 }
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 */
4758
/* Here's the fun part. Running the tests. */
4759
for (i = 0; i < 16; i++)
4761
for (j = 0; j < 16; j++)
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;
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));
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));
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])
4782
else if (related && (! related_matrix[i][j]))
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);
4789
else if ((! related) && related_matrix[i][j])
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);
4797
svn_pool_clear (subpool);
4802
/* Destroy the subpool. */
4803
svn_pool_destroy (subpool);
4805
return SVN_NO_ERROR;
4809
static svn_error_t *
4810
canonicalize_abspath (const char **msg,
4811
svn_boolean_t msg_only,
4812
svn_test_opts_t *opts,
4816
const char *paths[21][2] =
4825
{ "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" },
4841
*msg = "test svn_fs_base__canonicalize_abspath";
4844
return SVN_NO_ERROR;
4846
for (i = 0; i < (sizeof (paths) / 2 / sizeof (const char *)); i++)
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);
4852
if ((! output) && (! actual))
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'",
4865
return SVN_NO_ERROR;
4869
static svn_error_t *
4870
branch_test (const char **msg,
4871
svn_boolean_t msg_only,
4872
svn_test_opts_t *opts,
4875
apr_pool_t *spool = svn_pool_create (pool);
4878
svn_fs_root_t *txn_root, *rev_root;
4879
svn_revnum_t youngest_rev = 0;
4881
*msg = "test complex copies (branches)";
4884
return SVN_NO_ERROR;
4886
/* Create a filesystem and repository. */
4887
SVN_ERR (svn_test__create_fs (&fs, "test-repo-branch-test",
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);
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);
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);
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);
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));
4943
svn_pool_destroy (spool);
4945
return SVN_NO_ERROR;
4949
static svn_error_t *
4950
verify_checksum (const char **msg,
4951
svn_boolean_t msg_only,
4952
svn_test_opts_t *opts,
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];
4962
/* Write a file, compare the repository's idea of its checksum
4963
against our idea of its checksum. They should be the same. */
4965
*msg = "test checksums";
4968
return SVN_NO_ERROR;
4970
str = svn_stringbuf_create ("My text editor charges me rent.", pool);
4971
apr_md5 (expected_digest, str->data, str->len);
4973
SVN_ERR (svn_test__create_fs (&fs, "test-repo-verify-checksum",
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));
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"
4987
svn_md5_digest_to_cstring (expected_digest, pool),
4988
svn_md5_digest_to_cstring (actual_digest, pool));
4990
return SVN_NO_ERROR;
4993
static svn_error_t *
4994
create_within_copy (const char **msg,
4995
svn_boolean_t msg_only,
4996
svn_test_opts_t *opts,
4999
apr_pool_t *spool = svn_pool_create (pool);
5002
svn_fs_root_t *txn_root, *rev_root;
5003
svn_revnum_t youngest_rev = 0;
5005
*msg = "create new items within a copied directory";
5008
return SVN_NO_ERROR;
5010
/* Create a filesystem and repository. */
5011
SVN_ERR (svn_test__create_fs (&fs, "test-repo-create-within-copy",
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);
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);
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);
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);
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);
5061
/* New items should have same CopyID as their parent */
5064
const char *unparsed_id;
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" },
5079
}, *node = new_nodes;
5081
SVN_ERR (svn_fs_revision_root (&rev_root, fs, youngest_rev, spool));
5084
const svn_fs_id_t *id;
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);
5094
svn_pool_clear (spool);
5097
svn_pool_destroy (spool);
5098
return SVN_NO_ERROR;
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.
5106
static svn_error_t *
5107
skip_deltas (const char **msg,
5108
svn_boolean_t msg_only,
5109
svn_test_opts_t *opts,
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);
5120
*msg = "test skip deltas";
5123
return SVN_NO_ERROR;
5125
/* Create a filesystem and repository. */
5126
SVN_ERR (svn_test__create_fs (&fs, "test-repo-skip-deltas",
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);
5138
/* Now, commit changes to the file 128 times. */
5139
while (youngest_rev <= 128)
5141
/* Append another line to the ever-growing file contents. */
5142
svn_stringbuf_appendcstr (f, one_line);
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);
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",
5162
svn_pool_destroy (subpool);
5163
return SVN_NO_ERROR;
5167
/* Trail-ish helpers for redundant_copy(). */
5170
transaction_t **txn;
5171
const char *txn_name;
5175
static svn_error_t *
5176
txn_body_get_txn (void *baton, trail_t *trail)
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);
5184
static svn_error_t *
5185
redundant_copy (const char **msg,
5186
svn_boolean_t msg_only,
5187
svn_test_opts_t *opts,
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;
5199
*msg = "ensure no-op for redundant copies";
5202
return SVN_NO_ERROR;
5204
/* Create a filesystem and repository. */
5205
SVN_ERR (svn_test__create_fs (&fs, "test-repo-redundant-copy",
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));
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));
5221
/* Now, examine the transaction. There should have been only one
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);
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));
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));
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);
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
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");
5256
return SVN_NO_ERROR;
5260
/* ------------------------------------------------------------------------ */
5262
/* The test table. */
5264
struct svn_test_descriptor_t test_funcs[] =
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),