1 | """ |
---|
2 | Tests for allmydata.codec. |
---|
3 | |
---|
4 | Ported to Python 3. |
---|
5 | """ |
---|
6 | |
---|
7 | import os |
---|
8 | from twisted.trial import unittest |
---|
9 | from twisted.python import log |
---|
10 | from allmydata.codec import CRSEncoder, CRSDecoder, parse_params |
---|
11 | import random |
---|
12 | from allmydata.util import mathutil |
---|
13 | |
---|
14 | class T(unittest.TestCase): |
---|
15 | def do_test(self, size, required_shares, max_shares, fewer_shares=None): |
---|
16 | data0s = [os.urandom(mathutil.div_ceil(size, required_shares)) for i in range(required_shares)] |
---|
17 | enc = CRSEncoder() |
---|
18 | enc.set_params(size, required_shares, max_shares) |
---|
19 | params = enc.get_params() |
---|
20 | assert params == (size, required_shares, max_shares) |
---|
21 | serialized_params = enc.get_serialized_params() |
---|
22 | self.assertEqual(parse_params(serialized_params), params) |
---|
23 | log.msg("params: %s" % (params,)) |
---|
24 | d = enc.encode(data0s) |
---|
25 | def _done_encoding_all(shares_and_shareids): |
---|
26 | (shares, shareids) = shares_and_shareids |
---|
27 | self.failUnlessEqual(len(shares), max_shares) |
---|
28 | self.shares = shares |
---|
29 | self.shareids = shareids |
---|
30 | d.addCallback(_done_encoding_all) |
---|
31 | if fewer_shares is not None: |
---|
32 | # also validate that the desired_shareids= parameter works |
---|
33 | desired_shareids = random.sample(list(range(max_shares)), fewer_shares) |
---|
34 | d.addCallback(lambda res: enc.encode(data0s, desired_shareids)) |
---|
35 | def _check_fewer_shares(some_shares_and_their_shareids): |
---|
36 | (some_shares, their_shareids) = some_shares_and_their_shareids |
---|
37 | self.failUnlessEqual(tuple(their_shareids), tuple(desired_shareids)) |
---|
38 | d.addCallback(_check_fewer_shares) |
---|
39 | |
---|
40 | def _decode(shares_and_shareids): |
---|
41 | (shares, shareids) = shares_and_shareids |
---|
42 | dec = CRSDecoder() |
---|
43 | dec.set_params(*params) |
---|
44 | d1 = dec.decode(shares, shareids) |
---|
45 | return d1 |
---|
46 | |
---|
47 | def _check_data(decoded_shares): |
---|
48 | self.failUnlessEqual(len(b''.join(decoded_shares)), len(b''.join(data0s))) |
---|
49 | self.failUnlessEqual(len(decoded_shares), len(data0s)) |
---|
50 | for (i, (x, y)) in enumerate(zip(data0s, decoded_shares)): |
---|
51 | self.failUnlessEqual(x, y, "%s: %r != %r.... first share was %r" % (str(i), x, y, data0s[0],)) |
---|
52 | self.failUnless(b''.join(decoded_shares) == b''.join(data0s), "%s" % ("???",)) |
---|
53 | # 0data0sclipped = tuple(data0s) |
---|
54 | # data0sclipped[-1] = |
---|
55 | # self.failUnless(tuple(decoded_shares) == tuple(data0s)) |
---|
56 | |
---|
57 | def _decode_some(res): |
---|
58 | log.msg("_decode_some") |
---|
59 | # decode with a minimal subset of the shares |
---|
60 | some_shares = self.shares[:required_shares] |
---|
61 | some_shareids = self.shareids[:required_shares] |
---|
62 | return _decode((some_shares, some_shareids)) |
---|
63 | d.addCallback(_decode_some) |
---|
64 | d.addCallback(_check_data) |
---|
65 | |
---|
66 | def _decode_some_random(res): |
---|
67 | log.msg("_decode_some_random") |
---|
68 | # use a randomly-selected minimal subset |
---|
69 | l = random.sample(list(zip(self.shares, self.shareids)), required_shares) |
---|
70 | some_shares = [ x[0] for x in l ] |
---|
71 | some_shareids = [ x[1] for x in l ] |
---|
72 | return _decode((some_shares, some_shareids)) |
---|
73 | d.addCallback(_decode_some_random) |
---|
74 | d.addCallback(_check_data) |
---|
75 | |
---|
76 | def _decode_multiple(res): |
---|
77 | log.msg("_decode_multiple") |
---|
78 | # make sure we can re-use the decoder object |
---|
79 | shares1 = random.sample(self.shares, required_shares) |
---|
80 | sharesl1 = random.sample(list(zip(self.shares, self.shareids)), required_shares) |
---|
81 | shares1 = [ x[0] for x in sharesl1 ] |
---|
82 | shareids1 = [ x[1] for x in sharesl1 ] |
---|
83 | sharesl2 = random.sample(list(zip(self.shares, self.shareids)), required_shares) |
---|
84 | shares2 = [ x[0] for x in sharesl2 ] |
---|
85 | shareids2 = [ x[1] for x in sharesl2 ] |
---|
86 | dec = CRSDecoder() |
---|
87 | dec.set_params(*params) |
---|
88 | d1 = dec.decode(shares1, shareids1) |
---|
89 | d1.addCallback(_check_data) |
---|
90 | d1.addCallback(lambda res: dec.decode(shares2, shareids2)) |
---|
91 | d1.addCallback(_check_data) |
---|
92 | return d1 |
---|
93 | d.addCallback(_decode_multiple) |
---|
94 | |
---|
95 | return d |
---|
96 | |
---|
97 | def test_encode(self): |
---|
98 | return self.do_test(1000, 25, 100) |
---|
99 | |
---|
100 | def test_encode1(self): |
---|
101 | return self.do_test(8, 8, 16) |
---|
102 | |
---|
103 | def test_encode2(self): |
---|
104 | return self.do_test(125, 25, 100, 90) |
---|