From f4b17b379c2d7ce242928d626d942a941703113a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 12 Feb 2020 10:48:54 -0600 Subject: [PATCH] Added test.py support for tmpfs-backed disks RAM-backed testing is faster than file-backed testing. This is why test.py uses rambd by default. So why add support for tmpfs-backed disks if we can already run tests in RAM? For reentrant testing. Under reentrant testing we simulate power-loss by forcefully exiting the test program at specific times. To make this power-loss meaningful, we need to persist the disk across these power-losses. However, it's interesting to note this persistence doesn't need to be actually backed by the filesystem. It may be possible to rearchitecture the tests to simulate power-loss a different way, by say, using coroutines or setjmp/longjmp to leave behind ongoing filesystem operations without terminating the program completely. But at this point, I think it's best to work with what we have. And simply putting the test disks into a tmpfs mount-point seems to work just fine. Note this does force serialization of the tests, which isn't required otherwise. Currently they are only serialized due to limitations in test.py. If a future change wants to perallelize the tests, it may need to rework RAM-backed reentrant tests. --- .travis.yml | 6 ++++++ scripts/test.py | 15 +++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4697b1..16d3f10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,12 @@ script: -Duser_provided_block_device_sync=NULL -include stdio.h" + # setup a ram-backed disk to speed up reentrant tests + - | + mkdir disks + sudo mount -t tmpfs -o size=100m tmpfs disks + export TFLAGS="$TFLAGS --disk=disks/disk" + # run tests - make clean test TFLAGS+="-nrk" diff --git a/scripts/test.py b/scripts/test.py index c662a76..018d0b2 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -200,22 +200,25 @@ class TestCase: return True def test(self, exec=[], persist=False, cycles=None, - gdb=False, failure=None, **args): + gdb=False, failure=None, disk=None, **args): # build command cmd = exec + ['./%s.test' % self.suite.path, repr(self.caseno), repr(self.permno)] # persist disk or keep in RAM for speed? if persist: + if not disk: + disk = self.suite.path + '.disk' if persist != 'noerase': try: - os.remove(self.suite.path + '.disk') + with open(disk, 'w') as f: + f.truncate(0) if args.get('verbose', False): - print('rm', self.suite.path + '.disk') + print('truncate --size=0', disk) except FileNotFoundError: pass - cmd.append(self.suite.path + '.disk') + cmd.append(disk) # simulate power-loss after n cycles? if cycles: @@ -704,8 +707,6 @@ def main(**args): stdout = perm.result.stdout[:-1] else: stdout = perm.result.stdout - if (not args.get('verbose', False) and len(stdout) > 5): - sys.stdout.write('...\n') for line in stdout[-5:]: sys.stdout.write(line) if perm.result.assert_: @@ -766,4 +767,6 @@ if __name__ == "__main__": help="Run non-leaky tests under valgrind to check for memory leaks.") parser.add_argument('-e', '--exec', default=[], type=lambda e: e.split(' '), help="Run tests with another executable prefixed on the command line.") + parser.add_argument('-d', '--disk', + help="Specify a file to use for persistent/reentrant tests.") sys.exit(main(**vars(parser.parse_args())))