1 /* fs-test.c --- tests for the filesystem
3 * ====================================================================
4 * Copyright (c) 2000-2007 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"
28 #include "../svn_test.h"
29 #include "../svn_test_fs.h"
31 #include "../../libsvn_fs_base/id.h"
32 #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 "private/svn_fs_util.h"
37 #include "../../libsvn_delta/delta.h"
39 #define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))
42 /*-----------------------------------------------------------------*/
44 /** The actual fs-tests called by `make check` **/
46 /* Create a filesystem. */
48 create_berkeley_filesystem(const char **msg
,
49 svn_boolean_t msg_only
,
50 svn_test_opts_t
*opts
,
55 *msg
= "svn_fs_create_berkeley";
60 /* Create and close a repository. */
61 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-create-berkeley",
68 /* Generic Berkeley DB error handler function. */
70 berkeley_error_handler(const char *errpfx
, char *msg
)
72 fprintf(stderr
, "%s%s\n", errpfx
? errpfx
: "", msg
);
76 /* Open an existing filesystem. */
78 open_berkeley_filesystem(const char **msg
,
79 svn_boolean_t msg_only
,
80 svn_test_opts_t
*opts
,
85 *msg
= "open an existing Berkeley DB filesystem";
90 /* Create and close a repository (using fs). */
91 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-open-berkeley",
94 /* Create a different fs object, and use it to re-open the
96 SVN_ERR(svn_test__fs_new(&fs2
, pool
));
97 SVN_ERR(svn_fs_open_berkeley(fs2
, "test-repo-open-berkeley"));
99 /* Provide a handler for Berkeley DB error messages. */
100 SVN_ERR(svn_fs_set_berkeley_errcall(fs2
, berkeley_error_handler
));
106 /* Set *PRESENT to true if entry NAME is present in directory PATH
107 under ROOT, else set *PRESENT to false. */
109 check_entry(svn_fs_root_t
*root
,
112 svn_boolean_t
*present
,
116 svn_fs_dirent_t
*ent
;
118 SVN_ERR(svn_fs_dir_entries(&entries
, root
, path
, pool
));
119 ent
= apr_hash_get(entries
, name
, APR_HASH_KEY_STRING
);
130 /* Return an error if entry NAME is absent in directory PATH under ROOT. */
132 check_entry_present(svn_fs_root_t
*root
, const char *path
,
133 const char *name
, apr_pool_t
*pool
)
135 svn_boolean_t present
;
136 SVN_ERR(check_entry(root
, path
, name
, &present
, pool
));
139 return svn_error_createf
140 (SVN_ERR_FS_GENERAL
, NULL
,
141 "entry \"%s\" absent when it should be present", name
);
147 /* Return an error if entry NAME is present in directory PATH under ROOT. */
149 check_entry_absent(svn_fs_root_t
*root
, const char *path
,
150 const char *name
, apr_pool_t
*pool
)
152 svn_boolean_t present
;
153 SVN_ERR(check_entry(root
, path
, name
, &present
, pool
));
156 return svn_error_createf
157 (SVN_ERR_FS_GENERAL
, NULL
,
158 "entry \"%s\" present when it should be absent", name
);
167 const svn_fs_id_t
*id
;
168 svn_boolean_t present
;
173 txn_body_check_id(void *baton
, trail_t
*trail
)
175 struct check_id_args
*args
= baton
;
176 node_revision_t
*noderev
;
179 err
= svn_fs_bdb__get_node_revision(&noderev
, args
->fs
, args
->id
,
182 if (err
&& (err
->apr_err
== SVN_ERR_FS_ID_NOT_FOUND
))
183 args
->present
= FALSE
;
185 args
->present
= TRUE
;
188 svn_string_t
*id_str
= svn_fs_unparse_id(args
->id
, trail
->pool
);
189 return svn_error_createf
190 (SVN_ERR_FS_GENERAL
, err
,
191 "error looking for node revision id \"%s\"", id_str
->data
);
193 svn_error_clear(err
);
199 /* Set *PRESENT to true if node revision ID is present in filesystem
200 FS, else set *PRESENT to false. */
202 check_id(svn_fs_t
*fs
, const svn_fs_id_t
*id
, svn_boolean_t
*present
,
205 struct check_id_args args
;
209 SVN_ERR(svn_fs_base__retry_txn(fs
, txn_body_check_id
, &args
, pool
));
220 /* Return error if node revision ID is not present in FS. */
222 check_id_present(svn_fs_t
*fs
, const svn_fs_id_t
*id
, apr_pool_t
*pool
)
224 svn_boolean_t present
;
225 SVN_ERR(check_id(fs
, id
, &present
, pool
));
229 svn_string_t
*id_str
= svn_fs_unparse_id(id
, pool
);
230 return svn_error_createf
231 (SVN_ERR_FS_GENERAL
, NULL
,
232 "node revision id \"%s\" absent when should be present",
240 /* Return error if node revision ID is present in FS. */
242 check_id_absent(svn_fs_t
*fs
, const svn_fs_id_t
*id
, apr_pool_t
*pool
)
244 svn_boolean_t present
;
245 SVN_ERR(check_id(fs
, id
, &present
, pool
));
249 svn_string_t
*id_str
= svn_fs_unparse_id(id
, pool
);
250 return svn_error_createf
251 (SVN_ERR_FS_GENERAL
, NULL
,
252 "node revision id \"%s\" present when should be absent",
260 /* Test that aborting a Subversion transaction works.
262 NOTE: This function tests internal filesystem interfaces, not just
263 the public filesystem interface. */
265 abort_txn(const char **msg
,
266 svn_boolean_t msg_only
,
267 svn_test_opts_t
*opts
,
271 svn_fs_txn_t
*txn1
, *txn2
;
272 svn_fs_root_t
*txn1_root
, *txn2_root
;
273 const char *txn1_name
, *txn2_name
;
275 *msg
= "abort a transaction";
280 /* Prepare two txns to receive the Greek tree. */
281 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-abort-txn",
283 SVN_ERR(svn_fs_begin_txn(&txn1
, fs
, 0, pool
));
284 SVN_ERR(svn_fs_begin_txn(&txn2
, fs
, 0, pool
));
285 SVN_ERR(svn_fs_txn_root(&txn1_root
, txn1
, pool
));
286 SVN_ERR(svn_fs_txn_root(&txn2_root
, txn2
, pool
));
288 /* Save their names for later. */
289 SVN_ERR(svn_fs_txn_name(&txn1_name
, txn1
, pool
));
290 SVN_ERR(svn_fs_txn_name(&txn2_name
, txn2
, pool
));
292 /* Create greek trees in them. */
293 SVN_ERR(svn_test__create_greek_tree(txn1_root
, pool
));
294 SVN_ERR(svn_test__create_greek_tree(txn2_root
, pool
));
296 /* The test is to abort txn2, while leaving txn1.
298 * After we abort txn2, we make sure that a) all of its nodes
299 * disappeared from the database, and b) none of txn1's nodes
302 * Finally, we create a third txn, and check that the name it got is
303 * different from the names of txn1 and txn2.
307 /* Yes, I really am this paranoid. */
309 /* IDs for every file in the standard Greek Tree. */
311 *t1_root_id
, *t2_root_id
,
312 *t1_iota_id
, *t2_iota_id
,
314 *t1_mu_id
, *t2_mu_id
,
316 *t1_lambda_id
, *t2_lambda_id
,
318 *t1_alpha_id
, *t2_alpha_id
,
319 *t1_beta_id
, *t2_beta_id
,
323 *t1_gamma_id
, *t2_gamma_id
,
325 *t1_chi_id
, *t2_chi_id
,
326 *t1_psi_id
, *t2_psi_id
,
327 *t1_omega_id
, *t2_omega_id
,
329 *t1_pi_id
, *t2_pi_id
,
330 *t1_rho_id
, *t2_rho_id
,
331 *t1_tau_id
, *t2_tau_id
;
333 SVN_ERR(svn_fs_node_id(&t1_root_id
, txn1_root
, "", pool
));
334 SVN_ERR(svn_fs_node_id(&t2_root_id
, txn2_root
, "", pool
));
335 SVN_ERR(svn_fs_node_id(&t1_iota_id
, txn1_root
, "iota", pool
));
336 SVN_ERR(svn_fs_node_id(&t2_iota_id
, txn2_root
, "iota", pool
));
337 SVN_ERR(svn_fs_node_id(&t1_A_id
, txn1_root
, "/A", pool
));
338 SVN_ERR(svn_fs_node_id(&t2_A_id
, txn2_root
, "/A", pool
));
339 SVN_ERR(svn_fs_node_id(&t1_mu_id
, txn1_root
, "/A/mu", pool
));
340 SVN_ERR(svn_fs_node_id(&t2_mu_id
, txn2_root
, "/A/mu", pool
));
341 SVN_ERR(svn_fs_node_id(&t1_B_id
, txn1_root
, "/A/B", pool
));
342 SVN_ERR(svn_fs_node_id(&t2_B_id
, txn2_root
, "/A/B", pool
));
343 SVN_ERR(svn_fs_node_id(&t1_lambda_id
, txn1_root
, "/A/B/lambda", pool
));
344 SVN_ERR(svn_fs_node_id(&t2_lambda_id
, txn2_root
, "/A/B/lambda", pool
));
345 SVN_ERR(svn_fs_node_id(&t1_E_id
, txn1_root
, "/A/B/E", pool
));
346 SVN_ERR(svn_fs_node_id(&t2_E_id
, txn2_root
, "/A/B/E", pool
));
347 SVN_ERR(svn_fs_node_id(&t1_alpha_id
, txn1_root
, "/A/B/E/alpha", pool
));
348 SVN_ERR(svn_fs_node_id(&t2_alpha_id
, txn2_root
, "/A/B/E/alpha", pool
));
349 SVN_ERR(svn_fs_node_id(&t1_beta_id
, txn1_root
, "/A/B/E/beta", pool
));
350 SVN_ERR(svn_fs_node_id(&t2_beta_id
, txn2_root
, "/A/B/E/beta", pool
));
351 SVN_ERR(svn_fs_node_id(&t1_F_id
, txn1_root
, "/A/B/F", pool
));
352 SVN_ERR(svn_fs_node_id(&t2_F_id
, txn2_root
, "/A/B/F", pool
));
353 SVN_ERR(svn_fs_node_id(&t1_C_id
, txn1_root
, "/A/C", pool
));
354 SVN_ERR(svn_fs_node_id(&t2_C_id
, txn2_root
, "/A/C", pool
));
355 SVN_ERR(svn_fs_node_id(&t1_D_id
, txn1_root
, "/A/D", pool
));
356 SVN_ERR(svn_fs_node_id(&t2_D_id
, txn2_root
, "/A/D", pool
));
357 SVN_ERR(svn_fs_node_id(&t1_gamma_id
, txn1_root
, "/A/D/gamma", pool
));
358 SVN_ERR(svn_fs_node_id(&t2_gamma_id
, txn2_root
, "/A/D/gamma", pool
));
359 SVN_ERR(svn_fs_node_id(&t1_H_id
, txn1_root
, "/A/D/H", pool
));
360 SVN_ERR(svn_fs_node_id(&t2_H_id
, txn2_root
, "/A/D/H", pool
));
361 SVN_ERR(svn_fs_node_id(&t1_chi_id
, txn1_root
, "/A/D/H/chi", pool
));
362 SVN_ERR(svn_fs_node_id(&t2_chi_id
, txn2_root
, "/A/D/H/chi", pool
));
363 SVN_ERR(svn_fs_node_id(&t1_psi_id
, txn1_root
, "/A/D/H/psi", pool
));
364 SVN_ERR(svn_fs_node_id(&t2_psi_id
, txn2_root
, "/A/D/H/psi", pool
));
365 SVN_ERR(svn_fs_node_id(&t1_omega_id
, txn1_root
, "/A/D/H/omega", pool
));
366 SVN_ERR(svn_fs_node_id(&t2_omega_id
, txn2_root
, "/A/D/H/omega", pool
));
367 SVN_ERR(svn_fs_node_id(&t1_G_id
, txn1_root
, "/A/D/G", pool
));
368 SVN_ERR(svn_fs_node_id(&t2_G_id
, txn2_root
, "/A/D/G", pool
));
369 SVN_ERR(svn_fs_node_id(&t1_pi_id
, txn1_root
, "/A/D/G/pi", pool
));
370 SVN_ERR(svn_fs_node_id(&t2_pi_id
, txn2_root
, "/A/D/G/pi", pool
));
371 SVN_ERR(svn_fs_node_id(&t1_rho_id
, txn1_root
, "/A/D/G/rho", pool
));
372 SVN_ERR(svn_fs_node_id(&t2_rho_id
, txn2_root
, "/A/D/G/rho", pool
));
373 SVN_ERR(svn_fs_node_id(&t1_tau_id
, txn1_root
, "/A/D/G/tau", pool
));
374 SVN_ERR(svn_fs_node_id(&t2_tau_id
, txn2_root
, "/A/D/G/tau", pool
));
376 /* Abort just txn2. */
377 SVN_ERR(svn_fs_abort_txn(txn2
, pool
));
379 /* Now test that all the nodes in txn2 at the time of the abort
380 * are gone, but all of the ones in txn1 are still there.
383 /* Check that every node rev in t2 has vanished from the fs. */
384 SVN_ERR(check_id_absent(fs
, t2_root_id
, pool
));
385 SVN_ERR(check_id_absent(fs
, t2_iota_id
, pool
));
386 SVN_ERR(check_id_absent(fs
, t2_A_id
, pool
));
387 SVN_ERR(check_id_absent(fs
, t2_mu_id
, pool
));
388 SVN_ERR(check_id_absent(fs
, t2_B_id
, pool
));
389 SVN_ERR(check_id_absent(fs
, t2_lambda_id
, pool
));
390 SVN_ERR(check_id_absent(fs
, t2_E_id
, pool
));
391 SVN_ERR(check_id_absent(fs
, t2_alpha_id
, pool
));
392 SVN_ERR(check_id_absent(fs
, t2_beta_id
, pool
));
393 SVN_ERR(check_id_absent(fs
, t2_F_id
, pool
));
394 SVN_ERR(check_id_absent(fs
, t2_C_id
, pool
));
395 SVN_ERR(check_id_absent(fs
, t2_D_id
, pool
));
396 SVN_ERR(check_id_absent(fs
, t2_gamma_id
, pool
));
397 SVN_ERR(check_id_absent(fs
, t2_H_id
, pool
));
398 SVN_ERR(check_id_absent(fs
, t2_chi_id
, pool
));
399 SVN_ERR(check_id_absent(fs
, t2_psi_id
, pool
));
400 SVN_ERR(check_id_absent(fs
, t2_omega_id
, pool
));
401 SVN_ERR(check_id_absent(fs
, t2_G_id
, pool
));
402 SVN_ERR(check_id_absent(fs
, t2_pi_id
, pool
));
403 SVN_ERR(check_id_absent(fs
, t2_rho_id
, pool
));
404 SVN_ERR(check_id_absent(fs
, t2_tau_id
, pool
));
406 /* Check that every node rev in t1 is still in the fs. */
407 SVN_ERR(check_id_present(fs
, t1_root_id
, pool
));
408 SVN_ERR(check_id_present(fs
, t1_iota_id
, pool
));
409 SVN_ERR(check_id_present(fs
, t1_A_id
, pool
));
410 SVN_ERR(check_id_present(fs
, t1_mu_id
, pool
));
411 SVN_ERR(check_id_present(fs
, t1_B_id
, pool
));
412 SVN_ERR(check_id_present(fs
, t1_lambda_id
, pool
));
413 SVN_ERR(check_id_present(fs
, t1_E_id
, pool
));
414 SVN_ERR(check_id_present(fs
, t1_alpha_id
, pool
));
415 SVN_ERR(check_id_present(fs
, t1_beta_id
, pool
));
416 SVN_ERR(check_id_present(fs
, t1_F_id
, pool
));
417 SVN_ERR(check_id_present(fs
, t1_C_id
, pool
));
418 SVN_ERR(check_id_present(fs
, t1_D_id
, pool
));
419 SVN_ERR(check_id_present(fs
, t1_gamma_id
, pool
));
420 SVN_ERR(check_id_present(fs
, t1_H_id
, pool
));
421 SVN_ERR(check_id_present(fs
, t1_chi_id
, pool
));
422 SVN_ERR(check_id_present(fs
, t1_psi_id
, pool
));
423 SVN_ERR(check_id_present(fs
, t1_omega_id
, pool
));
424 SVN_ERR(check_id_present(fs
, t1_G_id
, pool
));
425 SVN_ERR(check_id_present(fs
, t1_pi_id
, pool
));
426 SVN_ERR(check_id_present(fs
, t1_rho_id
, pool
));
427 SVN_ERR(check_id_present(fs
, t1_tau_id
, pool
));
430 /* Test that txn2 itself is gone, by trying to open it. */
432 svn_fs_txn_t
*txn2_again
;
435 err
= svn_fs_open_txn(&txn2_again
, fs
, txn2_name
, pool
);
436 if (err
&& (err
->apr_err
!= SVN_ERR_FS_NO_SUCH_TRANSACTION
))
438 return svn_error_create
439 (SVN_ERR_FS_GENERAL
, err
,
440 "opening non-existent txn got wrong error");
444 return svn_error_create
445 (SVN_ERR_FS_GENERAL
, NULL
,
446 "opening non-existent txn failed to get error");
448 svn_error_clear(err
);
451 /* Test that txn names are not recycled, by opening a new txn. */
454 const char *txn3_name
;
456 SVN_ERR(svn_fs_begin_txn(&txn3
, fs
, 0, pool
));
457 SVN_ERR(svn_fs_txn_name(&txn3_name
, txn3
, pool
));
459 if ((strcmp(txn3_name
, txn2_name
) == 0)
460 || (strcmp(txn3_name
, txn1_name
) == 0))
462 return svn_error_createf
463 (SVN_ERR_FS_GENERAL
, NULL
,
464 "txn name \"%s\" was recycled", txn3_name
);
468 /* Test that aborting a txn that's already committed fails. */
471 const char *txn4_name
;
472 svn_revnum_t new_rev
;
473 const char *conflict
;
476 SVN_ERR(svn_fs_begin_txn(&txn4
, fs
, 0, pool
));
477 SVN_ERR(svn_fs_txn_name(&txn4_name
, txn4
, pool
));
478 SVN_ERR(svn_fs_commit_txn(&conflict
, &new_rev
, txn4
, pool
));
479 err
= svn_fs_abort_txn(txn4
, pool
);
481 return svn_error_create
482 (SVN_ERR_FS_GENERAL
, NULL
,
483 "expected error trying to abort a committed txn; got none");
484 else if (err
->apr_err
!= SVN_ERR_FS_TRANSACTION_NOT_MUTABLE
)
485 return svn_error_create
486 (SVN_ERR_FS_GENERAL
, err
,
487 "got an unexpected error trying to abort a committed txn");
489 svn_error_clear(err
);
495 /* This tests deleting of mutable nodes. We build a tree in a
496 * transaction, then try to delete various items in the tree. We
497 * never commit the tree, so every entry being deleted points to a
500 * ### todo: this test was written before commits worked. It might
501 * now be worthwhile to combine it with delete().
504 delete_mutables(const char **msg
,
505 svn_boolean_t msg_only
,
506 svn_test_opts_t
*opts
,
511 svn_fs_root_t
*txn_root
;
514 *msg
= "delete mutable nodes from directories";
519 /* Prepare a txn to receive the greek tree. */
520 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-del-from-dir",
522 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, 0, pool
));
523 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
525 /* Create the greek tree. */
526 SVN_ERR(svn_test__create_greek_tree(txn_root
, pool
));
528 /* Baby, it's time to test like you've never tested before. We do
529 * the following, in this order:
531 * 1. Delete a single file somewhere, succeed.
532 * 2. Delete two files of three, then make sure the third remains.
533 * 3. Delete the third and last file.
534 * 4. Try again to delete the dir, succeed.
535 * 5. Delete one of the natively empty dirs, succeed.
536 * 6. Try to delete root, fail.
537 * 7. Try to delete a top-level file, succeed.
539 * Specifically, that's:
541 * 1. Delete A/D/gamma.
542 * 2. Delete A/D/G/pi, A/D/G/rho.
543 * 3. Delete A/D/G/tau.
544 * 4. Try again to delete A/D/G, succeed.
546 * 6. Try to delete /, fail.
547 * 7. Try to delete iota, succeed.
549 * Before and after each deletion or attempted deletion, we probe
550 * the affected directory, to make sure everything is as it should
556 const svn_fs_id_t
*gamma_id
;
557 SVN_ERR(svn_fs_node_id(&gamma_id
, txn_root
, "A/D/gamma", pool
));
559 SVN_ERR(check_entry_present(txn_root
, "A/D", "gamma", pool
));
560 SVN_ERR(check_id_present(fs
, gamma_id
, pool
));
562 SVN_ERR(svn_fs_delete(txn_root
, "A/D/gamma", pool
));
564 SVN_ERR(check_entry_absent(txn_root
, "A/D", "gamma", pool
));
565 SVN_ERR(check_id_absent(fs
, gamma_id
, pool
));
570 const svn_fs_id_t
*pi_id
, *rho_id
, *tau_id
;
571 SVN_ERR(svn_fs_node_id(&pi_id
, txn_root
, "A/D/G/pi", pool
));
572 SVN_ERR(svn_fs_node_id(&rho_id
, txn_root
, "A/D/G/rho", pool
));
573 SVN_ERR(svn_fs_node_id(&tau_id
, txn_root
, "A/D/G/tau", pool
));
575 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "pi", pool
));
576 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "rho", pool
));
577 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
578 SVN_ERR(check_id_present(fs
, pi_id
, pool
));
579 SVN_ERR(check_id_present(fs
, rho_id
, pool
));
580 SVN_ERR(check_id_present(fs
, tau_id
, pool
));
582 SVN_ERR(svn_fs_delete(txn_root
, "A/D/G/pi", pool
));
584 SVN_ERR(check_entry_absent(txn_root
, "A/D/G", "pi", pool
));
585 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "rho", pool
));
586 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
587 SVN_ERR(check_id_absent(fs
, pi_id
, pool
));
588 SVN_ERR(check_id_present(fs
, rho_id
, pool
));
589 SVN_ERR(check_id_present(fs
, tau_id
, pool
));
591 SVN_ERR(svn_fs_delete(txn_root
, "A/D/G/rho", pool
));
593 SVN_ERR(check_entry_absent(txn_root
, "A/D/G", "pi", pool
));
594 SVN_ERR(check_entry_absent(txn_root
, "A/D/G", "rho", pool
));
595 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
596 SVN_ERR(check_id_absent(fs
, pi_id
, pool
));
597 SVN_ERR(check_id_absent(fs
, rho_id
, pool
));
598 SVN_ERR(check_id_present(fs
, tau_id
, pool
));
603 const svn_fs_id_t
*tau_id
;
604 SVN_ERR(svn_fs_node_id(&tau_id
, txn_root
, "A/D/G/tau", pool
));
606 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
607 SVN_ERR(check_id_present(fs
, tau_id
, pool
));
609 SVN_ERR(svn_fs_delete(txn_root
, "A/D/G/tau", pool
));
611 SVN_ERR(check_entry_absent(txn_root
, "A/D/G", "tau", pool
));
612 SVN_ERR(check_id_absent(fs
, tau_id
, pool
));
617 const svn_fs_id_t
*G_id
;
618 SVN_ERR(svn_fs_node_id(&G_id
, txn_root
, "A/D/G", pool
));
620 SVN_ERR(check_entry_present(txn_root
, "A/D", "G", pool
));
621 SVN_ERR(check_id_present(fs
, G_id
, pool
));
623 SVN_ERR(svn_fs_delete(txn_root
, "A/D/G", pool
)); /* succeed */
625 SVN_ERR(check_entry_absent(txn_root
, "A/D", "G", pool
));
626 SVN_ERR(check_id_absent(fs
, G_id
, pool
));
631 const svn_fs_id_t
*C_id
;
632 SVN_ERR(svn_fs_node_id(&C_id
, txn_root
, "A/C", pool
));
634 SVN_ERR(check_entry_present(txn_root
, "A", "C", pool
));
635 SVN_ERR(check_id_present(fs
, C_id
, pool
));
637 SVN_ERR(svn_fs_delete(txn_root
, "A/C", pool
));
639 SVN_ERR(check_entry_absent(txn_root
, "A", "C", pool
));
640 SVN_ERR(check_id_absent(fs
, C_id
, pool
));
645 const svn_fs_id_t
*root_id
;
646 SVN_ERR(svn_fs_node_id(&root_id
, txn_root
, "", pool
));
648 err
= svn_fs_delete(txn_root
, "", pool
);
650 if (err
&& (err
->apr_err
!= SVN_ERR_FS_ROOT_DIR
))
652 return svn_error_createf
653 (SVN_ERR_FS_GENERAL
, err
,
654 "deleting root directory got wrong error");
658 return svn_error_createf
659 (SVN_ERR_FS_GENERAL
, NULL
,
660 "deleting root directory failed to get error");
662 svn_error_clear(err
);
664 SVN_ERR(check_id_present(fs
, root_id
, pool
));
669 const svn_fs_id_t
*iota_id
;
670 SVN_ERR(svn_fs_node_id(&iota_id
, txn_root
, "iota", pool
));
672 SVN_ERR(check_entry_present(txn_root
, "", "iota", pool
));
673 SVN_ERR(check_id_present(fs
, iota_id
, pool
));
675 SVN_ERR(svn_fs_delete(txn_root
, "iota", pool
));
677 SVN_ERR(check_entry_absent(txn_root
, "", "iota", pool
));
678 SVN_ERR(check_id_absent(fs
, iota_id
, pool
));
685 /* This tests deleting in general.
687 * ### todo: this test was written after (and independently of)
688 * delete_mutables(). It might be worthwhile to combine them.
691 delete(const char **msg
,
692 svn_boolean_t msg_only
,
693 svn_test_opts_t
*opts
,
698 svn_fs_root_t
*txn_root
;
699 svn_revnum_t new_rev
;
701 *msg
= "delete nodes tree";
706 /* This function tests 5 cases:
708 * 1. Delete mutable file.
709 * 2. Delete mutable directory.
710 * 3. Delete mutable directory with immutable nodes.
711 * 4. Delete immutable file.
712 * 5. Delete immutable directory.
715 /* Prepare a txn to receive the greek tree. */
716 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-del-tree",
718 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, 0, pool
));
719 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
721 /* Create the greek tree. */
722 SVN_ERR(svn_test__create_greek_tree(txn_root
, pool
));
724 /* 1. Delete mutable file. */
726 const svn_fs_id_t
*iota_id
, *gamma_id
;
727 static svn_test__tree_entry_t expected_entries
[] = {
728 /* path, contents (0 = dir) */
730 { "A/mu", "This is the file 'mu'.\n" },
732 { "A/B/lambda", "This is the file 'lambda'.\n" },
734 { "A/B/E/alpha", "This is the file 'alpha'.\n" },
735 { "A/B/E/beta", "This is the file 'beta'.\n" },
740 { "A/D/G/pi", "This is the file 'pi'.\n" },
741 { "A/D/G/rho", "This is the file 'rho'.\n" },
742 { "A/D/G/tau", "This is the file 'tau'.\n" },
744 { "A/D/H/chi", "This is the file 'chi'.\n" },
745 { "A/D/H/psi", "This is the file 'psi'.\n" },
746 { "A/D/H/omega", "This is the file 'omega'.\n" }
749 /* Check nodes revision ID is gone. */
750 SVN_ERR(svn_fs_node_id(&iota_id
, txn_root
, "iota", pool
));
751 SVN_ERR(svn_fs_node_id(&gamma_id
, txn_root
, "A/D/gamma", pool
));
753 SVN_ERR(check_entry_present(txn_root
, "", "iota", pool
));
754 SVN_ERR(check_id_present(fs
, iota_id
, pool
));
755 SVN_ERR(check_id_present(fs
, gamma_id
, pool
));
757 /* Try deleting mutable files. */
758 SVN_ERR(svn_fs_delete(txn_root
, "iota", pool
));
759 SVN_ERR(svn_fs_delete(txn_root
, "A/D/gamma", pool
));
760 SVN_ERR(check_entry_absent(txn_root
, "", "iota", pool
));
761 SVN_ERR(check_entry_absent(txn_root
, "A/D", "gamma", pool
));
762 SVN_ERR(check_id_absent(fs
, iota_id
, pool
));
763 SVN_ERR(check_id_absent(fs
, gamma_id
, pool
));
765 /* Validate the tree. */
766 SVN_ERR(svn_test__validate_tree(txn_root
, expected_entries
, 18, pool
));
768 /* Abort transaction. */
769 SVN_ERR(svn_fs_abort_txn(txn
, pool
));
771 /* 2. Delete mutable directory. */
773 /* Prepare a txn to receive the greek tree. */
774 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, 0, pool
));
775 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
777 /* Create the greek tree. */
778 SVN_ERR(svn_test__create_greek_tree(txn_root
, pool
));
781 const svn_fs_id_t
*A_id
, *mu_id
, *B_id
, *lambda_id
, *E_id
, *alpha_id
,
782 *beta_id
, *F_id
, *C_id
, *D_id
, *gamma_id
, *H_id
, *chi_id
,
783 *psi_id
, *omega_id
, *G_id
, *pi_id
, *rho_id
, *tau_id
;
785 /* Check nodes revision ID is gone. */
786 SVN_ERR(svn_fs_node_id(&A_id
, txn_root
, "/A", pool
));
787 SVN_ERR(check_entry_present(txn_root
, "", "A", pool
));
788 SVN_ERR(svn_fs_node_id(&mu_id
, txn_root
, "/A/mu", pool
));
789 SVN_ERR(check_entry_present(txn_root
, "A", "mu", pool
));
790 SVN_ERR(svn_fs_node_id(&B_id
, txn_root
, "/A/B", pool
));
791 SVN_ERR(check_entry_present(txn_root
, "A", "B", pool
));
792 SVN_ERR(svn_fs_node_id(&lambda_id
, txn_root
, "/A/B/lambda", pool
));
793 SVN_ERR(check_entry_present(txn_root
, "A/B", "lambda", pool
));
794 SVN_ERR(svn_fs_node_id(&E_id
, txn_root
, "/A/B/E", pool
));
795 SVN_ERR(check_entry_present(txn_root
, "A/B", "E", pool
));
796 SVN_ERR(svn_fs_node_id(&alpha_id
, txn_root
, "/A/B/E/alpha", pool
));
797 SVN_ERR(check_entry_present(txn_root
, "A/B/E", "alpha", pool
));
798 SVN_ERR(svn_fs_node_id(&beta_id
, txn_root
, "/A/B/E/beta", pool
));
799 SVN_ERR(check_entry_present(txn_root
, "A/B/E", "beta", pool
));
800 SVN_ERR(svn_fs_node_id(&F_id
, txn_root
, "/A/B/F", pool
));
801 SVN_ERR(check_entry_present(txn_root
, "A/B", "F", pool
));
802 SVN_ERR(svn_fs_node_id(&C_id
, txn_root
, "/A/C", pool
));
803 SVN_ERR(check_entry_present(txn_root
, "A", "C", pool
));
804 SVN_ERR(svn_fs_node_id(&D_id
, txn_root
, "/A/D", pool
));
805 SVN_ERR(check_entry_present(txn_root
, "A", "D", pool
));
806 SVN_ERR(svn_fs_node_id(&gamma_id
, txn_root
, "/A/D/gamma", pool
));
807 SVN_ERR(check_entry_present(txn_root
, "A/D", "gamma", pool
));
808 SVN_ERR(svn_fs_node_id(&H_id
, txn_root
, "/A/D/H", pool
));
809 SVN_ERR(check_entry_present(txn_root
, "A/D", "H", pool
));
810 SVN_ERR(svn_fs_node_id(&chi_id
, txn_root
, "/A/D/H/chi", pool
));
811 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "chi", pool
));
812 SVN_ERR(svn_fs_node_id(&psi_id
, txn_root
, "/A/D/H/psi", pool
));
813 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "psi", pool
));
814 SVN_ERR(svn_fs_node_id(&omega_id
, txn_root
, "/A/D/H/omega", pool
));
815 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "omega", pool
));
816 SVN_ERR(svn_fs_node_id(&G_id
, txn_root
, "/A/D/G", pool
));
817 SVN_ERR(check_entry_present(txn_root
, "A/D", "G", pool
));
818 SVN_ERR(svn_fs_node_id(&pi_id
, txn_root
, "/A/D/G/pi", pool
));
819 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "pi", pool
));
820 SVN_ERR(svn_fs_node_id(&rho_id
, txn_root
, "/A/D/G/rho", pool
));
821 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "rho", pool
));
822 SVN_ERR(svn_fs_node_id(&tau_id
, txn_root
, "/A/D/G/tau", pool
));
823 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
825 /* Try deleting a mutable empty dir. */
826 SVN_ERR(svn_fs_delete(txn_root
, "A/C", pool
));
827 SVN_ERR(svn_fs_delete(txn_root
, "A/B/F", pool
));
828 SVN_ERR(check_entry_absent(txn_root
, "A", "C", pool
));
829 SVN_ERR(check_entry_absent(txn_root
, "A/B", "F", pool
));
830 SVN_ERR(check_id_absent(fs
, C_id
, pool
));
831 SVN_ERR(check_id_absent(fs
, F_id
, pool
));
833 /* Now delete a mutable non-empty dir. */
834 SVN_ERR(svn_fs_delete(txn_root
, "A", pool
));
835 SVN_ERR(check_entry_absent(txn_root
, "", "A", pool
));
836 SVN_ERR(check_id_absent(fs
, A_id
, pool
));
837 SVN_ERR(check_id_absent(fs
, mu_id
, pool
));
838 SVN_ERR(check_id_absent(fs
, B_id
, pool
));
839 SVN_ERR(check_id_absent(fs
, lambda_id
, pool
));
840 SVN_ERR(check_id_absent(fs
, E_id
, pool
));
841 SVN_ERR(check_id_absent(fs
, alpha_id
, pool
));
842 SVN_ERR(check_id_absent(fs
, beta_id
, pool
));
843 SVN_ERR(check_id_absent(fs
, D_id
, pool
));
844 SVN_ERR(check_id_absent(fs
, gamma_id
, pool
));
845 SVN_ERR(check_id_absent(fs
, H_id
, pool
));
846 SVN_ERR(check_id_absent(fs
, chi_id
, pool
));
847 SVN_ERR(check_id_absent(fs
, psi_id
, pool
));
848 SVN_ERR(check_id_absent(fs
, omega_id
, pool
));
849 SVN_ERR(check_id_absent(fs
, G_id
, pool
));
850 SVN_ERR(check_id_absent(fs
, pi_id
, pool
));
851 SVN_ERR(check_id_absent(fs
, rho_id
, pool
));
852 SVN_ERR(check_id_absent(fs
, tau_id
, pool
));
854 /* Validate the tree. */
856 static svn_test__tree_entry_t expected_entries
[] = {
857 /* path, contents (0 = dir) */
858 { "iota", "This is the file 'iota'.\n" } };
859 SVN_ERR(svn_test__validate_tree(txn_root
, expected_entries
, 1, pool
));
863 /* Abort transaction. */
864 SVN_ERR(svn_fs_abort_txn(txn
, pool
));
866 /* 3. Delete mutable directory with immutable nodes. */
868 /* Prepare a txn to receive the greek tree. */
869 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, 0, pool
));
870 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
872 /* Create the greek tree. */
873 SVN_ERR(svn_test__create_greek_tree(txn_root
, pool
));
875 /* Commit the greek tree. */
876 SVN_ERR(svn_fs_commit_txn(NULL
, &new_rev
, txn
, pool
));
878 /* Create new transaction. */
879 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, new_rev
, pool
));
880 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
883 const svn_fs_id_t
*A_id
, *mu_id
, *B_id
, *lambda_id
, *E_id
, *alpha_id
,
884 *beta_id
, *F_id
, *C_id
, *D_id
, *gamma_id
, *H_id
, *chi_id
,
885 *psi_id
, *omega_id
, *G_id
, *pi_id
, *rho_id
, *tau_id
, *sigma_id
;
887 /* Create A/D/G/sigma. This makes all components of A/D/G
889 SVN_ERR(svn_fs_make_file(txn_root
, "A/D/G/sigma", pool
));
890 SVN_ERR(svn_test__set_file_contents(txn_root
, "A/D/G/sigma",
891 "This is another file 'sigma'.\n", pool
));
893 /* Check that mutable node-revision-IDs are removed and immutable
895 SVN_ERR(svn_fs_node_id(&A_id
, txn_root
, "/A", pool
));
896 SVN_ERR(check_entry_present(txn_root
, "", "A", pool
));
897 SVN_ERR(svn_fs_node_id(&mu_id
, txn_root
, "/A/mu", pool
));
898 SVN_ERR(check_entry_present(txn_root
, "A", "mu", pool
));
899 SVN_ERR(svn_fs_node_id(&B_id
, txn_root
, "/A/B", pool
));
900 SVN_ERR(check_entry_present(txn_root
, "A", "B", pool
));
901 SVN_ERR(svn_fs_node_id(&lambda_id
, txn_root
, "/A/B/lambda", pool
));
902 SVN_ERR(check_entry_present(txn_root
, "A/B", "lambda", pool
));
903 SVN_ERR(svn_fs_node_id(&E_id
, txn_root
, "/A/B/E", pool
));
904 SVN_ERR(check_entry_present(txn_root
, "A/B", "E", pool
));
905 SVN_ERR(svn_fs_node_id(&alpha_id
, txn_root
, "/A/B/E/alpha", pool
));
906 SVN_ERR(check_entry_present(txn_root
, "A/B/E", "alpha", pool
));
907 SVN_ERR(svn_fs_node_id(&beta_id
, txn_root
, "/A/B/E/beta", pool
));
908 SVN_ERR(check_entry_present(txn_root
, "A/B/E", "beta", pool
));
909 SVN_ERR(svn_fs_node_id(&F_id
, txn_root
, "/A/B/F", pool
));
910 SVN_ERR(check_entry_present(txn_root
, "A/B", "F", pool
));
911 SVN_ERR(svn_fs_node_id(&C_id
, txn_root
, "/A/C", pool
));
912 SVN_ERR(check_entry_present(txn_root
, "A", "C", pool
));
913 SVN_ERR(svn_fs_node_id(&D_id
, txn_root
, "/A/D", pool
));
914 SVN_ERR(check_entry_present(txn_root
, "A", "D", pool
));
915 SVN_ERR(svn_fs_node_id(&gamma_id
, txn_root
, "/A/D/gamma", pool
));
916 SVN_ERR(check_entry_present(txn_root
, "A/D", "gamma", pool
));
917 SVN_ERR(svn_fs_node_id(&H_id
, txn_root
, "/A/D/H", pool
));
918 SVN_ERR(check_entry_present(txn_root
, "A/D", "H", pool
));
919 SVN_ERR(svn_fs_node_id(&chi_id
, txn_root
, "/A/D/H/chi", pool
));
920 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "chi", pool
));
921 SVN_ERR(svn_fs_node_id(&psi_id
, txn_root
, "/A/D/H/psi", pool
));
922 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "psi", pool
));
923 SVN_ERR(svn_fs_node_id(&omega_id
, txn_root
, "/A/D/H/omega", pool
));
924 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "omega", pool
));
925 SVN_ERR(svn_fs_node_id(&G_id
, txn_root
, "/A/D/G", pool
));
926 SVN_ERR(check_entry_present(txn_root
, "A/D", "G", pool
));
927 SVN_ERR(svn_fs_node_id(&pi_id
, txn_root
, "/A/D/G/pi", pool
));
928 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "pi", pool
));
929 SVN_ERR(svn_fs_node_id(&rho_id
, txn_root
, "/A/D/G/rho", pool
));
930 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "rho", pool
));
931 SVN_ERR(svn_fs_node_id(&tau_id
, txn_root
, "/A/D/G/tau", pool
));
932 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
933 SVN_ERR(svn_fs_node_id(&sigma_id
, txn_root
, "/A/D/G/sigma", pool
));
934 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "sigma", pool
));
937 SVN_ERR(svn_fs_delete(txn_root
, "A", pool
));
938 SVN_ERR(check_entry_absent(txn_root
, "", "A", pool
));
939 SVN_ERR(check_id_absent(fs
, A_id
, pool
));
940 SVN_ERR(check_id_present(fs
, mu_id
, pool
));
941 SVN_ERR(check_id_present(fs
, B_id
, pool
));
942 SVN_ERR(check_id_present(fs
, lambda_id
, pool
));
943 SVN_ERR(check_id_present(fs
, E_id
, pool
));
944 SVN_ERR(check_id_present(fs
, alpha_id
, pool
));
945 SVN_ERR(check_id_present(fs
, beta_id
, pool
));
946 SVN_ERR(check_id_present(fs
, F_id
, pool
));
947 SVN_ERR(check_id_present(fs
, C_id
, pool
));
948 SVN_ERR(check_id_absent(fs
, D_id
, pool
));
949 SVN_ERR(check_id_present(fs
, gamma_id
, pool
));
950 SVN_ERR(check_id_present(fs
, H_id
, pool
));
951 SVN_ERR(check_id_present(fs
, chi_id
, pool
));
952 SVN_ERR(check_id_present(fs
, psi_id
, pool
));
953 SVN_ERR(check_id_present(fs
, omega_id
, pool
));
954 SVN_ERR(check_id_absent(fs
, G_id
, pool
));
955 SVN_ERR(check_id_present(fs
, pi_id
, pool
));
956 SVN_ERR(check_id_present(fs
, rho_id
, pool
));
957 SVN_ERR(check_id_present(fs
, tau_id
, pool
));
958 SVN_ERR(check_id_absent(fs
, sigma_id
, pool
));
960 /* Validate the tree. */
962 static svn_test__tree_entry_t expected_entries
[] = {
963 /* path, contents (0 = dir) */
964 { "iota", "This is the file 'iota'.\n" }
967 SVN_ERR(svn_test__validate_tree(txn_root
, expected_entries
, 1, pool
));
971 /* Abort transaction. */
972 SVN_ERR(svn_fs_abort_txn(txn
, pool
));
974 /* 4. Delete immutable file. */
976 /* Create new transaction. */
977 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, new_rev
, pool
));
978 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
981 const svn_fs_id_t
*iota_id
, *gamma_id
;
983 /* Check nodes revision ID is present. */
984 SVN_ERR(svn_fs_node_id(&iota_id
, txn_root
, "iota", pool
));
985 SVN_ERR(svn_fs_node_id(&gamma_id
, txn_root
, "A/D/gamma", pool
));
986 SVN_ERR(check_entry_present(txn_root
, "", "iota", pool
));
987 SVN_ERR(check_entry_present(txn_root
, "A/D", "gamma", pool
));
988 SVN_ERR(check_id_present(fs
, iota_id
, pool
));
989 SVN_ERR(check_id_present(fs
, gamma_id
, pool
));
991 /* Delete some files. */
992 SVN_ERR(svn_fs_delete(txn_root
, "iota", pool
));
993 SVN_ERR(svn_fs_delete(txn_root
, "A/D/gamma", pool
));
994 SVN_ERR(check_entry_absent(txn_root
, "", "iota", pool
));
995 SVN_ERR(check_entry_absent(txn_root
, "A/D", "iota", pool
));
996 SVN_ERR(check_id_present(fs
, iota_id
, pool
));
997 SVN_ERR(check_id_present(fs
, gamma_id
, pool
));
999 /* Validate the tree. */
1001 static svn_test__tree_entry_t expected_entries
[] = {
1002 /* path, contents (0 = dir) */
1004 { "A/mu", "This is the file 'mu'.\n" },
1006 { "A/B/lambda", "This is the file 'lambda'.\n" },
1008 { "A/B/E/alpha", "This is the file 'alpha'.\n" },
1009 { "A/B/E/beta", "This is the file 'beta'.\n" },
1014 { "A/D/G/pi", "This is the file 'pi'.\n" },
1015 { "A/D/G/rho", "This is the file 'rho'.\n" },
1016 { "A/D/G/tau", "This is the file 'tau'.\n" },
1018 { "A/D/H/chi", "This is the file 'chi'.\n" },
1019 { "A/D/H/psi", "This is the file 'psi'.\n" },
1020 { "A/D/H/omega", "This is the file 'omega'.\n" }
1022 SVN_ERR(svn_test__validate_tree(txn_root
, expected_entries
, 18, pool
));
1026 /* Abort transaction. */
1027 SVN_ERR(svn_fs_abort_txn(txn
, pool
));
1029 /* 5. Delete immutable directory. */
1031 /* Create new transaction. */
1032 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, new_rev
, pool
));
1033 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
1036 const svn_fs_id_t
*A_id
, *mu_id
, *B_id
, *lambda_id
, *E_id
, *alpha_id
,
1037 *beta_id
, *F_id
, *C_id
, *D_id
, *gamma_id
, *H_id
, *chi_id
,
1038 *psi_id
, *omega_id
, *G_id
, *pi_id
, *rho_id
, *tau_id
;
1040 /* Check nodes revision ID is present. */
1041 SVN_ERR(svn_fs_node_id(&A_id
, txn_root
, "/A", pool
));
1042 SVN_ERR(check_entry_present(txn_root
, "", "A", pool
));
1043 SVN_ERR(svn_fs_node_id(&mu_id
, txn_root
, "/A/mu", pool
));
1044 SVN_ERR(check_entry_present(txn_root
, "A", "mu", pool
));
1045 SVN_ERR(svn_fs_node_id(&B_id
, txn_root
, "/A/B", pool
));
1046 SVN_ERR(check_entry_present(txn_root
, "A", "B", pool
));
1047 SVN_ERR(svn_fs_node_id(&lambda_id
, txn_root
, "/A/B/lambda", pool
));
1048 SVN_ERR(check_entry_present(txn_root
, "A/B", "lambda", pool
));
1049 SVN_ERR(svn_fs_node_id(&E_id
, txn_root
, "/A/B/E", pool
));
1050 SVN_ERR(check_entry_present(txn_root
, "A/B", "E", pool
));
1051 SVN_ERR(svn_fs_node_id(&alpha_id
, txn_root
, "/A/B/E/alpha", pool
));
1052 SVN_ERR(check_entry_present(txn_root
, "A/B/E", "alpha", pool
));
1053 SVN_ERR(svn_fs_node_id(&beta_id
, txn_root
, "/A/B/E/beta", pool
));
1054 SVN_ERR(check_entry_present(txn_root
, "A/B/E", "beta", pool
));
1055 SVN_ERR(svn_fs_node_id(&F_id
, txn_root
, "/A/B/F", pool
));
1056 SVN_ERR(check_entry_present(txn_root
, "A/B", "F", pool
));
1057 SVN_ERR(svn_fs_node_id(&C_id
, txn_root
, "/A/C", pool
));
1058 SVN_ERR(check_entry_present(txn_root
, "A", "C", pool
));
1059 SVN_ERR(svn_fs_node_id(&D_id
, txn_root
, "/A/D", pool
));
1060 SVN_ERR(check_entry_present(txn_root
, "A", "D", pool
));
1061 SVN_ERR(svn_fs_node_id(&gamma_id
, txn_root
, "/A/D/gamma", pool
));
1062 SVN_ERR(check_entry_present(txn_root
, "A/D", "gamma", pool
));
1063 SVN_ERR(svn_fs_node_id(&H_id
, txn_root
, "/A/D/H", pool
));
1064 SVN_ERR(check_entry_present(txn_root
, "A/D", "H", pool
));
1065 SVN_ERR(svn_fs_node_id(&chi_id
, txn_root
, "/A/D/H/chi", pool
));
1066 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "chi", pool
));
1067 SVN_ERR(svn_fs_node_id(&psi_id
, txn_root
, "/A/D/H/psi", pool
));
1068 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "psi", pool
));
1069 SVN_ERR(svn_fs_node_id(&omega_id
, txn_root
, "/A/D/H/omega", pool
));
1070 SVN_ERR(check_entry_present(txn_root
, "A/D/H", "omega", pool
));
1071 SVN_ERR(svn_fs_node_id(&G_id
, txn_root
, "/A/D/G", pool
));
1072 SVN_ERR(check_entry_present(txn_root
, "A/D", "G", pool
));
1073 SVN_ERR(svn_fs_node_id(&pi_id
, txn_root
, "/A/D/G/pi", pool
));
1074 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "pi", pool
));
1075 SVN_ERR(svn_fs_node_id(&rho_id
, txn_root
, "/A/D/G/rho", pool
));
1076 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "rho", pool
));
1077 SVN_ERR(svn_fs_node_id(&tau_id
, txn_root
, "/A/D/G/tau", pool
));
1078 SVN_ERR(check_entry_present(txn_root
, "A/D/G", "tau", pool
));
1081 SVN_ERR(svn_fs_delete(txn_root
, "A", pool
));
1082 SVN_ERR(check_entry_absent(txn_root
, "", "A", pool
));
1083 SVN_ERR(check_id_present(fs
, A_id
, pool
));
1084 SVN_ERR(check_id_present(fs
, mu_id
, pool
));
1085 SVN_ERR(check_id_present(fs
, B_id
, pool
));
1086 SVN_ERR(check_id_present(fs
, lambda_id
, pool
));
1087 SVN_ERR(check_id_present(fs
, E_id
, pool
));
1088 SVN_ERR(check_id_present(fs
, alpha_id
, pool
));
1089 SVN_ERR(check_id_present(fs
, beta_id
, pool
));
1090 SVN_ERR(check_id_present(fs
, F_id
, pool
));
1091 SVN_ERR(check_id_present(fs
, C_id
, pool
));
1092 SVN_ERR(check_id_present(fs
, D_id
, pool
));
1093 SVN_ERR(check_id_present(fs
, gamma_id
, pool
));
1094 SVN_ERR(check_id_present(fs
, H_id
, pool
));
1095 SVN_ERR(check_id_present(fs
, chi_id
, pool
));
1096 SVN_ERR(check_id_present(fs
, psi_id
, pool
));
1097 SVN_ERR(check_id_present(fs
, omega_id
, pool
));
1098 SVN_ERR(check_id_present(fs
, G_id
, pool
));
1099 SVN_ERR(check_id_present(fs
, pi_id
, pool
));
1100 SVN_ERR(check_id_present(fs
, rho_id
, pool
));
1101 SVN_ERR(check_id_present(fs
, tau_id
, pool
));
1103 /* Validate the tree. */
1105 static svn_test__tree_entry_t expected_entries
[] = {
1106 /* path, contents (0 = dir) */
1107 { "iota", "This is the file 'iota'.\n" }
1109 SVN_ERR(svn_test__validate_tree(txn_root
, expected_entries
, 1, pool
));
1113 return SVN_NO_ERROR
;
1118 struct node_created_rev_args
{
1124 static svn_error_t
*
1125 canonicalize_abspath(const char **msg
,
1126 svn_boolean_t msg_only
,
1127 svn_test_opts_t
*opts
,
1131 const char *paths
[21][2] =
1140 { "foo//", "/foo" },
1142 { "/foo/", "/foo" },
1143 { "/foo//", "/foo" },
1144 { "//foo//", "/foo" },
1145 { "foo/bar", "/foo/bar" },
1146 { "foo/bar/", "/foo/bar" },
1147 { "foo/bar//", "/foo/bar" },
1148 { "foo//bar", "/foo/bar" },
1149 { "foo//bar/", "/foo/bar" },
1150 { "foo//bar//", "/foo/bar" },
1151 { "/foo//bar//", "/foo/bar" },
1152 { "//foo//bar//", "/foo/bar" },
1153 { "///foo///bar///baz///", "/foo/bar/baz" },
1156 *msg
= "test svn_fs__canonicalize_abspath";
1159 return SVN_NO_ERROR
;
1161 for (i
= 0; i
< (sizeof(paths
) / 2 / sizeof(const char *)); i
++)
1163 const char *input
= paths
[i
][0];
1164 const char *output
= paths
[i
][1];
1165 const char *actual
= svn_fs__canonicalize_abspath(input
, pool
);
1167 if ((! output
) && (! actual
))
1169 if ((! output
) && actual
)
1170 return svn_error_createf(SVN_ERR_TEST_FAILED
, NULL
,
1171 "expected NULL path; got '%s'", actual
);
1172 if (output
&& (! actual
))
1173 return svn_error_createf(SVN_ERR_TEST_FAILED
, NULL
,
1174 "expected '%s' path; got NULL", output
);
1175 if (strcmp(output
, actual
))
1176 return svn_error_createf(SVN_ERR_TEST_FAILED
, NULL
,
1177 "expected '%s' path; got '%s'",
1180 return SVN_NO_ERROR
;
1184 static svn_error_t
*
1185 create_within_copy(const char **msg
,
1186 svn_boolean_t msg_only
,
1187 svn_test_opts_t
*opts
,
1190 apr_pool_t
*spool
= svn_pool_create(pool
);
1193 svn_fs_root_t
*txn_root
, *rev_root
;
1195 svn_revnum_t youngest_rev
= 0;
1197 *msg
= "create new items within a copied directory";
1200 return SVN_NO_ERROR
;
1202 /* Create a filesystem and repository. */
1203 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-create-within-copy",
1206 /*** Revision 1: Create the greek tree in revision. ***/
1207 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, spool
));
1208 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, spool
));
1209 SVN_ERR(svn_test__create_greek_tree(txn_root
, spool
));
1210 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, spool
));
1211 svn_pool_clear(spool
);
1213 /*** Revision 2: Copy A/D to A/D3 ***/
1214 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, spool
));
1215 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, spool
));
1216 SVN_ERR(svn_fs_revision_root(&rev_root
, fs
, youngest_rev
, spool
));
1217 SVN_ERR(svn_fs_copy(rev_root
, "A/D", txn_root
, "A/D3", spool
));
1218 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, spool
));
1219 svn_pool_clear(spool
);
1221 /*** Revision 3: Copy A/D/G to A/D/G2 ***/
1222 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, spool
));
1223 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, spool
));
1224 SVN_ERR(svn_fs_revision_root(&rev_root
, fs
, youngest_rev
, spool
));
1225 SVN_ERR(svn_fs_copy(rev_root
, "A/D/G", txn_root
, "A/D/G2", spool
));
1226 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, spool
));
1227 svn_pool_clear(spool
);
1229 /*** Revision 4: Copy A/D to A/D2 and create up and I in the existing
1230 A/D/G2, in the new A/D2, and in the nested, new A/D2/G2 ***/
1231 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, spool
));
1232 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, spool
));
1233 SVN_ERR(svn_fs_revision_root(&rev_root
, fs
, youngest_rev
, spool
));
1234 SVN_ERR(svn_fs_copy(rev_root
, "A/D", txn_root
, "A/D2", spool
));
1235 SVN_ERR(svn_fs_make_dir(txn_root
, "A/D/G2/I", spool
));
1236 SVN_ERR(svn_fs_make_file(txn_root
, "A/D/G2/up", spool
));
1237 SVN_ERR(svn_fs_make_dir(txn_root
, "A/D2/I", spool
));
1238 SVN_ERR(svn_fs_make_file(txn_root
, "A/D2/up", spool
));
1239 SVN_ERR(svn_fs_make_dir(txn_root
, "A/D2/G2/I", spool
));
1240 SVN_ERR(svn_fs_make_file(txn_root
, "A/D2/G2/up", spool
));
1241 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, spool
));
1242 svn_pool_clear(spool
);
1244 /*** Revision 5: Create A/D3/down and A/D3/J ***/
1245 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, spool
));
1246 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, spool
));
1247 SVN_ERR(svn_fs_make_file(txn_root
, "A/D3/down", spool
));
1248 SVN_ERR(svn_fs_make_dir(txn_root
, "A/D3/J", spool
));
1249 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, spool
));
1250 svn_pool_clear(spool
);
1253 /* New items should have same CopyID as their parent */
1254 const char *pathgroup
[4][3] =
1270 SVN_ERR(svn_fs_revision_root(&rev_root
, fs
, youngest_rev
, spool
));
1272 for (i
= 0; i
< 4; i
++)
1274 const svn_fs_id_t
*lead_id
;
1275 const char *lead_copy_id
;
1278 /* Get the FSIdentifier for the first path in each group... */
1279 SVN_ERR(svn_fs_node_id(&lead_id
, rev_root
, pathgroup
[i
][0], spool
));
1280 lead_copy_id
= svn_fs_base__id_copy_id(lead_id
);
1282 for (j
= 1; j
< 3; j
++)
1284 const svn_fs_id_t
*id
;
1285 const char *copy_id
;
1287 /* ... and make sure the other members of the group have
1288 the same copy_id component as the 'lead' member. */
1290 SVN_ERR(svn_fs_node_id(&id
, rev_root
, pathgroup
[i
][j
], spool
));
1291 copy_id
= svn_fs_base__id_copy_id(id
);
1293 if (strcmp(copy_id
, lead_copy_id
) != 0)
1294 return svn_error_createf
1295 (SVN_ERR_TEST_FAILED
, NULL
,
1296 "'%s' id: expected copy_id '%s'; got copy_id '%s'",
1297 pathgroup
[i
][j
], lead_copy_id
, copy_id
);
1300 svn_pool_clear(spool
);
1303 svn_pool_destroy(spool
);
1304 return SVN_NO_ERROR
;
1308 /* Test the skip delta support by commiting so many changes to a file
1309 * that some of its older revisions become reachable by skip deltas,
1310 * then try retrieving those revisions.
1312 static svn_error_t
*
1313 skip_deltas(const char **msg
,
1314 svn_boolean_t msg_only
,
1315 svn_test_opts_t
*opts
,
1320 svn_fs_root_t
*txn_root
, *rev_root
;
1321 apr_pool_t
*subpool
= svn_pool_create(pool
);
1322 svn_revnum_t youngest_rev
= 0;
1323 const char *one_line
= "This is a line in file 'f'.\n";
1324 svn_stringbuf_t
*f
= svn_stringbuf_create(one_line
, pool
);
1326 *msg
= "test skip deltas";
1329 return SVN_NO_ERROR
;
1331 /* Create a filesystem and repository. */
1332 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-skip-deltas",
1335 /* Create the file. */
1336 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, subpool
));
1337 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, subpool
));
1338 SVN_ERR(svn_fs_make_file(txn_root
, "f", subpool
));
1339 SVN_ERR(svn_test__set_file_contents(txn_root
, "f", f
->data
, subpool
));
1340 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, subpool
));
1341 SVN_ERR(svn_fs_deltify_revision(fs
, youngest_rev
, subpool
));
1342 svn_pool_clear(subpool
);
1344 /* Now, commit changes to the file 128 times. */
1345 while (youngest_rev
<= 128)
1347 /* Append another line to the ever-growing file contents. */
1348 svn_stringbuf_appendcstr(f
, one_line
);
1350 /* Commit the new contents. */
1351 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, subpool
));
1352 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, subpool
));
1353 SVN_ERR(svn_test__set_file_contents(txn_root
, "f", f
->data
, subpool
));
1354 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, subpool
));
1355 SVN_ERR(svn_fs_deltify_revision(fs
, youngest_rev
, subpool
));
1356 svn_pool_clear(subpool
);
1359 /* Now go back and check revision 1. */
1360 SVN_ERR(svn_fs_revision_root(&rev_root
, fs
, 1, pool
));
1361 SVN_ERR(svn_test__get_file_contents(rev_root
, "f", &f
, pool
));
1362 if (strcmp(one_line
, f
->data
) != 0)
1363 return svn_error_createf
1364 (SVN_ERR_TEST_FAILED
, NULL
,
1365 "Wrong contents. Expected:\n '%s'\nGot:\n '%s'\n",
1368 svn_pool_destroy(subpool
);
1369 return SVN_NO_ERROR
;
1373 /* Trail-ish helpers for redundant_copy(). */
1376 transaction_t
**txn
;
1377 const char *txn_name
;
1381 static svn_error_t
*
1382 txn_body_get_txn(void *baton
, trail_t
*trail
)
1384 struct get_txn_args
*args
= baton
;
1385 return svn_fs_bdb__get_txn(args
->txn
, args
->fs
, args
->txn_name
,
1386 trail
, trail
->pool
);
1390 static svn_error_t
*
1391 redundant_copy(const char **msg
,
1392 svn_boolean_t msg_only
,
1393 svn_test_opts_t
*opts
,
1398 const char *txn_name
;
1399 transaction_t
*transaction
;
1400 svn_fs_root_t
*txn_root
, *rev_root
;
1401 const svn_fs_id_t
*old_D_id
, *new_D_id
;
1402 svn_revnum_t youngest_rev
= 0;
1403 struct get_txn_args args
;
1405 *msg
= "ensure no-op for redundant copies";
1408 return SVN_NO_ERROR
;
1410 /* Create a filesystem and repository. */
1411 SVN_ERR(svn_test__create_fs(&fs
, "test-repo-redundant-copy",
1414 /* Create the greek tree in revision 1. */
1415 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, pool
));
1416 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
1417 SVN_ERR(svn_test__create_greek_tree(txn_root
, pool
));
1418 SVN_ERR(svn_fs_commit_txn(NULL
, &youngest_rev
, txn
, pool
));
1420 /* In a transaction, copy A to Z. */
1421 SVN_ERR(svn_fs_begin_txn(&txn
, fs
, youngest_rev
, pool
));
1422 SVN_ERR(svn_fs_txn_name(&txn_name
, txn
, pool
));
1423 SVN_ERR(svn_fs_txn_root(&txn_root
, txn
, pool
));
1424 SVN_ERR(svn_fs_revision_root(&rev_root
, fs
, youngest_rev
, pool
));
1425 SVN_ERR(svn_fs_copy(rev_root
, "A", txn_root
, "Z", pool
));
1427 /* Now, examine the transaction. There should have been only one
1430 args
.txn_name
= txn_name
;
1431 args
.txn
= &transaction
;
1432 SVN_ERR(svn_fs_base__retry_txn(fs
, txn_body_get_txn
, &args
, pool
));
1433 if (transaction
->copies
->nelts
!= 1)
1434 return svn_error_createf(SVN_ERR_TEST_FAILED
, NULL
,
1435 "Expected 1 copy; got %d",
1436 transaction
->copies
->nelts
);
1438 /* Get the node-rev-id for A/D (the reason will be clear a little later). */
1439 SVN_ERR(svn_fs_node_id(&old_D_id
, txn_root
, "A/D", pool
));
1441 /* Now copy A/D/G Z/D/G. */
1442 SVN_ERR(svn_fs_copy(rev_root
, "A/D/G", txn_root
, "Z/D/G", pool
));
1444 /* Now, examine the transaction. There should still only have been
1445 one copy operation that "took". */
1446 SVN_ERR(svn_fs_base__retry_txn(fs
, txn_body_get_txn
, &args
, pool
));
1447 if (transaction
->copies
->nelts
!= 1)
1448 return svn_error_createf(SVN_ERR_TEST_FAILED
, NULL
,
1449 "Expected only 1 copy; got %d",
1450 transaction
->copies
->nelts
);
1452 /* Finally, check the node-rev-id for "Z/D" -- it should never have
1453 been made mutable (since the second copy should not have taken
1455 SVN_ERR(svn_fs_node_id(&new_D_id
, txn_root
, "A/D", pool
));
1456 if (! svn_string_compare(svn_fs_unparse_id(old_D_id
, pool
),
1457 svn_fs_unparse_id(new_D_id
, pool
)))
1458 return svn_error_create
1459 (SVN_ERR_TEST_FAILED
, NULL
,
1460 "Expected equivalent node-rev-ids; got differing ones");
1462 return SVN_NO_ERROR
;
1466 /* ------------------------------------------------------------------------ */
1468 /* The test table. */
1470 struct svn_test_descriptor_t test_funcs
[] =
1473 SVN_TEST_PASS(create_berkeley_filesystem
),
1474 SVN_TEST_PASS(open_berkeley_filesystem
),
1475 SVN_TEST_PASS(delete_mutables
),
1476 SVN_TEST_PASS(delete),
1477 SVN_TEST_PASS(abort_txn
),
1478 SVN_TEST_PASS(create_within_copy
),
1479 SVN_TEST_PASS(canonicalize_abspath
),
1480 SVN_TEST_PASS(skip_deltas
),
1481 SVN_TEST_PASS(redundant_copy
),