Sfoglia il codice sorgente

Migrated bad-block tests

Even with adding better reentrance testing, the bad-block tests are
still very useful at isolating the block eviction logic.

This also required rewriting a bit of the internal testing wirework
to allow custom block devices which opens up quite a bit more straegies
for testing.
Christopher Haster 6 anni fa
parent
commit
ecc2857c0e
2 ha cambiato i file con 470 aggiunte e 29 eliminazioni
  1. 95 29
      scripts/test_.py
  2. 375 0
      tests_/test_badblocks.toml

+ 95 - 29
scripts/test_.py

@@ -19,6 +19,7 @@
 # x config chaining correct
 # - why can't gdb see my defines?
 # - say no to internal?
+# - buffering stdout issues?
 
 import toml
 import glob
@@ -55,8 +56,79 @@ GLOBALS = """
 #include "filebd/lfs_filebd.h"
 #include "rambd/lfs_rambd.h"
 #include <stdio.h>
+
+extern const char *lfs_testbd_disk;
+typedef union {
+    lfs_filebd_t filebd;
+    lfs_rambd_t rambd;
+} lfs_testbd_t; 
+struct lfs_testbd_config {
+    struct lfs_filebd_config filecfg;
+    struct lfs_rambd_config ramcfg;
+};
+
+__attribute__((unused))
+static int lfs_testbd_createcfg(const struct lfs_config *cfg,
+        const struct lfs_testbd_config *bdcfg) {
+    if (lfs_testbd_disk) {
+        return lfs_filebd_createcfg(cfg, lfs_testbd_disk, &bdcfg->filecfg);
+    } else {
+        return lfs_rambd_createcfg(cfg, &bdcfg->ramcfg);
+    }
+}
+
+__attribute__((unused))
+static void lfs_testbd_destroy(const struct lfs_config *cfg) {
+    if (lfs_testbd_disk) {
+        lfs_filebd_destroy(cfg);
+    } else {
+        lfs_rambd_destroy(cfg);
+    }
+}
+
+__attribute__((unused))
+static int lfs_testbd_read(const struct lfs_config *cfg, lfs_block_t block,
+        lfs_off_t off, void *buffer, lfs_size_t size) {
+    if (lfs_testbd_disk) {
+        return lfs_filebd_read(cfg, block, off, buffer, size);
+    } else {
+        return lfs_rambd_read(cfg, block, off, buffer, size);
+    }
+}
+
+__attribute__((unused))
+static int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block,
+        lfs_off_t off, const void *buffer, lfs_size_t size) {
+    if (lfs_testbd_disk) {
+        return lfs_filebd_prog(cfg, block, off, buffer, size);
+    } else {
+        return lfs_rambd_prog(cfg, block, off, buffer, size);
+    }
+}
+
+__attribute__((unused))
+static int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) {
+    if (lfs_testbd_disk) {
+        return lfs_filebd_erase(cfg, block);
+    } else {
+        return lfs_rambd_erase(cfg, block);
+    }
+}
+
+__attribute__((unused))
+static int lfs_testbd_sync(const struct lfs_config *cfg) {
+    if (lfs_testbd_disk) {
+        return lfs_filebd_sync(cfg);
+    } else {
+        return lfs_rambd_sync(cfg);
+    }
+}
 """
 DEFINES = {
+    "LFS_BD_READ": "lfs_testbd_read",
+    "LFS_BD_PROG": "lfs_testbd_prog",
+    "LFS_BD_ERASE": "lfs_testbd_erase",
+    "LFS_BD_SYNC": "lfs_testbd_sync",
     "LFS_READ_SIZE": 16,
     "LFS_PROG_SIZE": "LFS_READ_SIZE",
     "LFS_BLOCK_SIZE": 512,
@@ -68,11 +140,8 @@ DEFINES = {
 }
 PROLOGUE = """
     // prologue
-    extern const char *LFS_DISK;
-
     __attribute__((unused)) lfs_t lfs;
-    __attribute__((unused)) lfs_filebd_t filebd;
-    __attribute__((unused)) lfs_rambd_t rambd;
+    __attribute__((unused)) lfs_testbd_t bd;
     __attribute__((unused)) lfs_file_t file;
     __attribute__((unused)) lfs_dir_t dir;
     __attribute__((unused)) struct lfs_info info;
@@ -82,12 +151,11 @@ PROLOGUE = """
     __attribute__((unused)) int err;
     
     __attribute__((unused)) const struct lfs_config cfg = {
-        .context = LFS_DISK ? (void*)&filebd : (void*)&rambd,
-        .read  = LFS_DISK ? &lfs_filebd_read  : &lfs_rambd_read,
-        .prog  = LFS_DISK ? &lfs_filebd_prog  : &lfs_rambd_prog,
-        .erase = LFS_DISK ? &lfs_filebd_erase : &lfs_rambd_erase,
-        .sync  = LFS_DISK ? &lfs_filebd_sync  : &lfs_rambd_sync,
-
+        .context        = &bd,
+        .read           = LFS_BD_READ,
+        .prog           = LFS_BD_PROG,
+        .erase          = LFS_BD_ERASE,
+        .sync           = LFS_BD_SYNC,
         .read_size      = LFS_READ_SIZE,
         .prog_size      = LFS_PROG_SIZE,
         .block_size     = LFS_BLOCK_SIZE,
@@ -97,26 +165,16 @@ PROLOGUE = """
         .lookahead_size = LFS_LOOKAHEAD_SIZE,
     };
 
-    __attribute__((unused)) const struct lfs_filebd_config filecfg = {
-        .erase_value = LFS_ERASE_VALUE,
-    };
-    __attribute__((unused)) const struct lfs_rambd_config ramcfg = {
-        .erase_value = LFS_ERASE_VALUE,
+    __attribute__((unused)) const struct lfs_testbd_config bdcfg = {
+        .filecfg.erase_value = LFS_ERASE_VALUE,
+        .ramcfg.erase_value = LFS_ERASE_VALUE,
     };
 
-    if (LFS_DISK) {
-        lfs_filebd_createcfg(&cfg, LFS_DISK, &filecfg);
-    } else {
-        lfs_rambd_createcfg(&cfg, &ramcfg);
-    }
+    lfs_testbd_createcfg(&cfg, &bdcfg) => 0;
 """
 EPILOGUE = """
     // epilogue
-    if (LFS_DISK) {
-        lfs_filebd_destroy(&cfg);
-    } else {
-        lfs_rambd_destroy(&cfg);
-    }
+    lfs_testbd_destroy(&cfg);
 """
 PASS = '\033[32m✓\033[0m'
 FAIL = '\033[31m✗\033[0m'
@@ -363,15 +421,20 @@ class TestSuite:
                 if re.match(r'code\s*=\s*(\'\'\'|""")', line):
                     code_linenos.append(i+2)
 
+            code_linenos.reverse()
+
         # grab global config
         self.defines = config.get('define', {})
+        self.code = config.get('code', None)
+        if self.code is not None:
+            self.code_lineno = code_linenos.pop()
 
         # create initial test cases
         self.cases = []
         for i, (case, lineno) in enumerate(zip(config['case'], linenos)):
             # code lineno?
             if 'code' in case:
-                case['code_lineno'] = code_linenos.pop(0)
+                case['code_lineno'] = code_linenos.pop()
             # give our case's config a copy of our "global" config
             for k, v in config.items():
                 if k not in case:
@@ -452,8 +515,11 @@ class TestSuite:
         # build test files
         tf = open(self.path + '.test.c.t', 'w')
         tf.write(GLOBALS)
-        tfs = {None: tf}
+        if self.code is not None:
+            tf.write('#line %d "%s"\n' % (self.code_lineno, self.path))
+            tf.write(self.code)
 
+        tfs = {None: tf}
         for case in self.cases:
             if case.in_ not in tfs:
                 tfs[case.in_] = open(self.path+'.'+
@@ -469,11 +535,11 @@ class TestSuite:
             case.build(tfs[case.in_], **args)
 
         tf.write('\n')
-        tf.write('const char *LFS_DISK = NULL;\n')
+        tf.write('const char *lfs_testbd_disk;\n')
         tf.write('int main(int argc, char **argv) {\n')
         tf.write(4*' '+'int case_ = (argc >= 2) ? atoi(argv[1]) : 0;\n')
         tf.write(4*' '+'int perm = (argc >= 3) ? atoi(argv[2]) : 0;\n')
-        tf.write(4*' '+'LFS_DISK = (argc >= 4) ? argv[3] : NULL;\n')
+        tf.write(4*' '+'lfs_testbd_disk = (argc >= 4) ? argv[3] : NULL;\n')
         for perm in self.perms:
             # test declaration
             tf.write(4*' '+'extern void test_case%d(%s);\n' % (

+ 375 - 0
tests_/test_badblocks.toml

@@ -0,0 +1,375 @@
+# special bad-block block device hook for simulating blocks
+# that are no longer writable
+code = '''
+lfs_block_t *bbbd_badblocks;
+size_t bbbd_badblocks_count;
+
+int bbbd_read(const struct lfs_config *c, lfs_block_t block,
+        lfs_off_t off, void *buffer, lfs_size_t size) {
+    for (size_t i = 0; i < bbbd_badblocks_count; i++) {
+        if (bbbd_badblocks[i] == block) {
+            return LFS_ERR_CORRUPT;
+        }
+    }
+
+    return lfs_testbd_read(c, block, off, buffer, size);
+}
+
+int bbbd_prog(const struct lfs_config *c, lfs_block_t block,
+        lfs_off_t off, const void *buffer, lfs_size_t size) {
+    for (size_t i = 0; i < bbbd_badblocks_count; i++) {
+        if (bbbd_badblocks[i] == block) {
+            return LFS_ERR_CORRUPT;
+        }
+    }
+
+    return lfs_testbd_prog(c, block, off, buffer, size);
+}
+
+int bbbd_erase(const struct lfs_config *c, lfs_block_t block) {
+    for (size_t i = 0; i < bbbd_badblocks_count; i++) {
+        if (bbbd_badblocks[i] == block) {
+            return LFS_ERR_CORRUPT;
+        }
+    }
+
+    return lfs_testbd_erase(c, block);
+}
+'''
+
+[[case]] # single bad blocks
+define.LFS_BD_PROG = 'bbbd_prog'
+define.NAMEMULT = 64
+define.FILEMULT = 1
+code = '''
+    for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) {
+        bbbd_badblocks = &(lfs_block_t){badblock};
+        bbbd_badblocks_count = 1;
+        
+        lfs_format(&lfs, &cfg) => 0;
+
+        lfs_mount(&lfs, &cfg) => 0;
+        for (int i = 1; i < 10; i++) {
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j] = '0'+i;
+            }
+            buffer[NAMEMULT] = '\0';
+            lfs_mkdir(&lfs, (char*)buffer) => 0;
+
+            buffer[NAMEMULT] = '/';
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j+NAMEMULT+1] = '0'+i;
+            }
+            buffer[2*NAMEMULT+1] = '\0';
+            lfs_file_open(&lfs, &file, (char*)buffer,
+                    LFS_O_WRONLY | LFS_O_CREAT) => 0;
+            
+            size = NAMEMULT;
+            for (int j = 0; j < i*FILEMULT; j++) {
+                lfs_file_write(&lfs, &file, buffer, size) => size;
+            }
+
+            lfs_file_close(&lfs, &file) => 0;
+        }
+        lfs_unmount(&lfs) => 0;
+
+        lfs_mount(&lfs, &cfg) => 0;
+        for (int i = 1; i < 10; i++) {
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j] = '0'+i;
+            }
+            buffer[NAMEMULT] = '\0';
+            lfs_stat(&lfs, (char*)buffer, &info) => 0;
+            info.type => LFS_TYPE_DIR;
+
+            buffer[NAMEMULT] = '/';
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j+NAMEMULT+1] = '0'+i;
+            }
+            buffer[2*NAMEMULT+1] = '\0';
+            lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
+            
+            size = NAMEMULT;
+            for (int j = 0; j < i*FILEMULT; j++) {
+                uint8_t rbuffer[1024];
+                lfs_file_read(&lfs, &file, rbuffer, size) => size;
+                memcmp(buffer, rbuffer, size) => 0;
+            }
+
+            lfs_file_close(&lfs, &file) => 0;
+        }
+        lfs_unmount(&lfs) => 0;
+    }
+'''
+
+[[case]] # single persistent blocks (can't erase)
+define.LFS_BD_ERASE = 'bbbd_erase'
+define.NAMEMULT = 64
+define.FILEMULT = 1
+code = '''
+    for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) {
+        bbbd_badblocks = &(lfs_block_t){badblock};
+        bbbd_badblocks_count = 1;
+        
+        lfs_format(&lfs, &cfg) => 0;
+
+        lfs_mount(&lfs, &cfg) => 0;
+        for (int i = 1; i < 10; i++) {
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j] = '0'+i;
+            }
+            buffer[NAMEMULT] = '\0';
+            lfs_mkdir(&lfs, (char*)buffer) => 0;
+
+            buffer[NAMEMULT] = '/';
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j+NAMEMULT+1] = '0'+i;
+            }
+            buffer[2*NAMEMULT+1] = '\0';
+            lfs_file_open(&lfs, &file, (char*)buffer,
+                    LFS_O_WRONLY | LFS_O_CREAT) => 0;
+            
+            size = NAMEMULT;
+            for (int j = 0; j < i*FILEMULT; j++) {
+                lfs_file_write(&lfs, &file, buffer, size) => size;
+            }
+
+            lfs_file_close(&lfs, &file) => 0;
+        }
+        lfs_unmount(&lfs) => 0;
+
+        lfs_mount(&lfs, &cfg) => 0;
+        for (int i = 1; i < 10; i++) {
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j] = '0'+i;
+            }
+            buffer[NAMEMULT] = '\0';
+            lfs_stat(&lfs, (char*)buffer, &info) => 0;
+            info.type => LFS_TYPE_DIR;
+
+            buffer[NAMEMULT] = '/';
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j+NAMEMULT+1] = '0'+i;
+            }
+            buffer[2*NAMEMULT+1] = '\0';
+            lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
+            
+            size = NAMEMULT;
+            for (int j = 0; j < i*FILEMULT; j++) {
+                uint8_t rbuffer[1024];
+                lfs_file_read(&lfs, &file, rbuffer, size) => size;
+                memcmp(buffer, rbuffer, size) => 0;
+            }
+
+            lfs_file_close(&lfs, &file) => 0;
+        }
+        lfs_unmount(&lfs) => 0;
+    }
+'''
+
+[[case]] # single unreadable blocks (can't read)
+define.LFS_BD_READ = 'bbbd_read'
+define.NAMEMULT = 64
+define.FILEMULT = 1
+code = '''
+    for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) {
+        bbbd_badblocks = &(lfs_block_t){badblock};
+        bbbd_badblocks_count = 1;
+        
+        lfs_format(&lfs, &cfg) => 0;
+
+        lfs_mount(&lfs, &cfg) => 0;
+        for (int i = 1; i < 10; i++) {
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j] = '0'+i;
+            }
+            buffer[NAMEMULT] = '\0';
+            lfs_mkdir(&lfs, (char*)buffer) => 0;
+
+            buffer[NAMEMULT] = '/';
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j+NAMEMULT+1] = '0'+i;
+            }
+            buffer[2*NAMEMULT+1] = '\0';
+            lfs_file_open(&lfs, &file, (char*)buffer,
+                    LFS_O_WRONLY | LFS_O_CREAT) => 0;
+            
+            size = NAMEMULT;
+            for (int j = 0; j < i*FILEMULT; j++) {
+                lfs_file_write(&lfs, &file, buffer, size) => size;
+            }
+
+            lfs_file_close(&lfs, &file) => 0;
+        }
+        lfs_unmount(&lfs) => 0;
+
+        lfs_mount(&lfs, &cfg) => 0;
+        for (int i = 1; i < 10; i++) {
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j] = '0'+i;
+            }
+            buffer[NAMEMULT] = '\0';
+            lfs_stat(&lfs, (char*)buffer, &info) => 0;
+            info.type => LFS_TYPE_DIR;
+
+            buffer[NAMEMULT] = '/';
+            for (int j = 0; j < NAMEMULT; j++) {
+                buffer[j+NAMEMULT+1] = '0'+i;
+            }
+            buffer[2*NAMEMULT+1] = '\0';
+            lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
+            
+            size = NAMEMULT;
+            for (int j = 0; j < i*FILEMULT; j++) {
+                uint8_t rbuffer[1024];
+                lfs_file_read(&lfs, &file, rbuffer, size) => size;
+                memcmp(buffer, rbuffer, size) => 0;
+            }
+
+            lfs_file_close(&lfs, &file) => 0;
+        }
+        lfs_unmount(&lfs) => 0;
+    }
+'''
+
+[[case]] # region corruption (causes cascading failures)
+define.LFS_BD_PROG  = '"BADTYPE == 0 ? bbbd_prog  : lfs_testbd_prog "'
+define.LFS_BD_ERASE = '"BADTYPE == 1 ? bbbd_erase : lfs_testbd_erase"'
+define.LFS_BD_READ  = '"BADTYPE == 2 ? bbbd_read  : lfs_testbd_read "'
+define.BADTYPE = 'range(3)'
+define.NAMEMULT = 64
+define.FILEMULT = 1
+code = '''
+    bbbd_badblocks_count = LFS_BLOCK_COUNT/2;
+    bbbd_badblocks = malloc(bbbd_badblocks_count*sizeof(lfs_block_t));
+    for (size_t i = 0; i < bbbd_badblocks_count; i++) {
+        bbbd_badblocks[i] = i+2;
+    }
+    
+    lfs_format(&lfs, &cfg) => 0;
+
+    lfs_mount(&lfs, &cfg) => 0;
+    for (int i = 1; i < 10; i++) {
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j] = '0'+i;
+        }
+        buffer[NAMEMULT] = '\0';
+        lfs_mkdir(&lfs, (char*)buffer) => 0;
+
+        buffer[NAMEMULT] = '/';
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j+NAMEMULT+1] = '0'+i;
+        }
+        buffer[2*NAMEMULT+1] = '\0';
+        lfs_file_open(&lfs, &file, (char*)buffer,
+                LFS_O_WRONLY | LFS_O_CREAT) => 0;
+        
+        size = NAMEMULT;
+        for (int j = 0; j < i*FILEMULT; j++) {
+            lfs_file_write(&lfs, &file, buffer, size) => size;
+        }
+
+        lfs_file_close(&lfs, &file) => 0;
+    }
+    lfs_unmount(&lfs) => 0;
+
+    lfs_mount(&lfs, &cfg) => 0;
+    for (int i = 1; i < 10; i++) {
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j] = '0'+i;
+        }
+        buffer[NAMEMULT] = '\0';
+        lfs_stat(&lfs, (char*)buffer, &info) => 0;
+        info.type => LFS_TYPE_DIR;
+
+        buffer[NAMEMULT] = '/';
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j+NAMEMULT+1] = '0'+i;
+        }
+        buffer[2*NAMEMULT+1] = '\0';
+        lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
+        
+        size = NAMEMULT;
+        for (int j = 0; j < i*FILEMULT; j++) {
+            uint8_t rbuffer[1024];
+            lfs_file_read(&lfs, &file, rbuffer, size) => size;
+            memcmp(buffer, rbuffer, size) => 0;
+        }
+
+        lfs_file_close(&lfs, &file) => 0;
+    }
+    lfs_unmount(&lfs) => 0;
+
+    free(bbbd_badblocks);
+'''
+
+[[case]] # alternating corruption (causes cascading failures)
+define.LFS_BD_PROG  = '"BADTYPE == 0 ? bbbd_prog  : lfs_testbd_prog "'
+define.LFS_BD_ERASE = '"BADTYPE == 1 ? bbbd_erase : lfs_testbd_erase"'
+define.LFS_BD_READ  = '"BADTYPE == 2 ? bbbd_read  : lfs_testbd_read "'
+define.BADTYPE = 'range(3)'
+define.NAMEMULT = 64
+define.FILEMULT = 1
+code = '''
+    bbbd_badblocks_count = LFS_BLOCK_COUNT/2;
+    bbbd_badblocks = malloc(bbbd_badblocks_count*sizeof(lfs_block_t));
+    for (size_t i = 0; i < bbbd_badblocks_count; i++) {
+        bbbd_badblocks[i] = (2*i) + 2;
+    }
+    
+    lfs_format(&lfs, &cfg) => 0;
+
+    lfs_mount(&lfs, &cfg) => 0;
+    for (int i = 1; i < 10; i++) {
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j] = '0'+i;
+        }
+        buffer[NAMEMULT] = '\0';
+        lfs_mkdir(&lfs, (char*)buffer) => 0;
+
+        buffer[NAMEMULT] = '/';
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j+NAMEMULT+1] = '0'+i;
+        }
+        buffer[2*NAMEMULT+1] = '\0';
+        lfs_file_open(&lfs, &file, (char*)buffer,
+                LFS_O_WRONLY | LFS_O_CREAT) => 0;
+        
+        size = NAMEMULT;
+        for (int j = 0; j < i*FILEMULT; j++) {
+            lfs_file_write(&lfs, &file, buffer, size) => size;
+        }
+
+        lfs_file_close(&lfs, &file) => 0;
+    }
+    lfs_unmount(&lfs) => 0;
+
+    lfs_mount(&lfs, &cfg) => 0;
+    for (int i = 1; i < 10; i++) {
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j] = '0'+i;
+        }
+        buffer[NAMEMULT] = '\0';
+        lfs_stat(&lfs, (char*)buffer, &info) => 0;
+        info.type => LFS_TYPE_DIR;
+
+        buffer[NAMEMULT] = '/';
+        for (int j = 0; j < NAMEMULT; j++) {
+            buffer[j+NAMEMULT+1] = '0'+i;
+        }
+        buffer[2*NAMEMULT+1] = '\0';
+        lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
+        
+        size = NAMEMULT;
+        for (int j = 0; j < i*FILEMULT; j++) {
+            uint8_t rbuffer[1024];
+            lfs_file_read(&lfs, &file, rbuffer, size) => size;
+            memcmp(buffer, rbuffer, size) => 0;
+        }
+
+        lfs_file_close(&lfs, &file) => 0;
+    }
+    lfs_unmount(&lfs) => 0;
+
+    free(bbbd_badblocks);
+'''