test_mutable: add Roundtrip test, suitable for new share-mangling tests

This commit is contained in:
Brian Warner 2008-03-10 16:14:08 -07:00
parent 9e460cd22e
commit 647734cd3b
2 changed files with 69 additions and 17 deletions

View File

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

View File

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