~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/tests/libsvn_fs_fs/fs-pack-test.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* fs-pack-test.c --- tests for the filesystem
2
 
 *
3
 
 * ====================================================================
4
 
 *    Licensed to the Apache Software Foundation (ASF) under one
5
 
 *    or more contributor license agreements.  See the NOTICE file
6
 
 *    distributed with this work for additional information
7
 
 *    regarding copyright ownership.  The ASF licenses this file
8
 
 *    to you under the Apache License, Version 2.0 (the
9
 
 *    "License"); you may not use this file except in compliance
10
 
 *    with the License.  You may obtain a copy of the License at
11
 
 *
12
 
 *      http://www.apache.org/licenses/LICENSE-2.0
13
 
 *
14
 
 *    Unless required by applicable law or agreed to in writing,
15
 
 *    software distributed under the License is distributed on an
16
 
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
 
 *    KIND, either express or implied.  See the License for the
18
 
 *    specific language governing permissions and limitations
19
 
 *    under the License.
20
 
 * ====================================================================
21
 
 */
22
 
 
23
 
#include <stdlib.h>
24
 
#include <string.h>
25
 
#include <apr_pools.h>
26
 
 
27
 
#include "../svn_test.h"
28
 
#include "../../libsvn_fs_fs/fs.h"
29
 
 
30
 
#include "svn_pools.h"
31
 
#include "svn_props.h"
32
 
#include "svn_fs.h"
33
 
#include "private/svn_string_private.h"
34
 
 
35
 
#include "../svn_test_fs.h"
36
 
 
37
 
 
38
 
 
39
 
/*** Helper Functions ***/
40
 
 
41
 
static void
42
 
ignore_fs_warnings(void *baton, svn_error_t *err)
43
 
{
44
 
#ifdef SVN_DEBUG
45
 
  SVN_DBG(("Ignoring FS warning %s\n",
46
 
           svn_error_symbolic_name(err ? err->apr_err : 0)));
47
 
#endif
48
 
  return;
49
 
}
50
 
 
51
 
/* Write the format number and maximum number of files per directory
52
 
   to a new format file in PATH, overwriting a previously existing
53
 
   file.  Use POOL for temporary allocation.
54
 
 
55
 
   (This implementation is largely stolen from libsvn_fs_fs/fs_fs.c.) */
56
 
static svn_error_t *
57
 
write_format(const char *path,
58
 
             int format,
59
 
             int max_files_per_dir,
60
 
             apr_pool_t *pool)
61
 
{
62
 
  const char *contents;
63
 
 
64
 
  path = svn_dirent_join(path, "format", pool);
65
 
 
66
 
  if (format >= SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT)
67
 
    {
68
 
      if (max_files_per_dir)
69
 
        contents = apr_psprintf(pool,
70
 
                                "%d\n"
71
 
                                "layout sharded %d\n",
72
 
                                format, max_files_per_dir);
73
 
      else
74
 
        contents = apr_psprintf(pool,
75
 
                                "%d\n"
76
 
                                "layout linear",
77
 
                                format);
78
 
    }
79
 
  else
80
 
    {
81
 
      contents = apr_psprintf(pool, "%d\n", format);
82
 
    }
83
 
 
84
 
    {
85
 
      const char *path_tmp;
86
 
 
87
 
      SVN_ERR(svn_io_write_unique(&path_tmp,
88
 
                                  svn_dirent_dirname(path, pool),
89
 
                                  contents, strlen(contents),
90
 
                                  svn_io_file_del_none, pool));
91
 
 
92
 
      /* rename the temp file as the real destination */
93
 
      SVN_ERR(svn_io_file_rename(path_tmp, path, pool));
94
 
    }
95
 
 
96
 
  /* And set the perms to make it read only */
97
 
  return svn_io_set_file_read_only(path, FALSE, pool);
98
 
}
99
 
 
100
 
/* Return the expected contents of "iota" in revision REV. */
101
 
static const char *
102
 
get_rev_contents(svn_revnum_t rev, apr_pool_t *pool)
103
 
{
104
 
  /* Toss in a bunch of magic numbers for spice. */
105
 
  apr_int64_t num = ((rev * 1234353 + 4358) * 4583 + ((rev % 4) << 1)) / 42;
106
 
  return apr_psprintf(pool, "%" APR_INT64_T_FMT "\n", num);
107
 
}
108
 
 
109
 
struct pack_notify_baton
110
 
{
111
 
  apr_int64_t expected_shard;
112
 
  svn_fs_pack_notify_action_t expected_action;
113
 
};
114
 
 
115
 
static svn_error_t *
116
 
pack_notify(void *baton,
117
 
            apr_int64_t shard,
118
 
            svn_fs_pack_notify_action_t action,
119
 
            apr_pool_t *pool)
120
 
{
121
 
  struct pack_notify_baton *pnb = baton;
122
 
 
123
 
  SVN_TEST_ASSERT(shard == pnb->expected_shard);
124
 
  SVN_TEST_ASSERT(action == pnb->expected_action);
125
 
 
126
 
  /* Update expectations. */
127
 
  switch (action)
128
 
    {
129
 
      case svn_fs_pack_notify_start:
130
 
        pnb->expected_action = svn_fs_pack_notify_end;
131
 
        break;
132
 
 
133
 
      case svn_fs_pack_notify_end:
134
 
        pnb->expected_action = svn_fs_pack_notify_start;
135
 
        pnb->expected_shard++;
136
 
        break;
137
 
 
138
 
      default:
139
 
        return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
140
 
                                "Unknown notification action when packing");
141
 
    }
