mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-02 19:26:44 +00:00
more filetable_new tests
This commit is contained in:
parent
3e085efa7c
commit
cf53abab42
@ -84,6 +84,16 @@ class ISubTree(Interface):
|
|||||||
either (True, node), or (False, next_subtree_spec, prepath, postpath).
|
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):
|
class IMutableSubTree(Interface):
|
||||||
def mutation_affects_parent():
|
def mutation_affects_parent():
|
||||||
"""This returns True for CHK nodes where you must inform the 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.
|
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
|
"""Write a bencoded data structure to the given filehandle that can
|
||||||
be used to reproduce the contents of this subtree."""
|
be used to reproduce the contents of this subtree."""
|
||||||
|
|
||||||
@ -191,17 +201,14 @@ class SubTreeNode:
|
|||||||
for i in range(1, len(data), 2):
|
for i in range(1, len(data), 2):
|
||||||
name = data[i]
|
name = data[i]
|
||||||
child_data = data[i+1]
|
child_data = data[i+1]
|
||||||
assert isinstance(child_data, list)
|
assert isinstance(child_data, (list, tuple))
|
||||||
child_type = child_data[0]
|
child_type = child_data[0]
|
||||||
if child_type == "DIRECTORY":
|
if child_type == "DIRECTORY":
|
||||||
child = SubTreeNode(self.enclosing_tree)
|
child = SubTreeNode(self.enclosing_tree)
|
||||||
child.unserialize(child_data)
|
child.unserialize(child_data)
|
||||||
self.node_children[name] = child
|
self.node_children[name] = child
|
||||||
elif child_type == "LINK":
|
|
||||||
self.child_specifications[name] = child_data[1]
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("unknown serialized-node type '%s'" %
|
self.child_specifications[name] = child_data
|
||||||
child_type)
|
|
||||||
|
|
||||||
class _SubTreeMixin(object):
|
class _SubTreeMixin(object):
|
||||||
|
|
||||||
|
@ -2,38 +2,62 @@
|
|||||||
import os
|
import os
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
|
from twisted.internet import defer
|
||||||
from allmydata import filetable_new as ft
|
from allmydata import filetable_new as ft
|
||||||
from allmydata import workqueue
|
from allmydata import workqueue
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
class FakeOpener(object):
|
class FakeOpener(object):
|
||||||
implements(ft.IOpener)
|
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):
|
class FakeWorkQueue(object):
|
||||||
implements(workqueue.IWorkQueue)
|
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):
|
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):
|
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):
|
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,
|
def add_upload_ssk(self, source_filename, write_capability,
|
||||||
previous_version):
|
previous_version):
|
||||||
pass
|
self.first_commands.append(("upload_ssk", source_filename,
|
||||||
|
write_capability, previous_version))
|
||||||
def add_retain_ssk(self, read_capability):
|
def add_retain_ssk(self, read_capability):
|
||||||
pass
|
self.last_commands.append(("retain_ssk", read_capability))
|
||||||
def add_unlink_ssk(self, write_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):
|
def add_retain_uri_from_box(self, boxname):
|
||||||
pass
|
self.last_commands.append(("retain_uri_from_box", boxname))
|
||||||
def add_addpath(self, boxname, path):
|
def add_addpath(self, boxname, path):
|
||||||
pass
|
self.first_commands.append(("addpath", boxname, path))
|
||||||
def add_unlink_uri(self, uri):
|
def add_unlink_uri(self, uri):
|
||||||
pass
|
self.last_commands.append(("unlink_uri", uri))
|
||||||
def add_delete_tempfile(self, filename):
|
def add_delete_tempfile(self, filename):
|
||||||
pass
|
self.first_commands.append(("delete_tempfile", filename))
|
||||||
def add_delete_box(self, boxname):
|
def add_delete_box(self, boxname):
|
||||||
pass
|
self.last_commands.append(("delete_box", boxname))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class OneSubTree(unittest.TestCase):
|
class OneSubTree(unittest.TestCase):
|
||||||
@ -120,3 +144,158 @@ class OneSubTree(unittest.TestCase):
|
|||||||
d.addCallback(_got_two)
|
d.addCallback(_got_two)
|
||||||
return d
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user