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:
parent
2308420fc6
commit
9a8f68c41f
|
@ -6,7 +6,7 @@ from twisted.internet import defer
|
||||||
import simplejson
|
import simplejson
|
||||||
from allmydata.mutable import NotMutableError
|
from allmydata.mutable import NotMutableError
|
||||||
from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
|
from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
|
||||||
IURI, IFileNode, IMutableFileURI, IVerifierURI
|
IURI, IFileNode, IMutableFileURI, IVerifierURI, IFilesystemNode
|
||||||
from allmydata.util import hashutil
|
from allmydata.util import hashutil
|
||||||
from allmydata.util.hashutil import netstring
|
from allmydata.util.hashutil import netstring
|
||||||
from allmydata.uri import NewDirectoryURI
|
from allmydata.uri import NewDirectoryURI
|
||||||
|
@ -131,7 +131,7 @@ class NewDirectoryNode:
|
||||||
child, metadata = children[name]
|
child, metadata = children[name]
|
||||||
assert (IFileNode.providedBy(child)
|
assert (IFileNode.providedBy(child)
|
||||||
or IMutableFileNode.providedBy(child)
|
or IMutableFileNode.providedBy(child)
|
||||||
or IDirectoryNode.providedBy(child)), children
|
or IDirectoryNode.providedBy(child)), (name,child)
|
||||||
assert isinstance(metadata, dict)
|
assert isinstance(metadata, dict)
|
||||||
rwcap = child.get_uri() # might be RO if the child is not writeable
|
rwcap = child.get_uri() # might be RO if the child is not writeable
|
||||||
rocap = child.get_readonly_uri()
|
rocap = child.get_readonly_uri()
|
||||||
|
@ -224,7 +224,20 @@ class NewDirectoryNode:
|
||||||
|
|
||||||
If this directory node is read-only, the Deferred will errback with a
|
If this directory node is read-only, the Deferred will errback with a
|
||||||
NotMutableError."""
|
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):
|
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
|
"""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
|
If this directory node is read-only, the Deferred will errback with a
|
||||||
NotMutableError."""
|
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():
|
if self.is_readonly():
|
||||||
return defer.fail(NotMutableError())
|
return defer.fail(NotMutableError())
|
||||||
d = self._read()
|
d = self._read()
|
||||||
def _add(children):
|
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)
|
new_contents = self._pack_contents(children)
|
||||||
return self._node.replace(new_contents, wait_for_numpeers=wait_for_numpeers)
|
return self._node.replace(new_contents, wait_for_numpeers=wait_for_numpeers)
|
||||||
d.addCallback(_add)
|
d.addCallback(_add)
|
||||||
d.addCallback(lambda res: child)
|
d.addCallback(lambda res: None)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
def add_file(self, name, uploadable, wait_for_numpeers=None):
|
def add_file(self, name, uploadable, wait_for_numpeers=None):
|
||||||
"""I upload a file (using the given IUploadable), then attach the
|
"""I upload a file (using the given IUploadable), then attach the
|
||||||
resulting FileNode to the directory at the given name. I return a
|
resulting FileNode to the directory at the given name. I return a
|
||||||
|
|
|
@ -530,6 +530,13 @@ class IDirectoryNode(IMutableFilesystemNode):
|
||||||
If this directory node is read-only, the Deferred will errback with a
|
If this directory node is read-only, the Deferred will errback with a
|
||||||
NotMutableError."""
|
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):
|
def set_node(name, child):
|
||||||
"""I add a child at the specific name. I return a Deferred that fires
|
"""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
|
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
|
If this directory node is read-only, the Deferred will errback with a
|
||||||
NotMutableError."""
|
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):
|
def add_file(name, uploadable):
|
||||||
"""I upload a file (using the given IUploadable), then attach the
|
"""I upload a file (using the given IUploadable), then attach the
|
||||||
resulting FileNode to the directory at the given name. I return a
|
resulting FileNode to the directory at the given name. I return a
|
||||||
|
|
|
@ -606,6 +606,35 @@ class Web(WebMixin, unittest.TestCase):
|
||||||
|
|
||||||
return d
|
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):
|
def test_GET_DIRURL_json(self):
|
||||||
d = self.GET(self.public_url + "/foo?t=json")
|
d = self.GET(self.public_url + "/foo?t=json")
|
||||||
d.addCallback(self.failUnlessIsFooJSON)
|
d.addCallback(self.failUnlessIsFooJSON)
|
||||||
|
|
Loading…
Reference in New Issue