1 | """ |
---|
2 | Verify certain results against test vectors with well-known results. |
---|
3 | """ |
---|
4 | |
---|
5 | from __future__ import annotations |
---|
6 | |
---|
7 | from functools import partial |
---|
8 | from typing import AsyncGenerator, Iterator |
---|
9 | from itertools import starmap, product |
---|
10 | |
---|
11 | from attrs import evolve |
---|
12 | |
---|
13 | from pytest import mark |
---|
14 | from pytest_twisted import ensureDeferred |
---|
15 | |
---|
16 | from . import vectors |
---|
17 | from .vectors import parameters |
---|
18 | from .util import upload |
---|
19 | from .grid import Client |
---|
20 | |
---|
21 | @mark.parametrize('convergence', parameters.CONVERGENCE_SECRETS) |
---|
22 | def test_convergence(convergence): |
---|
23 | """ |
---|
24 | Convergence secrets are 16 bytes. |
---|
25 | """ |
---|
26 | assert isinstance(convergence, bytes), "Convergence secret must be bytes" |
---|
27 | assert len(convergence) == 16, "Convergence secret must by 16 bytes" |
---|
28 | |
---|
29 | |
---|
30 | @mark.slow |
---|
31 | @mark.parametrize('case,expected', vectors.capabilities.items()) |
---|
32 | @ensureDeferred |
---|
33 | async def test_capability(reactor, request, alice, case, expected): |
---|
34 | """ |
---|
35 | The capability that results from uploading certain well-known data |
---|
36 | with certain well-known parameters results in exactly the previously |
---|
37 | computed value. |
---|
38 | """ |
---|
39 | # rewrite alice's config to match params and convergence |
---|
40 | await alice.reconfigure_zfec( |
---|
41 | reactor, (1, case.params.required, case.params.total), case.convergence, case.segment_size) |
---|
42 | |
---|
43 | # upload data in the correct format |
---|
44 | actual = upload(alice, case.fmt, case.data) |
---|
45 | |
---|
46 | # compare the resulting cap to the expected result |
---|
47 | assert actual == expected |
---|
48 | |
---|
49 | |
---|
50 | @ensureDeferred |
---|
51 | async def skiptest_generate(reactor, request, alice): |
---|
52 | """ |
---|
53 | This is a helper for generating the test vectors. |
---|
54 | |
---|
55 | You can re-generate the test vectors by fixing the name of the test and |
---|
56 | running it. Normally this test doesn't run because it ran once and we |
---|
57 | captured its output. Other tests run against that output and we want them |
---|
58 | to run against the results produced originally, not a possibly |
---|
59 | ever-changing set of outputs. |
---|
60 | """ |
---|
61 | space = starmap( |
---|
62 | # segment_size could be a parameter someday but it's not easy to vary |
---|
63 | # using the Python implementation so it isn't one for now. |
---|
64 | partial(vectors.Case, segment_size=parameters.SEGMENT_SIZE), |
---|
65 | product( |
---|
66 | parameters.ZFEC_PARAMS, |
---|
67 | parameters.CONVERGENCE_SECRETS, |
---|
68 | parameters.OBJECT_DESCRIPTIONS, |
---|
69 | parameters.FORMATS, |
---|
70 | ), |
---|
71 | ) |
---|
72 | iterresults = generate(reactor, request, alice, space) |
---|
73 | |
---|
74 | results = [] |
---|
75 | async for result in iterresults: |
---|
76 | # Accumulate the new result |
---|
77 | results.append(result) |
---|
78 | # Then rewrite the whole output file with the new accumulator value. |
---|
79 | # This means that if we fail partway through, we will still have |
---|
80 | # recorded partial results -- instead of losing them all. |
---|
81 | vectors.save_capabilities(results) |
---|
82 | |
---|
83 | async def generate( |
---|
84 | reactor, |
---|
85 | request, |
---|
86 | alice: Client, |
---|
87 | cases: Iterator[vectors.Case], |
---|
88 | ) -> AsyncGenerator[[vectors.Case, str], None]: |
---|
89 | """ |
---|
90 | Generate all of the test vectors using the given node. |
---|
91 | |
---|
92 | :param reactor: The reactor to use to restart the Tahoe-LAFS node when it |
---|
93 | needs to be reconfigured. |
---|
94 | |
---|
95 | :param request: The pytest request object to use to arrange process |
---|
96 | cleanup. |
---|
97 | |
---|
98 | :param format: The name of the encryption/data format to use. |
---|
99 | |
---|
100 | :param alice: The Tahoe-LAFS node to use to generate the test vectors. |
---|
101 | |
---|
102 | :param case: The inputs for which to generate a value. |
---|
103 | |
---|
104 | :return: The capability for the case. |
---|
105 | """ |
---|
106 | # Share placement doesn't affect the resulting capability. For maximum |
---|
107 | # reliability of this generator, be happy if we can put shares anywhere |
---|
108 | happy = 1 |
---|
109 | for case in cases: |
---|
110 | await alice.reconfigure_zfec( |
---|
111 | reactor, |
---|
112 | (happy, case.params.required, case.params.total), |
---|
113 | case.convergence, |
---|
114 | case.segment_size |
---|
115 | ) |
---|
116 | |
---|
117 | # Give the format a chance to make an RSA key if it needs it. |
---|
118 | case = evolve(case, fmt=case.fmt.customize()) |
---|
119 | cap = upload(alice.process, case.fmt, case.data) |
---|
120 | yield case, cap |
---|