mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-20 05:28:04 +00:00
test_mutable: add Roundtrip test, suitable for new share-mangling tests
This commit is contained in:
parent
9e460cd22e
commit
647734cd3b
@ -454,10 +454,14 @@ class Retrieve:
|
|||||||
# might produce a result.
|
# might produce a result.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _do_read(self, ss, peerid, storage_index, shnums, readv):
|
||||||
|
d = ss.callRemote("slot_readv", storage_index, shnums, readv)
|
||||||
|
return d
|
||||||
|
|
||||||
def _do_query(self, ss, peerid, storage_index, readsize):
|
def _do_query(self, ss, peerid, storage_index, readsize):
|
||||||
started = time.time()
|
started = time.time()
|
||||||
self._queries_outstanding.add(peerid)
|
self._queries_outstanding.add(peerid)
|
||||||
d = ss.callRemote("slot_readv", storage_index, [], [(0, readsize)])
|
d = self._do_read(ss, peerid, storage_index, [], [(0, readsize)])
|
||||||
d.addCallback(self._got_results, peerid, readsize, (ss, storage_index),
|
d.addCallback(self._got_results, peerid, readsize, (ss, storage_index),
|
||||||
started)
|
started)
|
||||||
d.addErrback(self._query_failed, peerid)
|
d.addErrback(self._query_failed, peerid)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import itertools, struct
|
import itertools, struct
|
||||||
|
from cStringIO import StringIO
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.python import failure, log
|
from twisted.python import failure, log
|
||||||
@ -46,27 +47,56 @@ class FakeFilenode(mutable.MutableFileNode):
|
|||||||
self.all_contents[self.get_uri()] = newdata
|
self.all_contents[self.get_uri()] = newdata
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
|
|
||||||
|
class FakeStorage:
|
||||||
|
# this class replaces the collection of storage servers, allowing the
|
||||||
|
# tests to examine and manipulate the published shares. It also lets us
|
||||||
|
# control the order in which read queries are answered, to exercise more
|
||||||
|
# of the error-handling code in mutable.Retrieve .
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._peers = {}
|
||||||
|
|
||||||
|
def read(self, peerid, storage_index):
|
||||||
|
shares = self._peers.get(peerid, {})
|
||||||
|
return shares
|
||||||
|
|
||||||
|
def write(self, peerid, storage_index, shnum, offset, data):
|
||||||
|
if peerid not in self._peers:
|
||||||
|
self._peers[peerid] = {}
|
||||||
|
shares = self._peers[peerid]
|
||||||
|
f = StringIO()
|
||||||
|
f.write(shares.get(shnum, ""))
|
||||||
|
f.seek(offset)
|
||||||
|
f.write(data)
|
||||||
|
shares[shnum] = f.getvalue()
|
||||||
|
|
||||||
|
|
||||||
class FakePublish(mutable.Publish):
|
class FakePublish(mutable.Publish):
|
||||||
|
|
||||||
def _do_read(self, ss, peerid, storage_index, shnums, readv):
|
def _do_read(self, ss, peerid, storage_index, shnums, readv):
|
||||||
assert ss[0] == peerid
|
assert ss[0] == peerid
|
||||||
assert shnums == []
|
assert shnums == []
|
||||||
shares = self._peers[peerid]
|
return defer.succeed(self._storage.read(peerid, storage_index))
|
||||||
return defer.succeed(shares)
|
|
||||||
|
|
||||||
def _do_testreadwrite(self, peerid, secrets,
|
def _do_testreadwrite(self, peerid, secrets,
|
||||||
tw_vectors, read_vector):
|
tw_vectors, read_vector):
|
||||||
|
storage_index = self._node._uri.storage_index
|
||||||
# always-pass: parrot the test vectors back to them.
|
# always-pass: parrot the test vectors back to them.
|
||||||
readv = {}
|
readv = {}
|
||||||
for shnum, (testv, datav, new_length) in tw_vectors.items():
|
for shnum, (testv, writev, new_length) in tw_vectors.items():
|
||||||
for (offset, length, op, specimen) in testv:
|
for (offset, length, op, specimen) in testv:
|
||||||
assert op in ("le", "eq", "ge")
|
assert op in ("le", "eq", "ge")
|
||||||
readv[shnum] = [ specimen
|
readv[shnum] = [ specimen
|
||||||
for (offset, length, op, specimen)
|
for (offset, length, op, specimen)
|
||||||
in testv ]
|
in testv ]
|
||||||
|
for (offset, data) in writev:
|
||||||
|
self._storage.write(peerid, storage_index, shnum, offset, data)
|
||||||
answer = (True, readv)
|
answer = (True, readv)
|
||||||
return defer.succeed(answer)
|
return defer.succeed(answer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FakeNewDirectoryNode(dirnode.NewDirectoryNode):
|
class FakeNewDirectoryNode(dirnode.NewDirectoryNode):
|
||||||
filenode_class = FakeFilenode
|
filenode_class = FakeFilenode
|
||||||
|
|
||||||
@ -286,6 +316,7 @@ class Publish(unittest.TestCase):
|
|||||||
def setup_for_sharemap(self, num_peers):
|
def setup_for_sharemap(self, num_peers):
|
||||||
c = FakeClient(num_peers)
|
c = FakeClient(num_peers)
|
||||||
fn = FakeFilenode(c)
|
fn = FakeFilenode(c)
|
||||||
|
s = FakeStorage()
|
||||||
# .create usually returns a Deferred, but we happen to know it's
|
# .create usually returns a Deferred, but we happen to know it's
|
||||||
# synchronous
|
# synchronous
|
||||||
CONTENTS = "some initial contents"
|
CONTENTS = "some initial contents"
|
||||||
@ -295,9 +326,7 @@ class Publish(unittest.TestCase):
|
|||||||
p._new_seqnum = 3
|
p._new_seqnum = 3
|
||||||
p._read_size = 1000
|
p._read_size = 1000
|
||||||
#r = mutable.Retrieve(fn)
|
#r = mutable.Retrieve(fn)
|
||||||
p._peers = {}
|
p._storage = s
|
||||||
for peerid in c._peerids:
|
|
||||||
p._peers[peerid] = {}
|
|
||||||
return c, p
|
return c, p
|
||||||
|
|
||||||
def shouldFail(self, expected_failure, which, call, *args, **kwargs):
|
def shouldFail(self, expected_failure, which, call, *args, **kwargs):
|
||||||
@ -391,25 +420,44 @@ class Publish(unittest.TestCase):
|
|||||||
d.addCallback(_done)
|
d.addCallback(_done)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
class FakeRetrieve(mutable.Retrieve):
|
||||||
|
def _do_read(self, ss, peerid, storage_index, shnums, readv):
|
||||||
|
shares = self._storage.read(peerid, storage_index)
|
||||||
|
|
||||||
|
response = {}
|
||||||
|
for shnum in shares:
|
||||||
|
if shnums and shnum not in shnums:
|
||||||
|
continue
|
||||||
|
vector = response[shnum] = []
|
||||||
|
for (offset, length) in readv:
|
||||||
|
vector.append(shares[shnum][offset:offset+length])
|
||||||
|
return defer.succeed(response)
|
||||||
|
|
||||||
|
class Roundtrip(unittest.TestCase):
|
||||||
|
|
||||||
def setup_for_publish(self, num_peers):
|
def setup_for_publish(self, num_peers):
|
||||||
c = FakeClient(num_peers)
|
c = FakeClient(num_peers)
|
||||||
fn = FakeFilenode(c)
|
fn = FakeFilenode(c)
|
||||||
|
s = FakeStorage()
|
||||||
# .create usually returns a Deferred, but we happen to know it's
|
# .create usually returns a Deferred, but we happen to know it's
|
||||||
# synchronous
|
# synchronous
|
||||||
fn.create("")
|
fn.create("")
|
||||||
p = FakePublish(fn)
|
p = FakePublish(fn)
|
||||||
p._peers = {}
|
p._storage = s
|
||||||
for peerid in c._peerids:
|
|
||||||
p._peers[peerid] = {}
|
|
||||||
return c, fn, p
|
return c, fn, p
|
||||||
|
|
||||||
def test_publish(self):
|
def test_basic(self):
|
||||||
c, fn, p = self.setup_for_publish(20)
|
c, fn, p = self.setup_for_publish(20)
|
||||||
# make sure the length of our contents string is not a multiple of k,
|
contents = "New contents go here"
|
||||||
# to exercise the padding code.
|
d = p.publish(contents)
|
||||||
d = p.publish("New contents of the mutable filenode.")
|
def _published(res):
|
||||||
def _done(res):
|
|
||||||
# TODO: examine peers and check on their shares
|
# TODO: examine peers and check on their shares
|
||||||
pass
|
r = FakeRetrieve(fn)
|
||||||
d.addCallback(_done)
|
r._storage = p._storage
|
||||||
|
return r.retrieve()
|
||||||
|
d.addCallback(_published)
|
||||||
|
def _retrieved(new_contents):
|
||||||
|
self.failUnlessEqual(contents, new_contents)
|
||||||
|
d.addCallback(_retrieved)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user