15 from subprocess
import run
17 from fake_http_server.fake_test_server
import FakeTestServerBackground
21 Run aktualizr provisioning and update cycles with random IO failures,
22 then retry the procedure and make sure the second attempt succeeds.
24 Right now, the executable should be aktualizr-cycle-simple which has
25 been fine-tuned for this test, but others can be adapted on the same
28 On a sample run, this test calls ~3000/4000 io syscalls, so it's recommended
29 to run with pf = 1/4000 = 0.00025, so that there should be around one error
30 per run, for around 4000*log(4000) ~= 50000 runs
31 (see https://en.wikipedia.org/wiki/Coupon_collector%27s_problem)
35 @contextlib.contextmanager
36 def uptane_repo(uptane_gen):
37 with tempfile.TemporaryDirectory()
as repo_path:
38 arepo = [uptane_gen,
'--keytype',
'ed25519']
39 run([*arepo,
'generate',
'--path', repo_path])
40 fw_path = path.join(repo_path,
'images/firmware.txt')
41 os.makedirs(path.join(repo_path,
'images'))
42 with open(fw_path,
'wb')
as f:
44 run([*arepo,
'image',
'--path', repo_path,
'--filename', fw_path,
45 '--targetname',
'firmware.txt'])
46 run([*arepo,
'addtarget',
'--path', repo_path,
'--targetname',
47 'firmware.txt',
'--hwid',
'primary_hw',
'--serial',
'CA:FE:A6:D2:84:9D'])
48 run([*arepo,
'signtargets',
'--path', repo_path])
52 def run_test(akt_test, server, srcdir, pf, k):
53 print(f
'Running test {k}')
54 with tempfile.TemporaryDirectory()
as storage_dir:
56 cp_err = run([
'fiu-run',
'-x',
'-c', f
'enable_random name=posix/io/*,probability={pf}',
57 akt_test, storage_dir, server],
58 stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=srcdir)
59 if cp_err.returncode == 0:
62 print(
'update failed, checking state')
63 cp = run([akt_test, storage_dir, server],
64 stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=srcdir)
65 if cp.returncode != 0:
66 error_state_dir = f
'fail_state.{path.basename(storage_dir)}'
67 print(f
'Error detected, see {error_state_dir}')
68 shutil.copytree(storage_dir, error_state_dir)
69 with open(path.join(error_state_dir,
'output1.log'),
'wb')
as f:
70 f.write(cp_err.stdout)
71 with open(path.join(error_state_dir,
'output2.log'),
'wb')
as f:
78 parser = argparse.ArgumentParser(description=
'Run io failure tests')
79 parser.add_argument(
'-n',
'--n-tests', type=int, default=100,
80 help=
'number of random tests to run')
81 parser.add_argument(
'-j',
'--jobs', type=int, default=1,
82 help=
'number of parallel tests')
83 parser.add_argument(
'-pf',
'--probability-failure', type=float, default=0.00025,
84 help=
'probability of syscall failure')
85 parser.add_argument(
'--akt-srcdir', help=
'path to the aktualizr source directory')
86 parser.add_argument(
'--uptane-gen', help=
'path to uptane-generator executable')
87 parser.add_argument(
'--akt-test', help=
'path to aktualizr cycle test')
88 parser.add_argument(
'--serve-only', action=
'store_true',
89 help=
'only serve metadata, do not run tests')
90 args = parser.parse_args()
92 srcdir = path.abspath(args.akt_srcdir)
if args.akt_srcdir
is not None else os.getcwd()
94 with uptane_repo(args.uptane_gen)
as repo_dir, \
95 FakeTestServerBackground(repo_dir, srcdir=srcdir)
as uptane_server, \
96 multiprocessing.Pool(args.jobs)
as pool:
98 server = f
'http://localhost:{uptane_server.port}'
99 print(f
'Running tests on {server} (repo directory: {repo_dir})')
106 fk = functools.partial(run_test, path.abspath(args.akt_test),
107 server, srcdir, args.probability_failure)
108 for r
in pool.imap(fk, range(1, args.n_tests+1)):
110 print(
'error found!')
117 if __name__ ==
'__main__':