Fix compiler warning due to missing function prototype.
[svn.git] / subversion / tests / libsvn_fs_base / fs-base-test.c
blob5a362a0959c3095e3d7037f32a3735f0639a6a0e
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 * ====================================================================
18 #include <stdlib.h>
19 #include <string.h>
20 #include <apr_pools.h>
22 #include "svn_pools.h"
23 #include "svn_time.h"
24 #include "svn_string.h"
25 #include "svn_fs.h"
26 #include "svn_md5.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. */
47 static svn_error_t *
48 create_berkeley_filesystem(const char **msg,
49 svn_boolean_t msg_only,
50 svn_test_opts_t *opts,
51 apr_pool_t *pool)
53 svn_fs_t *fs;
55 *msg = "svn_fs_create_berkeley";
57 if (msg_only)
58 return SVN_NO_ERROR;
60 /* Create and close a repository. */
61 SVN_ERR(svn_test__create_fs(&fs, "test-repo-create-berkeley",
62 "bdb", pool));
64 return SVN_NO_ERROR;
68 /* Generic Berkeley DB error handler function. */
69 static void
70 berkeley_error_handler(const char *errpfx, char *msg)
72 fprintf(stderr, "%s%s\n", errpfx ? errpfx : "", msg);
76 /* Open an existing filesystem. */
77 static svn_error_t *
78 open_berkeley_filesystem(const char **msg,
79 svn_boolean_t msg_only,
80 svn_test_opts_t *opts,
81 apr_pool_t *pool)
83 svn_fs_t *fs, *fs2;
85 *msg = "open an existing Berkeley DB filesystem";
87 if (msg_only)
88 return SVN_NO_ERROR;
90 /* Create and close a repository (using fs). */
91 SVN_ERR(svn_test__create_fs(&fs, "test-repo-open-berkeley",
92 "bdb", pool));
94 /* Create a different fs object, and use it to re-open the
95 repository again. */
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));
102 return SVN_NO_ERROR;
106 /* Set *PRESENT to true if entry NAME is present in directory PATH
107 under ROOT, else set *PRESENT to false. */
108 static svn_error_t *
109 check_entry(svn_fs_root_t *root,
110 const char *path,
111 const char *name,
112 svn_boolean_t *present,
113 apr_pool_t *pool)
115 apr_hash_t *entries;
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);
121 if (ent)
122 *present = TRUE;
123 else
124 *present = FALSE;
126 return SVN_NO_ERROR;
130 /* Return an error if entry NAME is absent in directory PATH under ROOT. */
131 static svn_error_t *
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));
138 if (! present)
139 return svn_error_createf
140 (SVN_ERR_FS_GENERAL, NULL,
141 "entry \"%s\" absent when it should be present", name);
143 return SVN_NO_ERROR;
147 /* Return an error if entry NAME is present in directory PATH under ROOT. */
148 static svn_error_t *
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));
155 if (present)
156 return svn_error_createf
157 (SVN_ERR_FS_GENERAL, NULL,
158 "entry \"%s\" present when it should be absent", name);
160 return SVN_NO_ERROR;
164 struct check_id_args
166 svn_fs_t *fs;
167 const svn_fs_id_t *id;
168 svn_boolean_t present;
172 static svn_error_t *
173 txn_body_check_id(void *baton, trail_t *trail)
175 struct check_id_args *args = baton;
176 node_revision_t *noderev;
177 svn_error_t *err;
179 err = svn_fs_bdb__get_node_revision(&noderev, args->fs, args->id,
180 trail, trail->pool);
182 if (err && (err->apr_err == SVN_ERR_FS_ID_NOT_FOUND))
183 args->present = FALSE;
184 else if (! err)
185 args->present = TRUE;
186 else
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);
195 return SVN_NO_ERROR;
199 /* Set *PRESENT to true if node revision ID is present in filesystem
200 FS, else set *PRESENT to false. */
201 static svn_error_t *
202 check_id(svn_fs_t *fs, const svn_fs_id_t *id, svn_boolean_t *present,
203 apr_pool_t *pool)
205 struct check_id_args args;
207 args.id = id;
208 args.fs = fs;
209 SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_check_id, &args, pool));
211 if (args.present)
212 *present = TRUE;
213 else
214 *present = FALSE;
216 return SVN_NO_ERROR;
220 /* Return error if node revision ID is not present in FS. */
221 static svn_error_t *
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));
227 if (! present)
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",
233 id_str->data);
236 return SVN_NO_ERROR;
240 /* Return error if node revision ID is present in FS. */
241 static svn_error_t *
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));
247 if (present)
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",
253 id_str->data);
256 return SVN_NO_ERROR;
260 /* Test that aborting a Subversion transaction works.
262 NOTE: This function tests internal filesystem interfaces, not just
263 the public filesystem interface. */
264 static svn_error_t *
265 abort_txn(const char **msg,
266 svn_boolean_t msg_only,
267 svn_test_opts_t *opts,
268 apr_pool_t *pool)
270 svn_fs_t *fs;
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";
277 if (msg_only)
278 return SVN_NO_ERROR;
280 /* Prepare two txns to receive the Greek tree. */
281 SVN_ERR(svn_test__create_fs(&fs, "test-repo-abort-txn",
282 "bdb", pool));
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
300 * disappeared.
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. */
310 const svn_fs_id_t
311 *t1_root_id, *t2_root_id,
312 *t1_iota_id, *t2_iota_id,
313 *t1_A_id, *t2_A_id,
314 *t1_mu_id, *t2_mu_id,
315 *t1_B_id, *t2_B_id,
316 *t1_lambda_id, *t2_lambda_id,
317 *t1_E_id, *t2_E_id,
318 *t1_alpha_id, *t2_alpha_id,
319 *t1_beta_id, *t2_beta_id,
320 *t1_F_id, *t2_F_id,
321 *t1_C_id, *t2_C_id,
322 *t1_D_id, *t2_D_id,
323 *t1_gamma_id, *t2_gamma_id,
324 *t1_H_id, *t2_H_id,
325 *t1_chi_id, *t2_chi_id,
326 *t1_psi_id, *t2_psi_id,
327 *t1_omega_id, *t2_omega_id,
328 *t1_G_id, *t2_G_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;
433 svn_error_t *err;
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");
442 else if (! err)
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. */
453 svn_fs_txn_t *txn3;
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. */
470 svn_fs_txn_t *txn4;
471 const char *txn4_name;
472 svn_revnum_t new_rev;
473 const char *conflict;
474 svn_error_t *err;
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);
480 if (! err)
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");
488 else
489 svn_error_clear(err);
491 return SVN_NO_ERROR;
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
498 * mutable node.
500 * ### todo: this test was written before commits worked. It might
501 * now be worthwhile to combine it with delete().
503 static svn_error_t *
504 delete_mutables(const char **msg,
505 svn_boolean_t msg_only,
506 svn_test_opts_t *opts,
507 apr_pool_t *pool)
509 svn_fs_t *fs;
510 svn_fs_txn_t *txn;
511 svn_fs_root_t *txn_root;
512 svn_error_t *err;
514 *msg = "delete mutable nodes from directories";
516 if (msg_only)
517 return SVN_NO_ERROR;
519 /* Prepare a txn to receive the greek tree. */
520 SVN_ERR(svn_test__create_fs(&fs, "test-repo-del-from-dir",
521 "bdb", pool));
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.
545 * 5. Delete A/C.
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
551 * be.
554 /* 1 */
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));
568 /* 2 */
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));
601 /* 3 */
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));
615 /* 4 */
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));
629 /* 5 */
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));
643 /* 6 */
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");
656 else if (! err)
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));
667 /* 7 */
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));
681 return SVN_NO_ERROR;
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.
690 static svn_error_t *
691 delete(const char **msg,
692 svn_boolean_t msg_only,
693 svn_test_opts_t *opts,
694 apr_pool_t *pool)
696 svn_fs_t *fs;
697 svn_fs_txn_t *txn;
698 svn_fs_root_t *txn_root;
699 svn_revnum_t new_rev;
701 *msg = "delete nodes tree";
703 if (msg_only)
704 return SVN_NO_ERROR;
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",
717 "bdb", pool));
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) */
729 { "A", 0 },
730 { "A/mu", "This is the file 'mu'.\n" },
731 { "A/B", 0 },
732 { "A/B/lambda", "This is the file 'lambda'.\n" },
733 { "A/B/E", 0 },
734 { "A/B/E/alpha", "This is the file 'alpha'.\n" },
735 { "A/B/E/beta", "This is the file 'beta'.\n" },
736 { "A/C", 0 },
737 { "A/B/F", 0 },
738 { "A/D", 0 },
739 { "A/D/G", 0 },
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" },
743 { "A/D/H", 0 },
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
888 mutable. */
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
894 ones still exist. */
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));
936 /* Delete "A" */
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) */
1003 { "A", 0 },
1004 { "A/mu", "This is the file 'mu'.\n" },
1005 { "A/B", 0 },
1006 { "A/B/lambda", "This is the file 'lambda'.\n" },
1007 { "A/B/E", 0 },
1008 { "A/B/E/alpha", "This is the file 'alpha'.\n" },
1009 { "A/B/E/beta", "This is the file 'beta'.\n" },
1010 { "A/B/F", 0 },
1011 { "A/C", 0 },
1012 { "A/D", 0 },
1013 { "A/D/G", 0 },
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" },
1017 { "A/D/H", 0 },
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));
1080 /* Delete "A" */
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 {
1119 const char *path;
1120 svn_revnum_t rev;
1124 static svn_error_t *
1125 canonicalize_abspath(const char **msg,
1126 svn_boolean_t msg_only,
1127 svn_test_opts_t *opts,
1128 apr_pool_t *pool)
1130 apr_size_t i;
1131 const char *paths[21][2] =
1132 /* in out */
1133 { { NULL, NULL },
1134 { "", "/" },
1135 { "/", "/" },
1136 { "//", "/" },
1137 { "///", "/" },
1138 { "foo", "/foo" },
1139 { "foo/", "/foo" },
1140 { "foo//", "/foo" },
1141 { "/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";
1158 if (msg_only)
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))
1168 continue;
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'",
1178 output, actual);
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,
1188 apr_pool_t *pool)
1190 apr_pool_t *spool = svn_pool_create(pool);
1191 svn_fs_t *fs;
1192 svn_fs_txn_t *txn;
1193 svn_fs_root_t *txn_root, *rev_root;
1194 int i;
1195 svn_revnum_t youngest_rev = 0;
1197 *msg = "create new items within a copied directory";
1199 if (msg_only)
1200 return SVN_NO_ERROR;
1202 /* Create a filesystem and repository. */
1203 SVN_ERR(svn_test__create_fs(&fs, "test-repo-create-within-copy",
1204 "bdb", pool));
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] =
1256 { "A/D/G2",
1257 "A/D/G2/I",
1258 "A/D/G2/up" },
1259 { "A/D2",
1260 "A/D2/I",
1261 "A/D2/up" },
1262 { "A/D2/G2",
1263 "A/D2/G2/I",
1264 "A/D2/G2/up" },
1265 { "A/D3",
1266 "A/D3/down",
1267 "A/D3/J" }
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;
1276 int j;
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,
1316 apr_pool_t *pool)
1318 svn_fs_t *fs;
1319 svn_fs_txn_t *txn;
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";
1328 if (msg_only)
1329 return SVN_NO_ERROR;
1331 /* Create a filesystem and repository. */
1332 SVN_ERR(svn_test__create_fs(&fs, "test-repo-skip-deltas",
1333 "bdb", pool));
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",
1366 one_line, f->data);
1368 svn_pool_destroy(subpool);
1369 return SVN_NO_ERROR;
1373 /* Trail-ish helpers for redundant_copy(). */
1374 struct get_txn_args
1376 transaction_t **txn;
1377 const char *txn_name;
1378 svn_fs_t *fs;
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,
1394 apr_pool_t *pool)
1396 svn_fs_t *fs;
1397 svn_fs_txn_t *txn;
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";
1407 if (msg_only)
1408 return SVN_NO_ERROR;
1410 /* Create a filesystem and repository. */
1411 SVN_ERR(svn_test__create_fs(&fs, "test-repo-redundant-copy",
1412 "bdb", pool));
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
1428 copy there. */
1429 args.fs = fs;
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
1454 place). */
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[] =
1472 SVN_TEST_NULL,
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),
1482 SVN_TEST_NULL