ea28413eb2
This isn't the greatest coverage as we don't have a verifiable simulation. Simulating the splitting-bucket-tree that is the mtree is tricky. So right now this mostly just checks there's no internal assert failures and if we have the expected number of entries afterwards.
260 lines
7.8 KiB
TOML
260 lines
7.8 KiB
TOML
# test a single mroot
|
|
[cases.test_mtree_one_mroot]
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, cfg) => 0;
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# test a single mroot with a custom attribute
|
|
[cases.test_mtree_one_mroot_attr]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, cfg) => 0;
|
|
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, "ardvark", 7))) => 0;
|
|
|
|
uint8_t buffer[7];
|
|
lfsr_mdir_get(&lfs, &lfs.mroot,
|
|
-1, LFSR_TAG_UATTR(1), buffer, 7) => 7;
|
|
assert(memcmp(buffer, "ardvark", 7) == 0);
|
|
lfsr_unmount(&lfs) => 0;
|
|
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfsr_mdir_get(&lfs, &lfs.mroot,
|
|
-1, LFSR_TAG_UATTR(1), buffer, 7) => 7;
|
|
assert(memcmp(buffer, "ardvark", 7) == 0);
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# test a single mroot with many commits
|
|
[cases.test_mtree_one_mroot_many_commits]
|
|
defines.N = [5, 5000]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
const char *alphas = "abcdefghijklmnopqrstuvwxyz";
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, cfg) => 0;
|
|
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, &alphas[i % 26], 1))) => 0;
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &lfs.mroot,
|
|
-1, LFSR_TAG_UATTR(1), buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &lfs.mroot,
|
|
-1, LFSR_TAG_UATTR(1), buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[(N-1) % 26], 1) == 0);
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# TODO test many mroots
|
|
|
|
# try creating a range of entries that may or may not split our mtree
|
|
[cases.test_mtree_split]
|
|
defines.N = [5, 10, 20, 40, 80, 160, 320]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
const char *alphas = "abcdefghijklmnopqrstuvwxyz";
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, cfg) => 0;
|
|
|
|
// create entries
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfsr_mdir_t mdir;
|
|
lfsr_mtree_lookup(&lfs, lfsr_mtree_weight(&lfs)-1, &mdir) => 0;
|
|
|
|
lfs_ssize_t rid = 0;
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, MKINLINED, +1, &alphas[i % 26], 1))) => 0;
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
|
|
rid += 1;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
|
|
// try looking up each entry
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfs_ssize_t mid = -1;
|
|
rid = 0;
|
|
mdir = lfs.mroot;
|
|
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
if (rid >= (lfs_ssize_t)mdir.rbyd.weight) {
|
|
mid += 1;
|
|
rid = 0;
|
|
lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
|
|
}
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
|
|
rid += 1;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# create a range of entries, and commit to the mroot several times,
|
|
# this makes it more likely to force uninlining without necessarily
|
|
# splitting
|
|
[cases.test_mtree_uninline]
|
|
defines.N = [5, 10, 20, 40, 80, 160, 320]
|
|
defines.M = [5, 5000]
|
|
in = 'lfs.c'
|
|
code = '''
|
|
const char *alphas = "abcdefghijklmnopqrstuvwxyz";
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, cfg) => 0;
|
|
|
|
// create entries
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfsr_mdir_t mdir;
|
|
lfsr_mtree_lookup(&lfs, lfsr_mtree_weight(&lfs)-1, &mdir) => 0;
|
|
|
|
lfs_ssize_t rid = 0;
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, MKINLINED, +1, &alphas[i % 26], 1))) => 0;
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
|
|
rid += 1;
|
|
}
|
|
|
|
// also append a bunch of fs-level attributes, if the mdir should be
|
|
// uninlined this will force it to happen
|
|
for (lfs_size_t i = 0; i < M; i++) {
|
|
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
|
|
LFSR_ATTR(-1, UATTR(1), 0, &alphas[i % 26], 1))) => 0;
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &lfs.mroot,
|
|
-1, LFSR_TAG_UATTR(1), buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
|
|
// try looking up each entry
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
lfs_ssize_t mid = -1;
|
|
rid = 0;
|
|
mdir = lfs.mroot;
|
|
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
if (rid >= (lfs_ssize_t)mdir.rbyd.weight) {
|
|
mid += 1;
|
|
rid = 0;
|
|
lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
|
|
}
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
|
|
rid += 1;
|
|
}
|
|
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &lfs.mroot,
|
|
-1, LFSR_TAG_UATTR(1), buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[(M-1) % 26], 1) == 0);
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# create random entries
|
|
[cases.test_mtree_split_fuzz]
|
|
defines.N = [5, 10, 20, 40, 80, 160, 320]
|
|
defines.SAMPLES = 10
|
|
# -1 => all pseudo-random seeds
|
|
# n => reproduce a specific seed
|
|
defines.SEED = -1
|
|
in = 'lfs.c'
|
|
code = '''
|
|
const char *alphas = "abcdefghijklmnopqrstuvwxyz";
|
|
|
|
// iterate through severals seeds that we can reproduce easily
|
|
for (uint32_t seed = (SEED == -1 ? 1 : SEED);
|
|
(SEED == -1 ? seed < SAMPLES+1 : seed == SEED);
|
|
seed++) {
|
|
printf("--- seed: %d ---\n", seed);
|
|
// create lfs here since we need to reset each iteration, we're
|
|
// space constrained and we can't expect gc to work at this point
|
|
lfs_t lfs;
|
|
lfsr_format(&lfs, cfg) => 0;
|
|
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
// at least keep track of the number of entries we expect
|
|
lfs_size_t count = 0;
|
|
|
|
uint32_t prng = seed;
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
// choose a pseudo-random mid
|
|
lfs_ssize_t mid = lfsr_mtree_weight(&lfs) == 0
|
|
? -1
|
|
: (lfs_ssize_t)(TEST_PRNG(&prng) % lfsr_mtree_weight(&lfs));
|
|
// fetch mdir
|
|
lfsr_mdir_t mdir;
|
|
lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
|
|
// choose a pseudo-random rid
|
|
lfs_ssize_t rid = TEST_PRNG(&prng) % (mdir.rbyd.weight+1);
|
|
|
|
// add to rbyd, potentially splitting the mdir
|
|
lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS(
|
|
LFSR_ATTR(rid, MKINLINED, +1, &alphas[i % 26], 1))) => 0;
|
|
|
|
// make sure we can look up the new entry
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1;
|
|
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
|
|
|
count += 1;
|
|
}
|
|
lfsr_unmount(&lfs) => 0;
|
|
|
|
lfsr_mount(&lfs, cfg) => 0;
|
|
// try looking up each entry
|
|
lfs_size_t count_ = 0;
|
|
|
|
for (lfs_ssize_t mid = (lfsr_mtree_isinlined(&lfs) ? -1 : 0);
|
|
mid < lfsr_mtree_weight(&lfs);
|
|
mid++) {
|
|
lfsr_mdir_t mdir;
|
|
lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
|
|
for (lfs_ssize_t rid = 0;
|
|
rid < (lfs_ssize_t)mdir.rbyd.weight;
|
|
rid++) {
|
|
uint8_t buffer[4];
|
|
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED,
|
|
buffer, 4) => 1;
|
|
|
|
count_ += 1;
|
|
}
|
|
}
|
|
|
|
// the mtree is a bit difficult to simulate, but we can at least test
|
|
// we ended up with the right number of entries
|
|
assert(count_ == count);
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
}
|
|
'''
|