mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-20 21:43:09 +00:00
Get rid of ?replace= handling entirely and more-correctly support /uri variants
This commit is contained in:
parent
e0287a7bfe
commit
26d7a3a957
@ -21,6 +21,11 @@ from allmydata.uri import (
|
||||
)
|
||||
from allmydata.testing.web import (
|
||||
create_tahoe_treq_client,
|
||||
capability_generator,
|
||||
)
|
||||
|
||||
from hyperlink import (
|
||||
DecodedURL,
|
||||
)
|
||||
|
||||
from hypothesis import (
|
||||
@ -35,9 +40,12 @@ from testtools import (
|
||||
)
|
||||
from testtools.matchers import (
|
||||
Always,
|
||||
Equals,
|
||||
MatchesStructure,
|
||||
)
|
||||
from testtools.twistedsupport import (
|
||||
succeeded,
|
||||
failed,
|
||||
)
|
||||
|
||||
|
||||
@ -46,9 +54,9 @@ class FakeWebTest(TestCase):
|
||||
Test the WebUI verified-fakes infrastucture
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(FakeWebTest, self).setUp()
|
||||
self.http_client = create_tahoe_treq_client()
|
||||
# Note: do NOT use setUp() because Hypothesis doesn't work
|
||||
# properly with it. You must instead do all fixture-type work
|
||||
# yourself in each test.
|
||||
|
||||
@given(
|
||||
content=binary(),
|
||||
@ -58,21 +66,31 @@ class FakeWebTest(TestCase):
|
||||
Upload some content (via 'PUT /uri') and then download it (via
|
||||
'GET /uri?uri=...')
|
||||
"""
|
||||
http_client = create_tahoe_treq_client()
|
||||
|
||||
@inlineCallbacks
|
||||
def do_test():
|
||||
resp = yield self.http_client.put("http://example.com/uri?replace=true", content)
|
||||
resp = yield http_client.put("http://example.com/uri", content)
|
||||
self.assertEqual(resp.code, 201)
|
||||
|
||||
cap_raw = yield resp.content()
|
||||
cap = from_string(cap_raw)
|
||||
self.assertIsInstance(cap, CHKFileURI)
|
||||
|
||||
resp = yield self.http_client.get(
|
||||
resp = yield http_client.get(
|
||||
"http://example.com/uri?uri={}".format(cap.to_string())
|
||||
)
|
||||
self.assertEqual(resp.code, 200)
|
||||
|
||||
round_trip_content = yield resp.content()
|
||||
|
||||
# using the form "/uri/<cap>" is also valid
|
||||
|
||||
resp = yield http_client.get(
|
||||
"http://example.com/uri/{}".format(cap.to_string())
|
||||
)
|
||||
self.assertEqual(resp.code, 200)
|
||||
|
||||
round_trip_content = yield resp.content()
|
||||
self.assertEqual(content, round_trip_content)
|
||||
self.assertThat(
|
||||
@ -80,21 +98,67 @@ class FakeWebTest(TestCase):
|
||||
succeeded(Always()),
|
||||
)
|
||||
|
||||
@inlineCallbacks
|
||||
def test_duplicate_upload(self):
|
||||
@given(
|
||||
content=binary(),
|
||||
)
|
||||
def test_duplicate_upload(self, content):
|
||||
"""
|
||||
Upload the same content (via 'PUT /uri') twice with no overwrite
|
||||
Upload the same content (via 'PUT /uri') twice
|
||||
"""
|
||||
|
||||
content = "fake content\n" * 200
|
||||
http_client = create_tahoe_treq_client()
|
||||
|
||||
resp = yield self.http_client.put("http://example.com/uri", content)
|
||||
self.assertEqual(resp.code, 201)
|
||||
@inlineCallbacks
|
||||
def do_test():
|
||||
resp = yield http_client.put("http://example.com/uri", content)
|
||||
self.assertEqual(resp.code, 201)
|
||||
|
||||
cap_raw = yield resp.content()
|
||||
cap = from_string(cap_raw)
|
||||
self.assertIsInstance(cap, CHKFileURI)
|
||||
cap_raw = yield resp.content()
|
||||
cap = from_string(cap_raw)
|
||||
self.assertIsInstance(cap, CHKFileURI)
|
||||
|
||||
# this one fails: same content but no ?replace=true
|
||||
resp = yield self.http_client.put("http://example.com/uri", content)
|
||||
self.assertEqual(resp.code, 409)
|
||||
resp = yield http_client.put("http://example.com/uri", content)
|
||||
self.assertThat(resp.code, Equals(200))
|
||||
self.assertThat(
|
||||
do_test(),
|
||||
succeeded(Always()),
|
||||
)
|
||||
|
||||
def test_download_missing(self):
|
||||
"""
|
||||
Error if we download a capability that doesn't exist
|
||||
"""
|
||||
|
||||
http_client = create_tahoe_treq_client()
|
||||
cap_gen = capability_generator("URI:CHK:")
|
||||
|
||||
uri = DecodedURL.from_text(u"http://example.com/uri?uri={}".format(next(cap_gen)))
|
||||
resp = http_client.get(uri.to_uri().to_text())
|
||||
|
||||
self.assertThat(
|
||||
resp,
|
||||
succeeded(
|
||||
MatchesStructure(
|
||||
code=Equals(500)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def test_download_no_arg(self):
|
||||
"""
|
||||
Error if we GET from "/uri" with no ?uri= query-arg
|
||||
"""
|
||||
|
||||
http_client = create_tahoe_treq_client()
|
||||
|
||||
uri = DecodedURL.from_text(u"http://example.com/uri/")
|
||||
resp = http_client.get(uri.to_uri().to_text())
|
||||
|
||||
self.assertThat(
|
||||
resp,
|
||||
succeeded(
|
||||
MatchesStructure(
|
||||
code=Equals(400)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -76,7 +76,8 @@ class _FakeTahoeRoot(Resource, object):
|
||||
self.putChild(b"uri", self._uri)
|
||||
|
||||
def add_data(self, kind, data):
|
||||
return self._uri.add_data(kind, data)
|
||||
fresh, cap = self._uri.add_data(kind, data)
|
||||
return cap
|
||||
|
||||
|
||||
KNOWN_CAPABILITIES = [
|
||||
@ -156,39 +157,32 @@ class _FakeTahoeUriHandler(Resource, object):
|
||||
capability = next(self.capability_generators[kind])
|
||||
return capability
|
||||
|
||||
def add_data(self, kind, data, allow_duplicate=False):
|
||||
def add_data(self, kind, data):
|
||||
"""
|
||||
adds some data to our grid
|
||||
|
||||
:returns: a capability-string
|
||||
:returns: a two-tuple: a bool (True if the data is freshly added) and a capability-string
|
||||
"""
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("'data' must be bytes")
|
||||
|
||||
for k in self.data:
|
||||
if self.data[k] == data:
|
||||
if allow_duplicate:
|
||||
return k
|
||||
raise ValueError(
|
||||
"Duplicate data"
|
||||
)
|
||||
return (False, k)
|
||||
|
||||
cap = self._generate_capability(kind)
|
||||
if cap in self.data:
|
||||
raise ValueError("already have '{}'".format(cap))
|
||||
assert cap not in self.data, "logic error" # shouldn't happen
|
||||
self.data[cap] = data
|
||||
return cap
|
||||
return (True, cap)
|
||||
|
||||
def render_PUT(self, request):
|
||||
data = request.content.read()
|
||||
request.setResponseCode(http.CREATED) # real code does this for brand-new files
|
||||
replace = request.args.get("replace", None)
|
||||
try:
|
||||
return self.add_data("URI:CHK:", data, allow_duplicate=replace)
|
||||
except ValueError:
|
||||
msg, code = humanize_failure(Failure(ExistingChildError()))
|
||||
request.setResponseCode(code)
|
||||
return msg
|
||||
fresh, cap = self.add_data("URI:CHK:", data)
|
||||
if fresh:
|
||||
request.setResponseCode(http.CREATED) # real code does this for brand-new files
|
||||
else:
|
||||
request.setResponseCode(http.OK) # replaced/modified files
|
||||
return cap
|
||||
|
||||
def render_POST(self, request):
|
||||
t = request.args[u"t"][0]
|
||||
@ -198,7 +192,8 @@ class _FakeTahoeUriHandler(Resource, object):
|
||||
"mkdir-immutable": "URI:DIR2-CHK:"
|
||||
}
|
||||
kind = type_to_kind[t]
|
||||
return self.add_data(kind, data)
|
||||
fresh, cap = self.add_data(kind, data)
|
||||
return cap
|
||||
|
||||
def render_GET(self, request):
|
||||
uri = DecodedURL.from_text(request.uri.decode('utf8'))
|
||||
@ -206,14 +201,19 @@ class _FakeTahoeUriHandler(Resource, object):
|
||||
for arg, value in uri.query:
|
||||
if arg == u"uri":
|
||||
capability = value
|
||||
if capability is None:
|
||||
raise Exception(
|
||||
"No ?uri= arguent in GET '{}'".format(
|
||||
uri.to_string()
|
||||
)
|
||||
)
|
||||
# it's legal to use the form "/uri/<capability>"
|
||||
if capability is None and request.postpath and request.postpath[0]:
|
||||
capability = request.postpath[0]
|
||||
|
||||
# if we don't yet have a capability, that's an error
|
||||
if capability is None:
|
||||
request.setResponseCode(http.BAD_REQUEST)
|
||||
return b"GET /uri requires uri="
|
||||
|
||||
# the user gave us a capability; if our Grid doesn't have any
|
||||
# data for it, that's an error.
|
||||
if capability not in self.data:
|
||||
request.setResponseCode(http.BAD_REQUEST)
|
||||
return u"No data for '{}'".format(capability).decode("ascii")
|
||||
|
||||
return self.data[capability]
|
||||
|
Loading…
Reference in New Issue
Block a user