Ticket #999: test_backends.py

File test_backends.py, 7.6 KB (added by davidsarah, at 2011-09-29T17:14:08Z)

Snapshot of test_backends.py in David-Sarah's tree

Line 
1
2import mock
3from twisted.trial import unittest
4
5from allmydata.test.common_util import ReallyEqualMixin
6from allmydata.test.mock_s3 import MockS3Bucket
7
8# This is the code that we're going to be testing.
9from allmydata import node
10from allmydata.storage.server import StorageServer
11from allmydata.storage.backends.null.null_backend import NullBackend
12from allmydata.storage.backends.disk.disk_backend import DiskBackend, si_si2dir
13from allmydata.storage.backends.s3.s3_backend import S3Backend
14
15
16# The following share file content was generated with
17# storage.immutable.ShareFile from Tahoe-LAFS v1.8.2
18# with share data == 'a'. The total size of this input
19# is 85 bytes.
20shareversionnumber = '\x00\x00\x00\x01'
21sharedatalength = '\x00\x00\x00\x01'
22numberofleases = '\x00\x00\x00\x01'
23shareinputdata = 'a'
24ownernumber = '\x00\x00\x00\x00'
25renewsecret  = 'x'*32
26cancelsecret = 'y'*32
27expirationtime = '\x00(\xde\x80'
28nextlease = ''
29containerdata = shareversionnumber + sharedatalength + numberofleases
30client_data = shareinputdata + ownernumber + renewsecret + \
31    cancelsecret + expirationtime + nextlease
32share_data = containerdata + client_data
33testnodeid = 'testnodeidxxxxxxxxxx'
34
35
36class TestServerWithNullBackend(unittest.TestCase, ReallyEqualMixin):
37    """ NullBackend is just for testing and executable documentation, so
38    this test is actually a test of StorageServer in which we're using
39    NullBackend as helper code for the test, rather than a test of
40    NullBackend. """
41    def setUp(self):
42        self.ss = StorageServer(testnodeid, NullBackend())
43
44    @mock.patch('os.mkdir')
45    @mock.patch('__builtin__.open')
46    @mock.patch('os.listdir')
47    @mock.patch('os.path.isdir')
48    def test_write_share(self, mockisdir, mocklistdir, mockopen, mockmkdir):
49        """
50        Write a new share. This tests that StorageServer's remote_allocate_buckets
51        generates the correct return types when given test-vector arguments. That
52        bs is of the correct type is verified by attempting to invoke remote_write
53        on bs[0].
54        """
55        alreadygot, bs = self.ss.remote_allocate_buckets('teststorage_index', 'x'*32, 'y'*32, set((0,)), 1, mock.Mock())
56        bs[0].remote_write(0, 'a')
57        self.failIf(mockisdir.called)
58        self.failIf(mocklistdir.called)
59        self.failIf(mockopen.called)
60        self.failIf(mockmkdir.called)
61
62
63#class ServerWithS3Backend(Server):
64#    def create(self, name, reserved_space=0):
65#        workdir = self.workdir(name)
66#        s3bucket = MockS3Bucket(workdir)
67#        backend = S3Backend(s3bucket, readonly=False, reserved_space=reserved_space)
68#        ss = StorageServer("\x00" * 20, backend, workdir,
69#                           stats_provider=FakeStatsProvider())
70#        ss.setServiceParent(self.sparent)
71#        return ss
72
73
74#class ServerWithDiskBackend(Server):
75#    def create(self, name, reserved_space=0, klass=StorageServer):
76#        workdir = self.workdir(name)
77#        backend = DiskBackend(workdir)
78#        ss = StorageServer("\x00" * 20, backend, workdir,
79#                           stats_provider=FakeStatsProvider())
80#        ss.setServiceParent(self.sparent)
81#        return ss
82
83
84class Server(ReallyEqualMixin):
85    """ This tests the StorageServer with a given back-end. """
86    def set_up(self):
87        self.backend = DiskBackend(self.storedir)
88        self.ss = StorageServer(testnodeid, self.backend)
89
90        self.backendwithreserve = DiskBackend(self.storedir, reserved_space = 1)
91        self.sswithreserve = StorageServer(testnodeid, self.backendwithreserve)
92
93    @mock.patch('time.time')
94    def test_write_and_read_share(self, mocktime):
95        """
96        Write a new share, read it, and test the server's (and disk backend's)
97        handling of simultaneous and successive attempts to write the same
98        share.
99        """
100        mocktime.return_value = 0
101
102        shareset = self.ss.backend.get_shareset('teststorage_index')
103
104        self.failIf(shareset.has_incoming(0))
105
106        # Populate incoming with the sharenum: 0.
107        alreadygot, bs = self.ss.remote_allocate_buckets('teststorage_index', 'x'*32, 'y'*32, frozenset((0,)), 1, mock.Mock())
108
109        # This is a white-box test: Inspect incoming and fail unless the sharenum: 0 is listed there.
110        self.failUnless(shareset.has_incoming(0))
111
112        # Attempt to create a second share writer with the same sharenum.
113        alreadygota, bsa = self.ss.remote_allocate_buckets('teststorage_index', 'x'*32, 'y'*32, frozenset((0,)), 1, mock.Mock())
114
115        # Show that no sharewriter results from a remote_allocate_buckets
116        # with the same si and sharenum, until BucketWriter.remote_close()
117        # has been called.
118        self.failIf(bsa)
119
120        # Test allocated size.
121        spaceint = self.ss.allocated_size()
122        self.failUnlessReallyEqual(spaceint, 1)
123
124        # Write 'a' to shnum 0. Only tested together with close and read.
125        bs[0].remote_write(0, 'a')
126
127        # Preclose: Inspect final, failUnless nothing there.
128        self.failUnlessReallyEqual(len(list(self.backend.get_shares('teststorage_index'))), 0)
129        bs[0].remote_close()
130
131        # Postclose: (Omnibus) failUnless written data is in final.
132        sharesinfinal = list(self.backend.get_shares('teststorage_index'))
133        self.failUnlessReallyEqual(len(sharesinfinal), 1)
134        contents = sharesinfinal[0].read_share_data(0, 73)
135        self.failUnlessReallyEqual(contents, client_data)
136
137        # Exercise the case that the share we're asking to allocate is
138        # already (completely) uploaded.
139        self.ss.remote_allocate_buckets('teststorage_index', 'x'*32, 'y'*32, set((0,)), 1, mock.Mock())
140
141
142    def test_read_old_share(self):
143        """ This tests whether the code correctly finds and reads
144        shares written out by old (Tahoe-LAFS <= v1.8.2)
145        servers. There is a similar test in test_download, but that one
146        is from the perspective of the client and exercises a deeper
147        stack of code. This one is for exercising just the
148        StorageServer object. """
149        # Contruct a file with the appropriate contents in the mockfilesystem.
150        datalen = len(share_data)
151        finalhome = si_si2dir(self.basedir, 'teststorage_index').child(str(0))
152        finalhome.setContent(share_data)
153
154        # Now begin the test.
155        bs = self.ss.remote_get_buckets('teststorage_index')
156
157        self.failUnlessEqual(len(bs), 1)
158        b = bs['0']
159        # These should match by definition, the next two cases cover cases without (completely) unambiguous behaviors.
160        self.failUnlessReallyEqual(b.remote_read(0, datalen), client_data)
161        # If you try to read past the end you get the as much data as is there.
162        self.failUnlessReallyEqual(b.remote_read(0, datalen+20), client_data)
163        # If you start reading past the end of the file you get the empty string.
164        self.failUnlessReallyEqual(b.remote_read(datalen+1, 3), '')
165
166
167class MockConfigParser(object):
168    def __init__(self, configged_vals):
169        self.configged_vals = configged_vals
170    def read(self, fname):
171        pass
172    def getboolean(self, section, option):
173        raise NotImplementedError
174    def get(self, section, option):
175        return self.configged_vals[(section, option)]
176
177
178class TestConfigureBackends(ReallyEqualMixin, unittest.TestCase):
179    @mock.patch('ConfigParser.SafeConfigParser')
180    def test_configure_disk_backend_bad_reserved_space(self, mockCP):
181        mockCP.return_value = MockConfigParser({
182                ("storage", "backend"): "disk",
183                ("storage", "reserved_space"): "not a real answer",
184                })
185
186        self.failUnlessRaises(node.MissingConfigEntry, Client)