wapi: add POST /uri/$DIRECTORY?t=set_children

Unfinished bits: doc in webapi.txt, test handling of badly formed JSON, return reasonable HTTP response, examination of the effect of this patch on code coverage -- but I'm committing it anyway because MikeB can use it and I'm being called to dinner...
This commit is contained in:
Zooko O'Whielacronx 2008-02-29 18:40:27 -07:00
parent 5cdc678d24
commit 99f006c584
6 changed files with 73 additions and 26 deletions

View File

@ -250,7 +250,7 @@ class NewDirectoryNode:
assert isinstance(name, unicode)
return self.set_node(name, self._create_node(child_uri), metadata)
def set_uris(self, entries):
def set_children(self, entries):
node_entries = []
for e in entries:
if len(e) == 2:

View File

@ -669,7 +669,7 @@ class IDirectoryNode(IMutableFilesystemNode):
If this directory node is read-only, the Deferred will errback with a
NotMutableError."""
def set_uris(entries):
def set_children(entries):
"""Add multiple (name, child_uri) pairs (or (name, child_uri,
metadata) triples) to a directory node. Returns a Deferred that fires
(with None) when the operation finishes. This is equivalent to

View File

@ -110,7 +110,7 @@ def make_verifier_uri():
return uri.SSKVerifierURI(storage_index=os.urandom(16),
fingerprint=os.urandom(32))
class NonGridDirectoryNode(dirnode.NewDirectoryNode):
class FakeDirectoryNode(dirnode.NewDirectoryNode):
"""This offers IDirectoryNode, but uses a FakeMutableFileNode for the
backing store, so it doesn't go to the grid. The child data is still
encrypted and serialized, so this isn't useful for tests that want to

View File

@ -7,15 +7,13 @@ from allmydata.interfaces import IURI, IClient, IMutableFileNode, \
INewDirectoryURI, IReadonlyNewDirectoryURI, IFileNode
from allmydata.util import hashutil, testutil
from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \
NonGridDirectoryNode, create_chk_filenode
FakeDirectoryNode, create_chk_filenode
from twisted.internet import defer, reactor
# to test dirnode.py, we want to construct a tree of real DirectoryNodes that
# contain pointers to fake files. We start with a fake MutableFileNode that
# stores all of its data in a static table.
FakeDirectoryNode = NonGridDirectoryNode
class Marker:
implements(IFileNode, IMutableFileNode) # sure, why not
def __init__(self, nodeuri):
@ -281,8 +279,8 @@ class Dirnode(unittest.TestCase, testutil.ShouldFailMixin):
d.addCallback(lambda res: n.delete(u"d3"))
d.addCallback(lambda res: n.delete(u"d4"))
# metadata through set_uris()
d.addCallback(lambda res: n.set_uris([ (u"e1", fake_file_uri),
# metadata through set_children()
d.addCallback(lambda res: n.set_children([ (u"e1", fake_file_uri),
(u"e2", fake_file_uri, {}),
(u"e3", fake_file_uri,
{"key": "value"}),

View File

@ -7,7 +7,7 @@ from twisted.web import client, error, http
from twisted.python import failure, log
from allmydata import interfaces, provisioning, uri, webish, upload, download
from allmydata.util import fileutil
from allmydata.test.common import NonGridDirectoryNode, FakeCHKFileNode, FakeMutableFileNode, create_chk_filenode
from allmydata.test.common import FakeDirectoryNode, FakeCHKFileNode, FakeMutableFileNode, create_chk_filenode
from allmydata.interfaces import IURI, INewDirectoryURI, IReadonlyNewDirectoryURI, IFileURI, IMutableFileURI, IMutableFileNode
# create a fake uploader/downloader, and a couple of fake dirnodes, then
@ -35,18 +35,18 @@ class FakeClient(service.MultiService):
def connected_to_introducer(self):
return False
def create_node_from_uri(self, uri):
u = IURI(uri)
def create_node_from_uri(self, auri):
u = uri.from_string(auri)
if (INewDirectoryURI.providedBy(u)
or IReadonlyNewDirectoryURI.providedBy(u)):
return NonGridDirectoryNode(self).init_from_uri(u)
return FakeDirectoryNode(self).init_from_uri(u)
if IFileURI.providedBy(u):
return FakeCHKFileNode(u, self)
assert IMutableFileURI.providedBy(u), u
return FakeMutableFileNode(self).init_from_uri(u)
def create_empty_dirnode(self):
n = NonGridDirectoryNode(self)
n = FakeDirectoryNode(self)
d = n.create()
d.addCallback(lambda res: n)
return d
@ -1299,6 +1299,46 @@ class Web(WebMixin, unittest.TestCase):
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
def test_POST_set_children(self):
contents9, n9, newuri9 = self.makefile(9)
contents10, n10, newuri10 = self.makefile(10)
contents11, n11, newuri11 = self.makefile(11)
reqbody = """{
"atomic_added_1": [ "filenode", { "rw_uri": "%s",
"size": 0,
"metadata": {
"ctime": 1002777696.7564139,
"mtime": 1002777696.7564139
}
} ],
"atomic_added_2": [ "filenode", { "rw_uri": "%s",
"size": 1,
"metadata": {
"ctime": 1002777696.7564139,
"mtime": 1002777696.7564139
}
} ],
"atomic_added_3": [ "filenode", { "rw_uri": "%s",
"size": 2,
"metadata": {
"ctime": 1002777696.7564139,
"mtime": 1002777696.7564139
}
} ]
}""" % (newuri9, newuri10, newuri11)
url = self.webish_url + self.public_url + "/foo" + "?t=set_children"
d = client.getPage(url, method="POST", postdata=reqbody)
def _then(res):
self.failUnlessURIMatchesChild(newuri9, self._foo_node, u"atomic_added_1")
self.failUnlessURIMatchesChild(newuri10, self._foo_node, u"atomic_added_2")
self.failUnlessURIMatchesChild(newuri11, self._foo_node, u"atomic_added_3")
d.addCallback(_then)
return d
def test_POST_put_uri(self):
contents, n, newuri = self.makefile(8)
d = self.POST(self.public_url + "/foo", t="uri", name="new.txt", uri=newuri)

View File

@ -899,6 +899,16 @@ class POSTHandler(rend.Page):
d.addCallback(_got_child_check)
return d
def _POST_set_children(self, children):
cs = []
for name, (file_or_dir, mddict) in children.iteritems():
cap = str(mddict.get('rw_uri') or mddict.get('ro_uri'))
cs.append((name, cap, mddict.get('metadata')))
d = self._node.set_children(cs)
d.addCallback(lambda res: "Okay so I did it.")
return d
def renderHTTP(self, ctx):
req = inevow.IRequest(ctx)
@ -973,16 +983,16 @@ class POSTHandler(rend.Page):
d = self._POST_overwrite(contents)
elif t == "check":
d = self._POST_check(name)
# elif t == "set_children":
# d = self._POST_set_(name)
# if not name:
# raise RuntimeError("set-uri requires a name")
# newuri = get_arg(req, "uri")
# assert newuri is not None
# d = self._check_replacement(name)
# d.addCallback(lambda res: self._node.set_uri(name, newuri))
# d.addCallback(lambda res: newuri)
elif t == "set_children":
req.content.seek(0)
body = req.content.read()
try:
children = simplejson.loads(body)
except ValueError, le:
le.args = tuple(le.args + (body,))
# TODO test handling of bad JSON
raise
d = self._POST_set_children(children)
else:
print "BAD t=%s" % t
return "BAD t=%s" % t
@ -1346,9 +1356,8 @@ class UnlinkedPUTSSKUploader(rend.Page):
req = inevow.IRequest(ctx)
assert req.method == "PUT"
# SDMF: files are small, and we can only upload data
contents = req.content
contents.seek(0)
data = contents.read()
req.content.seek(0)
data = req.content.read()
d = IClient(ctx).create_mutable_file(data)
d.addCallback(lambda n: n.get_uri())
return d