142
 
 
143
 
  return SVN_NO_ERROR;
144
 
}
145
 
 
146
 
/* Create a packed filesystem in DIR.  Set the shard size to
147
 
   SHARD_SIZE and create NUM_REVS number of revisions (in addition to
148
 
   r0).  Use POOL for allocations.  After this function successfully
149
 
   completes, the filesystem's youngest revision number will be the
150
 
   same as NUM_REVS.  */
151
 
static svn_error_t *
152
 
create_packed_filesystem(const char *dir,
153
 
                         const svn_test_opts_t *opts,
154
 
                         int num_revs,
155
 
                         int shard_size,
156
 
                         apr_pool_t *pool)
157
 
{
158
 
  svn_fs_t *fs;
159
 
  svn_fs_txn_t *txn;
160
 
  svn_fs_root_t *txn_root;
161
 
  const char *conflict;
162
 
  svn_revnum_t after_rev;
163
 
  apr_pool_t *subpool = svn_pool_create(pool);
164
 
  struct pack_notify_baton pnb;
165
 
  apr_pool_t *iterpool;
166
 
  int version;
167
 
 
168
 
  /* Create a filesystem, then close it */
169
 
  SVN_ERR(svn_test__create_fs(&fs, dir, opts, subpool));
170
 
  svn_pool_destroy(subpool);
171
 
 
172
 
  subpool = svn_pool_create(pool);
173
 
 
174
 
  /* Rewrite the format file */
175
 
  SVN_ERR(svn_io_read_version_file(&version,
176
 
                                   svn_dirent_join(dir, "format", subpool),
177
 
                                   subpool));
178
 
  SVN_ERR(write_format(dir, version, shard_size, subpool));
179
 
 
180
 
  /* Reopen the filesystem */
181
 
  SVN_ERR(svn_fs_open(&fs, dir, NULL, subpool));
182
 
 
183
 
  /* Revision 1: the Greek tree */
184
 
  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
185
 
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
186
 
  SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
187
 
  SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
188
 
  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
189
 
 
190
 
  /* Revisions 2 thru NUM_REVS-1: content tweaks to "iota". */
191
 
  iterpool = svn_pool_create(subpool);
192
 
  while (after_rev < num_revs)
193
 
    {
194
 
      svn_pool_clear(iterpool);
195
 
      SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, iterpool));
196
 
      SVN_ERR(svn_fs_txn_root(&txn_root, txn, iterpool));
197
 
      SVN_ERR(svn_test__set_file_contents(txn_root, "iota",
198
 
                                          get_rev_contents(after_rev + 1,
199
 
                                                           iterpool),
200
 
                                          iterpool));
201
 
      SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, iterpool));
202
 
      SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
203
 
    }
204
 
  svn_pool_destroy(iterpool);
205
 
  svn_pool_destroy(subpool);
206
 
 
207
 
  /* Now pack the FS */
208
 
  pnb.expected_shard = 0;
209
 
  pnb.expected_action = svn_fs_pack_notify_start;
210
 
  return svn_fs_pack(dir, pack_notify, &pnb, NULL, NULL, pool);
211
 
}
212
 
 
213
 
/* Create a packed FSFS filesystem for revprop tests at REPO_NAME with
214
 
 * MAX_REV revisions and the given SHARD_SIZE and OPTS.  Return it in *FS.
215
 
 * Use POOL for allocations.
216
 
 */
217
 
static svn_error_t *
218
 
prepare_revprop_repo(svn_fs_t **fs,
219
 
                     const char *repo_name,
220
 
                     int max_rev,
221
 
                     int shard_size,
222
 
                     const svn_test_opts_t *opts,
223
 
                     apr_pool_t *pool)
224
 
{
225
 
  svn_fs_txn_t *txn;
226
 
  svn_fs_root_t *txn_root;
227
 
  const char *conflict;
228
 
  svn_revnum_t after_rev;
229
 
  apr_pool_t *subpool;
230
 
 
231
 
  /* Create the packed FS and open it. */
232
 
  SVN_ERR(create_packed_filesystem(repo_name, opts, max_rev, shard_size, pool));
233
 
  SVN_ERR(svn_fs_open(fs, repo_name, NULL, pool));
234
 
 
235
 
  subpool = svn_pool_create(pool);
236
 
  /* Do a commit to trigger packing. */
237
 
  SVN_ERR(svn_fs_begin_txn(&txn, *fs, max_rev, subpool));
238
 
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
239
 
  SVN_ERR(svn_test__set_file_contents(txn_root, "iota", "new-iota",  subpool));
240
 
  SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
241
 
  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
242
 
  svn_pool_destroy(subpool);
243
 
 
244
 
  /* Pack the repository. */
245
 
  SVN_ERR(svn_fs_pack(repo_name, NULL, NULL, NULL, NULL, pool));
246
 
 
247
 
  return SVN_NO_ERROR;
248
 
}
249
 
 
250
 
/* For revision REV, return a short log message allocated in POOL.
251
 
 */
252
 
static svn_string_t *
253
 
default_log(svn_revnum_t rev, apr_pool_t *pool)
254
 
