2 Copyright 2020 Google LLC
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
13 #include "reftable-reader.h"
16 #include "constants.h"
18 #include "test_framework.h"
19 #include "reftable-tests.h"
22 #include <sys/types.h>
25 static void clear_dir(const char *dirname
)
27 struct strbuf path
= STRBUF_INIT
;
28 strbuf_addstr(&path
, dirname
);
29 remove_dir_recursively(&path
, 0);
30 strbuf_release(&path
);
33 static int count_dir_entries(const char *dirname
)
35 DIR *dir
= opendir(dirname
);
41 while ((d
= readdir(dir
))) {
42 if (!strcmp(d
->d_name
, "..") || !strcmp(d
->d_name
, "."))
51 * Work linenumber into the tempdir, so we can see which tests forget to
54 static char *get_tmp_template(int linenumber
)
56 const char *tmp
= getenv("TMPDIR");
57 static char template[1024];
58 snprintf(template, sizeof(template) - 1, "%s/stack_test-%d.XXXXXX",
59 tmp
? tmp
: "/tmp", linenumber
);
63 static char *get_tmp_dir(int linenumber
)
65 char *dir
= get_tmp_template(linenumber
);
70 static void test_read_file(void)
72 char *fn
= get_tmp_template(__LINE__
);
74 char out
[1024] = "line1\n\nline2\nline3";
77 char *want
[] = { "line1", "line2", "line3" };
81 n
= write(fd
, out
, strlen(out
));
82 EXPECT(n
== strlen(out
));
86 err
= read_lines(fn
, &names
);
89 for (i
= 0; names
[i
]; i
++) {
90 EXPECT(0 == strcmp(want
[i
], names
[i
]));
96 static void test_parse_names(void)
98 char buf
[] = "line\n";
100 parse_names(buf
, strlen(buf
), &names
);
102 EXPECT(NULL
!= names
[0]);
103 EXPECT(0 == strcmp(names
[0], "line"));
104 EXPECT(NULL
== names
[1]);
108 static void test_names_equal(void)
110 char *a
[] = { "a", "b", "c", NULL
};
111 char *b
[] = { "a", "b", "d", NULL
};
112 char *c
[] = { "a", "b", NULL
};
114 EXPECT(names_equal(a
, a
));
115 EXPECT(!names_equal(a
, b
));
116 EXPECT(!names_equal(a
, c
));
119 static int write_test_ref(struct reftable_writer
*wr
, void *arg
)
121 struct reftable_ref_record
*ref
= arg
;
122 reftable_writer_set_limits(wr
, ref
->update_index
, ref
->update_index
);
123 return reftable_writer_add_ref(wr
, ref
);
126 struct write_log_arg
{
127 struct reftable_log_record
*log
;
128 uint64_t update_index
;
131 static int write_test_log(struct reftable_writer
*wr
, void *arg
)
133 struct write_log_arg
*wla
= arg
;
135 reftable_writer_set_limits(wr
, wla
->update_index
, wla
->update_index
);
136 return reftable_writer_add_log(wr
, wla
->log
);
139 static void test_reftable_stack_add_one(void)
141 char *dir
= get_tmp_dir(__LINE__
);
142 struct strbuf scratch
= STRBUF_INIT
;
143 int mask
= umask(002);
144 struct reftable_write_options cfg
= {
145 .default_permissions
= 0660,
147 struct reftable_stack
*st
= NULL
;
149 struct reftable_ref_record ref
= {
152 .value_type
= REFTABLE_REF_SYMREF
,
153 .value
.symref
= "master",
155 struct reftable_ref_record dest
= { NULL
};
156 struct stat stat_result
= { 0 };
157 err
= reftable_new_stack(&st
, dir
, cfg
);
160 err
= reftable_stack_add(st
, &write_test_ref
, &ref
);
163 err
= reftable_stack_read_ref(st
, ref
.refname
, &dest
);
165 EXPECT(0 == strcmp("master", dest
.value
.symref
));
166 EXPECT(st
->readers_len
> 0);
168 printf("testing print functionality:\n");
169 err
= reftable_stack_print_directory(dir
, GIT_SHA1_FORMAT_ID
);
172 err
= reftable_stack_print_directory(dir
, GIT_SHA256_FORMAT_ID
);
173 EXPECT(err
== REFTABLE_FORMAT_ERROR
);
175 #ifndef GIT_WINDOWS_NATIVE
176 strbuf_addstr(&scratch
, dir
);
177 strbuf_addstr(&scratch
, "/tables.list");
178 err
= stat(scratch
.buf
, &stat_result
);
180 EXPECT((stat_result
.st_mode
& 0777) == cfg
.default_permissions
);
182 strbuf_reset(&scratch
);
183 strbuf_addstr(&scratch
, dir
);
184 strbuf_addstr(&scratch
, "/");
185 /* do not try at home; not an external API for reftable. */
186 strbuf_addstr(&scratch
, st
->readers
[0]->name
);
187 err
= stat(scratch
.buf
, &stat_result
);
189 EXPECT((stat_result
.st_mode
& 0777) == cfg
.default_permissions
);
194 reftable_ref_record_release(&dest
);
195 reftable_stack_destroy(st
);
196 strbuf_release(&scratch
);
201 static void test_reftable_stack_uptodate(void)
203 struct reftable_write_options cfg
= { 0 };
204 struct reftable_stack
*st1
= NULL
;
205 struct reftable_stack
*st2
= NULL
;
206 char *dir
= get_tmp_dir(__LINE__
);
209 struct reftable_ref_record ref1
= {
212 .value_type
= REFTABLE_REF_SYMREF
,
213 .value
.symref
= "master",
215 struct reftable_ref_record ref2
= {
216 .refname
= "branch2",
218 .value_type
= REFTABLE_REF_SYMREF
,
219 .value
.symref
= "master",
223 /* simulate multi-process access to the same stack
224 by creating two stacks for the same directory.
226 err
= reftable_new_stack(&st1
, dir
, cfg
);
229 err
= reftable_new_stack(&st2
, dir
, cfg
);
232 err
= reftable_stack_add(st1
, &write_test_ref
, &ref1
);
235 err
= reftable_stack_add(st2
, &write_test_ref
, &ref2
);
236 EXPECT(err
== REFTABLE_LOCK_ERROR
);
238 err
= reftable_stack_reload(st2
);
241 err
= reftable_stack_add(st2
, &write_test_ref
, &ref2
);
243 reftable_stack_destroy(st1
);
244 reftable_stack_destroy(st2
);
248 static void test_reftable_stack_transaction_api(void)
250 char *dir
= get_tmp_dir(__LINE__
);
252 struct reftable_write_options cfg
= { 0 };
253 struct reftable_stack
*st
= NULL
;
255 struct reftable_addition
*add
= NULL
;
257 struct reftable_ref_record ref
= {
260 .value_type
= REFTABLE_REF_SYMREF
,
261 .value
.symref
= "master",
263 struct reftable_ref_record dest
= { NULL
};
266 err
= reftable_new_stack(&st
, dir
, cfg
);
269 reftable_addition_destroy(add
);
271 err
= reftable_stack_new_addition(&add
, st
);
274 err
= reftable_addition_add(add
, &write_test_ref
, &ref
);
277 err
= reftable_addition_commit(add
);
280 reftable_addition_destroy(add
);
282 err
= reftable_stack_read_ref(st
, ref
.refname
, &dest
);
284 EXPECT(REFTABLE_REF_SYMREF
== dest
.value_type
);
285 EXPECT(0 == strcmp("master", dest
.value
.symref
));
287 reftable_ref_record_release(&dest
);
288 reftable_stack_destroy(st
);
292 static void test_reftable_stack_validate_refname(void)
294 struct reftable_write_options cfg
= { 0 };
295 struct reftable_stack
*st
= NULL
;
297 char *dir
= get_tmp_dir(__LINE__
);
300 struct reftable_ref_record ref
= {
303 .value_type
= REFTABLE_REF_SYMREF
,
304 .value
.symref
= "master",
306 char *additions
[] = { "a", "a/b/c" };
308 err
= reftable_new_stack(&st
, dir
, cfg
);
311 err
= reftable_stack_add(st
, &write_test_ref
, &ref
);
314 for (i
= 0; i
< ARRAY_SIZE(additions
); i
++) {
315 struct reftable_ref_record ref
= {
316 .refname
= additions
[i
],
318 .value_type
= REFTABLE_REF_SYMREF
,
319 .value
.symref
= "master",
322 err
= reftable_stack_add(st
, &write_test_ref
, &ref
);
323 EXPECT(err
== REFTABLE_NAME_CONFLICT
);
326 reftable_stack_destroy(st
);
330 static int write_error(struct reftable_writer
*wr
, void *arg
)
332 return *((int *)arg
);
335 static void test_reftable_stack_update_index_check(void)
337 char *dir
= get_tmp_dir(__LINE__
);
339 struct reftable_write_options cfg
= { 0 };
340 struct reftable_stack
*st
= NULL
;
342 struct reftable_ref_record ref1
= {
345 .value_type
= REFTABLE_REF_SYMREF
,
346 .value
.symref
= "master",
348 struct reftable_ref_record ref2
= {
351 .value_type
= REFTABLE_REF_SYMREF
,
352 .value
.symref
= "master",
355 err
= reftable_new_stack(&st
, dir
, cfg
);
358 err
= reftable_stack_add(st
, &write_test_ref
, &ref1
);
361 err
= reftable_stack_add(st
, &write_test_ref
, &ref2
);
362 EXPECT(err
== REFTABLE_API_ERROR
);
363 reftable_stack_destroy(st
);
367 static void test_reftable_stack_lock_failure(void)
369 char *dir
= get_tmp_dir(__LINE__
);
371 struct reftable_write_options cfg
= { 0 };
372 struct reftable_stack
*st
= NULL
;
375 err
= reftable_new_stack(&st
, dir
, cfg
);
377 for (i
= -1; i
!= REFTABLE_EMPTY_TABLE_ERROR
; i
--) {
378 err
= reftable_stack_add(st
, &write_error
, &i
);
382 reftable_stack_destroy(st
);
386 static void test_reftable_stack_add(void)
390 struct reftable_write_options cfg
= {
391 .exact_log_message
= 1,
393 struct reftable_stack
*st
= NULL
;
394 char *dir
= get_tmp_dir(__LINE__
);
396 struct reftable_ref_record refs
[2] = { { NULL
} };
397 struct reftable_log_record logs
[2] = { { NULL
} };
398 int N
= ARRAY_SIZE(refs
);
401 err
= reftable_new_stack(&st
, dir
, cfg
);
403 st
->disable_auto_compact
= 1;
405 for (i
= 0; i
< N
; i
++) {
407 snprintf(buf
, sizeof(buf
), "branch%02d", i
);
408 refs
[i
].refname
= xstrdup(buf
);
409 refs
[i
].update_index
= i
+ 1;
410 refs
[i
].value_type
= REFTABLE_REF_VAL1
;
411 refs
[i
].value
.val1
= reftable_malloc(GIT_SHA1_RAWSZ
);
412 set_test_hash(refs
[i
].value
.val1
, i
);
414 logs
[i
].refname
= xstrdup(buf
);
415 logs
[i
].update_index
= N
+ i
+ 1;
416 logs
[i
].value_type
= REFTABLE_LOG_UPDATE
;
418 logs
[i
].value
.update
.new_hash
= reftable_malloc(GIT_SHA1_RAWSZ
);
419 logs
[i
].value
.update
.email
= xstrdup("identity@invalid");
420 set_test_hash(logs
[i
].value
.update
.new_hash
, i
);
423 for (i
= 0; i
< N
; i
++) {
424 int err
= reftable_stack_add(st
, &write_test_ref
, &refs
[i
]);
428 for (i
= 0; i
< N
; i
++) {
429 struct write_log_arg arg
= {
431 .update_index
= reftable_stack_next_update_index(st
),
433 int err
= reftable_stack_add(st
, &write_test_log
, &arg
);
437 err
= reftable_stack_compact_all(st
, NULL
);
440 for (i
= 0; i
< N
; i
++) {
441 struct reftable_ref_record dest
= { NULL
};
443 int err
= reftable_stack_read_ref(st
, refs
[i
].refname
, &dest
);
445 EXPECT(reftable_ref_record_equal(&dest
, refs
+ i
,
447 reftable_ref_record_release(&dest
);
450 for (i
= 0; i
< N
; i
++) {
451 struct reftable_log_record dest
= { NULL
};
452 int err
= reftable_stack_read_log(st
, refs
[i
].refname
, &dest
);
454 EXPECT(reftable_log_record_equal(&dest
, logs
+ i
,
456 reftable_log_record_release(&dest
);
460 reftable_stack_destroy(st
);
461 for (i
= 0; i
< N
; i
++) {
462 reftable_ref_record_release(&refs
[i
]);
463 reftable_log_record_release(&logs
[i
]);
468 static void test_reftable_stack_log_normalize(void)
471 struct reftable_write_options cfg
= {
474 struct reftable_stack
*st
= NULL
;
475 char *dir
= get_tmp_dir(__LINE__
);
477 uint8_t h1
[GIT_SHA1_RAWSZ
] = { 0x01 }, h2
[GIT_SHA1_RAWSZ
] = { 0x02 };
479 struct reftable_log_record input
= { .refname
= "branch",
481 .value_type
= REFTABLE_LOG_UPDATE
,
482 .value
= { .update
= {
486 struct reftable_log_record dest
= {
489 struct write_log_arg arg
= {
494 err
= reftable_new_stack(&st
, dir
, cfg
);
497 input
.value
.update
.message
= "one\ntwo";
498 err
= reftable_stack_add(st
, &write_test_log
, &arg
);
499 EXPECT(err
== REFTABLE_API_ERROR
);
501 input
.value
.update
.message
= "one";
502 err
= reftable_stack_add(st
, &write_test_log
, &arg
);
505 err
= reftable_stack_read_log(st
, input
.refname
, &dest
);
507 EXPECT(0 == strcmp(dest
.value
.update
.message
, "one\n"));
509 input
.value
.update
.message
= "two\n";
510 arg
.update_index
= 2;
511 err
= reftable_stack_add(st
, &write_test_log
, &arg
);
513 err
= reftable_stack_read_log(st
, input
.refname
, &dest
);
515 EXPECT(0 == strcmp(dest
.value
.update
.message
, "two\n"));
518 reftable_stack_destroy(st
);
519 reftable_log_record_release(&dest
);
523 static void test_reftable_stack_tombstone(void)
526 char *dir
= get_tmp_dir(__LINE__
);
528 struct reftable_write_options cfg
= { 0 };
529 struct reftable_stack
*st
= NULL
;
531 struct reftable_ref_record refs
[2] = { { NULL
} };
532 struct reftable_log_record logs
[2] = { { NULL
} };
533 int N
= ARRAY_SIZE(refs
);
534 struct reftable_ref_record dest
= { NULL
};
535 struct reftable_log_record log_dest
= { NULL
};
538 err
= reftable_new_stack(&st
, dir
, cfg
);
541 /* even entries add the refs, odd entries delete them. */
542 for (i
= 0; i
< N
; i
++) {
543 const char *buf
= "branch";
544 refs
[i
].refname
= xstrdup(buf
);
545 refs
[i
].update_index
= i
+ 1;
547 refs
[i
].value_type
= REFTABLE_REF_VAL1
;
548 refs
[i
].value
.val1
= reftable_malloc(GIT_SHA1_RAWSZ
);
549 set_test_hash(refs
[i
].value
.val1
, i
);
552 logs
[i
].refname
= xstrdup(buf
);
553 /* update_index is part of the key. */
554 logs
[i
].update_index
= 42;
556 logs
[i
].value_type
= REFTABLE_LOG_UPDATE
;
557 logs
[i
].value
.update
.new_hash
=
558 reftable_malloc(GIT_SHA1_RAWSZ
);
559 set_test_hash(logs
[i
].value
.update
.new_hash
, i
);
560 logs
[i
].value
.update
.email
=
561 xstrdup("identity@invalid");
564 for (i
= 0; i
< N
; i
++) {
565 int err
= reftable_stack_add(st
, &write_test_ref
, &refs
[i
]);
569 for (i
= 0; i
< N
; i
++) {
570 struct write_log_arg arg
= {
572 .update_index
= reftable_stack_next_update_index(st
),
574 int err
= reftable_stack_add(st
, &write_test_log
, &arg
);
578 err
= reftable_stack_read_ref(st
, "branch", &dest
);
580 reftable_ref_record_release(&dest
);
582 err
= reftable_stack_read_log(st
, "branch", &log_dest
);
584 reftable_log_record_release(&log_dest
);
586 err
= reftable_stack_compact_all(st
, NULL
);
589 err
= reftable_stack_read_ref(st
, "branch", &dest
);
592 err
= reftable_stack_read_log(st
, "branch", &log_dest
);
594 reftable_ref_record_release(&dest
);
595 reftable_log_record_release(&log_dest
);
598 reftable_stack_destroy(st
);
599 for (i
= 0; i
< N
; i
++) {
600 reftable_ref_record_release(&refs
[i
]);
601 reftable_log_record_release(&logs
[i
]);
606 static void test_reftable_stack_hash_id(void)
608 char *dir
= get_tmp_dir(__LINE__
);
610 struct reftable_write_options cfg
= { 0 };
611 struct reftable_stack
*st
= NULL
;
614 struct reftable_ref_record ref
= {
616 .value_type
= REFTABLE_REF_SYMREF
,
617 .value
.symref
= "target",
620 struct reftable_write_options cfg32
= { .hash_id
= GIT_SHA256_FORMAT_ID
};
621 struct reftable_stack
*st32
= NULL
;
622 struct reftable_write_options cfg_default
= { 0 };
623 struct reftable_stack
*st_default
= NULL
;
624 struct reftable_ref_record dest
= { NULL
};
626 err
= reftable_new_stack(&st
, dir
, cfg
);
629 err
= reftable_stack_add(st
, &write_test_ref
, &ref
);
632 /* can't read it with the wrong hash ID. */
633 err
= reftable_new_stack(&st32
, dir
, cfg32
);
634 EXPECT(err
== REFTABLE_FORMAT_ERROR
);
636 /* check that we can read it back with default config too. */
637 err
= reftable_new_stack(&st_default
, dir
, cfg_default
);
640 err
= reftable_stack_read_ref(st_default
, "master", &dest
);
643 EXPECT(reftable_ref_record_equal(&ref
, &dest
, GIT_SHA1_RAWSZ
));
644 reftable_ref_record_release(&dest
);
645 reftable_stack_destroy(st
);
646 reftable_stack_destroy(st_default
);
650 static void test_log2(void)
652 EXPECT(1 == fastlog2(3));
653 EXPECT(2 == fastlog2(4));
654 EXPECT(2 == fastlog2(5));
657 static void test_sizes_to_segments(void)
659 uint64_t sizes
[] = { 2, 3, 4, 5, 7, 9 };
660 /* .................0 1 2 3 4 5 */
663 struct segment
*segs
=
664 sizes_to_segments(&seglen
, sizes
, ARRAY_SIZE(sizes
));
665 EXPECT(segs
[2].log
== 3);
666 EXPECT(segs
[2].start
== 5);
667 EXPECT(segs
[2].end
== 6);
669 EXPECT(segs
[1].log
== 2);
670 EXPECT(segs
[1].start
== 2);
671 EXPECT(segs
[1].end
== 5);
675 static void test_sizes_to_segments_empty(void)
678 struct segment
*segs
= sizes_to_segments(&seglen
, NULL
, 0);
683 static void test_sizes_to_segments_all_equal(void)
685 uint64_t sizes
[] = { 5, 5 };
688 struct segment
*segs
=
689 sizes_to_segments(&seglen
, sizes
, ARRAY_SIZE(sizes
));
691 EXPECT(segs
[0].start
== 0);
692 EXPECT(segs
[0].end
== 2);
696 static void test_suggest_compaction_segment(void)
698 uint64_t sizes
[] = { 128, 64, 17, 16, 9, 9, 9, 16, 16 };
699 /* .................0 1 2 3 4 5 6 */
701 suggest_compaction_segment(sizes
, ARRAY_SIZE(sizes
));
702 EXPECT(min
.start
== 2);
703 EXPECT(min
.end
== 7);
706 static void test_suggest_compaction_segment_nothing(void)
708 uint64_t sizes
[] = { 64, 32, 16, 8, 4, 2 };
709 struct segment result
=
710 suggest_compaction_segment(sizes
, ARRAY_SIZE(sizes
));
711 EXPECT(result
.start
== result
.end
);
714 static void test_reflog_expire(void)
716 char *dir
= get_tmp_dir(__LINE__
);
718 struct reftable_write_options cfg
= { 0 };
719 struct reftable_stack
*st
= NULL
;
720 struct reftable_log_record logs
[20] = { { NULL
} };
721 int N
= ARRAY_SIZE(logs
) - 1;
724 struct reftable_log_expiry_config expiry
= {
727 struct reftable_log_record log
= { NULL
};
730 err
= reftable_new_stack(&st
, dir
, cfg
);
733 for (i
= 1; i
<= N
; i
++) {
735 snprintf(buf
, sizeof(buf
), "branch%02d", i
);
737 logs
[i
].refname
= xstrdup(buf
);
738 logs
[i
].update_index
= i
;
739 logs
[i
].value_type
= REFTABLE_LOG_UPDATE
;
740 logs
[i
].value
.update
.time
= i
;
741 logs
[i
].value
.update
.new_hash
= reftable_malloc(GIT_SHA1_RAWSZ
);
742 logs
[i
].value
.update
.email
= xstrdup("identity@invalid");
743 set_test_hash(logs
[i
].value
.update
.new_hash
, i
);
746 for (i
= 1; i
<= N
; i
++) {
747 struct write_log_arg arg
= {
749 .update_index
= reftable_stack_next_update_index(st
),
751 int err
= reftable_stack_add(st
, &write_test_log
, &arg
);
755 err
= reftable_stack_compact_all(st
, NULL
);
758 err
= reftable_stack_compact_all(st
, &expiry
);
761 err
= reftable_stack_read_log(st
, logs
[9].refname
, &log
);
764 err
= reftable_stack_read_log(st
, logs
[11].refname
, &log
);
767 expiry
.min_update_index
= 15;
768 err
= reftable_stack_compact_all(st
, &expiry
);
771 err
= reftable_stack_read_log(st
, logs
[14].refname
, &log
);
774 err
= reftable_stack_read_log(st
, logs
[16].refname
, &log
);
778 reftable_stack_destroy(st
);
779 for (i
= 0; i
<= N
; i
++) {
780 reftable_log_record_release(&logs
[i
]);
783 reftable_log_record_release(&log
);
786 static int write_nothing(struct reftable_writer
*wr
, void *arg
)
788 reftable_writer_set_limits(wr
, 1, 1);
792 static void test_empty_add(void)
794 struct reftable_write_options cfg
= { 0 };
795 struct reftable_stack
*st
= NULL
;
797 char *dir
= get_tmp_dir(__LINE__
);
799 struct reftable_stack
*st2
= NULL
;
802 err
= reftable_new_stack(&st
, dir
, cfg
);
805 err
= reftable_stack_add(st
, &write_nothing
, NULL
);
808 err
= reftable_new_stack(&st2
, dir
, cfg
);
811 reftable_stack_destroy(st
);
812 reftable_stack_destroy(st2
);
815 static void test_reftable_stack_auto_compaction(void)
817 struct reftable_write_options cfg
= { 0 };
818 struct reftable_stack
*st
= NULL
;
819 char *dir
= get_tmp_dir(__LINE__
);
824 err
= reftable_new_stack(&st
, dir
, cfg
);
827 st
->disable_auto_compact
= 1; /* call manually below for coverage. */
828 for (i
= 0; i
< N
; i
++) {
830 struct reftable_ref_record ref
= {
832 .update_index
= reftable_stack_next_update_index(st
),
833 .value_type
= REFTABLE_REF_SYMREF
,
834 .value
.symref
= "master",
836 snprintf(name
, sizeof(name
), "branch%04d", i
);
838 err
= reftable_stack_add(st
, &write_test_ref
, &ref
);
841 err
= reftable_stack_auto_compact(st
);
843 EXPECT(i
< 3 || st
->merged
->stack_len
< 2 * fastlog2(i
));
846 EXPECT(reftable_stack_compaction_stats(st
)->entries_written
<
847 (uint64_t)(N
* fastlog2(N
)));
849 reftable_stack_destroy(st
);
853 static void test_reftable_stack_compaction_concurrent(void)
855 struct reftable_write_options cfg
= { 0 };
856 struct reftable_stack
*st1
= NULL
, *st2
= NULL
;
857 char *dir
= get_tmp_dir(__LINE__
);
862 err
= reftable_new_stack(&st1
, dir
, cfg
);
865 for (i
= 0; i
< N
; i
++) {
867 struct reftable_ref_record ref
= {
869 .update_index
= reftable_stack_next_update_index(st1
),
870 .value_type
= REFTABLE_REF_SYMREF
,
871 .value
.symref
= "master",
873 snprintf(name
, sizeof(name
), "branch%04d", i
);
875 err
= reftable_stack_add(st1
, &write_test_ref
, &ref
);
879 err
= reftable_new_stack(&st2
, dir
, cfg
);
882 err
= reftable_stack_compact_all(st1
, NULL
);
885 reftable_stack_destroy(st1
);
886 reftable_stack_destroy(st2
);
888 EXPECT(count_dir_entries(dir
) == 2);
892 static void unclean_stack_close(struct reftable_stack
*st
)
894 /* break abstraction boundary to simulate unclean shutdown. */
896 for (; i
< st
->readers_len
; i
++) {
897 reftable_reader_free(st
->readers
[i
]);
900 FREE_AND_NULL(st
->readers
);
903 static void test_reftable_stack_compaction_concurrent_clean(void)
905 struct reftable_write_options cfg
= { 0 };
906 struct reftable_stack
*st1
= NULL
, *st2
= NULL
, *st3
= NULL
;
907 char *dir
= get_tmp_dir(__LINE__
);
912 err
= reftable_new_stack(&st1
, dir
, cfg
);
915 for (i
= 0; i
< N
; i
++) {
917 struct reftable_ref_record ref
= {
919 .update_index
= reftable_stack_next_update_index(st1
),
920 .value_type
= REFTABLE_REF_SYMREF
,
921 .value
.symref
= "master",
923 snprintf(name
, sizeof(name
), "branch%04d", i
);
925 err
= reftable_stack_add(st1
, &write_test_ref
, &ref
);
929 err
= reftable_new_stack(&st2
, dir
, cfg
);
932 err
= reftable_stack_compact_all(st1
, NULL
);
935 unclean_stack_close(st1
);
936 unclean_stack_close(st2
);
938 err
= reftable_new_stack(&st3
, dir
, cfg
);
941 err
= reftable_stack_clean(st3
);
943 EXPECT(count_dir_entries(dir
) == 2);
945 reftable_stack_destroy(st1
);
946 reftable_stack_destroy(st2
);
947 reftable_stack_destroy(st3
);
952 int stack_test_main(int argc
, const char *argv
[])
954 RUN_TEST(test_empty_add
);
956 RUN_TEST(test_names_equal
);
957 RUN_TEST(test_parse_names
);
958 RUN_TEST(test_read_file
);
959 RUN_TEST(test_reflog_expire
);
960 RUN_TEST(test_reftable_stack_add
);
961 RUN_TEST(test_reftable_stack_add_one
);
962 RUN_TEST(test_reftable_stack_auto_compaction
);
963 RUN_TEST(test_reftable_stack_compaction_concurrent
);
964 RUN_TEST(test_reftable_stack_compaction_concurrent_clean
);
965 RUN_TEST(test_reftable_stack_hash_id
);
966 RUN_TEST(test_reftable_stack_lock_failure
);
967 RUN_TEST(test_reftable_stack_log_normalize
);
968 RUN_TEST(test_reftable_stack_tombstone
);
969 RUN_TEST(test_reftable_stack_transaction_api
);
970 RUN_TEST(test_reftable_stack_update_index_check
);
971 RUN_TEST(test_reftable_stack_uptodate
);
972 RUN_TEST(test_reftable_stack_validate_refname
);
973 RUN_TEST(test_sizes_to_segments
);
974 RUN_TEST(test_sizes_to_segments_all_equal
);
975 RUN_TEST(test_sizes_to_segments_empty
);
976 RUN_TEST(test_suggest_compaction_segment
);
977 RUN_TEST(test_suggest_compaction_segment_nothing
);