1 /* strings-reps-test.c --- test `strings' and `representations' interfaces
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 <stdarg.h>
25 #include <string.h>
26 #include <stdio.h>
27 
28 #include <apr.h>
29 
30 #include "svn_error.h"
31 #include "private/svn_skel.h"
32 
33 #include "../svn_test.h"
34 #include "../svn_test_fs.h"
35 #include "../../libsvn_fs/fs-loader.h"
36 #include "../../libsvn_fs_base/fs.h"
37 #include "../../libsvn_fs_base/util/fs_skels.h"
38 #include "../../libsvn_fs_base/bdb/strings-table.h"
39 #include "../../libsvn_fs_base/bdb/reps-table.h"
40 
41 
42 
43 /*-----------------------------------------------------------------*/
44 /* Helper functions and batons for reps-table testing. */
45 struct rep_args
46 {
47   const char *key;
48   svn_fs_t *fs;
49   svn_skel_t *skel;
50 };
51 
52 
53 static svn_error_t *
txn_body_write_new_rep(void * baton,trail_t * trail)54 txn_body_write_new_rep(void *baton, trail_t *trail)
55 {
56   struct rep_args *b = (struct rep_args *) baton;
57   representation_t *rep;
58   SVN_ERR(svn_fs_base__parse_representation_skel(&rep, b->skel,
59                                                  trail->pool));
60   return svn_fs_bdb__write_new_rep(&(b->key), b->fs, rep, trail, trail->pool);
61 }
62 
63 
64 static svn_error_t *
txn_body_write_rep(void * baton,trail_t * trail)65 txn_body_write_rep(void *baton, trail_t *trail)
66 {
67   struct rep_args *b = (struct rep_args *) baton;
68   representation_t *rep;
69   SVN_ERR(svn_fs_base__parse_representation_skel(&rep, b->skel,
70                                                  trail->pool));
71   return svn_fs_bdb__write_rep(b->fs, b->key, rep, trail, trail->pool);
72 }
73 
74 
75 static svn_error_t *
txn_body_read_rep(void * baton,trail_t * trail)76 txn_body_read_rep(void *baton, trail_t *trail)
77 {
78   struct rep_args *b = (struct rep_args *) baton;
79   representation_t *rep;
80   base_fs_data_t *bfd = b->fs->fsap_data;
81   SVN_ERR(svn_fs_bdb__read_rep(&rep, b->fs, b->key, trail, trail->pool));
82   return svn_fs_base__unparse_representation_skel(&(b->skel), rep,
83                                                   bfd->format, trail->pool);
84 }
85 
86 
87 static svn_error_t *
txn_body_delete_rep(void * baton,trail_t * trail)88 txn_body_delete_rep(void *baton, trail_t *trail)
89 {
90   struct rep_args *b = (struct rep_args *) baton;
91   return svn_fs_bdb__delete_rep(b->fs, b->key, trail, trail->pool);
92 }
93 
94 
95 
96 /* Representation Table Test functions. */
97 
98 static svn_error_t *
write_new_rep(const svn_test_opts_t * opts,apr_pool_t * pool)99 write_new_rep(const svn_test_opts_t *opts,
100               apr_pool_t *pool)
101 {
102   struct rep_args args;
103   const char *rep = "((fulltext 0 ) a83t2Z0q)";
104   svn_fs_t *fs;
105 
106   /* Create a new fs and repos */
107   SVN_ERR(svn_test__create_bdb_fs
108           (&fs, "test-repo-write-new-rep", opts,
109            pool));
110 
111   /* Set up transaction baton */
112   args.fs = fs;
113   args.skel = svn_skel__parse(rep, strlen(rep), pool);
114   args.key = NULL;
115 
116   /* Write new rep to reps table. */
117   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_write_new_rep, &args,
118                                  FALSE, pool));
119 
120   if (args.key == NULL)
121     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
122                             "error writing new representation");
123 
124   return SVN_NO_ERROR;
125 }
126 
127 
128 static svn_error_t *
write_rep(const svn_test_opts_t * opts,apr_pool_t * pool)129 write_rep(const svn_test_opts_t *opts,
130           apr_pool_t *pool)
131 {
132   struct rep_args new_args;
133   struct rep_args args;
134   const char *new_rep = "((fulltext 0 ) a83t2Z0q)";
135   const char *rep = "((fulltext 0 ) kfogel31337)";
136   svn_fs_t *fs;
137 
138   /* Create a new fs and repos */
139   SVN_ERR(svn_test__create_bdb_fs
140           (&fs, "test-repo-write-rep", opts,
141            pool));
142 
143   /* Set up transaction baton */
144   new_args.fs = fs;
145   new_args.skel = svn_skel__parse(new_rep, strlen(new_rep), pool);
146   new_args.key = NULL;
147 
148   /* Write new rep to reps table. */
149   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_new_rep,
150                                  &new_args, FALSE, pool));
151 
152   /* Make sure we got a valid key. */
153   if (new_args.key == NULL)
154     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
155                             "error writing new representation");
156 
157   /* Set up transaction baton for re-writing reps. */
158   args.fs = new_args.fs;
159   args.skel = svn_skel__parse(rep, strlen(rep), pool);
160   args.key = new_args.key;
161 
162   /* Overwrite first rep in reps table. */
163   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_rep, &args,
164                                  FALSE, pool));
165 
166   return SVN_NO_ERROR;
167 }
168 
169 
170 static svn_error_t *
read_rep(const svn_test_opts_t * opts,apr_pool_t * pool)171 read_rep(const svn_test_opts_t *opts,
172          apr_pool_t *pool)
173 {
174   struct rep_args new_args;
175   struct rep_args args;
176   struct rep_args read_args;
177   svn_stringbuf_t *skel_data;
178   svn_fs_t *fs;
179 
180   const char *rep = "((fulltext 0 ) kfogel31337)";
181   const char *new_rep_before = "((fulltext 0 ) a83t2Z0)";
182 
183   /* This test also tests the introduction of checksums into skels that
184      didn't have them. */
185 
186   /* Get writeable strings. */
187   char *rep_after = apr_pstrdup
188     (pool, "((fulltext 0  (md5 16 XXXXXXXXXXXXXXXX)) kfogel31337");
189   char *new_rep_after = apr_pstrdup
190     (pool, "((fulltext 0  (md5 16 XXXXXXXXXXXXXXXX)) a83t2Z0");
191   size_t rep_after_len = strlen(rep_after);
192   size_t new_rep_after_len = strlen(new_rep_after);
193 
194   /* Replace the fake fake checksums with the real fake checksums.
195      And someday, when checksums are actually calculated, we can
196      replace the real fake checksums with real real checksums. */
197   {
198     char *p;
199 
200     for (p = rep_after; *p; p++)
201       if (*p == 'X')
202         *p = '\0';
203 
204     for (p = new_rep_after; *p; p++)
205       if (*p == 'X')
206         *p = '\0';
207   }
208 
209   /* Create a new fs and repos */
210   SVN_ERR(svn_test__create_bdb_fs
211           (&fs, "test-repo-read-rep", opts,
212            pool));
213 
214   /* Set up transaction baton */
215   new_args.fs = fs;
216   new_args.skel = svn_skel__parse(new_rep_before, strlen(new_rep_before),
217                                   pool);
218   new_args.key = NULL;
219 
220   /* Write new rep to reps table. */
221   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_new_rep,
222                                  &new_args, FALSE, pool));
223 
224   /* Make sure we got a valid key. */
225   if (new_args.key == NULL)
226     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
227                             "error writing new representation");
228 
229   /* Read the new rep back from the reps table. */
230   read_args.fs = new_args.fs;
231   read_args.skel = NULL;
232   read_args.key = new_args.key;
233   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_read_rep, &read_args,
234                                  FALSE, pool));
235 
236   /* Make sure the skel matches. */
237   if (! read_args.skel)
238     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
239                             "error reading new representation");
240 
241   skel_data = svn_skel__unparse(read_args.skel, pool);
242   if (memcmp(skel_data->data, new_rep_after, new_rep_after_len) != 0)
243     return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
244                              "representation corrupted (first check)");
245 
246   /* Set up transaction baton for re-writing reps. */
247   args.fs = new_args.fs;
248   args.skel = svn_skel__parse(rep, strlen(rep), pool);
249   args.key = new_args.key;
250 
251   /* Overwrite first rep in reps table. */
252   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_rep, &args,
253                                  FALSE, pool));
254 
255   /* Read the new rep back from the reps table (using the same FS and
256      key as the first read...let's make sure this thing didn't get
257      written to the wrong place). */
258   read_args.skel = NULL;
259   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_read_rep, &read_args,
260                                  FALSE, pool));
261 
262   /* Make sure the skel matches. */
263   if (! read_args.skel)
264     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
265                             "error reading new representation");
266 
267   skel_data = svn_skel__unparse(read_args.skel, pool);
268   if (memcmp(skel_data->data, rep_after, rep_after_len) != 0)
269     return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
270                              "representation corrupted (second check)");
271 
272   return SVN_NO_ERROR;
273 }
274 
275 
276 static svn_error_t *
delete_rep(const svn_test_opts_t * opts,apr_pool_t * pool)277 delete_rep(const svn_test_opts_t *opts,
278            apr_pool_t *pool)
279 {
280   struct rep_args new_args;
281   struct rep_args delete_args;
282   struct rep_args read_args;
283   const char *new_rep = "((fulltext 0 ) a83t2Z0q)";
284   svn_fs_t *fs;
285   svn_error_t *err;
286 
287   /* Create a new fs and repos */
288   SVN_ERR(svn_test__create_bdb_fs
289           (&fs, "test-repo-delete-rep", opts,
290            pool));
291 
292   /* Set up transaction baton */
293   new_args.fs = fs;
294   new_args.skel = svn_skel__parse(new_rep, strlen(new_rep), pool);
295   new_args.key = NULL;
296 
297   /* Write new rep to reps table. */
298   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_write_new_rep,
299                                  &new_args, FALSE, pool));
300 
301   /* Make sure we got a valid key. */
302   if (new_args.key == NULL)
303     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
304                             "error writing new representation");
305 
306   /* Delete the rep we just wrote. */
307   delete_args.fs = new_args.fs;
308   delete_args.key = new_args.key;
309   SVN_ERR(svn_fs_base__retry_txn(new_args.fs, txn_body_delete_rep,
310                                  &delete_args, FALSE, pool));
311 
312   /* Try to read the new rep back from the reps table. */
313   read_args.fs = new_args.fs;
314   read_args.skel = NULL;
315   read_args.key = new_args.key;
316   err = svn_fs_base__retry_txn(new_args.fs, txn_body_read_rep, &read_args,
317                                FALSE, pool);
318 
319   /* We better have an error... */
320   if ((! err) && (read_args.skel))
321     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
322                             "error deleting representation");
323   svn_error_clear(err);
324 
325   return SVN_NO_ERROR;
326 }
327 
328 
329 /* ------------------------------------------------------------------- */
330 /* Helper functions and batons for strings-table testing. */
331 
332 static svn_error_t *
verify_expected_record(svn_fs_t * fs,const char * key,const char * expected_text,apr_size_t expected_len,trail_t * trail)333 verify_expected_record(svn_fs_t *fs,
334                        const char *key,
335                        const char *expected_text,
336                        apr_size_t expected_len,
337                        trail_t *trail)
338 {
339   apr_size_t size;
340   char buf[100];
341   svn_stringbuf_t *text;
342   svn_filesize_t offset = 0;
343   svn_filesize_t string_size;
344 
345   /* Check the string size. */
346   SVN_ERR(svn_fs_bdb__string_size(&string_size, fs, key,
347                                   trail, trail->pool));
348   if (string_size > SVN_MAX_OBJECT_SIZE)
349     return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
350                              "record size is too large "
351                              "(got %" SVN_FILESIZE_T_FMT ", "
352                              "limit is %" APR_SIZE_T_FMT ")",
353                              string_size, SVN_MAX_OBJECT_SIZE);
354   size = (apr_size_t) string_size;
355   if (size != expected_len)
356     return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
357                              "record has unexpected size "
358                              "(got %" APR_SIZE_T_FMT ", "
359                              "expected %" APR_SIZE_T_FMT ")",
360                              size, expected_len);
361 
362   /* Read the string back in 100-byte chunks. */
363   text = svn_stringbuf_create_empty(trail->pool);
364   while (1)
365     {
366       size = sizeof(buf);
367       SVN_ERR(svn_fs_bdb__string_read(fs, key, buf, offset, &size,
368                                       trail, trail->pool));
369       if (size == 0)
370         break;
371       svn_stringbuf_appendbytes(text, buf, size);
372       offset += size;
373     }
374 
375   /* Check the size and contents of the read data. */
376   if (text->len != expected_len)
377     return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
378                              "record read returned unexpected size "
379                              "(got %" APR_SIZE_T_FMT ", "
380                              "expected %" APR_SIZE_T_FMT ")",
381                              size, expected_len);
382   if (memcmp(expected_text, text->data, expected_len))
383     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
384                             "record read returned unexpected data");
385 
386   return SVN_NO_ERROR;
387 }
388 
389 
390 struct string_args
391 {
392   svn_fs_t *fs;
393   const char *key;
394   const char *text;
395   apr_size_t len;
396 };
397 
398 
399 static svn_error_t *
txn_body_verify_string(void * baton,trail_t * trail)400 txn_body_verify_string(void *baton, trail_t *trail)
401 {
402   struct string_args *b = (struct string_args *) baton;
403   return verify_expected_record(b->fs, b->key, b->text, b->len, trail);
404 }
405 
406 
407 static svn_error_t *
txn_body_string_append(void * baton,trail_t * trail)408 txn_body_string_append(void *baton, trail_t *trail)
409 {
410   struct string_args *b = (struct string_args *) baton;
411   return svn_fs_bdb__string_append(b->fs, &(b->key), b->len,
412                                    b->text, trail, trail->pool);
413 }
414 
415 
416 static svn_error_t *
txn_body_string_clear(void * baton,trail_t * trail)417 txn_body_string_clear(void *baton, trail_t *trail)
418 {
419   struct string_args *b = (struct string_args *) baton;
420   return svn_fs_bdb__string_clear(b->fs, b->key, trail, trail->pool);
421 }
422 
423 
424 static svn_error_t *
txn_body_string_delete(void * baton,trail_t * trail)425 txn_body_string_delete(void *baton, trail_t *trail)
426 {
427   struct string_args *b = (struct string_args *) baton;
428   return svn_fs_bdb__string_delete(b->fs, b->key, trail, trail->pool);
429 }
430 
431 
432 static svn_error_t *
txn_body_string_size(void * baton,trail_t * trail)433 txn_body_string_size(void *baton, trail_t *trail)
434 {
435   struct string_args *b = (struct string_args *) baton;
436   svn_filesize_t string_size;
437   SVN_ERR(svn_fs_bdb__string_size(&string_size, b->fs, b->key,
438                                   trail, trail->pool));
439   if (string_size > SVN_MAX_OBJECT_SIZE)
440     return svn_error_createf
441       (SVN_ERR_FS_GENERAL, NULL,
442        "txn_body_string_size: string size is too large "
443        "(got %" SVN_FILESIZE_T_FMT ", limit is %" APR_SIZE_T_FMT ")",
444        string_size, SVN_MAX_OBJECT_SIZE);
445   b->len = (apr_size_t) string_size;
446   return SVN_NO_ERROR;
447 }
448 
449 
450 static svn_error_t *
txn_body_string_append_fail(void * baton,trail_t * trail)451 txn_body_string_append_fail(void *baton, trail_t *trail)
452 {
453   struct string_args *b = (struct string_args *) baton;
454   SVN_ERR(svn_fs_bdb__string_append(b->fs, &(b->key), b->len,
455                                     b->text, trail, trail->pool));
456   return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
457                           "la dee dah, la dee day...");
458 }
459 
460 static svn_error_t *
txn_body_string_copy(void * baton,trail_t * trail)461 txn_body_string_copy(void *baton, trail_t *trail)
462 {
463   struct string_args *b = (struct string_args *) baton;
464   return svn_fs_bdb__string_copy(b->fs, &(b->key), b->key,
465                                  trail, trail->pool);
466 }
467 
468 
469 static const char *bigstring1 =
470 "    Alice opened the door and found that it led into a small\n"
471 "passage, not much larger than a rat-hole:  she knelt down and\n"
472 "looked along the passage into the loveliest garden you ever saw.\n"
473 "How she longed to get out of that dark hall, and wander about\n"
474 "among those beds of bright flowers and those cool fountains, but\n"
475 "she could not even get her head though the doorway; 'and even if\n"
476 "my head would go through,' thought poor Alice, 'it would be of\n"
477 "very little use without my shoulders.  Oh, how I wish\n"
478 "I could shut up like a telescope!  I think I could, if I only\n"
479 "know how to begin.'  For, you see, so many out-of-the-way things\n"
480 "had happened lately, that Alice had begun to think that very few\n"
481 "things indeed were really impossible.";
482 
483 static const char *bigstring2 =
484 "    There seemed to be no use in waiting by the little door, so she\n"
485 "went back to the table, half hoping she might find another key on\n"
486 "it, or at any rate a book of rules for shutting people up like\n"
487 "telescopes:  this time she found a little bottle on it, ('which\n"
488 "certainly was not here before,' said Alice,) and round the neck\n"
489 "of the bottle was a paper label, with the words 'DRINK ME'\n"
490 "beautifully printed on it in large letters.";
491 
492 static const char *bigstring3 =
493 "    It was all very well to say 'Drink me,' but the wise little\n"
494 "Alice was not going to do THAT in a hurry.  'No, I'll look\n"
495 "first,' she said, 'and see whether it's marked \"poison\" or not';\n"
496 "for she had read several nice little histories about children who\n"
497 "had got burnt, and eaten up by wild beasts and other unpleasant\n"
498 "things, all because they WOULD not remember the simple rules\n"
499 "their friends had taught them:  such as, that a red-hot poker\n"
500 "will burn you if you hold it too long; and that if you cut your\n"
501 "finger VERY deeply with a knife, it usually bleeds; and she had\n"
502 "never forgotten that, if you drink much from a bottle marked\n"
503 "'poison,' it is almost certain to disagree with you, sooner or\n"
504 "later.";
505 
506 
507 static svn_error_t *
test_strings(const svn_test_opts_t * opts,apr_pool_t * pool)508 test_strings(const svn_test_opts_t *opts,
509              apr_pool_t *pool)
510 {
511   struct string_args args;
512   svn_fs_t *fs;
513   svn_stringbuf_t *string;
514 
515   /* Create a new fs and repos */
516   SVN_ERR(svn_test__create_bdb_fs
517           (&fs, "test-repo-test-strings", opts,
518            pool));
519 
520   /* The plan (after each step below, verify the size and contents of
521      the string):
522 
523      1.  Write a new string (string1).
524      2.  Append string2 to string.
525      3.  Clear string.
526      4.  Append string3 to string.
527      5.  Delete string (verify by size requested failure).
528      6.  Write a new string (string1), appending string2, string3, and
529          string4.
530   */
531 
532   /* 1. Write a new string (string1). */
533   args.fs = fs;
534   args.key = NULL;
535   args.text = bigstring1;
536   args.len = strlen(bigstring1);
537   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_append, &args,
538                                  FALSE, pool));
539 
540   /* Make sure a key was returned. */
541   if (! args.key)
542     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
543                             "write of new string failed to return new key");
544 
545   /* Verify record's size and contents. */
546   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
547                                  FALSE, pool));
548 
549   /* Append a second string to our first one. */
550   args.text = bigstring2;
551   args.len = strlen(bigstring2);
552   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_append, &args,
553                                  FALSE, pool));
554 
555   /* Verify record's size and contents. */
556   string = svn_stringbuf_create(bigstring1, pool);
557   svn_stringbuf_appendcstr(string, bigstring2);
558   args.text = string->data;
559   args.len = string->len;
560   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
561                                  FALSE, pool));
562 
563   /* Clear the record */
564   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_clear, &args,
565                                  FALSE, pool));
566 
567   /* Verify record's size and contents. */
568   args.text = "";
569   args.len = 0;
570   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
571                                  FALSE, pool));
572 
573   /* Append a third string to our first one. */
574   args.text = bigstring3;
575   args.len = strlen(bigstring3);
576   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_append, &args,
577                                  FALSE, pool));
578 
579   /* Verify record's size and contents. */
580   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
581                                  FALSE, pool));
582 
583   /* Delete our record...she's served us well. */
584   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_delete, &args,
585                                  FALSE, pool));
586 
587   /* Now, we expect a size request on this record to fail with
588      SVN_ERR_FS_NO_SUCH_STRING. */
589   {
590     svn_error_t *err = svn_fs_base__retry_txn(args.fs, txn_body_string_size,
591                                               &args, FALSE, pool);
592 
593     if (! err)
594       return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
595                               "query unexpectedly successful");
596     if (err->apr_err != SVN_ERR_FS_NO_SUCH_STRING)
597       return svn_error_create(SVN_ERR_FS_GENERAL, err,
598                               "query failed with unexpected error");
599     svn_error_clear(err);
600   }
601 
602   return SVN_NO_ERROR;
603 }
604 
605 
606 static svn_error_t *
write_null_string(const svn_test_opts_t * opts,apr_pool_t * pool)607 write_null_string(const svn_test_opts_t *opts,
608                   apr_pool_t *pool)
609 {
610   struct string_args args;
611   svn_fs_t *fs;
612 
613   /* Create a new fs and repos */
614   SVN_ERR(svn_test__create_bdb_fs
615           (&fs, "test-repo-write-null-string", opts,
616            pool));
617 
618   args.fs = fs;
619   args.key = NULL;
620   args.text = NULL;
621   args.len = 0;
622   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_append, &args,
623                                  FALSE, pool));
624 
625   return SVN_NO_ERROR;
626 }
627 
628 
629 static svn_error_t *
abort_string(const svn_test_opts_t * opts,apr_pool_t * pool)630 abort_string(const svn_test_opts_t *opts,
631              apr_pool_t *pool)
632 {
633   struct string_args args, args2;
634   svn_fs_t *fs;
635 
636   /* Create a new fs and repos */
637   SVN_ERR(svn_test__create_bdb_fs
638           (&fs, "test-repo-abort-string", opts,
639            pool));
640 
641   /* The plan:
642 
643      1.  Write a new string (string1).
644      2.  Overwrite string1 with string2, but then ABORT the transaction.
645      3.  Read string to make sure it is still string1.
646   */
647 
648   /* 1. Write a new string (string1). */
649   args.fs = fs;
650   args.key = NULL;
651   args.text = bigstring1;
652   args.len = strlen(bigstring1);
653   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_append, &args,
654                                  FALSE, pool));
655 
656   /* Make sure a key was returned. */
657   if (! args.key)
658     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
659                             "write of new string failed to return new key");
660 
661   /* Verify record's size and contents. */
662   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
663                                  FALSE, pool));
664 
665   /* Append a second string to our first one. */
666   args2.fs = fs;
667   args2.key = args.key;
668   args2.text = bigstring2;
669   args2.len = strlen(bigstring2);
670   {
671     svn_error_t *err;
672 
673     /* This function is *supposed* to fail with SVN_ERR_TEST_FAILED */
674     err = svn_fs_base__retry_txn(args.fs, txn_body_string_append_fail,
675                                  &args2, FALSE, pool);
676     if ((! err) || (err->apr_err != SVN_ERR_TEST_FAILED))
677       return svn_error_create(SVN_ERR_TEST_FAILED, err,
678                               "failed to intentionally abort a trail");
679     svn_error_clear(err);
680   }
681 
682   /* Verify that record's size and contents are still that of string1 */
683   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
684                                  FALSE, pool));
685 
686   return SVN_NO_ERROR;
687 }
688 
689 static svn_error_t *
copy_string(const svn_test_opts_t * opts,apr_pool_t * pool)690 copy_string(const svn_test_opts_t *opts,
691             apr_pool_t *pool)
692 {
693   struct string_args args;
694   svn_fs_t *fs;
695   const char *old_key;
696 
697   /* Create a new fs and repos */
698   SVN_ERR(svn_test__create_bdb_fs
699           (&fs, "test-repo-copy-string", opts,
700            pool));
701 
702   /*  Write a new string (string1). */
703   args.fs = fs;
704   args.key = NULL;
705   args.text = bigstring1;
706   args.len = strlen(bigstring1);
707   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_append, &args,
708                                  FALSE, pool));
709 
710   /* Make sure a key was returned. */
711   if (! (old_key = args.key))
712     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
713                             "write of new string failed to return new key");
714 
715   /* Now copy that string into a new location. */
716   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_string_copy, &args,
717                                  FALSE, pool));
718 
719   /* Make sure a different key was returned. */
720   if ((! args.key) || (! strcmp(old_key, args.key)))
721     return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
722                             "copy of string failed to return new key");
723 
724   /* Verify record's size and contents. */
725   SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_verify_string, &args,
726                                  FALSE, pool));
727 
728   return SVN_NO_ERROR;
729 }
730 
731 
732 
733 /* The test table.  */
734 
735 static int max_threads = 3;
736 
737 static struct svn_test_descriptor_t test_funcs[] =
738   {
739     SVN_TEST_NULL,
740     SVN_TEST_OPTS_PASS(write_new_rep,
741                        "write a new rep, get a new key back"),
742     SVN_TEST_OPTS_PASS(write_rep,
743                        "write a new rep, then overwrite it"),
744     SVN_TEST_OPTS_PASS(read_rep,
745                        "write and overwrite a new rep; confirm with reads"),
746     SVN_TEST_OPTS_PASS(delete_rep,
747                        "write, then delete, a new rep; confirm deletion"),
748     SVN_TEST_OPTS_PASS(test_strings,
749                        "test many strings table functions together"),
750     SVN_TEST_OPTS_PASS(write_null_string,
751                        "write a null string"),
752     SVN_TEST_OPTS_PASS(abort_string,
753                        "write a string, then abort during an overwrite"),
754     SVN_TEST_OPTS_PASS(copy_string,
755                        "create and copy a string"),
756     SVN_TEST_NULL
757   };
758 
759 SVN_TEST_MAIN
760