]> git.ipfire.org Git - thirdparty/git.git/blob - reftable/readwrite_test.c
Merge branch 'la/strvec-comment-fix' into maint-2.43
[thirdparty/git.git] / reftable / readwrite_test.c
1 /*
2 Copyright 2020 Google LLC
3
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://developers.google.com/open-source/licenses/bsd
7 */
8
9 #include "system.h"
10
11 #include "basics.h"
12 #include "block.h"
13 #include "blocksource.h"
14 #include "reader.h"
15 #include "record.h"
16 #include "test_framework.h"
17 #include "reftable-tests.h"
18 #include "reftable-writer.h"
19
20 static const int update_index = 5;
21
22 static void test_buffer(void)
23 {
24 struct strbuf buf = STRBUF_INIT;
25 struct reftable_block_source source = { NULL };
26 struct reftable_block out = { NULL };
27 int n;
28 uint8_t in[] = "hello";
29 strbuf_add(&buf, in, sizeof(in));
30 block_source_from_strbuf(&source, &buf);
31 EXPECT(block_source_size(&source) == 6);
32 n = block_source_read_block(&source, &out, 0, sizeof(in));
33 EXPECT(n == sizeof(in));
34 EXPECT(!memcmp(in, out.data, n));
35 reftable_block_done(&out);
36
37 n = block_source_read_block(&source, &out, 1, 2);
38 EXPECT(n == 2);
39 EXPECT(!memcmp(out.data, "el", 2));
40
41 reftable_block_done(&out);
42 block_source_close(&source);
43 strbuf_release(&buf);
44 }
45
46 static void write_table(char ***names, struct strbuf *buf, int N,
47 int block_size, uint32_t hash_id)
48 {
49 struct reftable_write_options opts = {
50 .block_size = block_size,
51 .hash_id = hash_id,
52 };
53 struct reftable_writer *w =
54 reftable_new_writer(&strbuf_add_void, buf, &opts);
55 struct reftable_ref_record ref = { NULL };
56 int i = 0, n;
57 struct reftable_log_record log = { NULL };
58 const struct reftable_stats *stats = NULL;
59 *names = reftable_calloc(sizeof(char *) * (N + 1));
60 reftable_writer_set_limits(w, update_index, update_index);
61 for (i = 0; i < N; i++) {
62 uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
63 char name[100];
64 int n;
65
66 set_test_hash(hash, i);
67
68 snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
69
70 ref.refname = name;
71 ref.update_index = update_index;
72 ref.value_type = REFTABLE_REF_VAL1;
73 ref.value.val1 = hash;
74 (*names)[i] = xstrdup(name);
75
76 n = reftable_writer_add_ref(w, &ref);
77 EXPECT(n == 0);
78 }
79
80 for (i = 0; i < N; i++) {
81 uint8_t hash[GIT_SHA256_RAWSZ] = { 0 };
82 char name[100];
83 int n;
84
85 set_test_hash(hash, i);
86
87 snprintf(name, sizeof(name), "refs/heads/branch%02d", i);
88
89 log.refname = name;
90 log.update_index = update_index;
91 log.value_type = REFTABLE_LOG_UPDATE;
92 log.value.update.new_hash = hash;
93 log.value.update.message = "message";
94
95 n = reftable_writer_add_log(w, &log);
96 EXPECT(n == 0);
97 }
98
99 n = reftable_writer_close(w);
100 EXPECT(n == 0);
101
102 stats = reftable_writer_stats(w);
103 for (i = 0; i < stats->ref_stats.blocks; i++) {
104 int off = i * opts.block_size;
105 if (off == 0) {
106 off = header_size(
107 (hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1);
108 }
109 EXPECT(buf->buf[off] == 'r');
110 }
111
112 EXPECT(stats->log_stats.blocks > 0);
113 reftable_writer_free(w);
114 }
115
116 static void test_log_buffer_size(void)
117 {
118 struct strbuf buf = STRBUF_INIT;
119 struct reftable_write_options opts = {
120 .block_size = 4096,
121 };
122 int err;
123 int i;
124 struct reftable_log_record
125 log = { .refname = "refs/heads/master",
126 .update_index = 0xa,
127 .value_type = REFTABLE_LOG_UPDATE,
128 .value = { .update = {
129 .name = "Han-Wen Nienhuys",
130 .email = "hanwen@google.com",
131 .tz_offset = 100,
132 .time = 0x5e430672,
133 .message = "commit: 9\n",
134 } } };
135 struct reftable_writer *w =
136 reftable_new_writer(&strbuf_add_void, &buf, &opts);
137
138 /* This tests buffer extension for log compression. Must use a random
139 hash, to ensure that the compressed part is larger than the original.
140 */
141 uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
142 for (i = 0; i < GIT_SHA1_RAWSZ; i++) {
143 hash1[i] = (uint8_t)(git_rand() % 256);
144 hash2[i] = (uint8_t)(git_rand() % 256);
145 }
146 log.value.update.old_hash = hash1;
147 log.value.update.new_hash = hash2;
148 reftable_writer_set_limits(w, update_index, update_index);
149 err = reftable_writer_add_log(w, &log);
150 EXPECT_ERR(err);
151 err = reftable_writer_close(w);
152 EXPECT_ERR(err);
153 reftable_writer_free(w);
154 strbuf_release(&buf);
155 }
156
157 static void test_log_overflow(void)
158 {
159 struct strbuf buf = STRBUF_INIT;
160 char msg[256] = { 0 };
161 struct reftable_write_options opts = {
162 .block_size = ARRAY_SIZE(msg),
163 };
164 int err;
165 struct reftable_log_record
166 log = { .refname = "refs/heads/master",
167 .update_index = 0xa,
168 .value_type = REFTABLE_LOG_UPDATE,
169 .value = { .update = {
170 .name = "Han-Wen Nienhuys",
171 .email = "hanwen@google.com",
172 .tz_offset = 100,
173 .time = 0x5e430672,
174 .message = msg,
175 } } };
176 struct reftable_writer *w =
177 reftable_new_writer(&strbuf_add_void, &buf, &opts);
178
179 uint8_t hash1[GIT_SHA1_RAWSZ] = {1}, hash2[GIT_SHA1_RAWSZ] = { 2 };
180
181 memset(msg, 'x', sizeof(msg) - 1);
182 log.value.update.old_hash = hash1;
183 log.value.update.new_hash = hash2;
184 reftable_writer_set_limits(w, update_index, update_index);
185 err = reftable_writer_add_log(w, &log);
186 EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
187 reftable_writer_free(w);
188 strbuf_release(&buf);
189 }
190
191 static void test_log_write_read(void)
192 {
193 int N = 2;
194 char **names = reftable_calloc(sizeof(char *) * (N + 1));
195 int err;
196 struct reftable_write_options opts = {
197 .block_size = 256,
198 };
199 struct reftable_ref_record ref = { NULL };
200 int i = 0;
201 struct reftable_log_record log = { NULL };
202 int n;
203 struct reftable_iterator it = { NULL };
204 struct reftable_reader rd = { NULL };
205 struct reftable_block_source source = { NULL };
206 struct strbuf buf = STRBUF_INIT;
207 struct reftable_writer *w =
208 reftable_new_writer(&strbuf_add_void, &buf, &opts);
209 const struct reftable_stats *stats = NULL;
210 reftable_writer_set_limits(w, 0, N);
211 for (i = 0; i < N; i++) {
212 char name[256];
213 struct reftable_ref_record ref = { NULL };
214 snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
215 names[i] = xstrdup(name);
216 ref.refname = name;
217 ref.update_index = i;
218
219 err = reftable_writer_add_ref(w, &ref);
220 EXPECT_ERR(err);
221 }
222 for (i = 0; i < N; i++) {
223 uint8_t hash1[GIT_SHA1_RAWSZ], hash2[GIT_SHA1_RAWSZ];
224 struct reftable_log_record log = { NULL };
225 set_test_hash(hash1, i);
226 set_test_hash(hash2, i + 1);
227
228 log.refname = names[i];
229 log.update_index = i;
230 log.value_type = REFTABLE_LOG_UPDATE;
231 log.value.update.old_hash = hash1;
232 log.value.update.new_hash = hash2;
233
234 err = reftable_writer_add_log(w, &log);
235 EXPECT_ERR(err);
236 }
237
238 n = reftable_writer_close(w);
239 EXPECT(n == 0);
240
241 stats = reftable_writer_stats(w);
242 EXPECT(stats->log_stats.blocks > 0);
243 reftable_writer_free(w);
244 w = NULL;
245
246 block_source_from_strbuf(&source, &buf);
247
248 err = init_reader(&rd, &source, "file.log");
249 EXPECT_ERR(err);
250
251 err = reftable_reader_seek_ref(&rd, &it, names[N - 1]);
252 EXPECT_ERR(err);
253
254 err = reftable_iterator_next_ref(&it, &ref);
255 EXPECT_ERR(err);
256
257 /* end of iteration. */
258 err = reftable_iterator_next_ref(&it, &ref);
259 EXPECT(0 < err);
260
261 reftable_iterator_destroy(&it);
262 reftable_ref_record_release(&ref);
263
264 err = reftable_reader_seek_log(&rd, &it, "");
265 EXPECT_ERR(err);
266
267 i = 0;
268 while (1) {
269 int err = reftable_iterator_next_log(&it, &log);
270 if (err > 0) {
271 break;
272 }
273
274 EXPECT_ERR(err);
275 EXPECT_STREQ(names[i], log.refname);
276 EXPECT(i == log.update_index);
277 i++;
278 reftable_log_record_release(&log);
279 }
280
281 EXPECT(i == N);
282 reftable_iterator_destroy(&it);
283
284 /* cleanup. */
285 strbuf_release(&buf);
286 free_names(names);
287 reader_close(&rd);
288 }
289
290 static void test_log_zlib_corruption(void)
291 {
292 struct reftable_write_options opts = {
293 .block_size = 256,
294 };
295 struct reftable_iterator it = { 0 };
296 struct reftable_reader rd = { 0 };
297 struct reftable_block_source source = { 0 };
298 struct strbuf buf = STRBUF_INIT;
299 struct reftable_writer *w =
300 reftable_new_writer(&strbuf_add_void, &buf, &opts);
301 const struct reftable_stats *stats = NULL;
302 uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
303 uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
304 char message[100] = { 0 };
305 int err, i, n;
306
307 struct reftable_log_record log = {
308 .refname = "refname",
309 .value_type = REFTABLE_LOG_UPDATE,
310 .value = {
311 .update = {
312 .new_hash = hash1,
313 .old_hash = hash2,
314 .name = "My Name",
315 .email = "myname@invalid",
316 .message = message,
317 },
318 },
319 };
320
321 for (i = 0; i < sizeof(message) - 1; i++)
322 message[i] = (uint8_t)(git_rand() % 64 + ' ');
323
324 reftable_writer_set_limits(w, 1, 1);
325
326 err = reftable_writer_add_log(w, &log);
327 EXPECT_ERR(err);
328
329 n = reftable_writer_close(w);
330 EXPECT(n == 0);
331
332 stats = reftable_writer_stats(w);
333 EXPECT(stats->log_stats.blocks > 0);
334 reftable_writer_free(w);
335 w = NULL;
336
337 /* corrupt the data. */
338 buf.buf[50] ^= 0x99;
339
340 block_source_from_strbuf(&source, &buf);
341
342 err = init_reader(&rd, &source, "file.log");
343 EXPECT_ERR(err);
344
345 err = reftable_reader_seek_log(&rd, &it, "refname");
346 EXPECT(err == REFTABLE_ZLIB_ERROR);
347
348 reftable_iterator_destroy(&it);
349
350 /* cleanup. */
351 strbuf_release(&buf);
352 reader_close(&rd);
353 }
354
355 static void test_table_read_write_sequential(void)
356 {
357 char **names;
358 struct strbuf buf = STRBUF_INIT;
359 int N = 50;
360 struct reftable_iterator it = { NULL };
361 struct reftable_block_source source = { NULL };
362 struct reftable_reader rd = { NULL };
363 int err = 0;
364 int j = 0;
365
366 write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
367
368 block_source_from_strbuf(&source, &buf);
369
370 err = init_reader(&rd, &source, "file.ref");
371 EXPECT_ERR(err);
372
373 err = reftable_reader_seek_ref(&rd, &it, "");
374 EXPECT_ERR(err);
375
376 while (1) {
377 struct reftable_ref_record ref = { NULL };
378 int r = reftable_iterator_next_ref(&it, &ref);
379 EXPECT(r >= 0);
380 if (r > 0) {
381 break;
382 }
383 EXPECT(0 == strcmp(names[j], ref.refname));
384 EXPECT(update_index == ref.update_index);
385
386 j++;
387 reftable_ref_record_release(&ref);
388 }
389 EXPECT(j == N);
390 reftable_iterator_destroy(&it);
391 strbuf_release(&buf);
392 free_names(names);
393
394 reader_close(&rd);
395 }
396
397 static void test_table_write_small_table(void)
398 {
399 char **names;
400 struct strbuf buf = STRBUF_INIT;
401 int N = 1;
402 write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
403 EXPECT(buf.len < 200);
404 strbuf_release(&buf);
405 free_names(names);
406 }
407
408 static void test_table_read_api(void)
409 {
410 char **names;
411 struct strbuf buf = STRBUF_INIT;
412 int N = 50;
413 struct reftable_reader rd = { NULL };
414 struct reftable_block_source source = { NULL };
415 int err;
416 int i;
417 struct reftable_log_record log = { NULL };
418 struct reftable_iterator it = { NULL };
419
420 write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
421
422 block_source_from_strbuf(&source, &buf);
423
424 err = init_reader(&rd, &source, "file.ref");
425 EXPECT_ERR(err);
426
427 err = reftable_reader_seek_ref(&rd, &it, names[0]);
428 EXPECT_ERR(err);
429
430 err = reftable_iterator_next_log(&it, &log);
431 EXPECT(err == REFTABLE_API_ERROR);
432
433 strbuf_release(&buf);
434 for (i = 0; i < N; i++) {
435 reftable_free(names[i]);
436 }
437 reftable_iterator_destroy(&it);
438 reftable_free(names);
439 reader_close(&rd);
440 strbuf_release(&buf);
441 }
442
443 static void test_table_read_write_seek(int index, int hash_id)
444 {
445 char **names;
446 struct strbuf buf = STRBUF_INIT;
447 int N = 50;
448 struct reftable_reader rd = { NULL };
449 struct reftable_block_source source = { NULL };
450 int err;
451 int i = 0;
452
453 struct reftable_iterator it = { NULL };
454 struct strbuf pastLast = STRBUF_INIT;
455 struct reftable_ref_record ref = { NULL };
456
457 write_table(&names, &buf, N, 256, hash_id);
458
459 block_source_from_strbuf(&source, &buf);
460
461 err = init_reader(&rd, &source, "file.ref");
462 EXPECT_ERR(err);
463 EXPECT(hash_id == reftable_reader_hash_id(&rd));
464
465 if (!index) {
466 rd.ref_offsets.index_offset = 0;
467 } else {
468 EXPECT(rd.ref_offsets.index_offset > 0);
469 }
470
471 for (i = 1; i < N; i++) {
472 int err = reftable_reader_seek_ref(&rd, &it, names[i]);
473 EXPECT_ERR(err);
474 err = reftable_iterator_next_ref(&it, &ref);
475 EXPECT_ERR(err);
476 EXPECT(0 == strcmp(names[i], ref.refname));
477 EXPECT(REFTABLE_REF_VAL1 == ref.value_type);
478 EXPECT(i == ref.value.val1[0]);
479
480 reftable_ref_record_release(&ref);
481 reftable_iterator_destroy(&it);
482 }
483
484 strbuf_addstr(&pastLast, names[N - 1]);
485 strbuf_addstr(&pastLast, "/");
486
487 err = reftable_reader_seek_ref(&rd, &it, pastLast.buf);
488 if (err == 0) {
489 struct reftable_ref_record ref = { NULL };
490 int err = reftable_iterator_next_ref(&it, &ref);
491 EXPECT(err > 0);
492 } else {
493 EXPECT(err > 0);
494 }
495
496 strbuf_release(&pastLast);
497 reftable_iterator_destroy(&it);
498
499 strbuf_release(&buf);
500 for (i = 0; i < N; i++) {
501 reftable_free(names[i]);
502 }
503 reftable_free(names);
504 reader_close(&rd);
505 }
506
507 static void test_table_read_write_seek_linear(void)
508 {
509 test_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
510 }
511
512 static void test_table_read_write_seek_linear_sha256(void)
513 {
514 test_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
515 }
516
517 static void test_table_read_write_seek_index(void)
518 {
519 test_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
520 }
521
522 static void test_table_refs_for(int indexed)
523 {
524 int N = 50;
525 char **want_names = reftable_calloc(sizeof(char *) * (N + 1));
526 int want_names_len = 0;
527 uint8_t want_hash[GIT_SHA1_RAWSZ];
528
529 struct reftable_write_options opts = {
530 .block_size = 256,
531 };
532 struct reftable_ref_record ref = { NULL };
533 int i = 0;
534 int n;
535 int err;
536 struct reftable_reader rd;
537 struct reftable_block_source source = { NULL };
538
539 struct strbuf buf = STRBUF_INIT;
540 struct reftable_writer *w =
541 reftable_new_writer(&strbuf_add_void, &buf, &opts);
542
543 struct reftable_iterator it = { NULL };
544 int j;
545
546 set_test_hash(want_hash, 4);
547
548 for (i = 0; i < N; i++) {
549 uint8_t hash[GIT_SHA1_RAWSZ];
550 char fill[51] = { 0 };
551 char name[100];
552 uint8_t hash1[GIT_SHA1_RAWSZ];
553 uint8_t hash2[GIT_SHA1_RAWSZ];
554 struct reftable_ref_record ref = { NULL };
555
556 memset(hash, i, sizeof(hash));
557 memset(fill, 'x', 50);
558 /* Put the variable part in the start */
559 snprintf(name, sizeof(name), "br%02d%s", i, fill);
560 name[40] = 0;
561 ref.refname = name;
562
563 set_test_hash(hash1, i / 4);
564 set_test_hash(hash2, 3 + i / 4);
565 ref.value_type = REFTABLE_REF_VAL2;
566 ref.value.val2.value = hash1;
567 ref.value.val2.target_value = hash2;
568
569 /* 80 bytes / entry, so 3 entries per block. Yields 17
570 */
571 /* blocks. */
572 n = reftable_writer_add_ref(w, &ref);
573 EXPECT(n == 0);
574
575 if (!memcmp(hash1, want_hash, GIT_SHA1_RAWSZ) ||
576 !memcmp(hash2, want_hash, GIT_SHA1_RAWSZ)) {
577 want_names[want_names_len++] = xstrdup(name);
578 }
579 }
580
581 n = reftable_writer_close(w);
582 EXPECT(n == 0);
583
584 reftable_writer_free(w);
585 w = NULL;
586
587 block_source_from_strbuf(&source, &buf);
588
589 err = init_reader(&rd, &source, "file.ref");
590 EXPECT_ERR(err);
591 if (!indexed) {
592 rd.obj_offsets.is_present = 0;
593 }
594
595 err = reftable_reader_seek_ref(&rd, &it, "");
596 EXPECT_ERR(err);
597 reftable_iterator_destroy(&it);
598
599 err = reftable_reader_refs_for(&rd, &it, want_hash);
600 EXPECT_ERR(err);
601
602 j = 0;
603 while (1) {
604 int err = reftable_iterator_next_ref(&it, &ref);
605 EXPECT(err >= 0);
606 if (err > 0) {
607 break;
608 }
609
610 EXPECT(j < want_names_len);
611 EXPECT(0 == strcmp(ref.refname, want_names[j]));
612 j++;
613 reftable_ref_record_release(&ref);
614 }
615 EXPECT(j == want_names_len);
616
617 strbuf_release(&buf);
618 free_names(want_names);
619 reftable_iterator_destroy(&it);
620 reader_close(&rd);
621 }
622
623 static void test_table_refs_for_no_index(void)
624 {
625 test_table_refs_for(0);
626 }
627
628 static void test_table_refs_for_obj_index(void)
629 {
630 test_table_refs_for(1);
631 }
632
633 static void test_write_empty_table(void)
634 {
635 struct reftable_write_options opts = { 0 };
636 struct strbuf buf = STRBUF_INIT;
637 struct reftable_writer *w =
638 reftable_new_writer(&strbuf_add_void, &buf, &opts);
639 struct reftable_block_source source = { NULL };
640 struct reftable_reader *rd = NULL;
641 struct reftable_ref_record rec = { NULL };
642 struct reftable_iterator it = { NULL };
643 int err;
644
645 reftable_writer_set_limits(w, 1, 1);
646
647 err = reftable_writer_close(w);
648 EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
649 reftable_writer_free(w);
650
651 EXPECT(buf.len == header_size(1) + footer_size(1));
652
653 block_source_from_strbuf(&source, &buf);
654
655 err = reftable_new_reader(&rd, &source, "filename");
656 EXPECT_ERR(err);
657
658 err = reftable_reader_seek_ref(rd, &it, "");
659 EXPECT_ERR(err);
660
661 err = reftable_iterator_next_ref(&it, &rec);
662 EXPECT(err > 0);
663
664 reftable_iterator_destroy(&it);
665 reftable_reader_free(rd);
666 strbuf_release(&buf);
667 }
668
669 static void test_write_object_id_min_length(void)
670 {
671 struct reftable_write_options opts = {
672 .block_size = 75,
673 };
674 struct strbuf buf = STRBUF_INIT;
675 struct reftable_writer *w =
676 reftable_new_writer(&strbuf_add_void, &buf, &opts);
677 uint8_t hash[GIT_SHA1_RAWSZ] = {42};
678 struct reftable_ref_record ref = {
679 .update_index = 1,
680 .value_type = REFTABLE_REF_VAL1,
681 .value.val1 = hash,
682 };
683 int err;
684 int i;
685
686 reftable_writer_set_limits(w, 1, 1);
687
688 /* Write the same hash in many refs. If there is only 1 hash, the
689 * disambiguating prefix is length 0 */
690 for (i = 0; i < 256; i++) {
691 char name[256];
692 snprintf(name, sizeof(name), "ref%05d", i);
693 ref.refname = name;
694 err = reftable_writer_add_ref(w, &ref);
695 EXPECT_ERR(err);
696 }
697
698 err = reftable_writer_close(w);
699 EXPECT_ERR(err);
700 EXPECT(reftable_writer_stats(w)->object_id_len == 2);
701 reftable_writer_free(w);
702 strbuf_release(&buf);
703 }
704
705 static void test_write_object_id_length(void)
706 {
707 struct reftable_write_options opts = {
708 .block_size = 75,
709 };
710 struct strbuf buf = STRBUF_INIT;
711 struct reftable_writer *w =
712 reftable_new_writer(&strbuf_add_void, &buf, &opts);
713 uint8_t hash[GIT_SHA1_RAWSZ] = {42};
714 struct reftable_ref_record ref = {
715 .update_index = 1,
716 .value_type = REFTABLE_REF_VAL1,
717 .value.val1 = hash,
718 };
719 int err;
720 int i;
721
722 reftable_writer_set_limits(w, 1, 1);
723
724 /* Write the same hash in many refs. If there is only 1 hash, the
725 * disambiguating prefix is length 0 */
726 for (i = 0; i < 256; i++) {
727 char name[256];
728 snprintf(name, sizeof(name), "ref%05d", i);
729 ref.refname = name;
730 ref.value.val1[15] = i;
731 err = reftable_writer_add_ref(w, &ref);
732 EXPECT_ERR(err);
733 }
734
735 err = reftable_writer_close(w);
736 EXPECT_ERR(err);
737 EXPECT(reftable_writer_stats(w)->object_id_len == 16);
738 reftable_writer_free(w);
739 strbuf_release(&buf);
740 }
741
742 static void test_write_empty_key(void)
743 {
744 struct reftable_write_options opts = { 0 };
745 struct strbuf buf = STRBUF_INIT;
746 struct reftable_writer *w =
747 reftable_new_writer(&strbuf_add_void, &buf, &opts);
748 struct reftable_ref_record ref = {
749 .refname = "",
750 .update_index = 1,
751 .value_type = REFTABLE_REF_DELETION,
752 };
753 int err;
754
755 reftable_writer_set_limits(w, 1, 1);
756 err = reftable_writer_add_ref(w, &ref);
757 EXPECT(err == REFTABLE_API_ERROR);
758
759 err = reftable_writer_close(w);
760 EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
761 reftable_writer_free(w);
762 strbuf_release(&buf);
763 }
764
765 static void test_write_key_order(void)
766 {
767 struct reftable_write_options opts = { 0 };
768 struct strbuf buf = STRBUF_INIT;
769 struct reftable_writer *w =
770 reftable_new_writer(&strbuf_add_void, &buf, &opts);
771 struct reftable_ref_record refs[2] = {
772 {
773 .refname = "b",
774 .update_index = 1,
775 .value_type = REFTABLE_REF_SYMREF,
776 .value = {
777 .symref = "target",
778 },
779 }, {
780 .refname = "a",
781 .update_index = 1,
782 .value_type = REFTABLE_REF_SYMREF,
783 .value = {
784 .symref = "target",
785 },
786 }
787 };
788 int err;
789
790 reftable_writer_set_limits(w, 1, 1);
791 err = reftable_writer_add_ref(w, &refs[0]);
792 EXPECT_ERR(err);
793 err = reftable_writer_add_ref(w, &refs[1]);
794 EXPECT(err == REFTABLE_API_ERROR);
795 reftable_writer_close(w);
796 reftable_writer_free(w);
797 strbuf_release(&buf);
798 }
799
800 static void test_corrupt_table_empty(void)
801 {
802 struct strbuf buf = STRBUF_INIT;
803 struct reftable_block_source source = { NULL };
804 struct reftable_reader rd = { NULL };
805 int err;
806
807 block_source_from_strbuf(&source, &buf);
808 err = init_reader(&rd, &source, "file.log");
809 EXPECT(err == REFTABLE_FORMAT_ERROR);
810 }
811
812 static void test_corrupt_table(void)
813 {
814 uint8_t zeros[1024] = { 0 };
815 struct strbuf buf = STRBUF_INIT;
816 struct reftable_block_source source = { NULL };
817 struct reftable_reader rd = { NULL };
818 int err;
819 strbuf_add(&buf, zeros, sizeof(zeros));
820
821 block_source_from_strbuf(&source, &buf);
822 err = init_reader(&rd, &source, "file.log");
823 EXPECT(err == REFTABLE_FORMAT_ERROR);
824 strbuf_release(&buf);
825 }
826
827 int readwrite_test_main(int argc, const char *argv[])
828 {
829 RUN_TEST(test_log_zlib_corruption);
830 RUN_TEST(test_corrupt_table);
831 RUN_TEST(test_corrupt_table_empty);
832 RUN_TEST(test_log_write_read);
833 RUN_TEST(test_write_key_order);
834 RUN_TEST(test_table_read_write_seek_linear_sha256);
835 RUN_TEST(test_log_buffer_size);
836 RUN_TEST(test_table_write_small_table);
837 RUN_TEST(test_buffer);
838 RUN_TEST(test_table_read_api);
839 RUN_TEST(test_table_read_write_sequential);
840 RUN_TEST(test_table_read_write_seek_linear);
841 RUN_TEST(test_table_read_write_seek_index);
842 RUN_TEST(test_table_refs_for_no_index);
843 RUN_TEST(test_table_refs_for_obj_index);
844 RUN_TEST(test_write_empty_key);
845 RUN_TEST(test_write_empty_table);
846 RUN_TEST(test_log_overflow);
847 RUN_TEST(test_write_object_id_length);
848 RUN_TEST(test_write_object_id_min_length);
849 return 0;
850 }