{
255
 
  return svn_string_createf(pool, "Default message for rev %ld", rev);
256
 
}
257
 
 
258
 
/* For revision REV, return a long log message allocated in POOL.
259
 
 */
260
 
static svn_string_t *
261
 
large_log(svn_revnum_t rev, apr_size_t length, apr_pool_t *pool)
262
 
{
263
 
  svn_stringbuf_t *temp = svn_stringbuf_create_ensure(100000, pool);
264
 
  int i, count = (int)(length - 50) / 6;
265
 
 
266
 
  svn_stringbuf_appendcstr(temp, "A ");
267
 
  for (i = 0; i < count; ++i)
268
 
    svn_stringbuf_appendcstr(temp, "very, ");
269
 
 
270
 
  svn_stringbuf_appendcstr(temp,
271
 
    apr_psprintf(pool, "very long message for rev %ld, indeed", rev));
272
 
 
273
 
  return svn_stringbuf__morph_into_string(temp);
274
 
}
275
 
 
276
 
/* For revision REV, return a long log message allocated in POOL.
277
 
 */
278
 
static svn_string_t *
279
 
huge_log(svn_revnum_t rev, apr_pool_t *pool)
280
 
{
281
 
  return large_log(rev, 90000, pool);
282
 
}
283
 
 
284
 
 
285
 
/*** Tests ***/
286
 
 
287
 
/* ------------------------------------------------------------------------ */
288
 
#define REPO_NAME "test-repo-fsfs-pack"
289
 
#define SHARD_SIZE 7
290
 
#define MAX_REV 53
291
 
static svn_error_t *
292
 
pack_filesystem(const svn_test_opts_t *opts,
293
 
                apr_pool_t *pool)
294
 
{
295
 
  int i;
296
 
  svn_node_kind_t kind;
297
 
  const char *path;
298
 
  char buf[80];
299
 
  apr_file_t *file;
300
 
  apr_size_t len;
301
 
 
302
 
  /* Bail (with success) on known-untestable scenarios */
303
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
304
 
      || (opts->server_minor_version && (opts->server_minor_version < 6)))
305
 
    return SVN_NO_ERROR;
306
 
 
307
 
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE,
308
 
                                   pool));
309
 
 
310
 
  /* Check to see that the pack files exist, and that the rev directories
311
 
     don't. */
312
 
  for (i = 0; i < (MAX_REV + 1) / SHARD_SIZE; i++)
313
 
    {
314
 
      path = svn_dirent_join_many(pool, REPO_NAME, "revs",
315
 
                                  apr_psprintf(pool, "%d.pack", i / SHARD_SIZE),
316
 
                                  "pack", NULL);
317
 
 
318
 
      /* These files should exist. */
319
 
      SVN_ERR(svn_io_check_path(path, &kind, pool));
320
 
      if (kind != svn_node_file)
321
 
        return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
322
 
                                 "Expected pack file '%s' not found", path);
323
 
 
324
 
      path = svn_dirent_join_many(pool, REPO_NAME, "revs",
325
 
                                  apr_psprintf(pool, "%d.pack", i / SHARD_SIZE),
326
 
                                  "manifest", NULL);
327
 
      SVN_ERR(svn_io_check_path(path, &kind, pool));
328
 
      if (kind != svn_node_file)
329
 
        return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
330
 
                                 "Expected manifest file '%s' not found",
331
 
                                 path);
332
 
 
333
 
      /* This directory should not exist. */
334
 
      path = svn_dirent_join_many(pool, REPO_NAME, "revs",
335
 
                                  apr_psprintf(pool, "%d", i / SHARD_SIZE),
336
 
                                  NULL);
337
 
      SVN_ERR(svn_io_check_path(path, &kind, pool));
338
 
      if (kind != svn_node_none)
339
 
        return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
340
 
                                 "Unexpected directory '%s' found", path);
341
 
    }
342
 
 
343
 
  /* Ensure the min-unpacked-rev jives with the above operations. */
344
 
  SVN_ERR(svn_io_file_open(&file,
345
 
                           svn_dirent_join(REPO_NAME, PATH_MIN_UNPACKED_REV,
346
 
                                           pool),
347
 
                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
348
 
  len = sizeof(buf);
349
 
  SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
350
 
  SVN_ERR(svn_io_file_close(file, pool));
351
 
  if (SVN_STR_TO_REV(buf) != (MAX_REV / SHARD_SIZE) * SHARD_SIZE)
352
 
    return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
353
 
                             "Bad '%s' contents", PATH_MIN_UNPACKED_REV);
354
 
 
355
 
  /* Finally, make sure the final revision directory does exist. */
356
 
  path = svn_dirent_join_many(pool, REPO_NAME, "revs",
357
 
                              apr_psprintf(pool, "%d", (i / SHARD_SIZE) + 1),
358
 
                              NULL);
359
 
  SVN_ERR(svn_io_check_path(path, &kind, pool));
360
 
  if (kind != svn_node_none)
361
 
    return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
362
 
                             "Expected directory '%s' not found", path);
363
 
 
364
 
 
365
 
  return SVN_NO_ERROR;
366
 
}
367
 
#undef REPO_NAME
368
 
#undef SHARD_SIZE
369
 
#undef MAX_REV
370
 
 
371
 
/* ------------------------------------------------------------------------ */
372
 
#define REPO_NAME "test-repo-fsfs-pack-even"
373
 
