]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
mutable: improve NewDirectoryNode test coverage
authorBrian Warner <warner@allmydata.com>
Fri, 2 Nov 2007 01:35:54 +0000 (18:35 -0700)
committerBrian Warner <warner@allmydata.com>
Fri, 2 Nov 2007 01:35:54 +0000 (18:35 -0700)
src/allmydata/mutable.py
src/allmydata/test/test_mutable.py
src/allmydata/uri.py

index a5e831df56c9b72a54583c6e2b352bf229cbbf81..d6757c81933c115d3e0db85915d12a0a4fef96e2 100644 (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)
index 0ed5dee4f8d2d2e1e2b906024dcbd4b41944007c..d7d78f4cdf6157e681b61091af1d24707d05ba65 100644 (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())
+            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())
-            def _check_list(children):
-                self.failUnless("child" in children)
-            d.addCallback(_check_list)
+            d.addCallback(lambda children:
+                          self.failUnlessEqual(sorted(children.keys()),
+                                               sorted(["child"])))
 
             return d
 
index 127c066c4c141b3d3c5de1f9436555db536e30ed..9a41f40bd83bca835e35731870aa01a6aa6597ba 100644 (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):