From 15cd1d29e070aebce945d04d011dfaf50bc3abf6 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 28 Jan 2024 00:32:22 -0600 Subject: [PATCH] Added explicit test over directory ordering It turned out the previous version had a subtle ordering bug when names where the same length that went unnoticed for years. And at this point is probably baked into the on-disk format permanently. This redesign, with a named-ordered btree, relies quite a bit more on name ordering, so it's unlikely the same mistake would make it through without breaking something. And sure enough this bug was unintentionally fixed at some point. But still, better safe than sorry. Added tests over character ordering and length ordering. Open to more ordering tests in the future. Found by andriyndev --- tests/test_dirs.toml | 224 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml index 1d9af561..a268b7a7 100644 --- a/tests/test_dirs.toml +++ b/tests/test_dirs.toml @@ -1396,6 +1396,230 @@ code = ''' ''' +# test some common ordering mistakes +[cases.test_dirs_ordering] +# ORDER=0 => inorder +# ORDER=1 => reversed +# ORDER=2 => random +defines.ORDER = [0, 1, 2] +defines.REMOUNT = [false, true] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (ORDER == 0) { + lfsr_mkdir(&lfs, "a") => 0; + lfsr_mkdir(&lfs, "b") => 0; + lfsr_mkdir(&lfs, "c") => 0; + lfsr_mkdir(&lfs, "d") => 0; + lfsr_mkdir(&lfs, "e") => 0; + lfsr_mkdir(&lfs, "f") => 0; + } else if (ORDER == 1) { + lfsr_mkdir(&lfs, "f") => 0; + lfsr_mkdir(&lfs, "e") => 0; + lfsr_mkdir(&lfs, "d") => 0; + lfsr_mkdir(&lfs, "c") => 0; + lfsr_mkdir(&lfs, "b") => 0; + lfsr_mkdir(&lfs, "a") => 0; + } else if (ORDER == 2) { + // "random", trust me + lfsr_mkdir(&lfs, "e") => 0; + lfsr_mkdir(&lfs, "c") => 0; + lfsr_mkdir(&lfs, "b") => 0; + lfsr_mkdir(&lfs, "d") => 0; + lfsr_mkdir(&lfs, "f") => 0; + lfsr_mkdir(&lfs, "a") => 0; + } + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.grm_g[0] == 0); + } + + // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "a", &info) => 0; + assert(strcmp(info.name, "a") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "b", &info) => 0; + assert(strcmp(info.name, "b") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "c", &info) => 0; + assert(strcmp(info.name, "c") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "d", &info) => 0; + assert(strcmp(info.name, "d") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "e", &info) => 0; + assert(strcmp(info.name, "e") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "f", &info) => 0; + assert(strcmp(info.name, "f") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + + // check the directory order + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "a") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "b") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "c") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "d") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "e") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "f") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dirs_ordering_length] +# ORDER=0 => inorder +# ORDER=1 => reversed +# ORDER=2 => random +defines.ORDER = [0, 1, 2] +defines.REMOUNT = [false, true] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (ORDER == 0) { + lfsr_mkdir(&lfs, "a") => 0; + lfsr_mkdir(&lfs, "aa") => 0; + lfsr_mkdir(&lfs, "aaa") => 0; + lfsr_mkdir(&lfs, "aaaa") => 0; + lfsr_mkdir(&lfs, "aaaaa") => 0; + lfsr_mkdir(&lfs, "aaaaaa") => 0; + } else if (ORDER == 1) { + lfsr_mkdir(&lfs, "aaaaaa") => 0; + lfsr_mkdir(&lfs, "aaaaa") => 0; + lfsr_mkdir(&lfs, "aaaa") => 0; + lfsr_mkdir(&lfs, "aaa") => 0; + lfsr_mkdir(&lfs, "aa") => 0; + lfsr_mkdir(&lfs, "a") => 0; + } else if (ORDER == 2) { + // "random", trust me + lfsr_mkdir(&lfs, "aaaaa") => 0; + lfsr_mkdir(&lfs, "aaa") => 0; + lfsr_mkdir(&lfs, "aa") => 0; + lfsr_mkdir(&lfs, "aaaa") => 0; + lfsr_mkdir(&lfs, "aaaaaa") => 0; + lfsr_mkdir(&lfs, "a") => 0; + } + + // remount? + if (REMOUNT) { + lfsr_unmount(&lfs) => 0; + lfsr_mount(&lfs, CFG) => 0; + // grm should be zero here + assert(lfs.grm_g[0] == 0); + } + + // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "a", &info) => 0; + assert(strcmp(info.name, "a") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "aa", &info) => 0; + assert(strcmp(info.name, "aa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "aaa", &info) => 0; + assert(strcmp(info.name, "aaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "aaaa", &info) => 0; + assert(strcmp(info.name, "aaaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "aaaaa", &info) => 0; + assert(strcmp(info.name, "aaaaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_stat(&lfs, "aaaaaa", &info) => 0; + assert(strcmp(info.name, "aaaaaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + + // check the directory order + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "a") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "aa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "aaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "aaaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "aaaaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "aaaaaa") == 0); + assert(info.type == LFS_TYPE_DIR); + assert(info.size == 0); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + + # test that did collisions don't cause issues [cases.test_dirs_did_collisions] defines.REMOUNT = [false, true]