From 647734cd3b523371e7fe13d2e0d6a4512f1a71fc Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 10 Mar 2008 16:14:08 -0700 Subject: [PATCH] test_mutable: add Roundtrip test, suitable for new share-mangling tests --- src/allmydata/mutable.py | 6 ++- src/allmydata/test/test_mutable.py | 80 ++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/allmydata/mutable.py b/src/allmydata/mutable.py index e6a47227..5eb1b178 100644 --- a/src/allmydata/mutable.py +++ b/src/allmydata/mutable.py @@ -454,10 +454,14 @@ class Retrieve: # might produce a result. 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): started = time.time() 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), started) d.addErrback(self._query_failed, peerid) diff --git a/src/allmydata/test/test_mutable.py b/src/allmydata/test/test_mutable.py index 32ef820c..e1c2cd10 100644 --- a/src/allmydata/test/test_mutable.py +++ b/src/allmydata/test/test_mutable.py @@ -1,5 +1,6 @@ import itertools, struct +from cStringIO import StringIO from twisted.trial import unittest from twisted.internet import defer from twisted.python import failure, log @@ -46,27 +47,56 @@ class FakeFilenode(mutable.MutableFileNode): self.all_contents[self.get_uri()] = newdata 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): + def _do_read(self, ss, peerid, storage_index, shnums, readv): assert ss[0] == peerid assert shnums == [] - shares = self._peers[peerid] - return defer.succeed(shares) + return defer.succeed(self._storage.read(peerid, storage_index)) def _do_testreadwrite(self, peerid, secrets, tw_vectors, read_vector): + storage_index = self._node._uri.storage_index # always-pass: parrot the test vectors back to them. 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: assert op in ("le", "eq", "ge") readv[shnum] = [ specimen for (offset, length, op, specimen) in testv ] + for (offset, data) in writev: + self._storage.write(peerid, storage_index, shnum, offset, data) answer = (True, readv) return defer.succeed(answer) + + class FakeNewDirectoryNode(dirnode.NewDirectoryNode): filenode_class = FakeFilenode @@ -286,6 +316,7 @@ class Publish(unittest.TestCase): def setup_for_sharemap(self, num_peers): c = FakeClient(num_peers) fn = FakeFilenode(c) + s = FakeStorage() # .create usually returns a Deferred, but we happen to know it's # synchronous CONTENTS = "some initial contents" @@ -295,9 +326,7 @@ class Publish(unittest.TestCase): p._new_seqnum = 3 p._read_size = 1000 #r = mutable.Retrieve(fn) - p._peers = {} - for peerid in c._peerids: - p._peers[peerid] = {} + p._storage = s return c, p def shouldFail(self, expected_failure, which, call, *args, **kwargs): @@ -391,25 +420,44 @@ class Publish(unittest.TestCase): d.addCallback(_done) 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): c = FakeClient(num_peers) fn = FakeFilenode(c) + s = FakeStorage() # .create usually returns a Deferred, but we happen to know it's # synchronous fn.create("") p = FakePublish(fn) - p._peers = {} - for peerid in c._peerids: - p._peers[peerid] = {} + p._storage = s return c, fn, p - def test_publish(self): + def test_basic(self): c, fn, p = self.setup_for_publish(20) - # make sure the length of our contents string is not a multiple of k, - # to exercise the padding code. - d = p.publish("New contents of the mutable filenode.") - def _done(res): + contents = "New contents go here" + d = p.publish(contents) + def _published(res): # TODO: examine peers and check on their shares - pass - d.addCallback(_done) + r = FakeRetrieve(fn) + r._storage = p._storage + return r.retrieve() + d.addCallback(_published) + def _retrieved(new_contents): + self.failUnlessEqual(contents, new_contents) + d.addCallback(_retrieved) return d + -- 2.45.2