#define SHARD_SIZE 4
374
 
#define MAX_REV 11
375
 
static svn_error_t *
376
 
pack_even_filesystem(const svn_test_opts_t *opts,
377
 
                     apr_pool_t *pool)
378
 
{
379
 
  svn_node_kind_t kind;
380
 
  const char *path;
381
 
 
382
 
  /* Bail (with success) on known-untestable scenarios */
383
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
384
 
      || (opts->server_minor_version && (opts->server_minor_version < 6)))
385
 
    return SVN_NO_ERROR;
386
 
 
387
 
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE,
388
 
                                   pool));
389
 
 
390
 
  path = svn_dirent_join_many(pool, REPO_NAME, "revs", "2.pack", NULL);
391
 
  SVN_ERR(svn_io_check_path(path, &kind, pool));
392
 
  if (kind != svn_node_dir)
393
 
    return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
394
 
                             "Packing did not complete as expected");
395
 
 
396
 
  return SVN_NO_ERROR;
397
 
}
398
 
#undef REPO_NAME
399
 
#undef SHARD_SIZE
400
 
#undef MAX_REV
401
 
 
402
 
/* ------------------------------------------------------------------------ */
403
 
#define REPO_NAME "test-repo-read-packed-fs"
404
 
#define SHARD_SIZE 5
405
 
#define MAX_REV 11
406
 
static svn_error_t *
407
 
read_packed_fs(const svn_test_opts_t *opts,
408
 
               apr_pool_t *pool)
409
 
{
410
 
  svn_fs_t *fs;
411
 
  svn_stream_t *rstream;
412
 
  svn_stringbuf_t *rstring;
413
 
  svn_revnum_t i;
414
 
 
415
 
  /* Bail (with success) on known-untestable scenarios */
416
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
417
 
      || (opts->server_minor_version && (opts->server_minor_version < 6)))
418
 
    return SVN_NO_ERROR;
419
 
 
420
 
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
421
 
  SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
422
 
 
423
 
  for (i = 1; i < (MAX_REV + 1); i++)
424
 
    {
425
 
      svn_fs_root_t *rev_root;
426
 
      svn_stringbuf_t *sb;
427
 
 
428
 
      SVN_ERR(svn_fs_revision_root(&rev_root, fs, i, pool));
429
 
      SVN_ERR(svn_fs_file_contents(&rstream, rev_root, "iota", pool));
430
 
      SVN_ERR(svn_test__stream_to_string(&rstring, rstream, pool));
431
 
 
432
 
      if (i == 1)
433
 
        sb = svn_stringbuf_create("This is the file 'iota'.\n", pool);
434
 
      else
435
 
        sb = svn_stringbuf_create(get_rev_contents(i, pool), pool);
436
 
 
437
 
      if (! svn_stringbuf_compare(rstring, sb))
438
 
        return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
439
 
                                 "Bad data in revision %ld.", i);
440
 
    }
441
 
 
442
 
  return SVN_NO_ERROR;
443
 
}
444
 
#undef REPO_NAME
445
 
#undef SHARD_SIZE
446
 
#undef MAX_REV
447
 
 
448
 
/* ------------------------------------------------------------------------ */
449
 
#define REPO_NAME "test-repo-commit-packed-fs"
450
 
#define SHARD_SIZE 5
451
 
#define MAX_REV 10
452
 
static svn_error_t *
453
 
commit_packed_fs(const svn_test_opts_t *opts,
454
 
                 apr_pool_t *pool)
455
 
{
456
 
  svn_fs_t *fs;
457
 
  svn_fs_txn_t *txn;
458
 
  svn_fs_root_t *txn_root;
459
 
  const char *conflict;
460
 
  svn_revnum_t after_rev;
461
 
 
462
 
  /* Bail (with success) on known-untestable scenarios */
463
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
464
 
      || (opts->server_minor_version && (opts->server_minor_version < 6)))
465
 
    return SVN_NO_ERROR;
466
 
 
467
 
  /* Create the packed FS and open it. */
468
 
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, 5, pool));
469
 
  SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
470
 
 
471
 
  /* Now do a commit. */
472
 
  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, pool));
473
 
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
474
 
  SVN_ERR(svn_test__set_file_contents(txn_root, "iota",
475
 
          "How much better is it to get wisdom than gold! and to get "
476
 
          "understanding rather to be chosen than silver!", pool));
477
 
  SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, pool));
478
 
  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
479
 
 
480
 
  return SVN_NO_ERROR;
481
 
}
482
 
#undef REPO_NAME
483
 
#undef MAX_REV
484
 
#undef SHARD_SIZE
485
 
 
486
 
/* ------------------------------------------------------------------------ */
487
 
#define REPO_NAME "test-repo-get-set-revprop-packed-fs"
488
 
#define SHARD_SIZE 4
489
 
#define MAX_REV 10
490
 
static svn_error_t *
491
 
get_set_revprop_packed_fs(const svn_test_opts_t *opts,
492
 
                          apr_pool_t *pool)
493
 
{
494
 
  svn_fs_t *fs;
495
 
  svn_string_t *prop_value;
496
 
 
497
 
  /* Bail (with success) on known-untestable scenarios */
498
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
499
 
      || (opts->server_minor_version && (opts->server_minor_version < 7)))
500
 
    return SVN_NO_ERROR;
