From eaf96b22fef6a128c944e9b649aa32f55b9d8dce Mon Sep 17 00:00:00 2001 From: meejah Date: Sat, 13 Jun 2020 01:55:14 -0600 Subject: [PATCH] replciate Tahoe's behavior for replace=true/false --- src/allmydata/test/test_testing.py | 21 +++++++++++++++++++- src/allmydata/testing/web.py | 31 +++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/allmydata/test/test_testing.py b/src/allmydata/test/test_testing.py index b5bbacad4..a995e756d 100644 --- a/src/allmydata/test/test_testing.py +++ b/src/allmydata/test/test_testing.py @@ -61,7 +61,7 @@ class FakeWebTest(TestCase): @inlineCallbacks def do_test(): - resp = yield self.http_client.put("http://example.com/uri", content) + resp = yield self.http_client.put("http://example.com/uri?replace=true", content) self.assertEqual(resp.code, 201) cap_raw = yield resp.content() @@ -79,3 +79,22 @@ class FakeWebTest(TestCase): do_test(), succeeded(Always()), ) + + @inlineCallbacks + def test_duplicate_upload(self): + """ + Upload the same content (via 'PUT /uri') twice with no overwrite + """ + + content = "fake content\n" * 200 + + resp = yield self.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) + + # 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) diff --git a/src/allmydata/testing/web.py b/src/allmydata/testing/web.py index 5ab870f4f..ef7cd5bed 100644 --- a/src/allmydata/testing/web.py +++ b/src/allmydata/testing/web.py @@ -30,6 +30,9 @@ from twisted.web import ( from twisted.internet.defer import ( succeed, ) +from twisted.python.failure import ( + Failure, +) from treq.client import ( HTTPClient, @@ -44,6 +47,13 @@ import allmydata.uri from allmydata.util import ( base32, ) +from allmydata.interfaces import ( + ExistingChildError, +) +from allmydata.web.common import ( + humanize_failure, +) + __all__ = ( "create_fake_tahoe_root", @@ -147,7 +157,7 @@ class _FakeTahoeUriHandler(Resource, object): capability = next(self._capability_generators[kind]) return capability - def add_data(self, kind, data): + def add_data(self, kind, data, allow_duplicate=False): """ adds some data to our grid @@ -156,9 +166,18 @@ class _FakeTahoeUriHandler(Resource, object): if not isinstance(data, bytes): raise TypeError("'data' must be bytes") - cap = self._generate_capability(kind) if self._data is None: self._data = dict() + + for k in self._data: + if self._data[k] == data: + if allow_duplicate: + return k + raise ValueError( + "Duplicate data" + ) + + cap = self._generate_capability(kind) if cap in self._data: raise ValueError("already have '{}'".format(cap)) self._data[cap] = data @@ -167,7 +186,13 @@ class _FakeTahoeUriHandler(Resource, object): def render_PUT(self, request): data = request.content.read() request.setResponseCode(http.CREATED) # real code does this for brand-new files - return self.add_data("URI:CHK:", data) + 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 def render_POST(self, request): t = request.args[u"t"][0]