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
14 #include "blocksource.h"
17 #include "test_framework.h"
18 #include "reftable-merged.h"
19 #include "reftable-tests.h"
20 #include "reftable-generic.h"
21 #include "reftable-writer.h"
23 static void write_test_table(struct strbuf
*buf
,
24 struct reftable_ref_record refs
[], int n
)
26 uint64_t min
= 0xffffffff;
31 struct reftable_write_options opts
= {
34 struct reftable_writer
*w
= NULL
;
35 for (i
= 0; i
< n
; i
++) {
36 uint64_t ui
= refs
[i
].update_index
;
45 w
= reftable_new_writer(&strbuf_add_void
, &noop_flush
, buf
, &opts
);
46 reftable_writer_set_limits(w
, min
, max
);
48 for (i
= 0; i
< n
; i
++) {
49 uint64_t before
= refs
[i
].update_index
;
50 int n
= reftable_writer_add_ref(w
, &refs
[i
]);
52 EXPECT(before
== refs
[i
].update_index
);
55 err
= reftable_writer_close(w
);
58 reftable_writer_free(w
);
61 static void write_test_log_table(struct strbuf
*buf
,
62 struct reftable_log_record logs
[], int n
,
63 uint64_t update_index
)
68 struct reftable_write_options opts
= {
70 .exact_log_message
= 1,
72 struct reftable_writer
*w
= NULL
;
73 w
= reftable_new_writer(&strbuf_add_void
, &noop_flush
, buf
, &opts
);
74 reftable_writer_set_limits(w
, update_index
, update_index
);
76 for (i
= 0; i
< n
; i
++) {
77 int err
= reftable_writer_add_log(w
, &logs
[i
]);
81 err
= reftable_writer_close(w
);
84 reftable_writer_free(w
);
87 static struct reftable_merged_table
*
88 merged_table_from_records(struct reftable_ref_record
**refs
,
89 struct reftable_block_source
**source
,
90 struct reftable_reader
***readers
, int *sizes
,
91 struct strbuf
*buf
, size_t n
)
93 struct reftable_merged_table
*mt
= NULL
;
94 struct reftable_table
*tabs
;
97 REFTABLE_CALLOC_ARRAY(tabs
, n
);
98 REFTABLE_CALLOC_ARRAY(*readers
, n
);
99 REFTABLE_CALLOC_ARRAY(*source
, n
);
101 for (size_t i
= 0; i
< n
; i
++) {
102 write_test_table(&buf
[i
], refs
[i
], sizes
[i
]);
103 block_source_from_strbuf(&(*source
)[i
], &buf
[i
]);
105 err
= reftable_new_reader(&(*readers
)[i
], &(*source
)[i
],
108 reftable_table_from_reader(&tabs
[i
], (*readers
)[i
]);
111 err
= reftable_new_merged_table(&mt
, tabs
, n
, GIT_SHA1_FORMAT_ID
);
116 static void readers_destroy(struct reftable_reader
**readers
, size_t n
)
120 reftable_reader_free(readers
[i
]);
121 reftable_free(readers
);
124 static void test_merged_between(void)
126 struct reftable_ref_record r1
[] = { {
129 .value_type
= REFTABLE_REF_VAL1
,
130 .value
.val1
= { 1, 2, 3, 0 },
132 struct reftable_ref_record r2
[] = { {
135 .value_type
= REFTABLE_REF_DELETION
,
138 struct reftable_ref_record
*refs
[] = { r1
, r2
};
139 int sizes
[] = { 1, 1 };
140 struct strbuf bufs
[2] = { STRBUF_INIT
, STRBUF_INIT
};
141 struct reftable_block_source
*bs
= NULL
;
142 struct reftable_reader
**readers
= NULL
;
143 struct reftable_merged_table
*mt
=
144 merged_table_from_records(refs
, &bs
, &readers
, sizes
, bufs
, 2);
146 struct reftable_ref_record ref
= { NULL
};
147 struct reftable_iterator it
= { NULL
};
148 int err
= reftable_merged_table_seek_ref(mt
, &it
, "a");
151 err
= reftable_iterator_next_ref(&it
, &ref
);
153 EXPECT(ref
.update_index
== 2);
154 reftable_ref_record_release(&ref
);
155 reftable_iterator_destroy(&it
);
156 readers_destroy(readers
, 2);
157 reftable_merged_table_free(mt
);
158 for (i
= 0; i
< ARRAY_SIZE(bufs
); i
++) {
159 strbuf_release(&bufs
[i
]);
164 static void test_merged(void)
166 struct reftable_ref_record r1
[] = {
170 .value_type
= REFTABLE_REF_VAL1
,
176 .value_type
= REFTABLE_REF_VAL1
,
182 .value_type
= REFTABLE_REF_VAL1
,
186 struct reftable_ref_record r2
[] = { {
189 .value_type
= REFTABLE_REF_DELETION
,
191 struct reftable_ref_record r3
[] = {
195 .value_type
= REFTABLE_REF_VAL1
,
201 .value_type
= REFTABLE_REF_VAL1
,
206 struct reftable_ref_record
*want
[] = {
213 struct reftable_ref_record
*refs
[] = { r1
, r2
, r3
};
214 int sizes
[3] = { 3, 1, 2 };
215 struct strbuf bufs
[3] = { STRBUF_INIT
, STRBUF_INIT
, STRBUF_INIT
};
216 struct reftable_block_source
*bs
= NULL
;
217 struct reftable_reader
**readers
= NULL
;
218 struct reftable_merged_table
*mt
=
219 merged_table_from_records(refs
, &bs
, &readers
, sizes
, bufs
, 3);
221 struct reftable_iterator it
= { NULL
};
222 int err
= reftable_merged_table_seek_ref(mt
, &it
, "a");
223 struct reftable_ref_record
*out
= NULL
;
229 EXPECT(reftable_merged_table_hash_id(mt
) == GIT_SHA1_FORMAT_ID
);
230 EXPECT(reftable_merged_table_min_update_index(mt
) == 1);
232 while (len
< 100) { /* cap loops/recursion. */
233 struct reftable_ref_record ref
= { NULL
};
234 int err
= reftable_iterator_next_ref(&it
, &ref
);
238 REFTABLE_ALLOC_GROW(out
, len
+ 1, cap
);
241 reftable_iterator_destroy(&it
);
243 EXPECT(ARRAY_SIZE(want
) == len
);
244 for (i
= 0; i
< len
; i
++) {
245 EXPECT(reftable_ref_record_equal(want
[i
], &out
[i
],
248 for (i
= 0; i
< len
; i
++) {
249 reftable_ref_record_release(&out
[i
]);
253 for (i
= 0; i
< 3; i
++) {
254 strbuf_release(&bufs
[i
]);
256 readers_destroy(readers
, 3);
257 reftable_merged_table_free(mt
);
261 static struct reftable_merged_table
*
262 merged_table_from_log_records(struct reftable_log_record
**logs
,
263 struct reftable_block_source
**source
,
264 struct reftable_reader
***readers
, int *sizes
,
265 struct strbuf
*buf
, size_t n
)
267 struct reftable_merged_table
*mt
= NULL
;
268 struct reftable_table
*tabs
;
271 REFTABLE_CALLOC_ARRAY(tabs
, n
);
272 REFTABLE_CALLOC_ARRAY(*readers
, n
);
273 REFTABLE_CALLOC_ARRAY(*source
, n
);
275 for (size_t i
= 0; i
< n
; i
++) {
276 write_test_log_table(&buf
[i
], logs
[i
], sizes
[i
], i
+ 1);
277 block_source_from_strbuf(&(*source
)[i
], &buf
[i
]);
279 err
= reftable_new_reader(&(*readers
)[i
], &(*source
)[i
],
282 reftable_table_from_reader(&tabs
[i
], (*readers
)[i
]);
285 err
= reftable_new_merged_table(&mt
, tabs
, n
, GIT_SHA1_FORMAT_ID
);
290 static void test_merged_logs(void)
292 struct reftable_log_record r1
[] = {
296 .value_type
= REFTABLE_LOG_UPDATE
,
301 .email
= "jane@invalid",
302 .message
= "message2",
308 .value_type
= REFTABLE_LOG_UPDATE
,
313 .email
= "jane@invalid",
314 .message
= "message1",
318 struct reftable_log_record r2
[] = {
322 .value_type
= REFTABLE_LOG_UPDATE
,
326 .email
= "jane@invalid",
327 .message
= "message3",
331 struct reftable_log_record r3
[] = {
335 .value_type
= REFTABLE_LOG_DELETION
,
338 struct reftable_log_record
*want
[] = {
344 struct reftable_log_record
*logs
[] = { r1
, r2
, r3
};
345 int sizes
[3] = { 2, 1, 1 };
346 struct strbuf bufs
[3] = { STRBUF_INIT
, STRBUF_INIT
, STRBUF_INIT
};
347 struct reftable_block_source
*bs
= NULL
;
348 struct reftable_reader
**readers
= NULL
;
349 struct reftable_merged_table
*mt
= merged_table_from_log_records(
350 logs
, &bs
, &readers
, sizes
, bufs
, 3);
352 struct reftable_iterator it
= { NULL
};
353 int err
= reftable_merged_table_seek_log(mt
, &it
, "a");
354 struct reftable_log_record
*out
= NULL
;
360 EXPECT(reftable_merged_table_hash_id(mt
) == GIT_SHA1_FORMAT_ID
);
361 EXPECT(reftable_merged_table_min_update_index(mt
) == 1);
363 while (len
< 100) { /* cap loops/recursion. */
364 struct reftable_log_record log
= { NULL
};
365 int err
= reftable_iterator_next_log(&it
, &log
);
369 REFTABLE_ALLOC_GROW(out
, len
+ 1, cap
);
372 reftable_iterator_destroy(&it
);
374 EXPECT(ARRAY_SIZE(want
) == len
);
375 for (i
= 0; i
< len
; i
++) {
376 EXPECT(reftable_log_record_equal(want
[i
], &out
[i
],
380 err
= reftable_merged_table_seek_log_at(mt
, &it
, "a", 2);
382 reftable_log_record_release(&out
[0]);
383 err
= reftable_iterator_next_log(&it
, &out
[0]);
385 EXPECT(reftable_log_record_equal(&out
[0], &r3
[0], GIT_SHA1_RAWSZ
));
386 reftable_iterator_destroy(&it
);
388 for (i
= 0; i
< len
; i
++) {
389 reftable_log_record_release(&out
[i
]);
393 for (i
= 0; i
< 3; i
++) {
394 strbuf_release(&bufs
[i
]);
396 readers_destroy(readers
, 3);
397 reftable_merged_table_free(mt
);
401 static void test_default_write_opts(void)
403 struct reftable_write_options opts
= { 0 };
404 struct strbuf buf
= STRBUF_INIT
;
405 struct reftable_writer
*w
=
406 reftable_new_writer(&strbuf_add_void
, &noop_flush
, &buf
, &opts
);
408 struct reftable_ref_record rec
= {
413 struct reftable_block_source source
= { NULL
};
414 struct reftable_table
*tab
= reftable_calloc(1, sizeof(*tab
));
416 struct reftable_reader
*rd
= NULL
;
417 struct reftable_merged_table
*merged
= NULL
;
419 reftable_writer_set_limits(w
, 1, 1);
421 err
= reftable_writer_add_ref(w
, &rec
);
424 err
= reftable_writer_close(w
);
426 reftable_writer_free(w
);
428 block_source_from_strbuf(&source
, &buf
);
430 err
= reftable_new_reader(&rd
, &source
, "filename");
433 hash_id
= reftable_reader_hash_id(rd
);
434 EXPECT(hash_id
== GIT_SHA1_FORMAT_ID
);
436 reftable_table_from_reader(&tab
[0], rd
);
437 err
= reftable_new_merged_table(&merged
, tab
, 1, GIT_SHA1_FORMAT_ID
);
440 reftable_reader_free(rd
);
441 reftable_merged_table_free(merged
);
442 strbuf_release(&buf
);
445 /* XXX test refs_for(oid) */
447 int merged_test_main(int argc
, const char *argv
[])
449 RUN_TEST(test_merged_logs
);
450 RUN_TEST(test_merged_between
);
451 RUN_TEST(test_merged
);
452 RUN_TEST(test_default_write_opts
);