501
 
 
502
 
  /* Create the packed FS and open it. */
503
 
  SVN_ERR(prepare_revprop_repo(&fs, REPO_NAME, MAX_REV, SHARD_SIZE, opts,
504
 
                               pool));
505
 
 
506
 
  /* Try to get revprop for revision 0
507
 
   * (non-packed due to special handling). */
508
 
  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR,
509
 
                               pool));
510
 
 
511
 
  /* Try to change revprop for revision 0
512
 
   * (non-packed due to special handling). */
513
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 0, SVN_PROP_REVISION_AUTHOR,
514
 
                                 svn_string_create("tweaked-author", pool),
515
 
                                 pool));
516
 
 
517
 
  /* verify */
518
 
  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR,
519
 
                               pool));
520
 
  SVN_TEST_STRING_ASSERT(prop_value->data, "tweaked-author");
521
 
 
522
 
  /* Try to get packed revprop for revision 5. */
523
 
  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 5, SVN_PROP_REVISION_AUTHOR,
524
 
                               pool));
525
 
 
526
 
  /* Try to change packed revprop for revision 5. */
527
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 5, SVN_PROP_REVISION_AUTHOR,
528
 
                                 svn_string_create("tweaked-author2", pool),
529
 
                                 pool));
530
 
 
531
 
  /* verify */
532
 
  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 5, SVN_PROP_REVISION_AUTHOR,
533
 
                               pool));
534
 
  SVN_TEST_STRING_ASSERT(prop_value->data, "tweaked-author2");
535
 
 
536
 
  return SVN_NO_ERROR;
537
 
}
538
 
#undef REPO_NAME
539
 
#undef MAX_REV
540
 
#undef SHARD_SIZE
541
 
 
542
 
/* ------------------------------------------------------------------------ */
543
 
#define REPO_NAME "test-repo-get-set-large-revprop-packed-fs"
544
 
#define SHARD_SIZE 4
545
 
#define MAX_REV 11
546
 
static svn_error_t *
547
 
get_set_large_revprop_packed_fs(const svn_test_opts_t *opts,
548
 
                                apr_pool_t *pool)
549
 
{
550
 
  svn_fs_t *fs;
551
 
  svn_string_t *prop_value;
552
 
  svn_revnum_t rev;
553
 
 
554
 
  /* Bail (with success) on known-untestable scenarios */
555
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
556
 
      || (opts->server_minor_version && (opts->server_minor_version < 7)))
557
 
    return SVN_NO_ERROR;
558
 
 
559
 
  /* Create the packed FS and open it. */
560
 
  SVN_ERR(prepare_revprop_repo(&fs, REPO_NAME, MAX_REV, SHARD_SIZE, opts,
561
 
                               pool));
562
 
 
563
 
  /* Set commit messages to different, large values that fill the pack
564
 
   * files but do not exceed the pack size limit. */
565
 
  for (rev = 0; rev <= MAX_REV; ++rev)
566
 
    SVN_ERR(svn_fs_change_rev_prop(fs, rev, SVN_PROP_REVISION_LOG,
567
 
                                   large_log(rev, 15000, pool),
568
 
                                   pool));
569
 
 
570
 
  /* verify */
571
 
  for (rev = 0; rev <= MAX_REV; ++rev)
572
 
    {
573
 
      SVN_ERR(svn_fs_revision_prop(&prop_value, fs, rev,
574
 
                                   SVN_PROP_REVISION_LOG, pool));
575
 
      SVN_TEST_STRING_ASSERT(prop_value->data,
576
 
                             large_log(rev, 15000, pool)->data);
577
 
    }
578
 
 
579
 
  /* Put a larger revprop into the last, some middle and the first revision
580
 
   * of a pack.  This should cause the packs to split in the middle. */
581
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 3, SVN_PROP_REVISION_LOG,
582
 
                                 /* rev 0 is not packed */
583
 
                                 large_log(3, 37000, pool),
584
 
                                 pool));
585
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 5, SVN_PROP_REVISION_LOG,
586
 
                                 large_log(5, 25000, pool),
587
 
                                 pool));
588
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 8, SVN_PROP_REVISION_LOG,
589
 
                                 large_log(8, 25000, pool),
590
 
                                 pool));
591
 
 
592
 
  /* verify */
593
 
  for (rev = 0; rev <= MAX_REV; ++rev)
594
 
    {
595
 
      SVN_ERR(svn_fs_revision_prop(&prop_value, fs, rev,
596
 
                                   SVN_PROP_REVISION_LOG, pool));
597
 
 
598
 
      if (rev == 3)
599
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
600
 
                               large_log(rev, 37000, pool)->data);
601
 
      else if (rev == 5 || rev == 8)
602
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
603
 
                               large_log(rev, 25000, pool)->data);
604
 
      else
605
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
606
 
                               large_log(rev, 15000, pool)->data);
607
 
    }
608
 
 
609
 
  return SVN_NO_ERROR;
610
 
}
611
 
#undef REPO_NAME
612
 
#undef MAX_REV
613
 
#undef SHARD_SIZE
614
 
 
615
 
/* ------------------------------------------------------------------------ */
616
 
#define REPO_NAME "test-repo-get-set-huge-revprop-packed-fs"
617
 
#define SHARD_SIZE 4
618
 
#define MAX_REV 10
619
 
static svn_error_t *
620
 
