dirnode: add set_uris() and set_nodes() (plural), to set multiple children at once. Use it to set up a new webapi test for issue #237.

This commit is contained in:
Brian Warner 2007-12-18 23:30:02 -07:00
parent 2308420fc6
commit 9a8f68c41f
3 changed files with 75 additions and 5 deletions

View File

@ -6,7 +6,7 @@ from twisted.internet import defer
import simplejson
from allmydata.mutable import NotMutableError
from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
IURI, IFileNode, IMutableFileURI, IVerifierURI
IURI, IFileNode, IMutableFileURI, IVerifierURI, IFilesystemNode
from allmydata.util import hashutil
from allmydata.util.hashutil import netstring
from allmydata.uri import NewDirectoryURI
@ -131,7 +131,7 @@ class NewDirectoryNode:
child, metadata = children[name]
assert (IFileNode.providedBy(child)
or IMutableFileNode.providedBy(child)
or IDirectoryNode.providedBy(child)), children
or IDirectoryNode.providedBy(child)), (name,child)
assert isinstance(metadata, dict)
rwcap = child.get_uri() # might be RO if the child is not writeable
rocap = child.get_readonly_uri()
@ -224,7 +224,20 @@ class NewDirectoryNode:
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
return self.set_node(name, self._create_node(child_uri), metadata, wait_for_numpeers=wait_for_numpeers)
return self.set_node(name, self._create_node(child_uri), metadata,
wait_for_numpeers)
def set_uris(self, entries, wait_for_numpeers=None):
node_entries = []
for e in entries:
if len(e) == 2:
name, child_uri = e
metadata = {}
else:
assert len(e) == 3
name, child_uri, metadata = e
node_entries.append( (name,self._create_node(child_uri),metadata) )
return self.set_nodes(node_entries, wait_for_numpeers)
def set_node(self, name, child, metadata={}, wait_for_numpeers=None):
"""I add a child at the specific name. I return a Deferred that fires
@ -234,17 +247,31 @@ class NewDirectoryNode:
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
assert IFilesystemNode.providedBy(child), child
d = self.set_nodes( [(name, child, metadata)], wait_for_numpeers)
d.addCallback(lambda res: child)
return d
def set_nodes(self, entries, wait_for_numpeers=None):
if self.is_readonly():
return defer.fail(NotMutableError())
d = self._read()
def _add(children):
children[name] = (child, metadata)
for e in entries:
if len(e) == 2:
name, child = e
metadata = {}
else:
assert len(e) == 3
name, child, metadata = e
children[name] = (child, metadata)
new_contents = self._pack_contents(children)
return self._node.replace(new_contents, wait_for_numpeers=wait_for_numpeers)
d.addCallback(_add)
d.addCallback(lambda res: child)
d.addCallback(lambda res: None)
return d
def add_file(self, name, uploadable, wait_for_numpeers=None):
"""I upload a file (using the given IUploadable), then attach the
resulting FileNode to the directory at the given name. I return a

View File

@ -530,6 +530,13 @@ class IDirectoryNode(IMutableFilesystemNode):
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
def set_uris(entries):
"""Add multiple (name, child_uri) pairs to a directory node. Returns
a Deferred that fires (with None) when the operation finishes. This
is equivalent to calling set_uri() multiple times, but is much more
efficient.
"""
def set_node(name, child):
"""I add a child at the specific name. I return a Deferred that fires
when the operation finishes. This Deferred will fire with the child
@ -539,6 +546,13 @@ class IDirectoryNode(IMutableFilesystemNode):
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
def set_nodes(entries):
"""Add multiple (name, child_node) pairs to a directory node. Returns
a Deferred that fires (with None) when the operation finishes. This
is equivalent to calling set_node() multiple times, but is much more
efficient."""
def add_file(name, uploadable):
"""I upload a file (using the given IUploadable), then attach the
resulting FileNode to the directory at the given name. I return a

View File

@ -606,6 +606,35 @@ class Web(WebMixin, unittest.TestCase):
return d
def test_GET_DIRURL_large(self):
# Nevow has a problem showing more than about 192 children of a
# directory: it uses defer.success() and d.addCallback in a way that
# can make the stack grow very quickly. See ticket #237 for details.
# To work around this, I think we'll need to put a 'return
# defer.fireEventually' in our render_ method. This test is intended
# to trigger the bug (and eventually verify that our workaround
# actually works), but it isn't yet failing for me.
d = self.s.create_empty_dirnode()
COUNT = 400
def _created(dirnode):
entries = [ (str(i), self._foo_uri) for i in range(COUNT) ]
d2 = dirnode.set_uris(entries)
d2.addCallback(lambda res: dirnode)
return d2
d.addCallback(_created)
def _check(dirnode):
large_url = "/uri/" + dirnode.get_uri() + "/"
return self.GET(large_url)
d.addCallback(_check)
def _done(res):
self.failUnless('<a href="%d">%d</a>' % (COUNT-1, COUNT-1) in res)
self.failIf("maximum recursion depth exceeded" in res)
d.addCallback(_done)
return d
def test_GET_DIRURL_json(self):
d = self.GET(self.public_url + "/foo?t=json")
d.addCallback(self.failUnlessIsFooJSON)