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