| 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) |
|---|