test: add tests for generic_array_bisect()

This commit is contained in:
Yu Watanabe
2023-12-01 10:08:49 +09:00
parent 1f21bc5811
commit f3714bd5a2
@@ -14,6 +14,7 @@
#include "log.h"
#include "logs-show.h"
#include "parse-util.h"
#include "random-util.h"
#include "rm-rf.h"
#include "tests.h"
@@ -532,6 +533,197 @@ TEST(sequence_numbers) {
test_sequence_numbers_one();
}
static int expected_result(uint64_t needle, const uint64_t *candidates, const uint64_t *offset, size_t n, direction_t direction, uint64_t *ret) {
switch (direction) {
case DIRECTION_DOWN:
for (size_t i = 0; i < n; i++) {
if (candidates[i] == 0) {
*ret = 0;
return 0;
}
if (needle <= candidates[i]) {
*ret = offset[i];
return 1;
}
}
*ret = 0;
return 0;
case DIRECTION_UP:
for (size_t i = 0; i < n; i++)
if (needle < candidates[i] || candidates[i] == 0) {
if (i == 0) {
*ret = 0;
return 0;
}
*ret = offset[i - 1];
return 1;
}
*ret = offset[n - 1];
return 1;
default:
assert_not_reached();
}
}
static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offset, size_t n) {
uint64_t p, q;
int r, e;
/* by seqnum (sequential) */
for (uint64_t i = 0; i < n + 2; i++) {
p = 0;
r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_DOWN, NULL, &p);
e = expected_result(i, seqnum, offset, n, DIRECTION_DOWN, &q);
assert_se(r == e);
assert_se(p == q);
p = 0;
r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_UP, NULL, &p);
e = expected_result(i, seqnum, offset, n, DIRECTION_UP, &q);
assert_se(r == e);
assert_se(p == q);
}
/* by seqnum (random) */
for (size_t trial = 0; trial < 3 * n; trial++) {
uint64_t i = random_u64_range(n + 2);
p = 0;
r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_DOWN, NULL, &p);
e = expected_result(i, seqnum, offset, n, DIRECTION_DOWN, &q);
assert_se(r == e);
assert_se(p == q);
}
for (size_t trial = 0; trial < 3 * n; trial++) {
uint64_t i = random_u64_range(n + 2);
p = 0;
r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_UP, NULL, &p);
e = expected_result(i, seqnum, offset, n, DIRECTION_UP, &q);
assert_se(r == e);
assert_se(p == q);
}
/* by offset (sequential) */
for (size_t i = 0; i < n; i++) {
p = 0;
r = journal_file_move_to_entry_by_offset(f, offset[i] - 1, DIRECTION_DOWN, NULL, &p);
e = expected_result(offset[i] - 1, offset, offset, n, DIRECTION_DOWN, &q);
assert_se(r == e);
assert_se(p == q);
p = 0;
r = journal_file_move_to_entry_by_offset(f, offset[i], DIRECTION_DOWN, NULL, &p);
e = expected_result(offset[i], offset, offset, n, DIRECTION_DOWN, &q);
assert_se(r == e);
assert_se(p == q);
p = 0;
r = journal_file_move_to_entry_by_offset(f, offset[i] + 1, DIRECTION_DOWN, NULL, &p);
e = expected_result(offset[i] + 1, offset, offset, n, DIRECTION_DOWN, &q);
assert_se(r == e);
assert_se(p == q);
p = 0;
r = journal_file_move_to_entry_by_offset(f, offset[i] - 1, DIRECTION_UP, NULL, &p);
e = expected_result(offset[i] - 1, offset, offset, n, DIRECTION_UP, &q);
assert_se(r == e);
assert_se(p == q);
p = 0;
r = journal_file_move_to_entry_by_offset(f, offset[i], DIRECTION_UP, NULL, &p);
e = expected_result(offset[i], offset, offset, n, DIRECTION_UP, &q);
assert_se(r == e);
assert_se(p == q);
p = 0;
r = journal_file_move_to_entry_by_offset(f, offset[i] + 1, DIRECTION_UP, NULL, &p);
e = expected_result(offset[i] + 1, offset, offset, n, DIRECTION_UP, &q);
assert_se(r == e);
assert_se(p == q);
}
/* by offset (random) */
for (size_t trial = 0; trial < 3 * n; trial++) {
uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2);
p = 0;
r = journal_file_move_to_entry_by_offset(f, i, DIRECTION_DOWN, NULL, &p);
e = expected_result(i, offset, offset, n, DIRECTION_DOWN, &q);
assert_se(r == e);
assert_se(p == q);
}
for (size_t trial = 0; trial < 3 * n; trial++) {
uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2);
p = 0;
r = journal_file_move_to_entry_by_offset(f, i, DIRECTION_UP, NULL, &p);
e = expected_result(i, offset, offset, n, DIRECTION_UP, &q);
assert_se(r == e);
assert_se(p == q);
}
}
static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
char t[] = "/var/tmp/journal-seq-XXXXXX";
_cleanup_free_ uint64_t *seqnum = NULL, *offset = NULL;
JournalFile *f;
log_info("/* %s(%zu, %zu) */", __func__, n, num_corrupted);
assert_se(m = mmap_cache_new());
mkdtemp_chdir_chattr(t);
assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
UINT64_MAX, NULL, m, NULL, &f) == 0);
assert_se(seqnum = new0(uint64_t, n));
assert_se(offset = new0(uint64_t, n));
for (size_t i = 0; i < n; i++) {
append_number(f, i, NULL, seqnum + i, offset + i);
if (i == 0) {
assert_se(seqnum[i] > 0);
assert_se(offset[i] > 0);
} else {
assert_se(seqnum[i] > seqnum[i-1]);
assert_se(offset[i] > offset[i-1]);
}
}
verify(f, seqnum, offset, n);
/* Reset chain cache. */
assert_se(journal_file_move_to_entry_by_offset(f, offset[0], DIRECTION_DOWN, NULL, NULL) > 0);
/* make journal corrupted by clearing seqnum. */
for (size_t i = n - num_corrupted; i < n; i++) {
Object *o;
assert_se(journal_file_move_to_object(f, OBJECT_ENTRY, offset[i], &o) >= 0);
assert_se(o);
o->entry.seqnum = 0;
seqnum[i] = 0;
}
verify(f, seqnum, offset, n);
test_close(f);
test_done(t);
}
TEST(generic_array_bisect) {
for (size_t n = 1; n < 10; n++)
for (size_t m = 1; m <= n; m++)
test_generic_array_bisect_one(n, m);
test_generic_array_bisect_one(100, 40);
}
static int intro(void) {
/* journal_file_open() requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)