1
/* lock-test.c --- tests for the filesystem locking functions
3
* ====================================================================
4
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
6
* This software is licensed as described in the file COPYING, which
7
* you should have received as part of this distribution. The terms
8
* are also available at http://subversion.tigris.org/license-1.html.
9
* If newer versions of this license are posted there, you may use a
10
* newer version instead, at your option.
12
* This software consists of voluntary contributions made by many
13
* individuals. For exact contribution history, see the revision
14
* history and logs, available at http://subversion.tigris.org/.
15
* ====================================================================
18
/* TODO how many of these can I get rid of? */
21
#include <apr_pools.h>
25
#include "svn_pools.h"
26
#include "svn_error.h"
30
#include "svn_delta.h"
32
#include "svn_props.h"
34
#include "../fs-helpers.h"
36
#define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))
39
/*-----------------------------------------------------------------*/
41
/** Helper functions **/
43
/* Implementations of the svn_fs_get_locks_callback_t interface and
44
baton, for verifying expected output from svn_fs_get_locks(). */
46
struct get_locks_baton_t
52
get_locks_callback (void *baton,
56
struct get_locks_baton_t *b = baton;
57
apr_pool_t *hash_pool = apr_hash_pool_get (b->locks);
58
svn_string_t *lock_path = svn_string_create (lock->path, hash_pool);
59
apr_hash_set (b->locks, lock_path->data, lock_path->len,
60
svn_lock_dup (lock, hash_pool));
64
/* A factory function. */
66
static struct get_locks_baton_t *
67
make_get_locks_baton (apr_pool_t *pool)
69
struct get_locks_baton_t *baton = apr_pcalloc (pool, sizeof (*baton));
70
baton->locks = apr_hash_make (pool);
75
/* And verification function(s). */
78
verify_matching_lock_paths (struct get_locks_baton_t *baton,
79
const char *expected_paths[],
80
apr_size_t num_expected_paths,
84
if (num_expected_paths != apr_hash_count (baton->locks))
85
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
86
"Unexpected number of locks.");
87
for (i = 0; i < num_expected_paths; i++)
89
const char *path = expected_paths[i];
90
if (! apr_hash_get (baton->locks, path, APR_HASH_KEY_STRING))
91
return svn_error_createf (SVN_ERR_TEST_FAILED, NULL,
92
"Missing lock for path '%s'", path);
98
/*-----------------------------------------------------------------*/
100
/** The actual lock-tests called by `make check` **/
104
/* Test that we can create a lock--nothing more. */
106
lock_only (const char **msg,
107
svn_boolean_t msg_only,
108
svn_test_opts_t *opts,
113
svn_fs_root_t *txn_root;
114
const char *conflict;
116
svn_fs_access_t *access;
124
/* Prepare a filesystem and a new txn. */
125
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lock-only",
126
opts->fs_type, pool));
127
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
128
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
130
/* Create the greek tree and commit it. */
131
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
132
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
134
/* We are now 'bubba'. */
135
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
136
SVN_ERR (svn_fs_set_access (fs, access));
138
/* Lock /A/D/G/rho. */
139
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
140
SVN_INVALID_REVNUM, FALSE, pool));
149
/* Test that we can create, fetch, and destroy a lock. It exercises
150
each of the five public fs locking functions. */
152
lookup_lock_by_path (const char **msg,
153
svn_boolean_t msg_only,
154
svn_test_opts_t *opts,
159
svn_fs_root_t *txn_root;
160
const char *conflict;
162
svn_fs_access_t *access;
163
svn_lock_t *mylock, *somelock;
165
*msg = "lookup lock by path";
170
/* Prepare a filesystem and a new txn. */
171
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lookup-lock-by-path",
172
opts->fs_type, pool));
173
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
174
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
176
/* Create the greek tree and commit it. */
177
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
178
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
180
/* We are now 'bubba'. */
181
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
182
SVN_ERR (svn_fs_set_access (fs, access));
184
/* Lock /A/D/G/rho. */
185
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
186
SVN_INVALID_REVNUM, FALSE, pool));
188
/* Can we look up the lock by path? */
189
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
190
if ((! somelock) || (strcmp (somelock->token, mylock->token) != 0))
191
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
192
"Couldn't look up a lock by pathname.");
197
/* Test that we can create a lock outside of the fs and attach it to a
200
attach_lock (const char **msg,
201
svn_boolean_t msg_only,
202
svn_test_opts_t *opts,
207
svn_fs_root_t *txn_root;
208
const char *conflict;
210
svn_fs_access_t *access;
211
svn_lock_t *somelock;
215
*msg = "attach lock";
220
/* Prepare a filesystem and a new txn. */
221
SVN_ERR (svn_test__create_fs (&fs, "test-repo-attach-lock",
222
opts->fs_type, pool));
223
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
224
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
226
/* Create the greek tree and commit it. */
227
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
228
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
230
/* We are now 'bubba'. */
231
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
232
SVN_ERR (svn_fs_set_access (fs, access));
234
SVN_ERR (svn_fs_generate_lock_token (&token, fs, pool));
235
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", token,
236
"This is a comment. Yay comment!", 0,
237
apr_time_now() + apr_time_from_sec(3),
238
SVN_INVALID_REVNUM, FALSE, pool));
240
/* Can we look up the lock by path? */
241
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
242
if ((! somelock) || (strcmp (somelock->token, mylock->token) != 0))
243
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
244
"Couldn't look up a lock by pathname.");
246
/* Unlock /A/D/G/rho, and verify that it's gone. */
247
SVN_ERR (svn_fs_unlock (fs, mylock->path, mylock->token, 0, pool));
248
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
250
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
251
"Removed a lock, but it's still there.");
257
/* Test that we can get all locks under a directory. */
259
get_locks (const char **msg,
260
svn_boolean_t msg_only,
261
svn_test_opts_t *opts,
266
svn_fs_root_t *txn_root;
267
const char *conflict;
269
svn_fs_access_t *access;
271
struct get_locks_baton_t *get_locks_baton;
272
apr_size_t i, num_expected_paths;
279
/* Prepare a filesystem and a new txn. */
280
SVN_ERR (svn_test__create_fs (&fs, "test-repo-get-locks",
281
opts->fs_type, pool));
282
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
283
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
285
/* Create the greek tree and commit it. */
286
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
287
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
289
/* We are now 'bubba'. */
290
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
291
SVN_ERR (svn_fs_set_access (fs, access));
293
/* Lock our paths; verify from "/". */
295
static const char *expected_paths[] = {
305
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
306
for (i = 0; i < num_expected_paths; i++)
308
SVN_ERR (svn_fs_lock (&mylock, fs, expected_paths[i], NULL, "", 0, 0,
309
SVN_INVALID_REVNUM, FALSE, pool));
311
get_locks_baton = make_get_locks_baton (pool);
312
SVN_ERR (svn_fs_get_locks (fs, "", get_locks_callback,
313
get_locks_baton, pool));
314
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
315
num_expected_paths, pool));
318
/* Verify from "/A/B". */
320
static const char *expected_paths[] = {
324
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
325
get_locks_baton = make_get_locks_baton (pool);
326
SVN_ERR (svn_fs_get_locks (fs, "A/B", get_locks_callback,
327
get_locks_baton, pool));
328
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
329
num_expected_paths, pool));
332
/* Verify from "/A/D". */
334
static const char *expected_paths[] = {
342
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
343
get_locks_baton = make_get_locks_baton (pool);
344
SVN_ERR (svn_fs_get_locks (fs, "A/D", get_locks_callback,
345
get_locks_baton, pool));
346
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
347
num_expected_paths, pool));
350
/* Verify from "/A/D/G". */
352
static const char *expected_paths[] = {
357
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
358
get_locks_baton = make_get_locks_baton (pool);
359
SVN_ERR (svn_fs_get_locks (fs, "A/D/G", get_locks_callback,
360
get_locks_baton, pool));
361
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
362
num_expected_paths, pool));
365
/* Verify from "/A/D/H/omega". */
367
static const char *expected_paths[] = {
370
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
371
get_locks_baton = make_get_locks_baton (pool);
372
SVN_ERR (svn_fs_get_locks (fs, "A/D/H/omega", get_locks_callback,
373
get_locks_baton, pool));
374
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
375
num_expected_paths, pool));
378
/* Verify from "/iota" (which wasn't locked... tricky...). */
380
static const char *expected_paths[] = { 0 };
381
num_expected_paths = 0;
382
get_locks_baton = make_get_locks_baton (pool);
383
SVN_ERR (svn_fs_get_locks (fs, "iota", get_locks_callback,
384
get_locks_baton, pool));
385
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
386
num_expected_paths, pool));
393
/* Test that we can create, fetch, and destroy a lock. It exercises
394
each of the five public fs locking functions. */
396
basic_lock (const char **msg,
397
svn_boolean_t msg_only,
398
svn_test_opts_t *opts,
403
svn_fs_root_t *txn_root;
404
const char *conflict;
406
svn_fs_access_t *access;
407
svn_lock_t *mylock, *somelock;
409
*msg = "basic locking";
414
/* Prepare a filesystem and a new txn. */
415
SVN_ERR (svn_test__create_fs (&fs, "test-repo-basic-lock",
416
opts->fs_type, pool));
417
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
418
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
420
/* Create the greek tree and commit it. */
421
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
422
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
424
/* We are now 'bubba'. */
425
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
426
SVN_ERR (svn_fs_set_access (fs, access));
428
/* Lock /A/D/G/rho. */
429
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
430
SVN_INVALID_REVNUM, FALSE, pool));
432
/* Can we look up the lock by path? */
433
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
434
if ((! somelock) || (strcmp (somelock->token, mylock->token) != 0))
435
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
436
"Couldn't look up a lock by pathname.");
438
/* Unlock /A/D/G/rho, and verify that it's gone. */
439
SVN_ERR (svn_fs_unlock (fs, mylock->path, mylock->token, 0, pool));
440
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
442
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
443
"Removed a lock, but it's still there.");
450
/* Test that locks are enforced -- specifically that both a username
451
and token are required to make use of the lock. */
453
lock_credentials (const char **msg,
454
svn_boolean_t msg_only,
455
svn_test_opts_t *opts,
460
svn_fs_root_t *txn_root;
461
const char *conflict;
463
svn_fs_access_t *access;
467
*msg = "test that locking requires proper credentials";
472
/* Prepare a filesystem and a new txn. */
473
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lock-credentials",
474
opts->fs_type, pool));
475
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
476
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
478
/* Create the greek tree and commit it. */
479
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
480
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
482
/* We are now 'bubba'. */
483
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
484
SVN_ERR (svn_fs_set_access (fs, access));
486
/* Lock /A/D/G/rho. */
487
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
488
SVN_INVALID_REVNUM, FALSE, pool));
490
/* Push the proper lock-token into the fs access context. */
491
SVN_ERR (svn_fs_access_add_lock_token (access, mylock->token));
493
/* Make a new transaction and change rho. */
494
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, newrev, SVN_FS_TXN_CHECK_LOCKS, pool));
495
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
496
SVN_ERR (svn_test__set_file_contents (txn_root, "/A/D/G/rho",
497
"new contents", pool));
499
/* We are no longer 'bubba'. We're nobody. */
500
SVN_ERR (svn_fs_set_access (fs, NULL));
502
/* Try to commit the file change. Should fail, because we're nobody. */
503
err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
505
return svn_error_create
506
(SVN_ERR_TEST_FAILED, NULL,
507
"Uhoh, able to commit locked file without any fs username.");
508
svn_error_clear (err);
510
/* We are now 'hortense'. */
511
SVN_ERR (svn_fs_create_access (&access, "hortense", pool));
512
SVN_ERR (svn_fs_set_access (fs, access));
514
/* Try to commit the file change. Should fail, because we're 'hortense'. */
515
err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
517
return svn_error_create
518
(SVN_ERR_TEST_FAILED, NULL,
519
"Uhoh, able to commit locked file as non-owner.");
520
svn_error_clear (err);
522
/* Be 'bubba' again. */
523
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
524
SVN_ERR (svn_fs_set_access (fs, access));
526
/* Try to commit the file change. Should fail, because there's no token. */
527
err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
529
return svn_error_create
530
(SVN_ERR_TEST_FAILED, NULL,
531
"Uhoh, able to commit locked file with no lock token.");
532
svn_error_clear (err);
534
/* Push the proper lock-token into the fs access context. */
535
SVN_ERR (svn_fs_access_add_lock_token (access, mylock->token));
537
/* Commit should now succeed. */
538
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
545
/* Test that locks are enforced at commit time. Somebody might lock
546
something behind your back, right before you run
547
svn_fs_commit_txn(). Also, this test verifies that recursive
548
lock-checks on directories is working properly. */
550
final_lock_check (const char **msg,
551
svn_boolean_t msg_only,
552
svn_test_opts_t *opts,
557
svn_fs_root_t *txn_root;
558
const char *conflict;
560
svn_fs_access_t *access;
564
*msg = "test that locking is enforced in final commit step";
569
/* Prepare a filesystem and a new txn. */
570
SVN_ERR (svn_test__create_fs (&fs, "test-repo-final-lock-check",
571
opts->fs_type, pool));
572
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
573
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
575
/* Create the greek tree and commit it. */
576
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
577
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
579
/* Make a new transaction and delete "/A" */
580
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, newrev, SVN_FS_TXN_CHECK_LOCKS, pool));
581
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
582
SVN_ERR (svn_fs_delete (txn_root, "/A", pool));
584
/* Become 'bubba' and lock "/A/D/G/rho". */
585
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
586
SVN_ERR (svn_fs_set_access (fs, access));
587
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
588
SVN_INVALID_REVNUM, FALSE, pool));
590
/* We are no longer 'bubba'. We're nobody. */
591
SVN_ERR (svn_fs_set_access (fs, NULL));
593
/* Try to commit the transaction. Should fail, because a child of
594
the deleted directory is locked by someone else. */
595
err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
597
return svn_error_create
598
(SVN_ERR_TEST_FAILED, NULL,
599
"Uhoh, able to commit dir deletion when a child is locked.");
600
svn_error_clear (err);
602
/* Supply correct username and token; commit should work. */
603
SVN_ERR (svn_fs_set_access (fs, access));
604
SVN_ERR (svn_fs_access_add_lock_token (access, mylock->token));
605
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
612
/* If a directory's child is locked by someone else, we should still
613
be able to commit a propchange on the directory. */
615
lock_dir_propchange (const char **msg,
616
svn_boolean_t msg_only,
617
svn_test_opts_t *opts,
622
svn_fs_root_t *txn_root;
623
const char *conflict;
625
svn_fs_access_t *access;
628
*msg = "dir propchange can be committed with locked child";
633
/* Prepare a filesystem and a new txn. */
634
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lock-dir-propchange",
635
opts->fs_type, pool));
636
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
637
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
639
/* Create the greek tree and commit it. */
640
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
641
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
643
/* Become 'bubba' and lock "/A/D/G/rho". */
644
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
645
SVN_ERR (svn_fs_set_access (fs, access));
646
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
647
SVN_INVALID_REVNUM, FALSE, pool));
649
/* We are no longer 'bubba'. We're nobody. */
650
SVN_ERR (svn_fs_set_access (fs, NULL));
652
/* Make a new transaction and make a propchange on "/A" */
653
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, newrev, SVN_FS_TXN_CHECK_LOCKS, pool));
654
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
655
SVN_ERR (svn_fs_change_node_prop (txn_root, "/A",
656
"foo", svn_string_create ("bar", pool),
659
/* Commit should succeed; this means we're doing a non-recursive
660
lock-check on directory, rather than a recursive one. */
661
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
668
/* DAV clients sometimes LOCK non-existent paths, as a way of
669
reserving names. Check that this technique works. */
671
lock_name_reservation (const char **msg,
672
svn_boolean_t msg_only,
673
svn_test_opts_t *opts,
678
svn_fs_root_t *txn_root, *rev_root;
679
const char *conflict;
681
svn_fs_access_t *access;
685
*msg = "able to reserve a name (lock non-existent path)";
690
/* Prepare a filesystem and a new txn. */
691
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lock-name-reservation",
692
opts->fs_type, pool));
693
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
694
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
696
/* Create the greek tree and commit it. */
697
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
698
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
700
/* Become 'bubba' and lock imaginary path "/A/D/G2/blooga". */
701
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
702
SVN_ERR (svn_fs_set_access (fs, access));
703
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G2/blooga", NULL, "", 0, 0,
704
SVN_INVALID_REVNUM, FALSE, pool));
706
/* We are no longer 'bubba'. We're nobody. */
707
SVN_ERR (svn_fs_set_access (fs, NULL));
709
/* Make a new transaction. */
710
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, newrev, SVN_FS_TXN_CHECK_LOCKS, pool));
711
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
713
/* This copy should fail, because an imaginary path in the target of
714
the copy is reserved by someone else. */
715
SVN_ERR (svn_fs_revision_root (&rev_root, fs, 1, pool));
716
err = svn_fs_copy (rev_root, "/A/D/G", txn_root, "/A/D/G2", pool);
718
return svn_error_create
719
(SVN_ERR_TEST_FAILED, NULL,
720
"Uhoh, copy succeeded when path within target was locked.");
721
svn_error_clear (err);
727
/* Test that we can set and get locks in and under a directory. We'll
728
use non-existent FS paths for this test, though, as the FS API
729
currently disallows directory locking. */
731
directory_locks_kinda (const char **msg,
732
svn_boolean_t msg_only,
733
svn_test_opts_t *opts,
738
svn_fs_root_t *txn_root;
739
svn_fs_access_t *access;
741
apr_size_t num_expected_paths, i;
742
struct get_locks_baton_t *get_locks_baton;
744
*msg = "directory locks (kinda)";
749
/* Prepare a filesystem and a new txn. */
750
SVN_ERR (svn_test__create_fs (&fs, "test-repo-directory-locks-kinda",
751
opts->fs_type, pool));
752
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
753
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
755
/* We are now 'bubba'. */
756
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
757
SVN_ERR (svn_fs_set_access (fs, access));
759
/*** Lock some various, non-existent, yet dir-name-spacily
760
overlapping paths; verify. ***/
762
static const char *expected_paths[] = {
763
"/Program Files/Tigris.org/Subversion",
764
"/Program Files/Tigris.org",
768
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
770
/* Lock all paths under /A/D/G. */
771
for (i = 0; i < num_expected_paths; i++)
773
SVN_ERR (svn_fs_lock (&mylock, fs, expected_paths[i], NULL, "", 0, 0,
774
SVN_INVALID_REVNUM, FALSE, pool));
776
get_locks_baton = make_get_locks_baton (pool);
777
SVN_ERR (svn_fs_get_locks (fs, "/", get_locks_callback,
778
get_locks_baton, pool));
779
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
780
num_expected_paths, pool));
783
/*** Now unlock a "middle directory" ***/
785
static const char *expected_paths[] = {
786
"/Program Files/Tigris.org/Subversion",
790
num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
792
SVN_ERR (svn_fs_unlock (fs, "/Program Files/Tigris.org", NULL,
794
get_locks_baton = make_get_locks_baton (pool);
795
SVN_ERR (svn_fs_get_locks (fs, "/", get_locks_callback,
796
get_locks_baton, pool));
797
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
798
num_expected_paths, pool));
805
/* Test that locks auto-expire correctly. */
807
lock_expiration (const char **msg,
808
svn_boolean_t msg_only,
809
svn_test_opts_t *opts,
814
svn_fs_root_t *txn_root;
815
const char *conflict;
817
svn_fs_access_t *access;
820
struct get_locks_baton_t *get_locks_baton;
822
*msg = "test that locks can expire";
827
/* Prepare a filesystem and a new txn. */
828
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lock-expiration",
829
opts->fs_type, pool));
830
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
831
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
833
/* Create the greek tree and commit it. */
834
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
835
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
837
/* Make a new transaction and change rho. */
838
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, newrev, SVN_FS_TXN_CHECK_LOCKS, pool));
839
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
840
SVN_ERR (svn_test__set_file_contents (txn_root, "/A/D/G/rho",
841
"new contents", pool));
843
/* We are now 'bubba'. */
844
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
845
SVN_ERR (svn_fs_set_access (fs, access));
847
/* Lock /A/D/G/rho, with an expiration 3 seconds from now. */
848
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0,
849
apr_time_now() + apr_time_from_sec(3),
850
SVN_INVALID_REVNUM, FALSE, pool));
853
SVN_ERR (svn_fs_set_access (fs, NULL));
855
/* Try to commit. Should fail because we're 'nobody', and the lock
856
hasn't expired yet. */
857
err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
859
return svn_error_create
860
(SVN_ERR_TEST_FAILED, NULL,
861
"Uhoh, able to commit a file that has a non-expired lock.");
862
svn_error_clear (err);
864
/* Check that the lock is there, by getting it via the paths parent. */
866
static const char *expected_paths [] = {
869
apr_size_t num_expected_paths = (sizeof (expected_paths)
870
/ sizeof (expected_paths[0]));
871
get_locks_baton = make_get_locks_baton (pool);
872
SVN_ERR (svn_fs_get_locks (fs, "/A/D/G", get_locks_callback,
873
get_locks_baton, pool));
874
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
875
num_expected_paths, pool));
878
/* Sleep 5 seconds, so the lock auto-expires. Anonymous commit
879
should then succeed. */
880
apr_sleep (apr_time_from_sec(5));
882
/* Verify that the lock auto-expired even in the recursive case. */
884
static const char *expected_paths [] = { 0 };
885
apr_size_t num_expected_paths = 0;
886
get_locks_baton = make_get_locks_baton (pool);
887
SVN_ERR (svn_fs_get_locks (fs, "/A/D/G", get_locks_callback,
888
get_locks_baton, pool));
889
SVN_ERR (verify_matching_lock_paths (get_locks_baton, expected_paths,
890
num_expected_paths, pool));
893
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
898
/* Test that a lock can be broken, stolen, or refreshed */
900
lock_break_steal_refresh (const char **msg,
901
svn_boolean_t msg_only,
902
svn_test_opts_t *opts,
907
svn_fs_root_t *txn_root;
908
const char *conflict;
910
svn_fs_access_t *access;
911
svn_lock_t *mylock, *somelock;
913
*msg = "breaking, stealing, refreshing a lock";
918
/* Prepare a filesystem and a new txn. */
919
SVN_ERR (svn_test__create_fs (&fs, "test-repo-steal-refresh",
920
opts->fs_type, pool));
921
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
922
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
924
/* Create the greek tree and commit it. */
925
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
926
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
928
/* Become 'bubba' and lock "/A/D/G/rho". */
929
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
930
SVN_ERR (svn_fs_set_access (fs, access));
931
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
932
SVN_INVALID_REVNUM, FALSE, pool));
934
/* Become 'hortense' and break bubba's lock, then verify it's gone. */
935
SVN_ERR (svn_fs_create_access (&access, "hortense", pool));
936
SVN_ERR (svn_fs_set_access (fs, access));
937
SVN_ERR (svn_fs_unlock (fs, mylock->path, mylock->token,
938
1 /* FORCE BREAK */, pool));
939
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
941
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
942
"Tried to break a lock, but it's still there.");
944
/* As hortense, create a new lock, and verify that we own it. */
945
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0,
946
SVN_INVALID_REVNUM, FALSE, pool));
947
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
948
if (strcmp (somelock->owner, mylock->owner) != 0)
949
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
950
"Made a lock, but we don't seem to own it.");
952
/* As bubba, steal hortense's lock, creating a new one that expires. */
953
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
954
SVN_ERR (svn_fs_set_access (fs, access));
955
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0,
956
apr_time_now() + apr_time_from_sec(300), /* 5 min. */
958
TRUE /* FORCE STEAL */,
960
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
961
if (strcmp (somelock->owner, mylock->owner) != 0)
962
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
963
"Made a lock, but we don't seem to own it.");
964
if (! somelock->expiration_date)
965
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
966
"Made expiring lock, but seems not to expire.");
968
/* Refresh the lock, so that it never expires. */
969
SVN_ERR (svn_fs_lock (&somelock, fs, somelock->path, somelock->token,
970
somelock->comment, 0, 0,
972
TRUE /* FORCE STEAL */,
974
SVN_ERR (svn_fs_get_lock (&somelock, fs, "/A/D/G/rho", pool));
975
if (somelock->expiration_date)
976
return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
977
"Made non-expirirng lock, but it expires.");
983
/* Test that svn_fs_lock() and svn_fs_attach_lock() can do
984
out-of-dateness checks.. */
986
lock_out_of_date (const char **msg,
987
svn_boolean_t msg_only,
988
svn_test_opts_t *opts,
993
svn_fs_root_t *txn_root;
994
const char *conflict;
996
svn_fs_access_t *access;
1000
*msg = "check out-of-dateness before locking";
1003
return SVN_NO_ERROR;
1005
/* Prepare a filesystem and a new txn. */
1006
SVN_ERR (svn_test__create_fs (&fs, "test-repo-lock-out-of-date",
1007
opts->fs_type, pool));
1008
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, 0, SVN_FS_TXN_CHECK_LOCKS, pool));
1009
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
1011
/* Create the greek tree and commit it. */
1012
SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
1013
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
1015
/* Commit a small change to /A/D/G/rho, creating revision 2. */
1016
SVN_ERR (svn_fs_begin_txn2 (&txn, fs, newrev, SVN_FS_TXN_CHECK_LOCKS, pool));
1017
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
1018
SVN_ERR (svn_test__set_file_contents (txn_root, "/A/D/G/rho",
1019
"new contents", pool));
1020
SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
1022
/* We are now 'bubba'. */
1023
SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
1024
SVN_ERR (svn_fs_set_access (fs, access));
1026
/* Try to lock /A/D/G/rho, but claim that we still have r1 of the file. */
1027
err = svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0, 0, 1, FALSE, pool);
1029
return svn_error_create
1030
(SVN_ERR_TEST_FAILED, NULL,
1031
"Uhoh, able to lock an out-of-date file.");
1032
svn_error_clear (err);
1034
/* Attempt lock again, this time claiming to have r2. */
1035
SVN_ERR (svn_fs_lock (&mylock, fs, "/A/D/G/rho", NULL, "", 0,
1036
0, 2, FALSE, pool));
1038
/* 'Refresh' the lock, claiming to have r1... should fail. */
1039
err = svn_fs_lock (&mylock, fs, mylock->path,
1040
mylock->token, mylock->comment, 0,
1041
apr_time_now() + apr_time_from_sec(50),
1043
TRUE /* FORCE STEAL */,
1046
return svn_error_create
1047
(SVN_ERR_TEST_FAILED, NULL,
1048
"Uhoh, able to refresh a lock on an out-of-date file.");
1049
svn_error_clear (err);
1051
return SVN_NO_ERROR;
1056
/* ------------------------------------------------------------------------ */
1058
/* The test table. */
1060
struct svn_test_descriptor_t test_funcs[] =
1063
SVN_TEST_PASS (lock_only),
1064
SVN_TEST_PASS (lookup_lock_by_path),
1065
SVN_TEST_PASS (attach_lock),
1066
SVN_TEST_PASS (get_locks),
1067
SVN_TEST_PASS (basic_lock),
1068
SVN_TEST_PASS (lock_credentials),
1069
SVN_TEST_PASS (final_lock_check),
1070
SVN_TEST_PASS (lock_dir_propchange),
1071
SVN_TEST_XFAIL (lock_name_reservation),
1072
SVN_TEST_XFAIL (directory_locks_kinda),
1073
SVN_TEST_PASS (lock_expiration),
1074
SVN_TEST_PASS (lock_break_steal_refresh),
1075
SVN_TEST_PASS (lock_out_of_date),