mutable: improve NewDirectoryNode test coverage

This commit is contained in:
Brian Warner 2007-11-01 18:35:54 -07:00
parent d777283e9e
commit f1c3ff62c1
3 changed files with 97 additions and 20 deletions

View File

@ -4,7 +4,8 @@ from zope.interface import implements
from twisted.internet import defer
import simplejson
from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError
IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError, \
IVerifierURI
from allmydata.util import hashutil
from allmydata.util.hashutil import netstring
from allmydata.dirnode import IntegrityCheckError, FileNode
@ -55,7 +56,7 @@ class MutableFileNode:
return cmp(self.uri, them.uri)
def get_verifier(self):
return IMutableFileURI(self.uri).get_verifier()
return IMutableFileURI(self._uri).get_verifier()
def check(self):
verifier = self.get_verifier()
@ -162,7 +163,7 @@ class NewDirectoryNode:
return self._client.create_file_from_uri(u)
if IMutableFileURI.providedBy(u):
return self._client.create_mutable_file_from_uri(u)
raise TypeError("cannot handle URI")
raise TypeError("cannot handle '%s' URI" % (u.__class__,))
def _unpack_contents(self, data):
# the directory is serialized as a list of netstrings, one per child.
@ -216,6 +217,9 @@ class NewDirectoryNode:
def get_uri(self):
return self._uri.to_string()
def get_readonly(self):
return self._uri.get_readonly().to_string()
def get_immutable_uri(self):
return self._uri.get_readonly().to_string()
@ -242,7 +246,12 @@ class NewDirectoryNode:
"""I return a Deferred that fires with a specific named child node,
either an IFileNode or an IDirectoryNode."""
d = self._read()
d.addCallback(lambda children: children[name])
d.addCallback(lambda children: children[name][0])
return d
def get_metadata_for(self, name):
d = self._read()
d.addCallback(lambda children: children[name][1])
return d
def get_child_at_path(self, path):
@ -315,25 +324,34 @@ class NewDirectoryNode:
def delete(self, name):
"""I remove the child at the specific name. I return a Deferred that
fires when the operation finishes."""
fires (with the node just removed) when the operation finishes."""
if self.is_readonly():
return defer.fail(NotMutableError())
d = self._read()
def _delete(children):
old_child, metadata = children[name]
del children[name]
new_contents = self._pack_contents(children)
return self._node.replace(new_contents)
d = self._node.replace(new_contents)
def _done(res):
return old_child
d.addCallback(_done)
return d
d.addCallback(_delete)
d.addCallback(lambda res: None)
return d
def create_empty_directory(self, name):
"""I create and attach an empty directory at the given name. I return
a Deferred that fires when the operation finishes."""
a Deferred that fires (with the new directory node) when the
operation finishes."""
if self.is_readonly():
return defer.fail(NotMutableError())
d = self._client.create_empty_dirnode()
d.addCallback(lambda child: self.set_node(name, child))
def _created(child):
d = self.set_node(name, child)
d.addCallback(lambda res: child)
return d
d.addCallback(_created)
return d
def move_child_to(self, current_child_name, new_parent,
@ -368,7 +386,7 @@ class NewDirectoryNode:
# They indicate this by returning None from their get_verifier
# method. We need to remove any such Nones from our set. We also
# want to convert all these caps into strings.
return frozenset([cap.to_string()
return frozenset([IVerifierURI(cap).to_string()
for cap in manifest
if cap is not None])
d.addCallback(_done)
@ -378,7 +396,7 @@ class NewDirectoryNode:
d = node.list()
def _got_list(res):
dl = []
for name, child in res.iteritems():
for name, (child, metadata) in res.iteritems():
verifier = child.get_verifier()
if verifier not in manifest:
manifest.add(verifier)

View File

@ -1,4 +1,5 @@
import itertools
from twisted.trial import unittest
from twisted.internet import defer
@ -38,18 +39,23 @@ class Netstring(unittest.TestCase):
self.failUnlessEqual(bottom, ("hello", "world", "extra stuff"))
class FakeFilenode(mutable.MutableFileNode):
counter = itertools.count(1)
all_contents = {}
def init_from_uri(self, myuri):
self._uri = myuri
self.writekey = myuri.writekey
return self
def create(self, initial_contents):
self.contents = initial_contents
self.init_from_uri(uri.WriteableSSKFileURI("key", "fingerprint"))
count = self.counter.next()
self.init_from_uri(uri.WriteableSSKFileURI("key%d" % count,
"fingerprint%d" % count))
self.all_contents[self._uri] = initial_contents
return defer.succeed(None)
def download_to_data(self):
return defer.succeed(self.contents)
return defer.succeed(self.all_contents[self._uri])
def replace(self, newdata):
self.contents = newdata
self.all_contents[self._uri] = newdata
return defer.succeed(None)
def is_readonly(self):
return False
@ -116,6 +122,8 @@ class Dirnode(unittest.TestCase):
self.client = MyClient()
def test_create(self):
self.expected_manifest = []
d = self.client.create_empty_dirnode()
def _check(n):
self.failUnless(n.is_mutable())
@ -126,18 +134,60 @@ class Dirnode(unittest.TestCase):
self.failUnless(u_ro.startswith("URI:DIR2-RO:"), u_ro)
u_v = n.get_verifier()
self.failUnless(u_v.startswith("URI:DIR2-Verifier:"), u_v)
self.expected_manifest.append(u_v)
d = n.list()
d.addCallback(lambda res: self.failUnlessEqual(res, {}))
d.addCallback(lambda res: n.has_child("missing"))
d.addCallback(lambda res: self.failIf(res))
fake_file_uri = uri.WriteableSSKFileURI("a"*16,"b"*32)
ffu_v = fake_file_uri.get_verifier().to_string()
self.expected_manifest.append(ffu_v)
d.addCallback(lambda res: n.set_uri("child", fake_file_uri))
d.addCallback(lambda res: self.failUnlessEqual(res, None))
d.addCallback(lambda res: n.create_empty_directory("subdir"))
def _created(subdir):
self.failUnless(isinstance(subdir, FakeNewDirectoryNode))
self.subdir = subdir
new_v = subdir.get_verifier()
self.expected_manifest.append(new_v)
d.addCallback(_created)
d.addCallback(lambda res: n.list())
def _check_list(children):
self.failUnless("child" in children)
d.addCallback(_check_list)
d.addCallback(lambda children:
self.failUnlessEqual(sorted(children.keys()),
sorted(["child", "subdir"])))
d.addCallback(lambda res: n.build_manifest())
def _check_manifest(manifest):
self.failUnlessEqual(sorted(manifest),
sorted(self.expected_manifest))
d.addCallback(_check_manifest)
def _add_subsubdir(res):
return self.subdir.create_empty_directory("subsubdir")
d.addCallback(_add_subsubdir)
d.addCallback(lambda res: n.get_child_at_path("subdir/subsubdir"))
d.addCallback(lambda subsubdir:
self.failUnless(isinstance(subsubdir,
FakeNewDirectoryNode)))
d.addCallback(lambda res: n.get_child_at_path(""))
d.addCallback(lambda res: self.failUnlessEqual(res.get_uri(),
n.get_uri()))
d.addCallback(lambda res: n.get_metadata_for("child"))
d.addCallback(lambda metadata: self.failUnlessEqual(metadata, {}))
d.addCallback(lambda res: n.delete("subdir"))
d.addCallback(lambda old_child:
self.failUnlessEqual(old_child.get_uri(),
self.subdir.get_uri()))
d.addCallback(lambda res: n.list())
d.addCallback(lambda children:
self.failUnlessEqual(sorted(children.keys()),
sorted(["child"])))
return d

View File

@ -4,7 +4,7 @@ from zope.interface import implements
from twisted.python.components import registerAdapter
from allmydata.util import idlib, hashutil
from allmydata.interfaces import IURI, IDirnodeURI, IFileURI, IVerifierURI, \
IMutableFileURI
IMutableFileURI, INewDirectoryURI
# the URI shall be an ascii representation of the file. It shall contain
# enough information to retrieve and validate the contents. It shall be
@ -272,7 +272,7 @@ class SSKVerifierURI(_BaseURI):
idlib.b2a(self.fingerprint))
class NewDirectoryURI(_BaseURI):
implements(IURI, IDirnodeURI)
implements(IURI, IDirnodeURI, INewDirectoryURI)
def __init__(self, filenode_uri=None):
if filenode_uri:
@ -293,6 +293,9 @@ class NewDirectoryURI(_BaseURI):
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
return "URI:DIR2:" + bits
def get_filenode_uri(self):
return self._filenode_uri
def is_readonly(self):
return False
def is_mutable(self):
@ -324,6 +327,9 @@ class ReadonlyNewDirectoryURI(_BaseURI):
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
return "URI:DIR2-RO:" + bits
def get_filenode_uri(self):
return self._filenode_uri
def is_readonly(self):
return True
def is_mutable(self):
@ -355,6 +361,9 @@ class NewDirectoryURIVerifier(_BaseURI):
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
return "URI:DIR2-Verifier:" + bits
def get_filenode_uri(self):
return self._filenode_uri
class DirnodeURI(_BaseURI):