Ticket #999: sservertests.darcs.patch

File sservertests.darcs.patch, 8.8 KB (added by arch_o_median, at 2011-03-25T20:41:34Z)
Line 
1Fri Mar 25 14:35:14 MDT 2011  wilcoxjg@gmail.com
2  * storage: new mocking tests of storage server read and write
3  There are already tests of read and functionality in test_storage.py, but those tests let the code under test use a real filesystem whereas these tests mock all file system calls.
4
5New patches:
6
7[storage: new mocking tests of storage server read and write
8wilcoxjg@gmail.com**20110325203514
9 Ignore-this: df65c3c4f061dd1516f88662023fdb41
10 There are already tests of read and functionality in test_storage.py, but those tests let the code under test use a real filesystem whereas these tests mock all file system calls.
11] {
12addfile ./src/allmydata/test/test_server.py
13hunk ./src/allmydata/test/test_server.py 1
14+from twisted.trial import unittest
15+
16+from StringIO import StringIO
17+
18+from allmydata.test.common_util import ReallyEqualMixin
19+
20+import mock
21+
22+# This is the code that we're going to be testing.
23+from allmydata.storage.server import StorageServer
24+
25+# The following share file contents was generated with
26+# storage.immutable.ShareFile from Tahoe-LAFS v1.8.2
27+# with share data == 'a'.
28+share_data = 'a\x00\x00\x00\x00xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\x00(\xde\x80'
29+share_file_data = '\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01' + share_data
30+
31+sharefname = 'testdir/shares/or/orsxg5dtorxxeylhmvpws3temv4a/0'
32+
33+class TestServerConstruction(unittest.TestCase, ReallyEqualMixin):
34+    @mock.patch('__builtin__.open')
35+    def test_create_server(self, mockopen):
36+        """ This tests whether a server instance can be constructed. """
37+
38+        def call_open(fname, mode):
39+            if fname == 'testdir/bucket_counter.state':
40+                raise IOError(2, "No such file or directory: 'testdir/bucket_counter.state'")
41+            elif fname == 'testdir/lease_checker.state':
42+                raise IOError(2, "No such file or directory: 'testdir/lease_checker.state'")
43+            elif fname == 'testdir/lease_checker.history':
44+                return StringIO()
45+        mockopen.side_effect = call_open
46+
47+        # Now begin the test.
48+        s = StorageServer('testdir', 'testnodeidxxxxxxxxxx')
49+
50+        # You passed!
51+
52+class TestServer(unittest.TestCase, ReallyEqualMixin):
53+    @mock.patch('__builtin__.open')
54+    def setUp(self, mockopen):
55+        def call_open(fname, mode):
56+            if fname == 'testdir/bucket_counter.state':
57+                raise IOError(2, "No such file or directory: 'testdir/bucket_counter.state'")
58+            elif fname == 'testdir/lease_checker.state':
59+                raise IOError(2, "No such file or directory: 'testdir/lease_checker.state'")
60+            elif fname == 'testdir/lease_checker.history':
61+                return StringIO()
62+        mockopen.side_effect = call_open
63+
64+        self.s = StorageServer('testdir', 'testnodeidxxxxxxxxxx')
65+
66+
67+    @mock.patch('time.time')
68+    @mock.patch('os.mkdir')
69+    @mock.patch('__builtin__.open')
70+    @mock.patch('os.listdir')
71+    @mock.patch('os.path.isdir')
72+    def test_write_share(self, mockisdir, mocklistdir, mockopen, mockmkdir, mocktime):
73+        """Handle a report of corruption."""
74+
75+        def call_listdir(dirname):
76+            self.failUnlessReallyEqual(dirname, 'testdir/shares/or/orsxg5dtorxxeylhmvpws3temv4a')
77+            raise OSError(2, "No such file or directory: 'testdir/shares/or/orsxg5dtorxxeylhmvpws3temv4a'")
78+
79+        mocklistdir.side_effect = call_listdir
80+
81+        class MockFile:
82+            def __init__(self):
83+                self.buffer = ''
84+                self.pos = 0
85+            def write(self, instring):
86+                begin = self.pos
87+                padlen = begin - len(self.buffer)
88+                if padlen > 0:
89+                    self.buffer += '\x00' * padlen
90+                end = self.pos + len(instring)
91+                self.buffer = self.buffer[:begin]+instring+self.buffer[end:]
92+                self.pos = end
93+            def close(self):
94+                pass
95+            def seek(self, pos):
96+                self.pos = pos
97+            def read(self, numberbytes):
98+                return self.buffer[self.pos:self.pos+numberbytes]
99+            def tell(self):
100+                return self.pos
101+
102+        mocktime.return_value = 0
103+
104+        sharefile = MockFile()
105+        def call_open(fname, mode):
106+            self.failUnlessReallyEqual(fname, 'testdir/shares/incoming/or/orsxg5dtorxxeylhmvpws3temv4a/0' )
107+            return sharefile
108+
109+        mockopen.side_effect = call_open
110+        # Now begin the test.
111+        alreadygot, bs = self.s.remote_allocate_buckets('teststorage_index', 'x'*32, 'y'*32, set((0,)), 1, mock.Mock())
112+        print bs
113+        bs[0].remote_write(0, 'a')
114+        self.failUnlessReallyEqual(sharefile.buffer, share_file_data)
115+
116+
117+    @mock.patch('os.path.exists')
118+    @mock.patch('os.path.getsize')
119+    @mock.patch('__builtin__.open')
120+    @mock.patch('os.listdir')
121+    def test_read_share(self, mocklistdir, mockopen, mockgetsize, mockexists):
122+        """ This tests whether the code correctly finds and reads
123+        shares written out by old (Tahoe-LAFS <= v1.8.2)
124+        servers. There is a similar test in test_download, but that one
125+        is from the perspective of the client and exercises a deeper
126+        stack of code. This one is for exercising just the
127+        StorageServer object. """
128+
129+        def call_listdir(dirname):
130+            self.failUnlessReallyEqual(dirname,'testdir/shares/or/orsxg5dtorxxeylhmvpws3temv4a')
131+            return ['0']
132+
133+        mocklistdir.side_effect = call_listdir
134+
135+        def call_open(fname, mode):
136+            self.failUnlessReallyEqual(fname, sharefname)
137+            self.failUnless('r' in mode, mode)
138+            self.failUnless('b' in mode, mode)
139+
140+            return StringIO(share_file_data)
141+        mockopen.side_effect = call_open
142+
143+        datalen = len(share_file_data)
144+        def call_getsize(fname):
145+            self.failUnlessReallyEqual(fname, sharefname)
146+            return datalen
147+        mockgetsize.side_effect = call_getsize
148+
149+        def call_exists(fname):
150+            self.failUnlessReallyEqual(fname, sharefname)
151+            return True
152+        mockexists.side_effect = call_exists
153+
154+        # Now begin the test.
155+        bs = self.s.remote_get_buckets('teststorage_index')
156+
157+        self.failUnlessEqual(len(bs), 1)
158+        b = bs[0]
159+        self.failUnlessReallyEqual(b.remote_read(0, datalen), share_data)
160+        # If you try to read past the end you get the as much data as is there.
161+        self.failUnlessReallyEqual(b.remote_read(0, datalen+20), share_data)
162+        # If you start reading past the end of the file you get the empty string.
163+        self.failUnlessReallyEqual(b.remote_read(datalen+1, 3), '')
164}
165
166Context:
167
168[test: increase timeout on a network test because Francois's ARM machine hit that timeout
169zooko@zooko.com**20110317165909
170 Ignore-this: 380c345cdcbd196268ca5b65664ac85b
171 I'm skeptical that the test was proceeding correctly but ran out of time. It seems more likely that it had gotten hung. But if we raise the timeout to an even more extravagant number then we can be even more certain that the test was never going to finish.
172]
173[docs/configuration.rst: add a "Frontend Configuration" section
174Brian Warner <warner@lothar.com>**20110222014323
175 Ignore-this: 657018aa501fe4f0efef9851628444ca
176 
177 this points to docs/frontends/*.rst, which were previously underlinked
178]
179[web/filenode.py: avoid calling req.finish() on closed HTTP connections. Closes #1366
180"Brian Warner <warner@lothar.com>"**20110221061544
181 Ignore-this: 799d4de19933f2309b3c0c19a63bb888
182]
183[Add unit tests for cross_check_pkg_resources_versus_import, and a regression test for ref #1355. This requires a little refactoring to make it testable.
184david-sarah@jacaranda.org**20110221015817
185 Ignore-this: 51d181698f8c20d3aca58b057e9c475a
186]
187[allmydata/__init__.py: .name was used in place of the correct .__name__ when printing an exception. Also, robustify string formatting by using %r instead of %s in some places. fixes #1355.
188david-sarah@jacaranda.org**20110221020125
189 Ignore-this: b0744ed58f161bf188e037bad077fc48
190]
191[Refactor StorageFarmBroker handling of servers
192Brian Warner <warner@lothar.com>**20110221015804
193 Ignore-this: 842144ed92f5717699b8f580eab32a51
194 
195 Pass around IServer instance instead of (peerid, rref) tuple. Replace
196 "descriptor" with "server". Other replacements:
197 
198  get_all_servers -> get_connected_servers/get_known_servers
199  get_servers_for_index -> get_servers_for_psi (now returns IServers)
200 
201 This change still needs to be pushed further down: lots of code is now
202 getting the IServer and then distributing (peerid, rref) internally.
203 Instead, it ought to distribute the IServer internally and delay
204 extracting a serverid or rref until the last moment.
205 
206 no_network.py was updated to retain parallelism.
207]
208[TAG allmydata-tahoe-1.8.2
209warner@lothar.com**20110131020101]
210Patch bundle hash:
2117eccf95ba9716bac521b34cec4554836a7e5aa9f