mirror of
https://gitee.com/openharmony/third_party_littlefs
synced 2025-03-02 04:38:17 +00:00

Moved .travis.yml over to use the new test framework. A part of this involved testing all of the configurations ran on the old framework and deciding which to carry over. The new framework duplicates some of the cases tested by the configurations so some configurations could be dropped. The .travis.yml includes some extreme ones, such as no inline files, relocations every cycle, no intrinsics, power-loss every byte, unaligned block_count and lookahead, and odd read_sizes. There were several configurations were some tests failed because of limitations in the tests themselves, so many conditions were added to make sure the configurations can run on as many tests as possible.
446 lines
14 KiB
TOML
446 lines
14 KiB
TOML
[[case]] # test running a filesystem to exhaustion
|
|
define.LFS_ERASE_CYCLES = 10
|
|
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
|
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
|
define.LFS_BADBLOCK_BEHAVIOR = [
|
|
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
|
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
|
'LFS_TESTBD_BADBLOCK_READERROR',
|
|
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
|
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
|
]
|
|
define.FILES = 10
|
|
code = '''
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_mkdir(&lfs, "roadrunner") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
uint32_t cycle = 0;
|
|
while (true) {
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// chose name, roughly random seed, and random 2^n size
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
|
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
|
|
assert(res == 1 || res == LFS_ERR_NOSPC);
|
|
if (res == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
err = lfs_file_close(&lfs, &file);
|
|
assert(err == 0 || err == LFS_ERR_NOSPC);
|
|
if (err == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
char r;
|
|
lfs_file_read(&lfs, &file, &r, 1) => 1;
|
|
assert(r == c);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
cycle += 1;
|
|
}
|
|
|
|
exhausted:
|
|
// should still be readable
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
lfs_stat(&lfs, path, &info) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
LFS_WARN("completed %d cycles", cycle);
|
|
'''
|
|
|
|
[[case]] # test running a filesystem to exhaustion
|
|
# which also requires expanding superblocks
|
|
define.LFS_ERASE_CYCLES = 10
|
|
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
|
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
|
define.LFS_BADBLOCK_BEHAVIOR = [
|
|
'LFS_TESTBD_BADBLOCK_PROGERROR',
|
|
'LFS_TESTBD_BADBLOCK_ERASEERROR',
|
|
'LFS_TESTBD_BADBLOCK_READERROR',
|
|
'LFS_TESTBD_BADBLOCK_PROGNOOP',
|
|
'LFS_TESTBD_BADBLOCK_ERASENOOP',
|
|
]
|
|
define.FILES = 10
|
|
code = '''
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
|
|
uint32_t cycle = 0;
|
|
while (true) {
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// chose name, roughly random seed, and random 2^n size
|
|
sprintf(path, "test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
|
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
|
|
assert(res == 1 || res == LFS_ERR_NOSPC);
|
|
if (res == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
err = lfs_file_close(&lfs, &file);
|
|
assert(err == 0 || err == LFS_ERR_NOSPC);
|
|
if (err == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
char r;
|
|
lfs_file_read(&lfs, &file, &r, 1) => 1;
|
|
assert(r == c);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
cycle += 1;
|
|
}
|
|
|
|
exhausted:
|
|
// should still be readable
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "test%d", i);
|
|
lfs_stat(&lfs, path, &info) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
LFS_WARN("completed %d cycles", cycle);
|
|
'''
|
|
|
|
# These are a sort of high-level litmus test for wear-leveling. One definition
|
|
# of wear-leveling is that increasing a block device's space translates directly
|
|
# into increasing the block devices lifetime. This is something we can actually
|
|
# check for.
|
|
|
|
[[case]] # wear-level test running a filesystem to exhaustion
|
|
define.LFS_ERASE_CYCLES = 20
|
|
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
|
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
|
define.FILES = 10
|
|
code = '''
|
|
uint32_t run_cycles[2];
|
|
const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT};
|
|
|
|
for (int run = 0; run < 2; run++) {
|
|
for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
|
|
lfs_testbd_setwear(&cfg, b,
|
|
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
|
|
}
|
|
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_mkdir(&lfs, "roadrunner") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
uint32_t cycle = 0;
|
|
while (true) {
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// chose name, roughly random seed, and random 2^n size
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
|
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
|
|
assert(res == 1 || res == LFS_ERR_NOSPC);
|
|
if (res == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
err = lfs_file_close(&lfs, &file);
|
|
assert(err == 0 || err == LFS_ERR_NOSPC);
|
|
if (err == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
char r;
|
|
lfs_file_read(&lfs, &file, &r, 1) => 1;
|
|
assert(r == c);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
cycle += 1;
|
|
}
|
|
|
|
exhausted:
|
|
// should still be readable
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
lfs_stat(&lfs, path, &info) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
run_cycles[run] = cycle;
|
|
LFS_WARN("completed %d blocks %d cycles",
|
|
run_block_count[run], run_cycles[run]);
|
|
}
|
|
|
|
// check we increased the lifetime by 2x with ~10% error
|
|
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
|
|
'''
|
|
|
|
[[case]] # wear-level test + expanding superblock
|
|
define.LFS_ERASE_CYCLES = 20
|
|
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
|
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
|
|
define.FILES = 10
|
|
code = '''
|
|
uint32_t run_cycles[2];
|
|
const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT};
|
|
|
|
for (int run = 0; run < 2; run++) {
|
|
for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
|
|
lfs_testbd_setwear(&cfg, b,
|
|
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
|
|
}
|
|
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
|
|
uint32_t cycle = 0;
|
|
while (true) {
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// chose name, roughly random seed, and random 2^n size
|
|
sprintf(path, "test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
|
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
|
|
assert(res == 1 || res == LFS_ERR_NOSPC);
|
|
if (res == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
err = lfs_file_close(&lfs, &file);
|
|
assert(err == 0 || err == LFS_ERR_NOSPC);
|
|
if (err == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << ((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
char r;
|
|
lfs_file_read(&lfs, &file, &r, 1) => 1;
|
|
assert(r == c);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
cycle += 1;
|
|
}
|
|
|
|
exhausted:
|
|
// should still be readable
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "test%d", i);
|
|
lfs_stat(&lfs, path, &info) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
run_cycles[run] = cycle;
|
|
LFS_WARN("completed %d blocks %d cycles",
|
|
run_block_count[run], run_cycles[run]);
|
|
}
|
|
|
|
// check we increased the lifetime by 2x with ~10% error
|
|
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
|
|
'''
|
|
|
|
[[case]] # test that we wear blocks roughly evenly
|
|
define.LFS_ERASE_CYCLES = 0xffffffff
|
|
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
|
|
define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1]
|
|
define.CYCLES = 100
|
|
define.FILES = 10
|
|
if = 'LFS_BLOCK_CYCLES < CYCLES/10'
|
|
code = '''
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_mkdir(&lfs, "roadrunner") => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
uint32_t cycle = 0;
|
|
while (cycle < CYCLES) {
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// chose name, roughly random seed, and random 2^n size
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << 4; //((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
|
|
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
|
|
assert(res == 1 || res == LFS_ERR_NOSPC);
|
|
if (res == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
err = lfs_file_close(&lfs, &file);
|
|
assert(err == 0 || err == LFS_ERR_NOSPC);
|
|
if (err == LFS_ERR_NOSPC) {
|
|
goto exhausted;
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
srand(cycle * i);
|
|
size = 1 << 4; //((rand() % 10)+2);
|
|
|
|
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
|
|
for (lfs_size_t j = 0; j < size; j++) {
|
|
char c = 'a' + (rand() % 26);
|
|
char r;
|
|
lfs_file_read(&lfs, &file, &r, 1) => 1;
|
|
assert(r == c);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
cycle += 1;
|
|
}
|
|
|
|
exhausted:
|
|
// should still be readable
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (uint32_t i = 0; i < FILES; i++) {
|
|
// check for errors
|
|
sprintf(path, "roadrunner/test%d", i);
|
|
lfs_stat(&lfs, path, &info) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
LFS_WARN("completed %d cycles", cycle);
|
|
|
|
// check the wear on our block device
|
|
lfs_testbd_wear_t minwear = -1;
|
|
lfs_testbd_wear_t totalwear = 0;
|
|
lfs_testbd_wear_t maxwear = 0;
|
|
// skip 0 and 1 as superblock movement is intentionally avoided
|
|
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) {
|
|
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b);
|
|
printf("%08x: wear %d\n", b, wear);
|
|
assert(wear >= 0);
|
|
if (wear < minwear) {
|
|
minwear = wear;
|
|
}
|
|
if (wear > maxwear) {
|
|
maxwear = wear;
|
|
}
|
|
totalwear += wear;
|
|
}
|
|
lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT;
|
|
LFS_WARN("max wear: %d cycles", maxwear);
|
|
LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT);
|
|
LFS_WARN("min wear: %d cycles", minwear);
|
|
|
|
// find standard deviation^2
|
|
lfs_testbd_wear_t dev2 = 0;
|
|
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) {
|
|
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b);
|
|
assert(wear >= 0);
|
|
lfs_testbd_swear_t diff = wear - avgwear;
|
|
dev2 += diff*diff;
|
|
}
|
|
dev2 /= totalwear;
|
|
LFS_WARN("std dev^2: %d", dev2);
|
|
assert(dev2 < 8);
|
|
'''
|
|
|