~svn/ubuntu/raring/subversion/ppa

« back to all changes in this revision

Viewing changes to subversion/tests/libsvn_fs/locks-test.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* lock-test.c --- tests for the filesystem locking functions
 
2
 *
 
3
 * ====================================================================
 
4
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 
5
 *
 
6
 * This software is licensed as described in the file COPYING, which
 
7
 * you should have received as part of this distribution.  The terms
 
8
 * are also available at http://subversion.tigris.org/license-1.html.
 
9
 * If newer versions of this license are posted there, you may use a
 
10
 * newer version instead, at your option.
 
11
 *
 
12
 * This software consists of voluntary contributions made by many
 
13
 * individuals.  For exact contribution history, see the revision
 
14
 * history and logs, available at http://subversion.tigris.org/.
 
15
 * ====================================================================
 
16
 */
 
17
 
 
18
/* TODO how many of these can I get rid of? */
 
19
#include <stdlib.h>
 
20
#include <string.h>
 
21
#include <apr_pools.h>
 
22
#include <apr_time.h>
 
23
#include <apr_md5.h>
 
24
 
 
25
#include "svn_pools.h"
 
26
#include "svn_error.h"
 
27
#include "svn_time.h"
 
28
#include "svn_fs.h"
 
29
#include "svn_path.h"
 
30
#include "svn_delta.h"
 
31
#include "svn_md5.h"
 
32
#include "svn_props.h"
 
33
 
 
34
#include "../fs-helpers.h"
 
35
 
 
36
#define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))
 
37
 
 
38
 
 
39
/*-----------------------------------------------------------------*/
 
40
 
 
41
/** Helper functions **/
 
42
 
 
43
/* Implementations of the svn_fs_get_locks_callback_t interface and
 
44
   baton, for verifying expected output from svn_fs_get_locks(). */
 
45
 
 
46
struct get_locks_baton_t
 
47
{
 
48
  apr_hash_t *locks;
 
49
};
 
50
 
 
51
static svn_error_t *
 
52
get_locks_callback (void *baton, 
 
53
                    svn_lock_t *lock, 
 
54
                    apr_pool_t *pool)
 
55
{
 
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));
 
61
  return SVN_NO_ERROR;
 
62
}
 
63
 
 
64
/* A factory function. */
 
65
 
 
66
static struct get_locks_baton_t *
 
67
make_get_locks_baton (apr_pool_t *pool)
 
68
{
 
69
  struct get_locks_baton_t *baton = apr_pcalloc (pool, sizeof (*baton));
 
70
  baton->locks = apr_hash_make (pool);
 
71
  return baton;
 
72
}
 
73
     
 
74
     
 
75
/* And verification function(s). */
 
76
 
 
77
static svn_error_t *
 
78
verify_matching_lock_paths (struct get_locks_baton_t *baton,
 
79
                            const char *expected_paths[],
 
80
                            apr_size_t num_expected_paths,
 
81
                            apr_pool_t *pool)
 
82
{
 
83
  apr_size_t i;
 
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++)
 
88
    {
 
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);
 
93
    }
 
94
  return SVN_NO_ERROR;
 
95
}
 
96
 
 
97
 
 
98
/*-----------------------------------------------------------------*/
 
99
 
 
100
/** The actual lock-tests called by `make check` **/
 
101
 
 
102
 
 
103
 
 
104
/* Test that we can create a lock--nothing more.  */
 
105
static svn_error_t *
 
106
lock_only (const char **msg,
 
107
           svn_boolean_t msg_only,
 
108
           svn_test_opts_t *opts,
 
109
           apr_pool_t *pool)
 
110
{
 
111
  svn_fs_t *fs;
 
112
  svn_fs_txn_t *txn;
 
113
  svn_fs_root_t *txn_root;
 
114
  const char *conflict;
 
115
  svn_revnum_t newrev;
 
116
  svn_fs_access_t *access;
 
117
  svn_lock_t *mylock;
 
118
  
 
119
  *msg = "lock only";
 
120
 
 
121
  if (msg_only)
 
122
    return SVN_NO_ERROR;
 
123
 
 
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));
 
129
 
 
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));
 
133
 
 
134
  /* We are now 'bubba'. */
 
135
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
136
  SVN_ERR (svn_fs_set_access (fs, access));
 
137
 
 
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));
 
141
 
 
142
  return SVN_NO_ERROR;
 
143
}
 
