1 /* strings-reps-test.c --- test `strings' and `representations' interfaces
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 * ====================================================================
25 #include "svn_error.h"
27 #include "../svn_test.h"
28 #include "../svn_test_fs.h"
29 #include "../../libsvn_fs_base/util/skel.h"
30 #include "../../libsvn_fs_base/util/fs_skels.h"
31 #include "../../libsvn_fs_base/bdb/strings-table.h"
32 #include "../../libsvn_fs_base/bdb/reps-table.h"
36 /*-----------------------------------------------------------------*/
37 /* Helper functions and batons for reps-table testing. */
47 txn_body_write_new_rep(void *baton
, trail_t
*trail
)
49 struct rep_args
*b
= (struct rep_args
*) baton
;
50 representation_t
*rep
;
51 SVN_ERR(svn_fs_base__parse_representation_skel(&rep
, b
->skel
,
53 return svn_fs_bdb__write_new_rep(&(b
->key
), b
->fs
, rep
, trail
, trail
->pool
);
58 txn_body_write_rep(void *baton
, trail_t
*trail
)
60 struct rep_args
*b
= (struct rep_args
*) baton
;
61 representation_t
*rep
;
62 SVN_ERR(svn_fs_base__parse_representation_skel(&rep
, b
->skel
,
64 return svn_fs_bdb__write_rep(b
->fs
, b
->key
, rep
, trail
, trail
->pool
);
69 txn_body_read_rep(void *baton
, trail_t
*trail
)
71 struct rep_args
*b
= (struct rep_args
*) baton
;
72 representation_t
*rep
;
73 SVN_ERR(svn_fs_bdb__read_rep(&rep
, b
->fs
, b
->key
, trail
, trail
->pool
));
74 return svn_fs_base__unparse_representation_skel(&(b
->skel
), rep
,
80 txn_body_delete_rep(void *baton
, trail_t
*trail
)
82 struct rep_args
*b
= (struct rep_args
*) baton
;
83 return svn_fs_bdb__delete_rep(b
->fs
, b
->key
, trail
, trail
->pool
);
88 /* Representation Table Test functions. */
91 write_new_rep(const char **msg
,
92 svn_boolean_t msg_only
,
93 svn_test_opts_t
*opts
,
97 const char *rep
= "((fulltext 0 ) a83t2Z0q)";
100 *msg
= "write a new rep, get a new key back";
105 /* Create a new fs and repos */
106 SVN_ERR(svn_test__create_fs
107 (&fs
, "test-repo-write-new-rep",
110 /* Set up transaction baton */
112 args
.skel
= svn_fs_base__parse_skel(rep
, strlen(rep
), pool
);
115 /* Write new rep to reps table. */
116 SVN_ERR(svn_fs_base__retry_txn(args
.fs
, txn_body_write_new_rep
, &args
,
119 if (args
.key
== NULL
)
120 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
121 "error writing new representation");
128 write_rep(const char **msg
,
129 svn_boolean_t msg_only
,
130 svn_test_opts_t
*opts
,
133 struct rep_args new_args
;
134 struct rep_args args
;
135 const char *new_rep
= "((fulltext 0 ) a83t2Z0q)";
136 const char *rep
= "((fulltext 0 ) kfogel31337)";
139 *msg
= "write a new rep, then overwrite it";
144 /* Create a new fs and repos */
145 SVN_ERR(svn_test__create_fs
146 (&fs
, "test-repo-write-rep",
149 /* Set up transaction baton */
151 new_args
.skel
= svn_fs_base__parse_skel(new_rep
, strlen(new_rep
), pool
);
154 /* Write new rep to reps table. */
155 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
156 txn_body_write_new_rep
, &new_args
, pool
));
158 /* Make sure we got a valid key. */
159 if (new_args
.key
== NULL
)
160 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
161 "error writing new representation");
163 /* Set up transaction baton for re-writing reps. */
164 args
.fs
= new_args
.fs
;
165 args
.skel
= svn_fs_base__parse_skel(rep
, strlen(rep
), pool
);
166 args
.key
= new_args
.key
;
168 /* Overwrite first rep in reps table. */
169 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
170 txn_body_write_rep
, &args
, pool
));
177 read_rep(const char **msg
,
178 svn_boolean_t msg_only
,
179 svn_test_opts_t
*opts
,
182 struct rep_args new_args
;
183 struct rep_args args
;
184 struct rep_args read_args
;
185 svn_stringbuf_t
*skel_data
;
188 const char *rep
= "((fulltext 0 ) kfogel31337)";
189 const char *new_rep_before
= "((fulltext 0 ) a83t2Z0)";
191 /* This test also tests the introduction of checksums into skels that
194 /* Get writeable strings. */
195 char *rep_after
= apr_pstrdup
196 (pool
, "((fulltext 0 (md5 16 XXXXXXXXXXXXXXXX)) kfogel31337");
197 char *new_rep_after
= apr_pstrdup
198 (pool
, "((fulltext 0 (md5 16 XXXXXXXXXXXXXXXX)) a83t2Z0");
199 int rep_after_len
= strlen(rep_after
);
200 int new_rep_after_len
= strlen(new_rep_after
);
202 /* Replace the fake fake checksums with the real fake checksums.
203 And someday, when checksums are actually calculated, we can
204 replace the real fake checksums with real real checksums. */
208 for (p
= rep_after
; *p
; p
++)
212 for (p
= new_rep_after
; *p
; p
++)
217 *msg
= "write and overwrite a new rep; confirm with reads";
222 /* Create a new fs and repos */
223 SVN_ERR(svn_test__create_fs
224 (&fs
, "test-repo-read-rep",
227 /* Set up transaction baton */
229 new_args
.skel
= svn_fs_base__parse_skel(new_rep_before
,
230 strlen(new_rep_before
), pool
);
233 /* Write new rep to reps table. */
234 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
235 txn_body_write_new_rep
, &new_args
, pool
));
237 /* Make sure we got a valid key. */
238 if (new_args
.key
== NULL
)
239 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
240 "error writing new representation");
242 /* Read the new rep back from the reps table. */
243 read_args
.fs
= new_args
.fs
;
244 read_args
.skel
= NULL
;
245 read_args
.key
= new_args
.key
;
246 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
247 txn_body_read_rep
, &read_args
, pool
));
249 /* Make sure the skel matches. */
250 if (! read_args
.skel
)
251 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
252 "error reading new representation");
254 skel_data
= svn_fs_base__unparse_skel(read_args
.skel
, pool
);
255 if (memcmp(skel_data
->data
, new_rep_after
, new_rep_after_len
) != 0)
256 return svn_error_createf(SVN_ERR_FS_GENERAL
, NULL
,
257 "representation corrupted (first check)");
259 /* Set up transaction baton for re-writing reps. */
260 args
.fs
= new_args
.fs
;
261 args
.skel
= svn_fs_base__parse_skel(rep
, strlen(rep
), pool
);
262 args
.key
= new_args
.key
;
264 /* Overwrite first rep in reps table. */
265 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
266 txn_body_write_rep
, &args
, pool
));
268 /* Read the new rep back from the reps table (using the same FS and
269 key as the first read...let's make sure this thing didn't get
270 written to the wrong place). */
271 read_args
.skel
= NULL
;
272 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
273 txn_body_read_rep
, &read_args
, pool
));
275 /* Make sure the skel matches. */
276 if (! read_args
.skel
)
277 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
278 "error reading new representation");
280 skel_data
= svn_fs_base__unparse_skel(read_args
.skel
, pool
);
281 if (memcmp(skel_data
->data
, rep_after
, rep_after_len
) != 0)
282 return svn_error_createf(SVN_ERR_FS_GENERAL
, NULL
,
283 "representation corrupted (second check)");
290 delete_rep(const char **msg
,
291 svn_boolean_t msg_only
,
292 svn_test_opts_t
*opts
,
295 struct rep_args new_args
;
296 struct rep_args delete_args
;
297 struct rep_args read_args
;
298 const char *new_rep
= "((fulltext 0 ) a83t2Z0q)";
302 *msg
= "write, then delete, a new rep; confirm deletion";
307 /* Create a new fs and repos */
308 SVN_ERR(svn_test__create_fs
309 (&fs
, "test-repo-delete-rep",
312 /* Set up transaction baton */
314 new_args
.skel
= svn_fs_base__parse_skel(new_rep
, strlen(new_rep
), pool
);
317 /* Write new rep to reps table. */
318 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
319 txn_body_write_new_rep
, &new_args
, pool
));
321 /* Make sure we got a valid key. */
322 if (new_args
.key
== NULL
)
323 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
324 "error writing new representation");
326 /* Delete the rep we just wrote. */
327 delete_args
.fs
= new_args
.fs
;
328 delete_args
.key
= new_args
.key
;
329 SVN_ERR(svn_fs_base__retry_txn(new_args
.fs
,
330 txn_body_delete_rep
, &delete_args
, pool
));
332 /* Try to read the new rep back from the reps table. */
333 read_args
.fs
= new_args
.fs
;
334 read_args
.skel
= NULL
;
335 read_args
.key
= new_args
.key
;
336 err
= svn_fs_base__retry_txn(new_args
.fs
,
337 txn_body_read_rep
, &read_args
, pool
);
339 /* We better have an error... */
340 if ((! err
) && (read_args
.skel
))
341 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
342 "error deleting representation");
343 svn_error_clear(err
);
349 /* ------------------------------------------------------------------- */
350 /* Helper functions and batons for strings-table testing. */
353 verify_expected_record(svn_fs_t
*fs
,
355 const char *expected_text
,
356 apr_size_t expected_len
,
361 svn_stringbuf_t
*text
;
362 svn_filesize_t offset
= 0;
363 svn_filesize_t string_size
;
365 /* Check the string size. */
366 SVN_ERR(svn_fs_bdb__string_size(&string_size
, fs
, key
,
367 trail
, trail
->pool
));
368 if (string_size
> SVN_MAX_OBJECT_SIZE
)
369 return svn_error_createf(SVN_ERR_FS_GENERAL
, NULL
,
370 "record size is too large "
371 "(got %" SVN_FILESIZE_T_FMT
", "
372 "limit is %" APR_SIZE_T_FMT
")",
373 string_size
, SVN_MAX_OBJECT_SIZE
);
374 size
= (apr_size_t
) string_size
;
375 if (size
!= expected_len
)
376 return svn_error_createf(SVN_ERR_FS_GENERAL
, NULL
,
377 "record has unexpected size "
378 "(got %" APR_SIZE_T_FMT
", "
379 "expected %" APR_SIZE_T_FMT
")",
382 /* Read the string back in 100-byte chunks. */
383 text
= svn_stringbuf_create("", trail
->pool
);
387 SVN_ERR(svn_fs_bdb__string_read(fs
, key
, buf
, offset
, &size
,
388 trail
, trail
->pool
));
391 svn_stringbuf_appendbytes(text
, buf
, size
);
395 /* Check the size and contents of the read data. */
396 if (text
->len
!= expected_len
)
397 return svn_error_createf(SVN_ERR_FS_GENERAL
, NULL
,
398 "record read returned unexpected size "
399 "(got %" APR_SIZE_T_FMT
", "
400 "expected %" APR_SIZE_T_FMT
")",
402 if (memcmp(expected_text
, text
->data
, expected_len
))
403 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
404 "record read returned unexpected data");
420 txn_body_verify_string(void *baton
, trail_t
*trail
)
422 struct string_args
*b
= (struct string_args
*) baton
;
423 return verify_expected_record(b
->fs
, b
->key
, b
->text
, b
->len
, trail
);
428 txn_body_string_append(void *baton
, trail_t
*trail
)
430 struct string_args
*b
= (struct string_args
*) baton
;
431 return svn_fs_bdb__string_append(b
->fs
, &(b
->key
), b
->len
,
432 b
->text
, trail
, trail
->pool
);
437 txn_body_string_clear(void *baton
, trail_t
*trail
)
439 struct string_args
*b
= (struct string_args
*) baton
;
440 return svn_fs_bdb__string_clear(b
->fs
, b
->key
, trail
, trail
->pool
);
445 txn_body_string_delete(void *baton
, trail_t
*trail
)
447 struct string_args
*b
= (struct string_args
*) baton
;
448 return svn_fs_bdb__string_delete(b
->fs
, b
->key
, trail
, trail
->pool
);
453 txn_body_string_size(void *baton
, trail_t
*trail
)
455 struct string_args
*b
= (struct string_args
*) baton
;
456 svn_filesize_t string_size
;
457 SVN_ERR(svn_fs_bdb__string_size(&string_size
, b
->fs
, b
->key
,
458 trail
, trail
->pool
));
459 if (string_size
> SVN_MAX_OBJECT_SIZE
)
460 return svn_error_createf
461 (SVN_ERR_FS_GENERAL
, NULL
,
462 "txn_body_string_size: string size is too large "
463 "(got %" SVN_FILESIZE_T_FMT
", limit is %" APR_SIZE_T_FMT
")",
464 string_size
, SVN_MAX_OBJECT_SIZE
);
465 b
->len
= (apr_size_t
) string_size
;
471 txn_body_string_append_fail(void *baton
, trail_t
*trail
)
473 struct string_args
*b
= (struct string_args
*) baton
;
474 SVN_ERR(svn_fs_bdb__string_append(b
->fs
, &(b
->key
), b
->len
,
475 b
->text
, trail
, trail
->pool
));
476 return svn_error_create(SVN_ERR_TEST_FAILED
, NULL
,
477 "la dee dah, la dee day...");
481 txn_body_string_copy(void *baton
, trail_t
*trail
)
483 struct string_args
*b
= (struct string_args
*) baton
;
484 return svn_fs_bdb__string_copy(b
->fs
, &(b
->key
), b
->key
,
489 static const char *bigstring1
=
490 " Alice opened the door and found that it led into a small\n"
491 "passage, not much larger than a rat-hole: she knelt down and\n"
492 "looked along the passage into the loveliest garden you ever saw.\n"
493 "How she longed to get out of that dark hall, and wander about\n"
494 "among those beds of bright flowers and those cool fountains, but\n"
495 "she could not even get her head though the doorway; 'and even if\n"
496 "my head would go through,' thought poor Alice, 'it would be of\n"
497 "very little use without my shoulders. Oh, how I wish\n"
498 "I could shut up like a telescope! I think I could, if I only\n"
499 "know how to begin.' For, you see, so many out-of-the-way things\n"
500 "had happened lately, that Alice had begun to think that very few\n"
501 "things indeed were really impossible.";
503 static const char *bigstring2
=
504 " There seemed to be no use in waiting by the little door, so she\n"
505 "went back to the table, half hoping she might find another key on\n"
506 "it, or at any rate a book of rules for shutting people up like\n"
507 "telescopes: this time she found a little bottle on it, ('which\n"
508 "certainly was not here before,' said Alice,) and round the neck\n"
509 "of the bottle was a paper label, with the words 'DRINK ME'\n"
510 "beautifully printed on it in large letters.";
512 static const char *bigstring3
=
513 " It was all very well to say 'Drink me,' but the wise little\n"
514 "Alice was not going to do THAT in a hurry. 'No, I'll look\n"
515 "first,' she said, 'and see whether it's marked \"poison\" or not';\n"
516 "for she had read several nice little histories about children who\n"
517 "had got burnt, and eaten up by wild beasts and other unpleasant\n"
518 "things, all because they WOULD not remember the simple rules\n"
519 "their friends had taught them: such as, that a red-hot poker\n"
520 "will burn you if you hold it too long; and that if you cut your\n"
521 "finger VERY deeply with a knife, it usually bleeds; and she had\n"
522 "never forgotten that, if you drink much from a bottle marked\n"
523 "'poison,' it is almost certain to disagree with you, sooner or\n"
528 test_strings(const char **msg
,
529 svn_boolean_t msg_only
,
530 svn_test_opts_t
*opts
,
533 struct string_args args
;
535 svn_stringbuf_t
*string
;
537 *msg
= "test many strings table functions together";
542 /* Create a new fs and repos */
543 SVN_ERR(svn_test__create_fs
544 (&fs
, "test-repo-test-strings",
547 /* The plan (after each step below, verify the size and contents of
550 1. Write a new string (string1).
551 2. Append string2 to string.
553 4. Append string3 to string.
554 5. Delete string (verify by size requested failure).
555 6. Write a new string (string1), appending string2, string3, and
559 /* 1. Write a new string (string1). */
562 args
.text
= bigstring1
;
563 args
.len
= strlen(bigstring1
);
564 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
565 txn_body_string_append
, &args
, pool
));
567 /* Make sure a key was returned. */
569 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
570 "write of new string failed to return new key");
572 /* Verify record's size and contents. */
573 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
574 txn_body_verify_string
, &args
, pool
));
576 /* Append a second string to our first one. */
577 args
.text
= bigstring2
;
578 args
.len
= strlen(bigstring2
);
579 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
580 txn_body_string_append
, &args
, pool
));
582 /* Verify record's size and contents. */
583 string
= svn_stringbuf_create(bigstring1
, pool
);
584 svn_stringbuf_appendcstr(string
, bigstring2
);
585 args
.text
= string
->data
;
586 args
.len
= string
->len
;
587 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
588 txn_body_verify_string
, &args
, pool
));
590 /* Clear the record */
591 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
592 txn_body_string_clear
, &args
, pool
));
594 /* Verify record's size and contents. */
597 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
598 txn_body_verify_string
, &args
, pool
));
600 /* Append a third string to our first one. */
601 args
.text
= bigstring3
;
602 args
.len
= strlen(bigstring3
);
603 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
604 txn_body_string_append
, &args
, pool
));
606 /* Verify record's size and contents. */
607 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
608 txn_body_verify_string
, &args
, pool
));
610 /* Delete our record...she's served us well. */
611 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
612 txn_body_string_delete
, &args
, pool
));
614 /* Now, we expect a size request on this record to fail with
615 SVN_ERR_FS_NO_SUCH_STRING. */
617 svn_error_t
*err
= svn_fs_base__retry_txn(args
.fs
, txn_body_string_size
,
621 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
622 "query unexpectedly successful");
623 if (err
->apr_err
!= SVN_ERR_FS_NO_SUCH_STRING
)
624 return svn_error_create(SVN_ERR_FS_GENERAL
, err
,
625 "query failed with unexpected error");
626 svn_error_clear(err
);
634 write_null_string(const char **msg
,
635 svn_boolean_t msg_only
,
636 svn_test_opts_t
*opts
,
639 struct string_args args
;
642 *msg
= "write a null string";
647 /* Create a new fs and repos */
648 SVN_ERR(svn_test__create_fs
649 (&fs
, "test-repo-test-strings",
656 SVN_ERR(svn_fs_base__retry_txn(args
.fs
, txn_body_string_append
, &args
,
664 abort_string(const char **msg
,
665 svn_boolean_t msg_only
,
666 svn_test_opts_t
*opts
,
669 struct string_args args
, args2
;
672 *msg
= "write a string, then abort during an overwrite";
677 /* Create a new fs and repos */
678 SVN_ERR(svn_test__create_fs
679 (&fs
, "test-repo-abort-string",
684 1. Write a new string (string1).
685 2. Overwrite string1 with string2, but then ABORT the transaction.
686 3. Read string to make sure it is still string1.
689 /* 1. Write a new string (string1). */
692 args
.text
= bigstring1
;
693 args
.len
= strlen(bigstring1
);
694 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
695 txn_body_string_append
, &args
, pool
));
697 /* Make sure a key was returned. */
699 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
700 "write of new string failed to return new key");
702 /* Verify record's size and contents. */
703 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
704 txn_body_verify_string
, &args
, pool
));
706 /* Append a second string to our first one. */
708 args2
.key
= args
.key
;
709 args2
.text
= bigstring2
;
710 args2
.len
= strlen(bigstring2
);
714 /* This function is *supposed* to fail with SVN_ERR_TEST_FAILED */
715 err
= svn_fs_base__retry_txn(args
.fs
, txn_body_string_append_fail
,
717 if ((! err
) || (err
->apr_err
!= SVN_ERR_TEST_FAILED
))
718 return svn_error_create(SVN_ERR_TEST_FAILED
, err
,
719 "failed to intentionally abort a trail");
720 svn_error_clear(err
);
723 /* Verify that record's size and contents are still that of string1 */
724 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
725 txn_body_verify_string
, &args
, pool
));
731 copy_string(const char **msg
,
732 svn_boolean_t msg_only
,
733 svn_test_opts_t
*opts
,
736 struct string_args args
;
740 *msg
= "create and copy a string";
745 /* Create a new fs and repos */
746 SVN_ERR(svn_test__create_fs
747 (&fs
, "test-repo-copy-string",
750 /* Write a new string (string1). */
753 args
.text
= bigstring1
;
754 args
.len
= strlen(bigstring1
);
755 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
756 txn_body_string_append
, &args
, pool
));
758 /* Make sure a key was returned. */
759 if (! (old_key
= args
.key
))
760 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
761 "write of new string failed to return new key");
763 /* Now copy that string into a new location. */
764 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
765 txn_body_string_copy
, &args
, pool
));
767 /* Make sure a different key was returned. */
768 if ((! args
.key
) || (! strcmp(old_key
, args
.key
)))
769 return svn_error_create(SVN_ERR_FS_GENERAL
, NULL
,
770 "copy of string failed to return new key");
772 /* Verify record's size and contents. */
773 SVN_ERR(svn_fs_base__retry_txn(args
.fs
,
774 txn_body_verify_string
, &args
, pool
));
781 /* The test table. */
783 struct svn_test_descriptor_t test_funcs
[] =
786 SVN_TEST_PASS(write_new_rep
),
787 SVN_TEST_PASS(write_rep
),
788 SVN_TEST_PASS(read_rep
),
789 SVN_TEST_PASS(delete_rep
),
790 SVN_TEST_PASS(test_strings
),
791 SVN_TEST_PASS(write_null_string
),
792 SVN_TEST_PASS(abort_string
),
793 SVN_TEST_PASS(copy_string
),