Added some more tests over reading dirs during fs mutation
These tests serve as a direct example of why we can't just return the difference between the dir's bookmark mid and position mid, which is unfortunate.
This commit is contained in:
+388
-3
@@ -288,10 +288,395 @@ code = '''
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test dir read works when under filesystem modifications
|
||||
#
|
||||
# this is a bit complex and subtle
|
||||
# test neighbor changes don't mess with an unrelated dir read
|
||||
[cases.test_dseek_read_neighbor_mkdirs]
|
||||
defines.N = 5
|
||||
# where in the dir read do we mkdir?
|
||||
defines.I = 'range(6)'
|
||||
defines.PARENT = true
|
||||
# bit 0x2 = left neighbor
|
||||
# bit 0x1 = right neighbor
|
||||
defines.NEIGHBORS = [0x1, 0x2, 0x3]
|
||||
# more neighbors ensures mdir splits which can be its own source
|
||||
# of problems
|
||||
defines.NEIGHBOR_N = [1, 10, 100]
|
||||
# 0 => don't seek
|
||||
# 1 => seek
|
||||
# 2 => rewind then seek
|
||||
# 3 => seek with offset before mutation
|
||||
# 4 => rewind then seek with offset before mutation
|
||||
defines.SEEK = [0, 1, 2, 3, 4]
|
||||
# neighbors only make sense if we have a parent
|
||||
if = 'PARENT || NEIGHBORS == 0'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, CFG) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
|
||||
if (PARENT) {
|
||||
lfsr_mkdir(&lfs, "pricklypear") => 0;
|
||||
|
||||
if (NEIGHBORS & 0x2) {
|
||||
assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000);
|
||||
lfsr_mkdir(&lfs, "a_IplRNrPH") => 0;
|
||||
}
|
||||
|
||||
if (NEIGHBORS & 0x1) {
|
||||
assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff);
|
||||
lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// create our directories
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
|
||||
// start reading
|
||||
lfsr_dir_t dir;
|
||||
lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
|
||||
// read until I
|
||||
for (lfs_size_t i = 0; i < I; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "dir%04d", i);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
}
|
||||
|
||||
// since modification is unrelated, the dir position should go unchanged
|
||||
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
|
||||
assert(off == I+2);
|
||||
|
||||
// make unrelated dirs
|
||||
if (NEIGHBORS & 0x2) {
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "a_IplRNrPH/a_%04d", i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIGHBORS & 0x1) {
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "f_VtoMnwRH/f_%04d", i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// seek after mkdir?
|
||||
if (SEEK) {
|
||||
// note dir pos after reaching end of dir can be anything
|
||||
lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir);
|
||||
assert(off_ >= 0);
|
||||
if (I < N) {
|
||||
assert(off_ == off);
|
||||
}
|
||||
|
||||
if (SEEK == 2 || SEEK == 4) {
|
||||
lfsr_dir_rewind(&lfs, &dir) => 0;
|
||||
}
|
||||
|
||||
if (SEEK == 3 || SEEK == 4) {
|
||||
lfsr_dir_seek(&lfs, &dir, off) => 0;
|
||||
} else {
|
||||
lfsr_dir_seek(&lfs, &dir, off_) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// we should be able to keep reading where we left off
|
||||
for (lfs_size_t i = I; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "dir%04d", i);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
}
|
||||
|
||||
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||
lfsr_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_dseek_read_neighbor_rms]
|
||||
defines.N = 5
|
||||
# where in the dir read do we mkdir?
|
||||
defines.I = 'range(6)'
|
||||
defines.PARENT = true
|
||||
# bit 0x2 = left neighbor
|
||||
# bit 0x1 = right neighbor
|
||||
defines.NEIGHBORS = [0x1, 0x2, 0x3]
|
||||
# more neighbors ensures mdir splits which can be its own source
|
||||
# of problems
|
||||
defines.NEIGHBOR_N = [1, 10, 100]
|
||||
# 0 => don't seek
|
||||
# 1 => seek
|
||||
# 2 => rewind then seek
|
||||
# 3 => seek with offset before mutation
|
||||
# 4 => rewind then seek with offset before mutation
|
||||
defines.SEEK = [0, 1, 2, 3, 4]
|
||||
# neighbors only make sense if we have a parent
|
||||
if = 'PARENT || NEIGHBORS == 0'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, CFG) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
|
||||
if (PARENT) {
|
||||
lfsr_mkdir(&lfs, "pricklypear") => 0;
|
||||
|
||||
if (NEIGHBORS & 0x2) {
|
||||
assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000);
|
||||
lfsr_mkdir(&lfs, "a_IplRNrPH") => 0;
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "a_IplRNrPH/a_%04d", i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIGHBORS & 0x1) {
|
||||
assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff);
|
||||
lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0;
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "f_VtoMnwRH/f_%04d", i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create our directories
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
|
||||
// start reading
|
||||
lfsr_dir_t dir;
|
||||
lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
|
||||
// read until I
|
||||
for (lfs_size_t i = 0; i < I; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "dir%04d", i);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
}
|
||||
|
||||
// since modification is unrelated, the dir position should go unchanged
|
||||
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
|
||||
assert(off == I+2);
|
||||
|
||||
// remove unrelated dirs
|
||||
if (NEIGHBORS & 0x2) {
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "a_IplRNrPH/a_%04d", i);
|
||||
lfsr_remove(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIGHBORS & 0x1) {
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "f_VtoMnwRH/f_%04d", i);
|
||||
lfsr_remove(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// seek after mkdir?
|
||||
if (SEEK) {
|
||||
// note dir pos after reaching end of dir can be anything
|
||||
lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir);
|
||||
assert(off_ >= 0);
|
||||
if (I < N) {
|
||||
assert(off_ == off);
|
||||
}
|
||||
|
||||
if (SEEK == 2 || SEEK == 4) {
|
||||
lfsr_dir_rewind(&lfs, &dir) => 0;
|
||||
}
|
||||
|
||||
if (SEEK == 3 || SEEK == 4) {
|
||||
lfsr_dir_seek(&lfs, &dir, off) => 0;
|
||||
} else {
|
||||
lfsr_dir_seek(&lfs, &dir, off_) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// we should be able to keep reading where we left off
|
||||
for (lfs_size_t i = I; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "dir%04d", i);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
}
|
||||
|
||||
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||
lfsr_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_dseek_read_neighbor_mvs]
|
||||
defines.N = 5
|
||||
# where in the dir read do we mkdir?
|
||||
defines.I = 'range(6)'
|
||||
defines.PARENT = true
|
||||
# bit 0x2 = left neighbor
|
||||
# bit 0x1 = right neighbor
|
||||
defines.NEIGHBORS = [0x1, 0x2, 0x3]
|
||||
# more neighbors ensures mdir splits which can be its own source
|
||||
# of problems
|
||||
defines.NEIGHBOR_N = [1, 10, 100]
|
||||
# 0 => don't seek
|
||||
# 1 => seek
|
||||
# 2 => rewind then seek
|
||||
# 3 => seek with offset before mutation
|
||||
# 4 => rewind then seek with offset before mutation
|
||||
defines.SEEK = [0, 1, 2, 3, 4]
|
||||
# neighbors only make sense if we have a parent
|
||||
if = 'PARENT || NEIGHBORS == 0'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, CFG) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
|
||||
if (PARENT) {
|
||||
lfsr_mkdir(&lfs, "pricklypear") => 0;
|
||||
|
||||
if (NEIGHBORS & 0x2) {
|
||||
assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000);
|
||||
lfsr_mkdir(&lfs, "a_IplRNrPH") => 0;
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "a_IplRNrPH/a_%04d", i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIGHBORS & 0x1) {
|
||||
assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff);
|
||||
lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0;
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "f_VtoMnwRH/f_%04d", i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create our directories
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i);
|
||||
lfsr_mkdir(&lfs, name) => 0;
|
||||
}
|
||||
|
||||
// start reading
|
||||
lfsr_dir_t dir;
|
||||
lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
|
||||
// read until I
|
||||
for (lfs_size_t i = 0; i < I; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "dir%04d", i);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
}
|
||||
|
||||
// since modification is unrelated, the dir position should go unchanged
|
||||
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
|
||||
assert(off == I+2);
|
||||
|
||||
// rename unrelated dirs
|
||||
if (NEIGHBORS & 0x2) {
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "a_IplRNrPH/a_%04d", i);
|
||||
char name_[256];
|
||||
sprintf(name_, "a_IplRNrPH/b_%04d", i);
|
||||
lfsr_rename(&lfs, name, name_) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (NEIGHBORS & 0x1) {
|
||||
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "f_VtoMnwRH/f_%04d", i);
|
||||
char name_[256];
|
||||
sprintf(name_, "f_VtoMnwRH/b_%04d", i);
|
||||
lfsr_rename(&lfs, name, name_) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// seek after mkdir?
|
||||
if (SEEK) {
|
||||
// note dir pos after reaching end of dir can be anything
|
||||
lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir);
|
||||
assert(off_ >= 0);
|
||||
if (I < N) {
|
||||
assert(off_ == off);
|
||||
}
|
||||
|
||||
if (SEEK == 2 || SEEK == 4) {
|
||||
lfsr_dir_rewind(&lfs, &dir) => 0;
|
||||
}
|
||||
|
||||
if (SEEK == 3 || SEEK == 4) {
|
||||
lfsr_dir_seek(&lfs, &dir, off) => 0;
|
||||
} else {
|
||||
lfsr_dir_seek(&lfs, &dir, off_) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// we should be able to keep reading where we left off
|
||||
for (lfs_size_t i = I; i < N; i++) {
|
||||
char name[256];
|
||||
sprintf(name, "dir%04d", i);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
}
|
||||
|
||||
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||
lfsr_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test dir read has somewhat reasonable behaviour when the dir is modified
|
||||
[cases.test_dseek_read_with_mkdirs]
|
||||
defines.N = 5
|
||||
# where in the dir read do we mkdir?
|
||||
|
||||
Reference in New Issue
Block a user