144
 
 
145
 
 
146
 
 
147
 
 
148
 
 
149
/* Test that we can create, fetch, and destroy a lock.  It exercises
 
150
   each of the five public fs locking functions.  */
 
151
static svn_error_t *
 
152
lookup_lock_by_path (const char **msg,
 
153
                     svn_boolean_t msg_only,
 
154
                     svn_test_opts_t *opts,
 
155
                     apr_pool_t *pool)
 
156
{
 
157
  svn_fs_t *fs;
 
158
  svn_fs_txn_t *txn;
 
159
  svn_fs_root_t *txn_root;
 
160
  const char *conflict;
 
161
  svn_revnum_t newrev;
 
162
  svn_fs_access_t *access;
 
163
  svn_lock_t *mylock, *somelock;
 
164
  
 
165
  *msg = "lookup lock by path";
 
166
 
 
167
  if (msg_only)
 
168
    return SVN_NO_ERROR;
 
169
 
 
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));
 
175
 
 
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));
 
179
 
 
180
  /* We are now 'bubba'. */
 
181
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
182
  SVN_ERR (svn_fs_set_access (fs, access));
 
183
 
 
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));
 
187
 
 
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.");
 
193
 
 
194
  return SVN_NO_ERROR;
 
195
}
 
196
 
 
197
/* Test that we can create a lock outside of the fs and attach it to a
 
198
   path.  */
 
199
static svn_error_t *
 
200
attach_lock (const char **msg,
 
201
             svn_boolean_t msg_only,
 
202
             svn_test_opts_t *opts,
 
203
             apr_pool_t *pool)
 
204
{
 
205
  svn_fs_t *fs;
 
206
  svn_fs_txn_t *txn;
 
207
  svn_fs_root_t *txn_root;
 
208
  const char *conflict;
 
209
  svn_revnum_t newrev;
 
210
  svn_fs_access_t *access;
 
211
  svn_lock_t *somelock;
 
212
  svn_lock_t *mylock;
 
213
  const char *token;
 
214
 
 
215
  *msg = "attach lock";
 
216
 
 
217
  if (msg_only)
 
218
    return SVN_NO_ERROR;
 
219
 
 
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));
 
225
 
 
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));
 
229
 
 
230
  /* We are now 'bubba'. */
 
231
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
232
  SVN_ERR (svn_fs_set_access (fs, access));
 
233
 
 
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));
 
239
 
 
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.");
 
245
 
 
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));
 
249
  if (somelock)
 
250
    return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
 
251
                             "Removed a lock, but it's still there.");
 
252
 
 
253
  return SVN_NO_ERROR;
 
254
}
 
255
 
 
256
 
 
257
/* Test that we can get all locks under a directory. */
 
258
static svn_error_t *
 
259
get_locks (const char **msg,
 
260
           svn_boolean_t msg_only,
 
261
           svn_test_opts_t *opts,
 
262
           apr_pool_t *pool)
 
263
{
 
264
  svn_fs_t *fs;
 
265
  svn_fs_txn_t *txn;
 
266
  svn_fs_root_t *txn_root;
 
267
  const char *conflict;
 
268
  svn_revnum_t newrev;
 
269
  svn_fs_access_t *access;
 
270
  svn_lock_t *mylock;
 
271
  struct get_locks_baton_t *get_locks_baton;
 
272
  apr_size_t i, num_expected_paths;
 
273
 
 
274
  *msg = "get locks";
 
275
 
 
276
  if (msg_only)
 
277
    return SVN_NO_ERROR;
 
278
 
 
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));
 
284
 
 
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));
 
288
 
 
289
  /* We are now 'bubba'. */
 
290
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
291
  SVN_ERR (svn_fs_set_access (fs, access));
 
292
 
 
293
  /* Lock our paths; verify from "/". */
 
294
  {
 
295
    static const char *expected_paths[] = { 
 
296
      "/A/D/G/pi", 
 
297
      "/A/D/G/rho", 
 
298
      "/A/D/G/tau",
 
299
      "/A/D/H/psi", 
 
300
      "/A/D/H/chi", 
 
301
      "/A/D/H/omega",
 
302
      "/A/B/E/alpha",
 
303
      "/A/B/E/beta",
 
304
    };
 
305
    num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
 
306
    for (i = 0; i < num_expected_paths; i++)
 
307
      {
 
308
        SVN_ERR (svn_fs_lock (&mylock, fs, expected_paths[i], NULL, "", 0, 0, 
 
309
                              SVN_INVALID_REVNUM, FALSE, pool));
 
310
      }
 
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));
 
