mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-21 10:01:54 +00:00
mutable: improve NewDirectoryNode test coverage
This commit is contained in:
parent
d777283e9e
commit
f1c3ff62c1
@ -4,7 +4,8 @@ from zope.interface import implements
|
|||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
import simplejson
|
import simplejson
|
||||||
from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
|
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 import hashutil
|
||||||
from allmydata.util.hashutil import netstring
|
from allmydata.util.hashutil import netstring
|
||||||
from allmydata.dirnode import IntegrityCheckError, FileNode
|
from allmydata.dirnode import IntegrityCheckError, FileNode
|
||||||
@ -55,7 +56,7 @@ class MutableFileNode:
|
|||||||
return cmp(self.uri, them.uri)
|
return cmp(self.uri, them.uri)
|
||||||
|
|
||||||
def get_verifier(self):
|
def get_verifier(self):
|
||||||
return IMutableFileURI(self.uri).get_verifier()
|
return IMutableFileURI(self._uri).get_verifier()
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
verifier = self.get_verifier()
|
verifier = self.get_verifier()
|
||||||
@ -162,7 +163,7 @@ class NewDirectoryNode:
|
|||||||
return self._client.create_file_from_uri(u)
|
return self._client.create_file_from_uri(u)
|
||||||
if IMutableFileURI.providedBy(u):
|
if IMutableFileURI.providedBy(u):
|
||||||
return self._client.create_mutable_file_from_uri(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):
|
def _unpack_contents(self, data):
|
||||||
# the directory is serialized as a list of netstrings, one per child.
|
# the directory is serialized as a list of netstrings, one per child.
|
||||||
@ -216,6 +217,9 @@ class NewDirectoryNode:
|
|||||||
def get_uri(self):
|
def get_uri(self):
|
||||||
return self._uri.to_string()
|
return self._uri.to_string()
|
||||||
|
|
||||||
|
def get_readonly(self):
|
||||||
|
return self._uri.get_readonly().to_string()
|
||||||
|
|
||||||
def get_immutable_uri(self):
|
def get_immutable_uri(self):
|
||||||
return self._uri.get_readonly().to_string()
|
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,
|
"""I return a Deferred that fires with a specific named child node,
|
||||||
either an IFileNode or an IDirectoryNode."""
|
either an IFileNode or an IDirectoryNode."""
|
||||||
d = self._read()
|
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
|
return d
|
||||||
|
|
||||||
def get_child_at_path(self, path):
|
def get_child_at_path(self, path):
|
||||||
@ -315,25 +324,34 @@ class NewDirectoryNode:
|
|||||||
|
|
||||||
def delete(self, name):
|
def delete(self, name):
|
||||||
"""I remove the child at the specific name. I return a Deferred that
|
"""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():
|
if self.is_readonly():
|
||||||
return defer.fail(NotMutableError())
|
return defer.fail(NotMutableError())
|
||||||
d = self._read()
|
d = self._read()
|
||||||
def _delete(children):
|
def _delete(children):
|
||||||
|
old_child, metadata = children[name]
|
||||||
del children[name]
|
del children[name]
|
||||||
new_contents = self._pack_contents(children)
|
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(_delete)
|
||||||
d.addCallback(lambda res: None)
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def create_empty_directory(self, name):
|
def create_empty_directory(self, name):
|
||||||
"""I create and attach an empty directory at the given name. I return
|
"""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():
|
if self.is_readonly():
|
||||||
return defer.fail(NotMutableError())
|
return defer.fail(NotMutableError())
|
||||||
d = self._client.create_empty_dirnode()
|
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
|
return d
|
||||||
|
|
||||||
def move_child_to(self, current_child_name, new_parent,
|
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
|
# They indicate this by returning None from their get_verifier
|
||||||
# method. We need to remove any such Nones from our set. We also
|
# method. We need to remove any such Nones from our set. We also
|
||||||
# want to convert all these caps into strings.
|
# want to convert all these caps into strings.
|
||||||
return frozenset([cap.to_string()
|
return frozenset([IVerifierURI(cap).to_string()
|
||||||
for cap in manifest
|
for cap in manifest
|
||||||
if cap is not None])
|
if cap is not None])
|
||||||
d.addCallback(_done)
|
d.addCallback(_done)
|
||||||
@ -378,7 +396,7 @@ class NewDirectoryNode:
|
|||||||
d = node.list()
|
d = node.list()
|
||||||
def _got_list(res):
|
def _got_list(res):
|
||||||
dl = []
|
dl = []
|
||||||
for name, child in res.iteritems():
|
for name, (child, metadata) in res.iteritems():
|
||||||
verifier = child.get_verifier()
|
verifier = child.get_verifier()
|
||||||
if verifier not in manifest:
|
if verifier not in manifest:
|
||||||
manifest.add(verifier)
|
manifest.add(verifier)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
import itertools
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
@ -38,18 +39,23 @@ class Netstring(unittest.TestCase):
|
|||||||
self.failUnlessEqual(bottom, ("hello", "world", "extra stuff"))
|
self.failUnlessEqual(bottom, ("hello", "world", "extra stuff"))
|
||||||
|
|
||||||
class FakeFilenode(mutable.MutableFileNode):
|
class FakeFilenode(mutable.MutableFileNode):
|
||||||
|
counter = itertools.count(1)
|
||||||
|
all_contents = {}
|
||||||
|
|
||||||
def init_from_uri(self, myuri):
|
def init_from_uri(self, myuri):
|
||||||
self._uri = myuri
|
self._uri = myuri
|
||||||
self.writekey = myuri.writekey
|
self.writekey = myuri.writekey
|
||||||
return self
|
return self
|
||||||
def create(self, initial_contents):
|
def create(self, initial_contents):
|
||||||
self.contents = initial_contents
|
count = self.counter.next()
|
||||||
self.init_from_uri(uri.WriteableSSKFileURI("key", "fingerprint"))
|
self.init_from_uri(uri.WriteableSSKFileURI("key%d" % count,
|
||||||
|
"fingerprint%d" % count))
|
||||||
|
self.all_contents[self._uri] = initial_contents
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
def download_to_data(self):
|
def download_to_data(self):
|
||||||
return defer.succeed(self.contents)
|
return defer.succeed(self.all_contents[self._uri])
|
||||||
def replace(self, newdata):
|
def replace(self, newdata):
|
||||||
self.contents = newdata
|
self.all_contents[self._uri] = newdata
|
||||||
return defer.succeed(None)
|
return defer.succeed(None)
|
||||||
def is_readonly(self):
|
def is_readonly(self):
|
||||||
return False
|
return False
|
||||||
@ -116,6 +122,8 @@ class Dirnode(unittest.TestCase):
|
|||||||
self.client = MyClient()
|
self.client = MyClient()
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
|
self.expected_manifest = []
|
||||||
|
|
||||||
d = self.client.create_empty_dirnode()
|
d = self.client.create_empty_dirnode()
|
||||||
def _check(n):
|
def _check(n):
|
||||||
self.failUnless(n.is_mutable())
|
self.failUnless(n.is_mutable())
|
||||||
@ -126,18 +134,60 @@ class Dirnode(unittest.TestCase):
|
|||||||
self.failUnless(u_ro.startswith("URI:DIR2-RO:"), u_ro)
|
self.failUnless(u_ro.startswith("URI:DIR2-RO:"), u_ro)
|
||||||
u_v = n.get_verifier()
|
u_v = n.get_verifier()
|
||||||
self.failUnless(u_v.startswith("URI:DIR2-Verifier:"), u_v)
|
self.failUnless(u_v.startswith("URI:DIR2-Verifier:"), u_v)
|
||||||
|
self.expected_manifest.append(u_v)
|
||||||
|
|
||||||
d = n.list()
|
d = n.list()
|
||||||
d.addCallback(lambda res: self.failUnlessEqual(res, {}))
|
d.addCallback(lambda res: self.failUnlessEqual(res, {}))
|
||||||
d.addCallback(lambda res: n.has_child("missing"))
|
d.addCallback(lambda res: n.has_child("missing"))
|
||||||
d.addCallback(lambda res: self.failIf(res))
|
d.addCallback(lambda res: self.failIf(res))
|
||||||
fake_file_uri = uri.WriteableSSKFileURI("a"*16,"b"*32)
|
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: n.set_uri("child", fake_file_uri))
|
||||||
d.addCallback(lambda res: self.failUnlessEqual(res, None))
|
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())
|
d.addCallback(lambda res: n.list())
|
||||||
def _check_list(children):
|
d.addCallback(lambda children:
|
||||||
self.failUnless("child" in children)
|
self.failUnlessEqual(sorted(children.keys()),
|
||||||
d.addCallback(_check_list)
|
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
|
return d
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ from zope.interface import implements
|
|||||||
from twisted.python.components import registerAdapter
|
from twisted.python.components import registerAdapter
|
||||||
from allmydata.util import idlib, hashutil
|
from allmydata.util import idlib, hashutil
|
||||||
from allmydata.interfaces import IURI, IDirnodeURI, IFileURI, IVerifierURI, \
|
from allmydata.interfaces import IURI, IDirnodeURI, IFileURI, IVerifierURI, \
|
||||||
IMutableFileURI
|
IMutableFileURI, INewDirectoryURI
|
||||||
|
|
||||||
# the URI shall be an ascii representation of the file. It shall contain
|
# the URI shall be an ascii representation of the file. It shall contain
|
||||||
# enough information to retrieve and validate the contents. It shall be
|
# enough information to retrieve and validate the contents. It shall be
|
||||||
@ -272,7 +272,7 @@ class SSKVerifierURI(_BaseURI):
|
|||||||
idlib.b2a(self.fingerprint))
|
idlib.b2a(self.fingerprint))
|
||||||
|
|
||||||
class NewDirectoryURI(_BaseURI):
|
class NewDirectoryURI(_BaseURI):
|
||||||
implements(IURI, IDirnodeURI)
|
implements(IURI, IDirnodeURI, INewDirectoryURI)
|
||||||
|
|
||||||
def __init__(self, filenode_uri=None):
|
def __init__(self, filenode_uri=None):
|
||||||
if filenode_uri:
|
if filenode_uri:
|
||||||
@ -293,6 +293,9 @@ class NewDirectoryURI(_BaseURI):
|
|||||||
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
|
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
|
||||||
return "URI:DIR2:" + bits
|
return "URI:DIR2:" + bits
|
||||||
|
|
||||||
|
def get_filenode_uri(self):
|
||||||
|
return self._filenode_uri
|
||||||
|
|
||||||
def is_readonly(self):
|
def is_readonly(self):
|
||||||
return False
|
return False
|
||||||
def is_mutable(self):
|
def is_mutable(self):
|
||||||
@ -324,6 +327,9 @@ class ReadonlyNewDirectoryURI(_BaseURI):
|
|||||||
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
|
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
|
||||||
return "URI:DIR2-RO:" + bits
|
return "URI:DIR2-RO:" + bits
|
||||||
|
|
||||||
|
def get_filenode_uri(self):
|
||||||
|
return self._filenode_uri
|
||||||
|
|
||||||
def is_readonly(self):
|
def is_readonly(self):
|
||||||
return True
|
return True
|
||||||
def is_mutable(self):
|
def is_mutable(self):
|
||||||
@ -355,6 +361,9 @@ class NewDirectoryURIVerifier(_BaseURI):
|
|||||||
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
|
(header_uri, header_ssk, bits) = fn_u.split(":", 2)
|
||||||
return "URI:DIR2-Verifier:" + bits
|
return "URI:DIR2-Verifier:" + bits
|
||||||
|
|
||||||
|
def get_filenode_uri(self):
|
||||||
|
return self._filenode_uri
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DirnodeURI(_BaseURI):
|
class DirnodeURI(_BaseURI):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user