]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
more filetable_new tests
authorBrian Warner <warner@lothar.com>
Mon, 25 Dec 2006 07:56:18 +0000 (00:56 -0700)
committerBrian Warner <warner@lothar.com>
Mon, 25 Dec 2006 07:56:18 +0000 (00:56 -0700)
src/allmydata/filetable_new.py
src/allmydata/test/test_filetable_new.py

index 215da26c3d51b912be205ac0c75efc59dfdfa6ea..fdd10a365b1aa8b84e439253b9f0780381439eb4 100644 (file)
@@ -84,6 +84,16 @@ class ISubTree(Interface):
         either (True, node), or (False, next_subtree_spec, prepath, postpath).
         """
 
+    def serialize():
+        """Return a series of nested lists which describe my structure
+        in a form that can be bencoded."""
+
+    def unserialize(serialized_data):
+        """Populate all nodes from serialized_data, previously created by
+        calling my serialize() method. 'serialized_data' is a series of
+        nested lists (s-expressions), probably recorded in bencoded form."""
+
+
 class IMutableSubTree(Interface):
     def mutation_affects_parent():
         """This returns True for CHK nodes where you must inform the parent
@@ -106,7 +116,7 @@ class IMutableSubTree(Interface):
         everything has been added to the work queue.
         """
 
-    def serialize_to_file():
+    def serialize_to_file(f):
         """Write a bencoded data structure to the given filehandle that can
         be used to reproduce the contents of this subtree."""
 
@@ -191,17 +201,14 @@ class SubTreeNode:
         for i in range(1, len(data), 2):
             name = data[i]
             child_data = data[i+1]
-            assert isinstance(child_data, list)
+            assert isinstance(child_data, (list, tuple))
             child_type = child_data[0]
             if child_type == "DIRECTORY":
                 child = SubTreeNode(self.enclosing_tree)
                 child.unserialize(child_data)
                 self.node_children[name] = child
-            elif child_type == "LINK":
-                self.child_specifications[name] = child_data[1]
             else:
-                raise RuntimeError("unknown serialized-node type '%s'" %
-                                   child_type)
+                self.child_specifications[name] = child_data
 
 class _SubTreeMixin(object):
 
index b9dd230dd6cdb7f94ef84f9215ce00a5518daa1b..5c64afa21c53f646a2659e757fd0cbd0ab42d123 100644 (file)
@@ -2,38 +2,62 @@
 import os
 from zope.interface import implements
 from twisted.trial import unittest
+from twisted.internet import defer
 from allmydata import filetable_new as ft
 from allmydata import workqueue
 from cStringIO import StringIO
 
 class FakeOpener(object):
     implements(ft.IOpener)
+    def __init__(self, objects={}):
+        self.objects = objects
+    def open(self, subtree_specification, parent_is_mutable):
+        #print "open", subtree_specification, subtree_specification.serialize(), parent_is_mutable
+        return defer.succeed(self.objects[subtree_specification.serialize()])
 
 class FakeWorkQueue(object):
     implements(workqueue.IWorkQueue)
+    def __init__(self):
+        self.first_commands = []
+        self.last_commands = []
+        self.tempfile_number = 0
+        self.boxname_number = 0
+    def dump_commands(self):
+        return self.first_commands + self.last_commands
+    def clear_commands(self):
+        self.first_commands = []
+        self.last_commands = []
+
     def create_tempfile(self):
-        return (StringIO(), "dummy_filename")
+        self.tempfile_number += 1
+        self.first_commands.append("create_tempfile-%d" % self.tempfile_number)
+        return (StringIO(), "dummy_filename-%d" % self.tempfile_number)
     def create_boxname(self):
-        return "dummy_boxname"
+        self.boxname_number += 1
+        self.first_commands.append("create_boxname-%d" % self.boxname_number)
+        return "dummy_boxname-%d" % self.boxname_number
     def add_upload_chk(self, source_filename, stash_uri_in_boxname):
-        pass
+        self.first_commands.append(("upload_chk", source_filename,
+                                    stash_uri_in_boxname))
     def add_upload_ssk(self, source_filename, write_capability,
                        previous_version):
-        pass
+        self.first_commands.append(("upload_ssk", source_filename,
+                                    write_capability, previous_version))
     def add_retain_ssk(self, read_capability):
-        pass
+        self.last_commands.append(("retain_ssk", read_capability))
     def add_unlink_ssk(self, write_capability):
-        pass
+        self.last_commands.append(("unlink_ssk", write_capability))
     def add_retain_uri_from_box(self, boxname):
-        pass
+        self.last_commands.append(("retain_uri_from_box", boxname))
     def add_addpath(self, boxname, path):
-        pass
+        self.first_commands.append(("addpath", boxname, path))
     def add_unlink_uri(self, uri):
-        pass
+        self.last_commands.append(("unlink_uri", uri))
     def add_delete_tempfile(self, filename):
-        pass
+        self.first_commands.append(("delete_tempfile", filename))
     def add_delete_box(self, boxname):
-        pass
+        self.last_commands.append(("delete_box", boxname))
+
 
 
 class OneSubTree(unittest.TestCase):
@@ -120,3 +144,158 @@ class OneSubTree(unittest.TestCase):
         d.addCallback(_got_two)
         return d
 
+    def test_addpath(self):
+        o = FakeOpener()
+        wq = FakeWorkQueue()
+        st = ft.MutableCHKDirectorySubTree()
+        st.new()
+        st.set_uri(None)
+        file_three = ft.CHKFileSpecification()
+        file_three.set_uri("file_three_uri")
+        d = st.add(["one", "two", "three"], file_three, o, wq)
+        def _done(res):
+            expected = [
+                "create_tempfile-1",
+                "create_boxname-1",
+                ('upload_chk', 'dummy_filename-1', 'dummy_boxname-1'),
+                ('delete_tempfile', 'dummy_filename-1'),
+                ('addpath', 'dummy_boxname-1', []),
+                ('retain_uri_from_box', 'dummy_boxname-1'),
+                ('delete_box', 'dummy_boxname-1'),
+                ('unlink_uri', None),
+                ]
+            self.failUnlessEqual(wq.dump_commands(), expected)
+            #print
+            #for c in wq.dump_commands():
+            #    print c
+        d.addCallback(_done)
+        return d
+
+    def test_serialize(self):
+        st = ft.ImmutableDirectorySubTree()
+        st.new()
+        one = ft.SubTreeNode(st)
+        two = ft.SubTreeNode(st)
+        three = ft.SubTreeNode(st)
+        st.root.node_children["one"] = one
+        st.root.node_children["two"] = two
+        two.node_children["three"] = three
+        file_four = ft.CHKFileSpecification()
+        file_four.set_uri("file_four_uri")
+        two.child_specifications["four"] = file_four
+        data = st.serialize()
+        st_new = ft.ImmutableDirectorySubTree()
+        st_new.unserialize(data)
+
+        st_four = ft.ImmutableDirectorySubTree()
+        st_four.new()
+        st_four.root.node_children["five"] = ft.SubTreeNode(st_four)
+
+        o = FakeOpener({("CHK-File", "file_four_uri"): st_four})
+        d = st.get([], o)
+        def _got_root(root):
+            self.failUnless(ft.IDirectoryNode.providedBy(root))
+            self.failUnlessEqual(root.list(), ["one", "two"])
+        d.addCallback(_got_root)
+        d.addCallback(lambda res: st.get(["two"], o))
+        def _got_two(_two):
+            self.failUnless(ft.IDirectoryNode.providedBy(_two))
+            self.failUnlessEqual(_two.list(), ["four", "three"])
+        d.addCallback(_got_two)
+
+        d.addCallback(lambda res: st.get(["two", "four"], o))
+        def _got_four(_four):
+            self.failUnless(ft.IDirectoryNode.providedBy(_four))
+            self.failUnlessEqual(_four.list(), ["five"])
+        d.addCallback(_got_four)
+
+class MultipleSubTrees(unittest.TestCase):
+
+    def test_open(self):
+        st = ft.ImmutableDirectorySubTree()
+        st.new()
+        # populate it with some internal directories and child links and see
+        # if we can follow them
+        one = ft.SubTreeNode(st)
+        two = ft.SubTreeNode(st)
+        three = ft.SubTreeNode(st)
+        st.root.node_children["one"] = one
+        st.root.node_children["two"] = two
+        two.node_children["three"] = three
+
+    def test_addpath(self):
+        wq = FakeWorkQueue()
+        st1 = ft.MutableCHKDirectorySubTree()
+        st1.new()
+        st1.set_uri(None)
+        one = ft.SubTreeNode(st1)
+        two = ft.SubTreeNode(st1)
+        st1.root.node_children["one"] = one
+        one.node_children["two"] = two
+        three = ft.CHKDirectorySpecification()
+        three.set_uri("dir_three_uri")
+        two.child_specifications["three"] = three
+
+        st2 = ft.MutableCHKDirectorySubTree()
+        st2.new()
+        st2.set_uri(None)
+        four = ft.SubTreeNode(st2)
+        five = ft.SubTreeNode(st2)
+        st2.root.node_children["four"] = four
+        four.node_children["five"] = five
+
+        file_six = ft.CHKFileSpecification()
+        file_six.set_uri("file_six_uri")
+
+        o = FakeOpener({("CHK-Directory", "dir_three_uri"): st2})
+
+        d = defer.succeed(None)
+        #d.addCallback(lambda res:
+        #              st1.get(["one", "two", "three", "four", "five"], o))
+        def _got_five(res):
+            self.failUnless(ft.IDirectoryNode.providedBy(res))
+            self.failUnlessIdentical(res, five)
+        #d.addCallback(_got_five)
+
+        d.addCallback(lambda res:
+                      st1.add(["one", "two", "six"],
+                              file_six, o, wq))
+        def _done(res):
+            expected = [
+                "create_tempfile-1",
+                "create_boxname-1",
+                ('upload_chk', 'dummy_filename-1', 'dummy_boxname-1'),
+                ('delete_tempfile', 'dummy_filename-1'),
+                # one/two/six only modifies the top-most CHKDirectory, so
+                # the addpath that gets scheduled is targeted at the root
+                ('addpath', 'dummy_boxname-1', []),
+                ('retain_uri_from_box', 'dummy_boxname-1'),
+                ('delete_box', 'dummy_boxname-1'),
+                ('unlink_uri', None),
+                ]
+            self.failUnlessEqual(wq.dump_commands(), expected)
+            wq.clear_commands()
+        d.addCallback(_done)
+
+        d.addCallback(lambda res:
+                      st1.add(["one", "two", "three", "four", "six"],
+                              file_six, o, wq))
+        def _done2(res):
+            expected = [
+                "create_tempfile-2",
+                "create_boxname-2",
+                ('upload_chk', 'dummy_filename-2', 'dummy_boxname-2'),
+                ('delete_tempfile', 'dummy_filename-2'),
+                # one/two/three/four/six modifies the lower CHKDirectory, so
+                # we schedule an addpath of the link that points from the
+                # upper CHKDirectory to the lower one (at one/two/three).
+                ('addpath', 'dummy_boxname-2', ["one", "two", "three"]),
+                ('retain_uri_from_box', 'dummy_boxname-2'),
+                ('delete_box', 'dummy_boxname-2'),
+                ('unlink_uri', None),
+                ]
+            self.failUnlessEqual(wq.dump_commands(), expected)
+        d.addCallback(_done2)
+
+
+        return d