You need to test your applications ability to handle i/o issues:
- Mock your storage layer. At what level? libc? Higher? How do I test i/o code then? 🤦
- LD_PRELOAD... Did you know glibc's fopen calls __open? What about io_uring interception? no_std? 🙄
- Stumble upon dmsetup. Loopback device, block device, block size, mke2fs, mount... 😮💨 suspend, reload, resume... what block offset is base.db at? AAAHH 😠 dmsetup message x123... Now your CD drive opens. What, heck, you still have that one? SMASH IT 👊 Calm down 😤 Proceeed to (4)
- Use Broken Fuse 😎
Broken Fuse is built on top of FUSE (Filesystem in userspace) and provides high-level io fault injection.
It is intended exclusively for testing, never use it for performance and security sensitive cases!
./brokenfuse /mnt/testfs
cd /mnt/testfs
echo 'works' > test.txt
cat test.tx
> works
Lets verify cat does indeed read our file and not just guess its content.
getfattr test.txt --only-values -n bk.stats
> {"reads":1,"read_volume":6,"writes":1,"write_volume":6,"errors":0}
Let's hold the 🐈⬛ back, reads only for now
setfattr test.txt -n bk.effect.delay -v '{"op":"r","millis":1000}'
time cat test.txt
> 1.0006 total
time (echo 'more text' >> test.txt)
> 0.001 total
Effects applied to parent folders are inherited. Let's complicate writing to our filesystem
setfattr . -n bk.effect.flakey -v '{"op":"w", "prob": 0.5}' # fail writes with 50% chance in folder
echo 'more text' >> test.txt
> echo: write error: Input/output error
echo 'more text' >> test.txt
>
Cool.