]> git.ipfire.org Git - thirdparty/git.git/blame - reftable/merged_test.c
dir.h: move DTYPE defines from cache.h
[thirdparty/git.git] / reftable / merged_test.c
CommitLineData
1ae2b8cd
HWN
1/*
2Copyright 2020 Google LLC
3
4Use of this source code is governed by a BSD-style
5license that can be found in the LICENSE file or at
6https://developers.google.com/open-source/licenses/bsd
7*/
8
9#include "merged.h"
10
11#include "system.h"
12
13#include "basics.h"
14#include "blocksource.h"
15#include "constants.h"
16#include "reader.h"
17#include "record.h"
18#include "test_framework.h"
19#include "reftable-merged.h"
20#include "reftable-tests.h"
21#include "reftable-generic.h"
22#include "reftable-writer.h"
23
24static void write_test_table(struct strbuf *buf,
25 struct reftable_ref_record refs[], int n)
26{
22d2f70e
ÆAB
27 uint64_t min = 0xffffffff;
28 uint64_t max = 0;
1ae2b8cd
HWN
29 int i = 0;
30 int err;
31
32 struct reftable_write_options opts = {
33 .block_size = 256,
34 };
35 struct reftable_writer *w = NULL;
36 for (i = 0; i < n; i++) {
37 uint64_t ui = refs[i].update_index;
38 if (ui > max) {
39 max = ui;
40 }
41 if (ui < min) {
42 min = ui;
43 }
44 }
45
46 w = reftable_new_writer(&strbuf_add_void, buf, &opts);
47 reftable_writer_set_limits(w, min, max);
48
49 for (i = 0; i < n; i++) {
50 uint64_t before = refs[i].update_index;
51 int n = reftable_writer_add_ref(w, &refs[i]);
52 EXPECT(n == 0);
53 EXPECT(before == refs[i].update_index);
54 }
55
56 err = reftable_writer_close(w);
57 EXPECT_ERR(err);
58
59 reftable_writer_free(w);
60}
61
62static void write_test_log_table(struct strbuf *buf,
63 struct reftable_log_record logs[], int n,
64 uint64_t update_index)
65{
66 int i = 0;
67 int err;
68
69 struct reftable_write_options opts = {
70 .block_size = 256,
71 .exact_log_message = 1,
72 };
73 struct reftable_writer *w = NULL;
74 w = reftable_new_writer(&strbuf_add_void, buf, &opts);
75 reftable_writer_set_limits(w, update_index, update_index);
76
77 for (i = 0; i < n; i++) {
78 int err = reftable_writer_add_log(w, &logs[i]);
79 EXPECT_ERR(err);
80 }
81
82 err = reftable_writer_close(w);
83 EXPECT_ERR(err);
84
85 reftable_writer_free(w);
86}
87
88static struct reftable_merged_table *
89merged_table_from_records(struct reftable_ref_record **refs,
90 struct reftable_block_source **source,
91 struct reftable_reader ***readers, int *sizes,
92 struct strbuf *buf, int n)
93{
94 int i = 0;
95 struct reftable_merged_table *mt = NULL;
96 int err;
97 struct reftable_table *tabs =
98 reftable_calloc(n * sizeof(struct reftable_table));
99 *readers = reftable_calloc(n * sizeof(struct reftable_reader *));
100 *source = reftable_calloc(n * sizeof(**source));
101 for (i = 0; i < n; i++) {
102 write_test_table(&buf[i], refs[i], sizes[i]);
103 block_source_from_strbuf(&(*source)[i], &buf[i]);
104
105 err = reftable_new_reader(&(*readers)[i], &(*source)[i],
106 "name");
107 EXPECT_ERR(err);
108 reftable_table_from_reader(&tabs[i], (*readers)[i]);
109 }
110
111 err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
112 EXPECT_ERR(err);
113 return mt;
114}
115
116static void readers_destroy(struct reftable_reader **readers, size_t n)
117{
118 int i = 0;
119 for (; i < n; i++)
120 reftable_reader_free(readers[i]);
121 reftable_free(readers);
122}
123
124static void test_merged_between(void)
125{
126 uint8_t hash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 0 };
127
128 struct reftable_ref_record r1[] = { {
129 .refname = "b",
130 .update_index = 1,
131 .value_type = REFTABLE_REF_VAL1,
132 .value.val1 = hash1,
133 } };
134 struct reftable_ref_record r2[] = { {
135 .refname = "a",
136 .update_index = 2,
137 .value_type = REFTABLE_REF_DELETION,
138 } };
139
140 struct reftable_ref_record *refs[] = { r1, r2 };
141 int sizes[] = { 1, 1 };
142 struct strbuf bufs[2] = { STRBUF_INIT, STRBUF_INIT };
143 struct reftable_block_source *bs = NULL;
144 struct reftable_reader **readers = NULL;
145 struct reftable_merged_table *mt =
146 merged_table_from_records(refs, &bs, &readers, sizes, bufs, 2);
147 int i;
148 struct reftable_ref_record ref = { NULL };
149 struct reftable_iterator it = { NULL };
150 int err = reftable_merged_table_seek_ref(mt, &it, "a");
151 EXPECT_ERR(err);
152
153 err = reftable_iterator_next_ref(&it, &ref);
154 EXPECT_ERR(err);
155 EXPECT(ref.update_index == 2);
156 reftable_ref_record_release(&ref);
157 reftable_iterator_destroy(&it);
158 readers_destroy(readers, 2);
159 reftable_merged_table_free(mt);
160 for (i = 0; i < ARRAY_SIZE(bufs); i++) {
161 strbuf_release(&bufs[i]);
162 }
163 reftable_free(bs);
164}
165
166static void test_merged(void)
167{
168 uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
169 uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
170 struct reftable_ref_record r1[] = {
171 {
172 .refname = "a",
173 .update_index = 1,
174 .value_type = REFTABLE_REF_VAL1,
175 .value.val1 = hash1,
176 },
177 {
178 .refname = "b",
179 .update_index = 1,
180 .value_type = REFTABLE_REF_VAL1,
181 .value.val1 = hash1,
182 },
183 {
184 .refname = "c",
185 .update_index = 1,
186 .value_type = REFTABLE_REF_VAL1,
187 .value.val1 = hash1,
188 }
189 };
190 struct reftable_ref_record r2[] = { {
191 .refname = "a",
192 .update_index = 2,
193 .value_type = REFTABLE_REF_DELETION,
194 } };
195 struct reftable_ref_record r3[] = {
196 {
197 .refname = "c",
198 .update_index = 3,
199 .value_type = REFTABLE_REF_VAL1,
200 .value.val1 = hash2,
201 },
202 {
203 .refname = "d",
204 .update_index = 3,
205 .value_type = REFTABLE_REF_VAL1,
206 .value.val1 = hash1,
207 },
208 };
209
f2b25514
HWN
210 struct reftable_ref_record *want[] = {
211 &r2[0],
212 &r1[1],
213 &r3[0],
214 &r3[1],
1ae2b8cd
HWN
215 };
216
217 struct reftable_ref_record *refs[] = { r1, r2, r3 };
218 int sizes[3] = { 3, 1, 2 };
219 struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
220 struct reftable_block_source *bs = NULL;
221 struct reftable_reader **readers = NULL;
222 struct reftable_merged_table *mt =
223 merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3);
224
225 struct reftable_iterator it = { NULL };
226 int err = reftable_merged_table_seek_ref(mt, &it, "a");
227 struct reftable_ref_record *out = NULL;
228 size_t len = 0;
229 size_t cap = 0;
230 int i = 0;
231
232 EXPECT_ERR(err);
233 EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID);
234 EXPECT(reftable_merged_table_min_update_index(mt) == 1);
235
236 while (len < 100) { /* cap loops/recursion. */
237 struct reftable_ref_record ref = { NULL };
238 int err = reftable_iterator_next_ref(&it, &ref);
239 if (err > 0) {
240 break;
241 }
242 if (len == cap) {
243 cap = 2 * cap + 1;
244 out = reftable_realloc(
245 out, sizeof(struct reftable_ref_record) * cap);
246 }
247 out[len++] = ref;
248 }
249 reftable_iterator_destroy(&it);
250
251 EXPECT(ARRAY_SIZE(want) == len);
252 for (i = 0; i < len; i++) {
f2b25514 253 EXPECT(reftable_ref_record_equal(want[i], &out[i],
1ae2b8cd
HWN
254 GIT_SHA1_RAWSZ));
255 }
256 for (i = 0; i < len; i++) {
257 reftable_ref_record_release(&out[i]);
258 }
259 reftable_free(out);
260
261 for (i = 0; i < 3; i++) {
262 strbuf_release(&bufs[i]);
263 }
264 readers_destroy(readers, 3);
265 reftable_merged_table_free(mt);
266 reftable_free(bs);
267}
268
269static struct reftable_merged_table *
270merged_table_from_log_records(struct reftable_log_record **logs,
271 struct reftable_block_source **source,
272 struct reftable_reader ***readers, int *sizes,
273 struct strbuf *buf, int n)
274{
275 int i = 0;
276 struct reftable_merged_table *mt = NULL;
277 int err;
278 struct reftable_table *tabs =
279 reftable_calloc(n * sizeof(struct reftable_table));
280 *readers = reftable_calloc(n * sizeof(struct reftable_reader *));
281 *source = reftable_calloc(n * sizeof(**source));
282 for (i = 0; i < n; i++) {
283 write_test_log_table(&buf[i], logs[i], sizes[i], i + 1);
284 block_source_from_strbuf(&(*source)[i], &buf[i]);
285
286 err = reftable_new_reader(&(*readers)[i], &(*source)[i],
287 "name");
288 EXPECT_ERR(err);
289 reftable_table_from_reader(&tabs[i], (*readers)[i]);
290 }
291
292 err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID);
293 EXPECT_ERR(err);
294 return mt;
295}
296
297static void test_merged_logs(void)
298{
299 uint8_t hash1[GIT_SHA1_RAWSZ] = { 1 };
300 uint8_t hash2[GIT_SHA1_RAWSZ] = { 2 };
301 uint8_t hash3[GIT_SHA1_RAWSZ] = { 3 };
302 struct reftable_log_record r1[] = {
303 {
304 .refname = "a",
305 .update_index = 2,
306 .value_type = REFTABLE_LOG_UPDATE,
307 .value.update = {
308 .old_hash = hash2,
309 /* deletion */
310 .name = "jane doe",
311 .email = "jane@invalid",
312 .message = "message2",
313 }
314 },
315 {
316 .refname = "a",
317 .update_index = 1,
318 .value_type = REFTABLE_LOG_UPDATE,
319 .value.update = {
320 .old_hash = hash1,
321 .new_hash = hash2,
322 .name = "jane doe",
323 .email = "jane@invalid",
324 .message = "message1",
325 }
326 },
327 };
328 struct reftable_log_record r2[] = {
329 {
330 .refname = "a",
331 .update_index = 3,
332 .value_type = REFTABLE_LOG_UPDATE,
333 .value.update = {
334 .new_hash = hash3,
335 .name = "jane doe",
336 .email = "jane@invalid",
337 .message = "message3",
338 }
339 },
340 };
341 struct reftable_log_record r3[] = {
342 {
343 .refname = "a",
344 .update_index = 2,
345 .value_type = REFTABLE_LOG_DELETION,
346 },
347 };
f2b25514
HWN
348 struct reftable_log_record *want[] = {
349 &r2[0],
350 &r3[0],
351 &r1[1],
1ae2b8cd
HWN
352 };
353
354 struct reftable_log_record *logs[] = { r1, r2, r3 };
355 int sizes[3] = { 2, 1, 1 };
356 struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT };
357 struct reftable_block_source *bs = NULL;
358 struct reftable_reader **readers = NULL;
359 struct reftable_merged_table *mt = merged_table_from_log_records(
360 logs, &bs, &readers, sizes, bufs, 3);
361
362 struct reftable_iterator it = { NULL };
363 int err = reftable_merged_table_seek_log(mt, &it, "a");
364 struct reftable_log_record *out = NULL;
365 size_t len = 0;
366 size_t cap = 0;
367 int i = 0;
368
369 EXPECT_ERR(err);
370 EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID);
371 EXPECT(reftable_merged_table_min_update_index(mt) == 1);
372
373 while (len < 100) { /* cap loops/recursion. */
374 struct reftable_log_record log = { NULL };
375 int err = reftable_iterator_next_log(&it, &log);
376 if (err > 0) {
377 break;
378 }
379 if (len == cap) {
380 cap = 2 * cap + 1;
381 out = reftable_realloc(
382 out, sizeof(struct reftable_log_record) * cap);
383 }
384 out[len++] = log;
385 }
386 reftable_iterator_destroy(&it);
387
388 EXPECT(ARRAY_SIZE(want) == len);
389 for (i = 0; i < len; i++) {
f2b25514 390 EXPECT(reftable_log_record_equal(want[i], &out[i],
1ae2b8cd
HWN
391 GIT_SHA1_RAWSZ));
392 }
393
394 err = reftable_merged_table_seek_log_at(mt, &it, "a", 2);
395 EXPECT_ERR(err);
396 reftable_log_record_release(&out[0]);
397 err = reftable_iterator_next_log(&it, &out[0]);
398 EXPECT_ERR(err);
399 EXPECT(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ));
400 reftable_iterator_destroy(&it);
401
402 for (i = 0; i < len; i++) {
403 reftable_log_record_release(&out[i]);
404 }
405 reftable_free(out);
406
407 for (i = 0; i < 3; i++) {
408 strbuf_release(&bufs[i]);
409 }
410 readers_destroy(readers, 3);
411 reftable_merged_table_free(mt);
412 reftable_free(bs);
413}
414
415static void test_default_write_opts(void)
416{
417 struct reftable_write_options opts = { 0 };
418 struct strbuf buf = STRBUF_INIT;
419 struct reftable_writer *w =
420 reftable_new_writer(&strbuf_add_void, &buf, &opts);
421
422 struct reftable_ref_record rec = {
423 .refname = "master",
424 .update_index = 1,
425 };
426 int err;
427 struct reftable_block_source source = { NULL };
428 struct reftable_table *tab = reftable_calloc(sizeof(*tab) * 1);
429 uint32_t hash_id;
430 struct reftable_reader *rd = NULL;
431 struct reftable_merged_table *merged = NULL;
432
433 reftable_writer_set_limits(w, 1, 1);
434
435 err = reftable_writer_add_ref(w, &rec);
436 EXPECT_ERR(err);
437
438 err = reftable_writer_close(w);
439 EXPECT_ERR(err);
440 reftable_writer_free(w);
441
442 block_source_from_strbuf(&source, &buf);
443
444 err = reftable_new_reader(&rd, &source, "filename");
445 EXPECT_ERR(err);
446
447 hash_id = reftable_reader_hash_id(rd);
448 EXPECT(hash_id == GIT_SHA1_FORMAT_ID);
449
450 reftable_table_from_reader(&tab[0], rd);
451 err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID);
452 EXPECT_ERR(err);
453
454 reftable_reader_free(rd);
455 reftable_merged_table_free(merged);
456 strbuf_release(&buf);
457}
458
459/* XXX test refs_for(oid) */
460
461int merged_test_main(int argc, const char *argv[])
462{
463 RUN_TEST(test_merged_logs);
464 RUN_TEST(test_merged_between);
465 RUN_TEST(test_merged);
466 RUN_TEST(test_default_write_opts);
467 return 0;
468}