316
  }
 
317
 
 
318
  /* Verify from "/A/B". */
 
319
  {
 
320
    static const char *expected_paths[] = { 
 
321
      "/A/B/E/alpha",
 
322
      "/A/B/E/beta",
 
323
    };
 
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));
 
330
  }
 
331
 
 
332
  /* Verify from "/A/D". */
 
333
  {
 
334
    static const char *expected_paths[] = { 
 
335
      "/A/D/G/pi", 
 
336
      "/A/D/G/rho", 
 
337
      "/A/D/G/tau",
 
338
      "/A/D/H/psi", 
 
339
      "/A/D/H/chi", 
 
340
      "/A/D/H/omega",
 
341
    };
 
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));
 
348
  }
 
349
 
 
350
  /* Verify from "/A/D/G". */
 
351
  {
 
352
    static const char *expected_paths[] = { 
 
353
      "/A/D/G/pi", 
 
354
      "/A/D/G/rho", 
 
355
      "/A/D/G/tau",
 
356
    };
 
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));
 
363
  }
 
364
                                    
 
365
  /* Verify from "/A/D/H/omega". */
 
366
  {
 
367
    static const char *expected_paths[] = { 
 
368
      "/A/D/H/omega",
 
369
    };
 
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));
 
376
  }
 
377
 
 
378
  /* Verify from "/iota" (which wasn't locked... tricky...). */
 
379
  {
 
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));
 
387
  }
 
388
 
 
389
  return SVN_NO_ERROR;
 
390
}
 
391
 
 
392
 
 
393
/* Test that we can create, fetch, and destroy a lock.  It exercises
 
394
   each of the five public fs locking functions.  */
 
395
static svn_error_t *
 
396
basic_lock (const char **msg,
 
397
            svn_boolean_t msg_only,
 
398
            svn_test_opts_t *opts,
 
399
            apr_pool_t *pool)
 
400
{
 
401
  svn_fs_t *fs;
 
402
  svn_fs_txn_t *txn;
 
403
  svn_fs_root_t *txn_root;
 
404
  const char *conflict;
 
405
  svn_revnum_t newrev;
 
406
  svn_fs_access_t *access;
 
407
  svn_lock_t *mylock, *somelock;
 
408
  
 
409
  *msg = "basic locking";
 
410
 
 
411
  if (msg_only)
 
412
    return SVN_NO_ERROR;
 
413
 
 
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));
 
419
 
 
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));
 
423
 
 
424
  /* We are now 'bubba'. */
 
425
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
426
  SVN_ERR (svn_fs_set_access (fs, access));
 
427
 
 
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));
 
431
 
 
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.");
 
437
    
 
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));
 
441
  if (somelock)
 
442
    return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
 
443
                             "Removed a lock, but it's still there.");
 
444
 
 
445
  return SVN_NO_ERROR;
 
446
}
 
447
 
 
448
 
 
449
 
 
450
/* Test that locks are enforced -- specifically that both a username
 
451
   and token are required to make use of the lock.  */
 
452
static svn_error_t *
 
453
lock_credentials (const char **msg,
 
454
                  svn_boolean_t msg_only,
 
455
                  svn_test_opts_t *opts,
 
456
                  apr_pool_t *pool)
 
457
{
 
458
  svn_fs_t *fs;
 
459
  svn_fs_txn_t *txn;
 
460
  svn_fs_root_t *txn_root;
 
461
  const char *conflict;
 
462
  svn_revnum_t newrev;
 
463
  svn_fs_access_t *access;
 
464
  svn_lock_t *mylock;
 
465
  svn_error_t *err;
 
466
 
 
467
  *msg = "test that locking requires proper credentials";
 
468
 
 
469
  if (msg_only)
 
470
    return SVN_NO_ERROR;
 
471
 
 
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));
 
477
 
 
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));
 
481
 
 
482
  /* We are now 'bubba'. */
 
483
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
484
  SVN_ERR (svn_fs_set_access (fs, access));
 
485
 
 
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));
 
489
 
 
490
  /* Push the proper lock-token into the fs access context. */
 
491
  SVN_ERR (svn_fs_access_add_lock_token (access, mylock->token));
 
492
 
 
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));
 
498
 
 
499
  /* We are no longer 'bubba'.  We're nobody. */
 
500
  SVN_ERR (svn_fs_set_access (fs, NULL));
 
501
 
 
502
  /* Try to commit the file change.  Should fail, because we're nobody. */
 