get_set_huge_revprop_packed_fs(const svn_test_opts_t *opts,
621
 
                               apr_pool_t *pool)
622
 
{
623
 
  svn_fs_t *fs;
624
 
  svn_string_t *prop_value;
625
 
  svn_revnum_t rev;
626
 
 
627
 
  /* Bail (with success) on known-untestable scenarios */
628
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
629
 
      || (opts->server_minor_version && (opts->server_minor_version < 7)))
630
 
    return SVN_NO_ERROR;
631
 
 
632
 
  /* Create the packed FS and open it. */
633
 
  SVN_ERR(prepare_revprop_repo(&fs, REPO_NAME, MAX_REV, SHARD_SIZE, opts,
634
 
                               pool));
635
 
 
636
 
  /* Set commit messages to different values */
637
 
  for (rev = 0; rev <= MAX_REV; ++rev)
638
 
    SVN_ERR(svn_fs_change_rev_prop(fs, rev, SVN_PROP_REVISION_LOG,
639
 
                                   default_log(rev, pool),
640
 
                                   pool));
641
 
 
642
 
  /* verify */
643
 
  for (rev = 0; rev <= MAX_REV; ++rev)
644
 
    {
645
 
      SVN_ERR(svn_fs_revision_prop(&prop_value, fs, rev,
646
 
                                   SVN_PROP_REVISION_LOG, pool));
647
 
      SVN_TEST_STRING_ASSERT(prop_value->data, default_log(rev, pool)->data);
648
 
    }
649
 
 
650
 
  /* Put a huge revprop into the last, some middle and the first revision
651
 
   * of a pack.  They will cause the pack files to split accordingly. */
652
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 3, SVN_PROP_REVISION_LOG,
653
 
                                 huge_log(3, pool),
654
 
                                 pool));
655
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 5, SVN_PROP_REVISION_LOG,
656
 
                                 huge_log(5, pool),
657
 
                                 pool));
658
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 8, SVN_PROP_REVISION_LOG,
659
 
                                 huge_log(8, pool),
660
 
                                 pool));
661
 
 
662
 
  /* verify */
663
 
  for (rev = 0; rev <= MAX_REV; ++rev)
664
 
    {
665
 
      SVN_ERR(svn_fs_revision_prop(&prop_value, fs, rev,
666
 
                                   SVN_PROP_REVISION_LOG, pool));
667
 
 
668
 
      if (rev == 3 || rev == 5 || rev == 8)
669
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
670
 
                               huge_log(rev, pool)->data);
671
 
      else
672
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
673
 
                               default_log(rev, pool)->data);
674
 
    }
675
 
 
676
 
  return SVN_NO_ERROR;
677
 
}
678
 
#undef REPO_NAME
679
 
#undef MAX_REV
680
 
#undef SHARD_SIZE
681
 
 
682
 
/* ------------------------------------------------------------------------ */
683
 
/* Regression test for issue #3571 (fsfs 'svnadmin recover' expects
684
 
   youngest revprop to be outside revprops.db). */
685
 
#define REPO_NAME "test-repo-recover-fully-packed"
686
 
#define SHARD_SIZE 4
687
 
#define MAX_REV 7
688
 
static svn_error_t *
689
 
recover_fully_packed(const svn_test_opts_t *opts,
690
 
                     apr_pool_t *pool)
691
 
{
692
 
  apr_pool_t *subpool;
693
 
  svn_fs_t *fs;
694
 
  svn_fs_txn_t *txn;
695
 
  svn_fs_root_t *txn_root;
696
 
  const char *conflict;
697
 
  svn_revnum_t after_rev;
698
 
  svn_error_t *err;
699
 
 
700
 
  /* Bail (with success) on known-untestable scenarios */
701
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
702
 
      || (opts->server_minor_version && (opts->server_minor_version < 7)))
703
 
    return SVN_NO_ERROR;
704
 
 
705
 
  /* Create a packed FS for which every revision will live in a pack
706
 
     digest file, and then recover it. */
707
 
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
708
 
  SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool));
709
 
 
710
 
  /* Add another revision, re-pack, re-recover. */
711
 
  subpool = svn_pool_create(pool);
712
 
  SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, subpool));
713
 
  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool));
714
 
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
715
 
  SVN_ERR(svn_test__set_file_contents(txn_root, "A/mu", "new-mu", subpool));
716
 
  SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
717
 
  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
718
 
  svn_pool_destroy(subpool);
719
 
  SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool));
720
 
  SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool));
721
 
 
722
 
  /* Now, delete the youngest revprop file, and recover again.  This
723
 
     time we want to see an error! */
724
 
  SVN_ERR(svn_io_remove_file2(
725
 
              svn_dirent_join_many(pool, REPO_NAME, PATH_REVPROPS_DIR,
726
 
                                   apr_psprintf(pool, "%ld/%ld",
727
 
                                                after_rev / SHARD_SIZE,
728
 
                                                after_rev),
729
 
                                   NULL),
730
 
              FALSE, pool));
731
 
  err = svn_fs_recover(REPO_NAME, NULL, NULL, pool);
732
 
  if (! err)
733
 
    return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
734
 
                            "Expected SVN_ERR_FS_CORRUPT error; got none");
735
 
  if (err->apr_err != SVN_ERR_FS_CORRUPT)
736
 
    return svn_error_create(SVN_ERR_TEST_FAILED, err,
737
 
                            "Expected SVN_ERR_FS_CORRUPT error; got:");
