Adapt reftable merged test file to use clar testing framework by using clar assertions where necessary. Signed-off-by: Seyi Kuforiji <kuforiji98@xxxxxxxxx> --- Makefile | 2 +- t/meson.build | 2 +- t/unit-tests/t-reftable-merged.c | 546 ------------------------------- t/unit-tests/u-reftable-merged.c | 515 +++++++++++++++++++++++++++++ 4 files changed, 517 insertions(+), 548 deletions(-) delete mode 100644 t/unit-tests/t-reftable-merged.c create mode 100644 t/unit-tests/u-reftable-merged.c diff --git a/Makefile b/Makefile index 3fc012f86a..a7a519ac81 100644 --- a/Makefile +++ b/Makefile @@ -1364,6 +1364,7 @@ CLAR_TEST_SUITES += u-oidtree CLAR_TEST_SUITES += u-prio-queue CLAR_TEST_SUITES += u-reftable-basics CLAR_TEST_SUITES += u-reftable-block +CLAR_TEST_SUITES += u-reftable-merged CLAR_TEST_SUITES += u-reftable-tree CLAR_TEST_SUITES += u-strbuf CLAR_TEST_SUITES += u-strcmp-offset @@ -1377,7 +1378,6 @@ CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o -UNIT_TEST_PROGRAMS += t-reftable-merged UNIT_TEST_PROGRAMS += t-reftable-pq UNIT_TEST_PROGRAMS += t-reftable-reader UNIT_TEST_PROGRAMS += t-reftable-readwrite diff --git a/t/meson.build b/t/meson.build index eb9e69eb27..a4210dc561 100644 --- a/t/meson.build +++ b/t/meson.build @@ -10,6 +10,7 @@ clar_test_suites = [ 'unit-tests/u-prio-queue.c', 'unit-tests/u-reftable-basics.c', 'unit-tests/u-reftable-block.c', + 'unit-tests/u-reftable-merged.c', 'unit-tests/u-reftable-tree.c', 'unit-tests/u-strbuf.c', 'unit-tests/u-strcmp-offset.c', @@ -57,7 +58,6 @@ clar_unit_tests = executable('unit-tests', test('unit-tests', clar_unit_tests) unit_test_programs = [ - 'unit-tests/t-reftable-merged.c', 'unit-tests/t-reftable-pq.c', 'unit-tests/t-reftable-reader.c', 'unit-tests/t-reftable-readwrite.c', diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/t-reftable-merged.c deleted file mode 100644 index 60836f80d6..0000000000 --- a/t/unit-tests/t-reftable-merged.c +++ /dev/null @@ -1,546 +0,0 @@ -/* -Copyright 2020 Google LLC - -Use of this source code is governed by a BSD-style -license that can be found in the LICENSE file or at -https://developers.google.com/open-source/licenses/bsd -*/ - -#include "test-lib.h" -#include "lib-reftable.h" -#include "reftable/blocksource.h" -#include "reftable/constants.h" -#include "reftable/merged.h" -#include "reftable/reader.h" -#include "reftable/reftable-error.h" -#include "reftable/reftable-merged.h" -#include "reftable/reftable-writer.h" - -static struct reftable_merged_table * -merged_table_from_records(struct reftable_ref_record **refs, - struct reftable_block_source **source, - struct reftable_reader ***readers, const size_t *sizes, - struct reftable_buf *buf, const size_t n) -{ - struct reftable_merged_table *mt = NULL; - struct reftable_write_options opts = { - .block_size = 256, - }; - int err; - - REFTABLE_CALLOC_ARRAY(*readers, n); - check(*readers != NULL); - REFTABLE_CALLOC_ARRAY(*source, n); - check(*source != NULL); - - for (size_t i = 0; i < n; i++) { - t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); - block_source_from_buf(&(*source)[i], &buf[i]); - - err = reftable_reader_new(&(*readers)[i], &(*source)[i], - "name"); - check(!err); - } - - err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); - check(!err); - return mt; -} - -static void readers_destroy(struct reftable_reader **readers, const size_t n) -{ - for (size_t i = 0; i < n; i++) - reftable_reader_decref(readers[i]); - reftable_free(readers); -} - -static void t_merged_single_record(void) -{ - struct reftable_ref_record r1[] = { { - .refname = (char *) "b", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1, 2, 3, 0 }, - } }; - struct reftable_ref_record r2[] = { { - .refname = (char *) "a", - .update_index = 2, - .value_type = REFTABLE_REF_DELETION, - } }; - struct reftable_ref_record r3[] = { { - .refname = (char *) "c", - .update_index = 3, - .value_type = REFTABLE_REF_DELETION, - } }; - - struct reftable_ref_record *refs[] = { r1, r2, r3 }; - size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; - struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; - struct reftable_block_source *bs = NULL; - struct reftable_reader **readers = NULL; - struct reftable_merged_table *mt = - merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); - struct reftable_ref_record ref = { 0 }; - struct reftable_iterator it = { 0 }; - int err; - - err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); - check(!err); - err = reftable_iterator_seek_ref(&it, "a"); - check(!err); - - err = reftable_iterator_next_ref(&it, &ref); - check(!err); - check(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1)); - reftable_ref_record_release(&ref); - reftable_iterator_destroy(&it); - readers_destroy(readers, 3); - reftable_merged_table_free(mt); - for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) - reftable_buf_release(&bufs[i]); - reftable_free(bs); -} - -static void t_merged_refs(void) -{ - struct reftable_ref_record r1[] = { - { - .refname = (char *) "a", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1 }, - }, - { - .refname = (char *) "b", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1 }, - }, - { - .refname = (char *) "c", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1 }, - } - }; - struct reftable_ref_record r2[] = { { - .refname = (char *) "a", - .update_index = 2, - .value_type = REFTABLE_REF_DELETION, - } }; - struct reftable_ref_record r3[] = { - { - .refname = (char *) "c", - .update_index = 3, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 2 }, - }, - { - .refname = (char *) "d", - .update_index = 3, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1 }, - }, - }; - - struct reftable_ref_record *want[] = { - &r2[0], - &r1[1], - &r3[0], - &r3[1], - }; - - struct reftable_ref_record *refs[] = { r1, r2, r3 }; - size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; - struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; - struct reftable_block_source *bs = NULL; - struct reftable_reader **readers = NULL; - struct reftable_merged_table *mt = - merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); - struct reftable_iterator it = { 0 }; - int err; - struct reftable_ref_record *out = NULL; - size_t len = 0; - size_t cap = 0; - size_t i; - - err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); - check(!err); - err = reftable_iterator_seek_ref(&it, "a"); - check(!err); - check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1); - check_int(reftable_merged_table_min_update_index(mt), ==, 1); - check_int(reftable_merged_table_max_update_index(mt), ==, 3); - - while (len < 100) { /* cap loops/recursion. */ - struct reftable_ref_record ref = { 0 }; - int err = reftable_iterator_next_ref(&it, &ref); - if (err > 0) - break; - - check(!REFTABLE_ALLOC_GROW(out, len + 1, cap)); - out[len++] = ref; - } - reftable_iterator_destroy(&it); - - check_int(ARRAY_SIZE(want), ==, len); - for (i = 0; i < len; i++) - check(reftable_ref_record_equal(want[i], &out[i], - REFTABLE_HASH_SIZE_SHA1)); - for (i = 0; i < len; i++) - reftable_ref_record_release(&out[i]); - reftable_free(out); - - for (i = 0; i < 3; i++) - reftable_buf_release(&bufs[i]); - readers_destroy(readers, 3); - reftable_merged_table_free(mt); - reftable_free(bs); -} - -static void t_merged_seek_multiple_times(void) -{ - struct reftable_ref_record r1[] = { - { - .refname = (char *) "a", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1 }, - }, - { - .refname = (char *) "c", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 2 }, - } - }; - struct reftable_ref_record r2[] = { - { - .refname = (char *) "b", - .update_index = 2, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 3 }, - }, - { - .refname = (char *) "d", - .update_index = 2, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 4 }, - }, - }; - struct reftable_ref_record *refs[] = { - r1, r2, - }; - size_t sizes[] = { - ARRAY_SIZE(r1), ARRAY_SIZE(r2), - }; - struct reftable_buf bufs[] = { - REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, - }; - struct reftable_block_source *sources = NULL; - struct reftable_reader **readers = NULL; - struct reftable_ref_record rec = { 0 }; - struct reftable_iterator it = { 0 }; - struct reftable_merged_table *mt; - - mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); - merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); - - for (size_t i = 0; i < 5; i++) { - int err = reftable_iterator_seek_ref(&it, "c"); - check(!err); - - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r1[1], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); - - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r2[1], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); - - err = reftable_iterator_next_ref(&it, &rec); - check(err > 0); - } - - for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) - reftable_buf_release(&bufs[i]); - readers_destroy(readers, ARRAY_SIZE(refs)); - reftable_ref_record_release(&rec); - reftable_iterator_destroy(&it); - reftable_merged_table_free(mt); - reftable_free(sources); -} - -static void t_merged_seek_multiple_times_without_draining(void) -{ - struct reftable_ref_record r1[] = { - { - .refname = (char *) "a", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 1 }, - }, - { - .refname = (char *) "c", - .update_index = 1, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 2 }, - } - }; - struct reftable_ref_record r2[] = { - { - .refname = (char *) "b", - .update_index = 2, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 3 }, - }, - { - .refname = (char *) "d", - .update_index = 2, - .value_type = REFTABLE_REF_VAL1, - .value.val1 = { 4 }, - }, - }; - struct reftable_ref_record *refs[] = { - r1, r2, - }; - size_t sizes[] = { - ARRAY_SIZE(r1), ARRAY_SIZE(r2), - }; - struct reftable_buf bufs[] = { - REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, - }; - struct reftable_block_source *sources = NULL; - struct reftable_reader **readers = NULL; - struct reftable_ref_record rec = { 0 }; - struct reftable_iterator it = { 0 }; - struct reftable_merged_table *mt; - int err; - - mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); - merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); - - err = reftable_iterator_seek_ref(&it, "b"); - check(!err); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r2[0], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); - - err = reftable_iterator_seek_ref(&it, "a"); - check(!err); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r1[0], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); - - for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) - reftable_buf_release(&bufs[i]); - readers_destroy(readers, ARRAY_SIZE(refs)); - reftable_ref_record_release(&rec); - reftable_iterator_destroy(&it); - reftable_merged_table_free(mt); - reftable_free(sources); -} - -static struct reftable_merged_table * -merged_table_from_log_records(struct reftable_log_record **logs, - struct reftable_block_source **source, - struct reftable_reader ***readers, const size_t *sizes, - struct reftable_buf *buf, const size_t n) -{ - struct reftable_merged_table *mt = NULL; - struct reftable_write_options opts = { - .block_size = 256, - .exact_log_message = 1, - }; - int err; - - REFTABLE_CALLOC_ARRAY(*readers, n); - check(*readers != NULL); - REFTABLE_CALLOC_ARRAY(*source, n); - check(*source != NULL); - - for (size_t i = 0; i < n; i++) { - t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); - block_source_from_buf(&(*source)[i], &buf[i]); - - err = reftable_reader_new(&(*readers)[i], &(*source)[i], - "name"); - check(!err); - } - - err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); - check(!err); - return mt; -} - -static void t_merged_logs(void) -{ - struct reftable_log_record r1[] = { - { - .refname = (char *) "a", - .update_index = 2, - .value_type = REFTABLE_LOG_UPDATE, - .value.update = { - .old_hash = { 2 }, - /* deletion */ - .name = (char *) "jane doe", - .email = (char *) "jane@invalid", - .message = (char *) "message2", - } - }, - { - .refname = (char *) "a", - .update_index = 1, - .value_type = REFTABLE_LOG_UPDATE, - .value.update = { - .old_hash = { 1 }, - .new_hash = { 2 }, - .name = (char *) "jane doe", - .email = (char *) "jane@invalid", - .message = (char *) "message1", - } - }, - }; - struct reftable_log_record r2[] = { - { - .refname = (char *) "a", - .update_index = 3, - .value_type = REFTABLE_LOG_UPDATE, - .value.update = { - .new_hash = { 3 }, - .name = (char *) "jane doe", - .email = (char *) "jane@invalid", - .message = (char *) "message3", - } - }, - }; - struct reftable_log_record r3[] = { - { - .refname = (char *) "a", - .update_index = 2, - .value_type = REFTABLE_LOG_DELETION, - }, - }; - struct reftable_log_record *want[] = { - &r2[0], - &r3[0], - &r1[1], - }; - - struct reftable_log_record *logs[] = { r1, r2, r3 }; - size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; - struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; - struct reftable_block_source *bs = NULL; - struct reftable_reader **readers = NULL; - struct reftable_merged_table *mt = merged_table_from_log_records( - logs, &bs, &readers, sizes, bufs, 3); - struct reftable_iterator it = { 0 }; - int err; - struct reftable_log_record *out = NULL; - size_t len = 0; - size_t cap = 0; - size_t i; - - err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); - check(!err); - err = reftable_iterator_seek_log(&it, "a"); - check(!err); - check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1); - check_int(reftable_merged_table_min_update_index(mt), ==, 1); - check_int(reftable_merged_table_max_update_index(mt), ==, 3); - - while (len < 100) { /* cap loops/recursion. */ - struct reftable_log_record log = { 0 }; - int err = reftable_iterator_next_log(&it, &log); - if (err > 0) - break; - - check(!REFTABLE_ALLOC_GROW(out, len + 1, cap)); - out[len++] = log; - } - reftable_iterator_destroy(&it); - - check_int(ARRAY_SIZE(want), ==, len); - for (i = 0; i < len; i++) - check(reftable_log_record_equal(want[i], &out[i], - REFTABLE_HASH_SIZE_SHA1)); - - err = merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); - check(!err); - err = reftable_iterator_seek_log_at(&it, "a", 2); - check(!err); - reftable_log_record_release(&out[0]); - err = reftable_iterator_next_log(&it, &out[0]); - check(!err); - check(reftable_log_record_equal(&out[0], &r3[0], REFTABLE_HASH_SIZE_SHA1)); - reftable_iterator_destroy(&it); - - for (i = 0; i < len; i++) - reftable_log_record_release(&out[i]); - reftable_free(out); - - for (i = 0; i < 3; i++) - reftable_buf_release(&bufs[i]); - readers_destroy(readers, 3); - reftable_merged_table_free(mt); - reftable_free(bs); -} - -static void t_default_write_opts(void) -{ - struct reftable_write_options opts = { 0 }; - struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); - struct reftable_ref_record rec = { - .refname = (char *) "master", - .update_index = 1, - }; - int err; - struct reftable_block_source source = { 0 }; - uint32_t hash_id; - struct reftable_reader *rd = NULL; - struct reftable_merged_table *merged = NULL; - - reftable_writer_set_limits(w, 1, 1); - - err = reftable_writer_add_ref(w, &rec); - check(!err); - - err = reftable_writer_close(w); - check(!err); - reftable_writer_free(w); - - block_source_from_buf(&source, &buf); - - err = reftable_reader_new(&rd, &source, "filename"); - check(!err); - - hash_id = reftable_reader_hash_id(rd); - check_int(hash_id, ==, REFTABLE_HASH_SHA1); - - err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA256); - check_int(err, ==, REFTABLE_FORMAT_ERROR); - err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA1); - check(!err); - - reftable_reader_decref(rd); - reftable_merged_table_free(merged); - reftable_buf_release(&buf); -} - - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_default_write_opts(), "merged table with default write opts"); - TEST(t_merged_logs(), "merged table with multiple log updates for same ref"); - TEST(t_merged_refs(), "merged table with multiple updates to same ref"); - TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times"); - TEST(t_merged_seek_multiple_times_without_draining(), "merged table can seek multiple times without draining"); - TEST(t_merged_single_record(), "ref occurring in only one record can be fetched"); - - return test_done(); -} diff --git a/t/unit-tests/u-reftable-merged.c b/t/unit-tests/u-reftable-merged.c new file mode 100644 index 0000000000..48c8f9f6b5 --- /dev/null +++ b/t/unit-tests/u-reftable-merged.c @@ -0,0 +1,515 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#include "unit-test.h" +#include "lib-reftable.h" +#include "reftable/blocksource.h" +#include "reftable/constants.h" +#include "reftable/merged.h" +#include "reftable/reader.h" +#include "reftable/reftable-error.h" +#include "reftable/reftable-merged.h" +#include "reftable/reftable-writer.h" + +static struct reftable_merged_table * +merged_table_from_records(struct reftable_ref_record **refs, + struct reftable_block_source **source, + struct reftable_reader ***readers, const size_t *sizes, + struct reftable_buf *buf, const size_t n) +{ + struct reftable_merged_table *mt = NULL; + struct reftable_write_options opts = { + .block_size = 256, + }; + int err; + + REFTABLE_CALLOC_ARRAY(*readers, n); + cl_assert(*readers != NULL); + REFTABLE_CALLOC_ARRAY(*source, n); + cl_assert(*source != NULL); + + for (size_t i = 0; i < n; i++) { + cl_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); + block_source_from_buf(&(*source)[i], &buf[i]); + + err = reftable_reader_new(&(*readers)[i], &(*source)[i], + "name"); + cl_assert(err == 0); + } + + err = reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1); + cl_assert(err == 0); + return mt; +} + +static void readers_destroy(struct reftable_reader **readers, const size_t n) +{ + for (size_t i = 0; i < n; i++) + reftable_reader_decref(readers[i]); + reftable_free(readers); +} + +void test_reftable_merged__merged_single_record(void) +{ + struct reftable_ref_record r1[] = { { + .refname = (char *) "b", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1, 2, 3, 0 }, + } }; + struct reftable_ref_record r2[] = { { + .refname = (char *) "a", + .update_index = 2, + .value_type = REFTABLE_REF_DELETION, + } }; + struct reftable_ref_record r3[] = { { + .refname = (char *) "c", + .update_index = 3, + .value_type = REFTABLE_REF_DELETION, + } }; + + struct reftable_ref_record *refs[] = { r1, r2, r3 }; + size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; + struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; + struct reftable_block_source *bs = NULL; + struct reftable_reader **readers = NULL; + struct reftable_merged_table *mt = + merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); + struct reftable_ref_record ref = { 0 }; + struct reftable_iterator it = { 0 }; + int err; + + err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); + cl_assert(err == 0); + err = reftable_iterator_seek_ref(&it, "a"); + cl_assert(err == 0); + + err = reftable_iterator_next_ref(&it, &ref); + cl_assert(err == 0); + cl_assert(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1) != 0); + reftable_ref_record_release(&ref); + reftable_iterator_destroy(&it); + readers_destroy(readers, 3); + reftable_merged_table_free(mt); + for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) + reftable_buf_release(&bufs[i]); + reftable_free(bs); +} + +void test_reftable_merged__merged_refs(void) +{ + struct reftable_ref_record r1[] = { + { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + }, + { + .refname = (char *) "b", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + }, + { + .refname = (char *) "c", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + } + }; + struct reftable_ref_record r2[] = { { + .refname = (char *) "a", + .update_index = 2, + .value_type = REFTABLE_REF_DELETION, + } }; + struct reftable_ref_record r3[] = { + { + .refname = (char *) "c", + .update_index = 3, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 2 }, + }, + { + .refname = (char *) "d", + .update_index = 3, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + }, + }; + + struct reftable_ref_record *want[] = { + &r2[0], + &r1[1], + &r3[0], + &r3[1], + }; + + struct reftable_ref_record *refs[] = { r1, r2, r3 }; + size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; + struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; + struct reftable_block_source *bs = NULL; + struct reftable_reader **readers = NULL; + struct reftable_merged_table *mt = + merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); + struct reftable_iterator it = { 0 }; + int err; + struct reftable_ref_record *out = NULL; + size_t len = 0; + size_t cap = 0; + size_t i; + + err = merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); + cl_assert(err == 0); + err = reftable_iterator_seek_ref(&it, "a"); + cl_assert(err == 0); + cl_assert_equal_i(reftable_merged_table_hash_id(mt), REFTABLE_HASH_SHA1); + cl_assert_equal_i(reftable_merged_table_min_update_index(mt), 1); + cl_assert_equal_i(reftable_merged_table_max_update_index(mt), 3); + + while (len < 100) { /* cap loops/recursion. */ + struct reftable_ref_record ref = { 0 }; + int err = reftable_iterator_next_ref(&it, &ref); + if (err > 0) + break; + + cl_assert(REFTABLE_ALLOC_GROW(out, len + 1, cap) == 0); + out[len++] = ref; + } + reftable_iterator_destroy(&it); + + cl_assert_equal_i(ARRAY_SIZE(want), len); + for (i = 0; i < len; i++) + cl_assert(reftable_ref_record_equal(want[i], &out[i], + REFTABLE_HASH_SIZE_SHA1) != 0); + for (i = 0; i < len; i++) + reftable_ref_record_release(&out[i]); + reftable_free(out); + + for (i = 0; i < 3; i++) + reftable_buf_release(&bufs[i]); + readers_destroy(readers, 3); + reftable_merged_table_free(mt); + reftable_free(bs); +} + +void test_reftable_merged__merged_seek_multiple_times(void) +{ + struct reftable_ref_record r1[] = { + { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + }, + { + .refname = (char *) "c", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 2 }, + } + }; + struct reftable_ref_record r2[] = { + { + .refname = (char *) "b", + .update_index = 2, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 3 }, + }, + { + .refname = (char *) "d", + .update_index = 2, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 4 }, + }, + }; + struct reftable_ref_record *refs[] = { + r1, r2, + }; + size_t sizes[] = { + ARRAY_SIZE(r1), ARRAY_SIZE(r2), + }; + struct reftable_buf bufs[] = { + REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, + }; + struct reftable_block_source *sources = NULL; + struct reftable_reader **readers = NULL; + struct reftable_ref_record rec = { 0 }; + struct reftable_iterator it = { 0 }; + struct reftable_merged_table *mt; + + mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); + merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); + + for (size_t i = 0; i < 5; i++) { + int err = reftable_iterator_seek_ref(&it, "c"); + cl_assert(err == 0); + + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r1[1], + REFTABLE_HASH_SIZE_SHA1), 1); + + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r2[1], + REFTABLE_HASH_SIZE_SHA1), 1); + + cl_assert(reftable_iterator_next_ref(&it, &rec) > 0); + } + + for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) + reftable_buf_release(&bufs[i]); + readers_destroy(readers, ARRAY_SIZE(refs)); + reftable_ref_record_release(&rec); + reftable_iterator_destroy(&it); + reftable_merged_table_free(mt); + reftable_free(sources); +} + +void test_reftable_merged__merged_seek_multiple_times_no_drain(void) +{ + struct reftable_ref_record r1[] = { + { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 1 }, + }, + { + .refname = (char *) "c", + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 2 }, + } + }; + struct reftable_ref_record r2[] = { + { + .refname = (char *) "b", + .update_index = 2, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 3 }, + }, + { + .refname = (char *) "d", + .update_index = 2, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = { 4 }, + }, + }; + struct reftable_ref_record *refs[] = { + r1, r2, + }; + size_t sizes[] = { + ARRAY_SIZE(r1), ARRAY_SIZE(r2), + }; + struct reftable_buf bufs[] = { + REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, + }; + struct reftable_block_source *sources = NULL; + struct reftable_reader **readers = NULL; + struct reftable_ref_record rec = { 0 }; + struct reftable_iterator it = { 0 }; + struct reftable_merged_table *mt; + + mt = merged_table_from_records(refs, &sources, &readers, sizes, bufs, 2); + merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); + + cl_assert(reftable_iterator_seek_ref(&it, "b") == 0); + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r2[0], + REFTABLE_HASH_SIZE_SHA1), 1); + + cl_assert(reftable_iterator_seek_ref(&it, "a") == 0); + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r1[0], + REFTABLE_HASH_SIZE_SHA1), 1); + + for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) + reftable_buf_release(&bufs[i]); + readers_destroy(readers, ARRAY_SIZE(refs)); + reftable_ref_record_release(&rec); + reftable_iterator_destroy(&it); + reftable_merged_table_free(mt); + reftable_free(sources); +} + +static struct reftable_merged_table * +merged_table_from_log_records(struct reftable_log_record **logs, + struct reftable_block_source **source, + struct reftable_reader ***readers, const size_t *sizes, + struct reftable_buf *buf, const size_t n) +{ + struct reftable_merged_table *mt = NULL; + struct reftable_write_options opts = { + .block_size = 256, + .exact_log_message = 1, + }; + int err; + + REFTABLE_CALLOC_ARRAY(*readers, n); + cl_assert(*readers != NULL); + REFTABLE_CALLOC_ARRAY(*source, n); + cl_assert(*source != NULL); + + for (size_t i = 0; i < n; i++) { + cl_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); + block_source_from_buf(&(*source)[i], &buf[i]); + + err = reftable_reader_new(&(*readers)[i], &(*source)[i], + "name"); + cl_assert(err == 0); + } + + cl_assert(reftable_merged_table_new(&mt, *readers, n, REFTABLE_HASH_SHA1) == 0); + return mt; +} + +void test_reftable_merged__merged_logs(void) +{ + struct reftable_log_record r1[] = { + { + .refname = (char *) "a", + .update_index = 2, + .value_type = REFTABLE_LOG_UPDATE, + .value.update = { + .old_hash = { 2 }, + /* deletion */ + .name = (char *) "jane doe", + .email = (char *) "jane@invalid", + .message = (char *) "message2", + } + }, + { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_LOG_UPDATE, + .value.update = { + .old_hash = { 1 }, + .new_hash = { 2 }, + .name = (char *) "jane doe", + .email = (char *) "jane@invalid", + .message = (char *) "message1", + } + }, + }; + struct reftable_log_record r2[] = { + { + .refname = (char *) "a", + .update_index = 3, + .value_type = REFTABLE_LOG_UPDATE, + .value.update = { + .new_hash = { 3 }, + .name = (char *) "jane doe", + .email = (char *) "jane@invalid", + .message = (char *) "message3", + } + }, + }; + struct reftable_log_record r3[] = { + { + .refname = (char *) "a", + .update_index = 2, + .value_type = REFTABLE_LOG_DELETION, + }, + }; + struct reftable_log_record *want[] = { + &r2[0], + &r3[0], + &r1[1], + }; + + struct reftable_log_record *logs[] = { r1, r2, r3 }; + size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; + struct reftable_buf bufs[3] = { REFTABLE_BUF_INIT, REFTABLE_BUF_INIT, REFTABLE_BUF_INIT }; + struct reftable_block_source *bs = NULL; + struct reftable_reader **readers = NULL; + struct reftable_merged_table *mt = merged_table_from_log_records( + logs, &bs, &readers, sizes, bufs, 3); + struct reftable_iterator it = { 0 }; + struct reftable_log_record *out = NULL; + size_t len = 0; + size_t cap = 0; + size_t i; + + cl_assert(merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG) == 0); + cl_assert(reftable_iterator_seek_log(&it, "a") == 0); + cl_assert_equal_i(reftable_merged_table_hash_id(mt), REFTABLE_HASH_SHA1); + cl_assert_equal_i(reftable_merged_table_min_update_index(mt), 1); + cl_assert_equal_i(reftable_merged_table_max_update_index(mt), 3); + + while (len < 100) { /* cap loops/recursion. */ + struct reftable_log_record log = { 0 }; + int err = reftable_iterator_next_log(&it, &log); + if (err > 0) + break; + + cl_assert(REFTABLE_ALLOC_GROW(out, len + 1, cap) == 0); + out[len++] = log; + } + reftable_iterator_destroy(&it); + + cl_assert_equal_i(ARRAY_SIZE(want), len); + for (i = 0; i < len; i++) + cl_assert(reftable_log_record_equal(want[i], &out[i], + REFTABLE_HASH_SIZE_SHA1) != 0); + + cl_assert(merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG) == 0); + cl_assert(reftable_iterator_seek_log_at(&it, "a", 2) == 0); + reftable_log_record_release(&out[0]); + cl_assert(reftable_iterator_next_log(&it, &out[0]) == 0); + cl_assert(reftable_log_record_equal(&out[0], &r3[0], + REFTABLE_HASH_SIZE_SHA1) != 0); + reftable_iterator_destroy(&it); + + for (i = 0; i < len; i++) + reftable_log_record_release(&out[i]); + reftable_free(out); + + for (i = 0; i < 3; i++) + reftable_buf_release(&bufs[i]); + readers_destroy(readers, 3); + reftable_merged_table_free(mt); + reftable_free(bs); +} + +void test_reftable_merged__default_write_opts(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + struct reftable_ref_record rec = { + .refname = (char *) "master", + .update_index = 1, + }; + int err; + struct reftable_block_source source = { 0 }; + uint32_t hash_id; + struct reftable_reader *rd = NULL; + struct reftable_merged_table *merged = NULL; + + reftable_writer_set_limits(w, 1, 1); + + cl_assert(reftable_writer_add_ref(w, &rec) == 0); + + cl_assert(reftable_writer_close(w) == 0); + reftable_writer_free(w); + + block_source_from_buf(&source, &buf); + + cl_assert(reftable_reader_new(&rd, &source, "filename") == 0); + + hash_id = reftable_reader_hash_id(rd); + cl_assert_equal_i(hash_id, REFTABLE_HASH_SHA1); + + err = reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA256); + cl_assert_equal_i(err, REFTABLE_FORMAT_ERROR); + cl_assert(reftable_merged_table_new(&merged, &rd, 1, REFTABLE_HASH_SHA1) == 0); + + reftable_reader_decref(rd); + reftable_merged_table_free(merged); + reftable_buf_release(&buf); +} -- 2.43.0