503
  err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
 
504
  if (! err)
 
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);
 
509
    
 
510
  /* We are now 'hortense'. */
 
511
  SVN_ERR (svn_fs_create_access (&access, "hortense", pool));
 
512
  SVN_ERR (svn_fs_set_access (fs, access));
 
513
 
 
514
  /* Try to commit the file change.  Should fail, because we're 'hortense'. */
 
515
  err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
 
516
  if (! err)
 
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);
 
521
 
 
522
  /* Be 'bubba' again. */
 
523
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
524
  SVN_ERR (svn_fs_set_access (fs, access));
 
525
  
 
526
  /* Try to commit the file change.  Should fail, because there's no token. */
 
527
  err = svn_fs_commit_txn (&conflict, &newrev, txn, pool);
 
528
  if (! err)
 
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);
 
533
  
 
534
  /* Push the proper lock-token into the fs access context. */
 
535
  SVN_ERR (svn_fs_access_add_lock_token (access, mylock->token));
 
536
 
 
537
  /* Commit should now succeed. */
 
538
  SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
 
539
 
 
540
  return SVN_NO_ERROR;
 
541
}
 
542
 
 
543
 
 
544
 
 
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. */
 
549
static svn_error_t *
 
550
final_lock_check (const char **msg,
 
551
                  svn_boolean_t msg_only,
 
552
                  svn_test_opts_t *opts,
 
553
                  apr_pool_t *pool)
 
554
{
 
555
  svn_fs_t *fs;
 
556
  svn_fs_txn_t *txn;
 
557
  svn_fs_root_t *txn_root;
 
558
  const char *conflict;
 
559
  svn_revnum_t newrev;
 
560
  svn_fs_access_t *access;
 
561
  svn_lock_t *mylock;
 
562
  svn_error_t *err;
 
563
 
 
564
  *msg = "test that locking is enforced in final commit step";
 
565
 
 
566
  if (msg_only)
 
567
    return SVN_NO_ERROR;
 
568
 
 
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));
 
574
 
 
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));
 
578
 
 
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));
 
583
 
 
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));
 
589
 
 
590
  /* We are no longer 'bubba'.  We're nobody. */
 
591
  SVN_ERR (svn_fs_set_access (fs, NULL));
 
592
 
 
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);
 
596
  if (! err)
 
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);
 
601
 
 
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));
 
606
 
 
607
  return SVN_NO_ERROR;
 
608
}
 
609
 
 
610
 
 
611
 
 
612
/* If a directory's child is locked by someone else, we should still
 
613
   be able to commit a propchange on the directory. */
 
614
static svn_error_t *
 
615
lock_dir_propchange (const char **msg,
 
616
                     svn_boolean_t msg_only,
 
617
                     svn_test_opts_t *opts,
 
618
                     apr_pool_t *pool)
 
619
{
 
620
  svn_fs_t *fs;
 
621
  svn_fs_txn_t *txn;
 
622
  svn_fs_root_t *txn_root;
 
623
  const char *conflict;
 
624
  svn_revnum_t newrev;
 
625
  svn_fs_access_t *access;
 
626
  svn_lock_t *mylock;
 
627
 
 
628
  *msg = "dir propchange can be committed with locked child";
 
629
 
 
630
  if (msg_only)
 
631
    return SVN_NO_ERROR;
 
632
 
 
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));
 
638
 
 
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));
 
642
 
 
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));
 
648
 
 
649
  /* We are no longer 'bubba'.  We're nobody. */
 
650
  SVN_ERR (svn_fs_set_access (fs, NULL));
 
651
 
 
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),
 
657
                                    pool));
 
658
 
 
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));
 
662
 
 
663
  return SVN_NO_ERROR;
 
664
}
 
665
 
 
666
 
 
667
 
 
668
/* DAV clients sometimes LOCK non-existent paths, as a way of
 
669
   reserving names.  Check that this technique works. */
 
670
static svn_error_t *
 
671
lock_name_reservation (const char **msg,
 
672
                       svn_boolean_t msg_only,
 
673
                       svn_test_opts_t *opts,
 
674
                       apr_pool_t *pool)
 
675
{
 
676
  svn_fs_t *fs;
 
677
  svn_fs_txn_t *txn;
 
678
  svn_fs_root_t *txn_root, *rev_root;
 
679
  const char *conflict;
 
680
  svn_revnum_t newrev;
 
681
  svn_fs_access_t *access;
 
682
  svn_lock_t *mylock;
 
683
  svn_error_t *err;
 
684
 
 
685
  *msg = "able to reserve a name (lock non-existent path)";
 
686
 
 
687
  if (msg_only)
 
688
    return SVN_NO_ERROR;
 
689
 
 
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));
 