738
 
  svn_error_clear(err);
739
 
  return SVN_NO_ERROR;
740
 
}
741
 
#undef REPO_NAME
742
 
#undef MAX_REV
743
 
#undef SHARD_SIZE
744
 
 
745
 
/* ------------------------------------------------------------------------ */
746
 
/* Regression test for issue #4320 (fsfs file-hinting fails when reading a rep
747
 
   from the transaction that is commiting rev = SHARD_SIZE). */
748
 
#define REPO_NAME "test-repo-file-hint-at-shard-boundary"
749
 
#define SHARD_SIZE 4
750
 
#define MAX_REV (SHARD_SIZE - 1)
751
 
static svn_error_t *
752
 
file_hint_at_shard_boundary(const svn_test_opts_t *opts,
753
 
                            apr_pool_t *pool)
754
 
{
755
 
  apr_pool_t *subpool;
756
 
  svn_fs_t *fs;
757
 
  svn_fs_txn_t *txn;
758
 
  svn_fs_root_t *txn_root;
759
 
  const char *file_contents;
760
 
  svn_stringbuf_t *retrieved_contents;
761
 
  svn_error_t *err = SVN_NO_ERROR;
762
 
 
763
 
  /* Bail (with success) on known-untestable scenarios */
764
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
765
 
      || (opts->server_minor_version && (opts->server_minor_version < 8)))
766
 
    return SVN_NO_ERROR;
767
 
 
768
 
  /* Create a packed FS and MAX_REV revisions */
769
 
  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
770
 
 
771
 
  /* Reopen the filesystem */
772
 
  subpool = svn_pool_create(pool);
773
 
  SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, subpool));
774
 
 
775
 
  /* Revision = SHARD_SIZE */
776
 
  file_contents = get_rev_contents(SHARD_SIZE, subpool);
777
 
  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool));
778
 
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
779
 
  SVN_ERR(svn_test__set_file_contents(txn_root, "iota", file_contents,
780
 
                                      subpool));
781
 
 
782
 
  /* Retrieve the file. */
783
 
  SVN_ERR(svn_test__get_file_contents(txn_root, "iota", &retrieved_contents,
784
 
                                      subpool));
785
 
  if (strcmp(retrieved_contents->data, file_contents))
786
 
    {
787
 
      err = svn_error_create(SVN_ERR_TEST_FAILED, err,
788
 
                              "Retrieved incorrect contents from iota.");
789
 
    }
790
 
 
791
 
  /* Close the repo. */
792
 
  svn_pool_destroy(subpool);
793
 
 
794
 
  return err;
795
 
}
796
 
#undef REPO_NAME
797
 
#undef MAX_REV
798
 
#undef SHARD_SIZE
799
 
 
800
 
/* ------------------------------------------------------------------------ */
801
 
#define REPO_NAME "get_set_multiple_huge_revprops_packed_fs"
802
 
#define SHARD_SIZE 4
803
 
#define MAX_REV 9
804
 
static svn_error_t *
805
 
get_set_multiple_huge_revprops_packed_fs(const svn_test_opts_t *opts,
806
 
                                         apr_pool_t *pool)
807
 
{
808
 
  svn_fs_t *fs;
809
 
  svn_string_t *prop_value;
810
 
  svn_revnum_t rev;
811
 
 
812
 
  /* Bail (with success) on known-untestable scenarios */
813
 
  if ((strcmp(opts->fs_type, "fsfs") != 0)
814
 
      || (opts->server_minor_version && (opts->server_minor_version < 7)))
815
 
    return SVN_NO_ERROR;
816
 
 
817
 
  /* Create the packed FS and open it. */
818
 
  SVN_ERR(prepare_revprop_repo(&fs, REPO_NAME, MAX_REV, SHARD_SIZE, opts,
819
 
                               pool));
820
 
 
821
 
  /* Set commit messages to different values */
822
 
  for (rev = 0; rev <= MAX_REV; ++rev)
823
 
    SVN_ERR(svn_fs_change_rev_prop(fs, rev, SVN_PROP_REVISION_LOG,
824
 
                                   default_log(rev, pool),
825
 
                                   pool));
826
 
 
827
 
  /* verify */
828
 
  for (rev = 0; rev <= MAX_REV; ++rev)
829
 
    {
830
 
      SVN_ERR(svn_fs_revision_prop(&prop_value, fs, rev,
831
 
                                   SVN_PROP_REVISION_LOG, pool));
832
 
      SVN_TEST_STRING_ASSERT(prop_value->data, default_log(rev, pool)->data);
833
 
    }
834
 
 
835
 
  /* Put a huge revprop into revision 1 and 2. */
836
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 1, SVN_PROP_REVISION_LOG,
837
 
                                 huge_log(1, pool),
838
 
                                 pool));
839
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 2, SVN_PROP_REVISION_LOG,
840
 
                                 huge_log(2, pool),
841
 
                                 pool));
842
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 5, SVN_PROP_REVISION_LOG,
843
 
                                 huge_log(5, pool),
844
 
                                 pool));
845
 
  SVN_ERR(svn_fs_change_rev_prop(fs, 6, SVN_PROP_REVISION_LOG,
846
 
                                 huge_log(6, pool),
847
 
                                 pool));
848
 
 
849
 
  /* verify */