695
 
 
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));
 
699
 
 
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));
 
705
 
 
706
  /* We are no longer 'bubba'.  We're nobody. */
 
707
  SVN_ERR (svn_fs_set_access (fs, NULL));
 
708
 
 
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));
 
712
 
 
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);
 
717
  if (! err)
 
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);
 
722
   
 
723
  return SVN_NO_ERROR;
 
724
}
 
725
 
 
726
 
 
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.  */
 
730
static svn_error_t *
 
731
directory_locks_kinda (const char **msg,
 
732
                       svn_boolean_t msg_only,
 
733
                       svn_test_opts_t *opts,
 
734
                       apr_pool_t *pool)
 
735
{
 
736
  svn_fs_t *fs;
 
737
  svn_fs_txn_t *txn;
 
738
  svn_fs_root_t *txn_root;
 
739
  svn_fs_access_t *access;
 
740
  svn_lock_t *mylock;
 
741
  apr_size_t num_expected_paths, i;
 
742
  struct get_locks_baton_t *get_locks_baton;
 
743
 
 
744
  *msg = "directory locks (kinda)";
 
745
 
 
746
  if (msg_only)
 
747
    return SVN_NO_ERROR;
 
748
 
 
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));
 
754
 
 
755
  /* We are now 'bubba'. */
 
756
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
757
  SVN_ERR (svn_fs_set_access (fs, access));
 
758
 
 
759
  /*** Lock some various, non-existent, yet dir-name-spacily
 
760
       overlapping paths; verify. ***/
 
761
  {
 
762
    static const char *expected_paths[] = { 
 
763
      "/Program Files/Tigris.org/Subversion", 
 
764
      "/Program Files/Tigris.org",
 
765
      "/Stuff/Junk/Fluff",
 
766
      "/Program Files",
 
767
    };
 
768
    num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
 
769
 
 
770
    /* Lock all paths under /A/D/G. */
 
771
    for (i = 0; i < num_expected_paths; i++)
 
772
      {
 
773
        SVN_ERR (svn_fs_lock (&mylock, fs, expected_paths[i], NULL, "", 0, 0, 
 
774
                              SVN_INVALID_REVNUM, FALSE, pool));
 
775
      }
 
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));
 
781
  }
 
782
 
 
783
  /*** Now unlock a "middle directory" ***/
 
784
  {
 
785
    static const char *expected_paths[] = { 
 
786
      "/Program Files/Tigris.org/Subversion", 
 
787
      "/Stuff/Junk/Fluff",
 
788
      "/Program Files",
 
789
    };
 
790
    num_expected_paths = sizeof (expected_paths) / sizeof (const char *);
 
791
 
 
792
    SVN_ERR (svn_fs_unlock (fs, "/Program Files/Tigris.org", NULL, 
 
793
                            TRUE, pool));
 
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));
 
799
  }
 
800
 
 
801
  return SVN_NO_ERROR;
 
802
}
 
803
 
 
804
 
 
805
/* Test that locks auto-expire correctly. */
 
806
static svn_error_t *
 
807
lock_expiration (const char **msg,
 
808
                 svn_boolean_t msg_only,
 
809
                 svn_test_opts_t *opts,
 
810
                 apr_pool_t *pool)
 
811
{
 
812
  svn_fs_t *fs;
 
813
  svn_fs_txn_t *txn;
 
814
  svn_fs_root_t *txn_root;
 
815
  const char *conflict;
 
816
  svn_revnum_t newrev;
 
817
  svn_fs_access_t *access;
 
818
  svn_lock_t *mylock;
 
819
  svn_error_t *err;
 
820
  struct get_locks_baton_t *get_locks_baton;
 
821
 
 
822
  *msg = "test that locks can expire";
 
823
 
 
824
  if (msg_only)
 
825
    return SVN_NO_ERROR;
 
826
 
 
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));
 
832
 
 
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));
 
836
 
 
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));
 
842
 
 
843
  /* We are now 'bubba'. */
 
844
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
845
  SVN_ERR (svn_fs_set_access (fs, access));
 
846
 
 
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));
 
851
 
 
852
  /* Become nobody. */
 
853
  SVN_ERR (svn_fs_set_access (fs, NULL));
 
854
  
 
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);
 
858
  if (! err)
 
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);
 
863
 
 
864
  /* Check that the lock is there, by getting it via the paths parent. */
 
865
  {
 
866
    static const char *expected_paths [] = {
 
867
      "/A/D/G/rho"
 
868
    };
 
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));
 
876
  }
 
877
 
 
878
  /* Sleep 5 seconds, so the lock auto-expires.  Anonymous commit
 
879
     should then succeed. */
 
880
  apr_sleep (apr_time_from_sec(5));
 
881
 
 
882
  /* Verify that the lock auto-expired even in the recursive case. */
 
883
  {
 
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));
 
891
  }
 
892
 
 
893
  SVN_ERR (svn_fs_commit_txn (&conflict, &newrev, txn, pool));
 
894
 
 
895
  return SVN_NO_ERROR;
 
896
}
 
897
 
 
898
/* Test that a lock can be broken, stolen, or refreshed */
 
899
static svn_error_t *
 
900
lock_break_steal_refresh (const char **msg,
 
901
                          svn_boolean_t msg_only,
 
902
                          svn_test_opts_t *opts,
 
903
                          apr_pool_t *pool)
 
904
{
 
905
  svn_fs_t *fs;
 
906
  svn_fs_txn_t *txn;
 
907
  svn_fs_root_t *txn_root;
 
908
  const char *conflict;
 
909
  svn_revnum_t newrev;
 
910
  svn_fs_access_t *access;
 
911
  svn_lock_t *mylock, *somelock;
 
912
 
 
913
  *msg = "breaking, stealing, refreshing a lock";
 
914
 
 
915
  if (msg_only)
 
916
    return SVN_NO_ERROR;
 
917
 
 
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));
 
923
 
 
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));
 
927
 
 
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));
 
933
 
 
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));
 
940
  if (somelock)
 
941
    return svn_error_create (SVN_ERR_TEST_FAILED, NULL,
 
942
                             "Tried to break a lock, but it's still there.");
 
943
 
 
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.");
 
951
  
 
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. */
 
957
                        SVN_INVALID_REVNUM, 
 
958
                        TRUE /* FORCE STEAL */,
 
959
                        pool));
 
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.");
 
967
    
 
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,
 
971
                        SVN_INVALID_REVNUM, 
 
972
                        TRUE /* FORCE STEAL */,
 
973
                        pool));
 
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.");  
 
978
 
 
979
  return SVN_NO_ERROR;
 
980
}
 
981
 
 
982
 
 
983
/* Test that svn_fs_lock() and svn_fs_attach_lock() can do
 
984
   out-of-dateness checks..  */
 
985
static svn_error_t *
 
986
lock_out_of_date (const char **msg,
 
987
                  svn_boolean_t msg_only,
 
988
                  svn_test_opts_t *opts,
 
989
                  apr_pool_t *pool)
 
990
{
 
991
  svn_fs_t *fs;
 
992
  svn_fs_txn_t *txn;
 
993
  svn_fs_root_t *txn_root;
 
994
  const char *conflict;
 
995
  svn_revnum_t newrev;
 
996
  svn_fs_access_t *access;
 
997
  svn_lock_t *mylock;
 
998
  svn_error_t *err;
 
999
  
 
1000
  *msg = "check out-of-dateness before locking";
 
1001
 
 
1002
  if (msg_only)
 
1003
    return SVN_NO_ERROR;
 
1004
 
 
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));
 
1010
 
 
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));
 
1014
 
 
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));
 
1021
  
 
1022
  /* We are now 'bubba'. */
 
1023
  SVN_ERR (svn_fs_create_access (&access, "bubba", pool));
 
1024
  SVN_ERR (svn_fs_set_access (fs, access));
 
1025
 
 
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);
 
1028
  if (! err)
 
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);
 
1033
 
 
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));
 
1037
 
 
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),
 
1042
                     1,
 
1043
                     TRUE /* FORCE STEAL */,
 
1044
                     pool);
 
1045
  if (! err)
 
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);
 
1050
 
 
1051
  return SVN_NO_ERROR;
 
1052
}
 
1053
 
 
1054
 
 
1055
 
 
1056
/* ------------------------------------------------------------------------ */
 
1057
 
 
1058
/* The test table.  */
 
1059
 
 
1060
struct svn_test_descriptor_t test_funcs[] =
 
1061
  {
 
1062
    SVN_TEST_NULL,
 
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),
 
1076
    SVN_TEST_NULL
 
1077
  };