850
 
  for (rev = 0; rev <= MAX_REV; ++rev)
851
 
    {
852
 
      SVN_ERR(svn_fs_revision_prop(&prop_value, fs, rev,
853
 
                                   SVN_PROP_REVISION_LOG, pool));
854
 
 
855
 
      if (rev == 1 || rev == 2 || rev == 5 || rev == 6)
856
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
857
 
                               huge_log(rev, pool)->data);
858
 
      else
859
 
        SVN_TEST_STRING_ASSERT(prop_value->data,
860
 
                               default_log(rev, pool)->data);
861
 
    }
862
 
 
863
 
  return SVN_NO_ERROR;
864
 
}
865
 
#undef REPO_NAME
866
 
#undef MAX_REV
867
 
#undef SHARD_SIZE
868
 
 
869
 
/* ------------------------------------------------------------------------ */
870
 
 
871
 
#define REPO_NAME "revprop_caching_on_off"
872
 
static svn_error_t *
873
 
revprop_caching_on_off(const svn_test_opts_t *opts,
874
 
                       apr_pool_t *pool)
875
 
{
876
 
  svn_fs_t *fs1;
877
 
  svn_fs_t *fs2;
878
 
  apr_hash_t *fs_config;
879
 
  svn_string_t *value;
880
 
  const svn_string_t *another_value_for_avoiding_warnings_from_a_broken_api;
881
 
  const svn_string_t *new_value = svn_string_create("new", pool);
882
 
 
883
 
  if (strcmp(opts->fs_type, "fsfs") != 0)
884
 
    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
885
 
 
886
 
  /* Open two filesystem objects, enable revision property caching
887
 
   * in one of them. */
888
 
  SVN_ERR(svn_test__create_fs(&fs1, REPO_NAME, opts, pool));
889
 
 
890
 
  fs_config = apr_hash_make(pool);
891
 
  apr_hash_set(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
892
 
               APR_HASH_KEY_STRING, "1");
893
 
 
894
 
  SVN_ERR(svn_fs_open(&fs2, svn_fs_path(fs1, pool), fs_config, pool));
895
 
 
896
 
  /* With inefficient named atomics, the filesystem will output a warning
897
 
     and disable the revprop caching, but we still would like to test
898
 
     these cases.  Ignore the warning(s). */
899
 
  svn_fs_set_warning_func(fs2, ignore_fs_warnings, NULL);
900
 
 
901
 
  SVN_ERR(svn_fs_revision_prop(&value, fs2, 0, "svn:date", pool));
902
 
  another_value_for_avoiding_warnings_from_a_broken_api = value;
903
 
  SVN_ERR(svn_fs_change_rev_prop2(
904
 
              fs1, 0, "svn:date",
905
 
              &another_value_for_avoiding_warnings_from_a_broken_api,
906
 
              new_value, pool));
907
 
 
908
 
  /* Expect the change to be visible through both objects.*/
909
 
  SVN_ERR(svn_fs_revision_prop(&value, fs1, 0, "svn:date", pool));
910
 
  SVN_TEST_STRING_ASSERT(value->data, "new");
911
 
 
912
 
  SVN_ERR(svn_fs_revision_prop(&value, fs2, 0, "svn:date", pool));
913
 
  SVN_TEST_STRING_ASSERT(value->data, "new");
914
 
 
915
 
  return SVN_NO_ERROR;
916
 
}
917
 
 
918
 
#undef REPO_NAME
919
 
 
920
 
/* ------------------------------------------------------------------------ */
921
 
 
922
 
/* The test table.  */
923
 
 
924
 
struct svn_test_descriptor_t test_funcs[] =
925
 
  {
926
 
    SVN_TEST_NULL,
927
 
    SVN_TEST_OPTS_PASS(pack_filesystem,
928
 
                       "pack a FSFS filesystem"),
929
 
    SVN_TEST_OPTS_PASS(pack_even_filesystem,
930
 
                       "pack FSFS where revs % shard = 0"),
931
 
    SVN_TEST_OPTS_PASS(read_packed_fs,
932
 
                       "read from a packed FSFS filesystem"),
933
 
    SVN_TEST_OPTS_PASS(commit_packed_fs,
934
 
                       "commit to a packed FSFS filesystem"),
935
 
    SVN_TEST_OPTS_PASS(get_set_revprop_packed_fs,
936
 
                       "get/set revprop while packing FSFS filesystem"),
937
 
    SVN_TEST_OPTS_PASS(get_set_large_revprop_packed_fs,
938
 
                       "get/set large packed revprops in FSFS"),
939
 
    SVN_TEST_OPTS_PASS(get_set_huge_revprop_packed_fs,
940
 
                       "get/set huge packed revprops in FSFS"),
941
 
    SVN_TEST_OPTS_PASS(recover_fully_packed,
942
 
                       "recover a fully packed filesystem"),
943
 
    SVN_TEST_OPTS_PASS(file_hint_at_shard_boundary,
944
 
                       "test file hint at shard boundary"),
945
 
    SVN_TEST_OPTS_PASS(get_set_multiple_huge_revprops_packed_fs,
946
 
                       "set multiple huge revprops in packed FSFS"),
947
 
    SVN_TEST_OPTS_PASS(revprop_caching_on_off,
948
 
                       "change revprops with enabled and disabled caching"),
949
 
    SVN_TEST_NULL
950
 
  };