From b185e34c8d8460ea73ad642d68a86937dfbcad2f Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Fri, 5 Jul 2019 13:40:00 -0400
Subject: [PATCH] advise_corrupt_share

---
 .../_storage_client.py                        | 14 +++++
 .../_storage_server.py                        |  3 ++
 .../tests/test_storage_protocol.py            | 53 +++++++++++++++++--
 3 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/src/_secureaccesstokenauthorizer/_storage_client.py b/src/_secureaccesstokenauthorizer/_storage_client.py
index bfdf7b9..9a77fbc 100644
--- a/src/_secureaccesstokenauthorizer/_storage_client.py
+++ b/src/_secureaccesstokenauthorizer/_storage_client.py
@@ -103,3 +103,17 @@ class SecureAccessTokenAuthorizerStorageClient(object):
             renew_secret,
         )
 
+    def advise_corrupt_share(
+            self,
+            share_type,
+            storage_index,
+            shnum,
+            reason,
+    ):
+        return self._rref.callRemote(
+            "advise_corrupt_share",
+            share_type,
+            storage_index,
+            shnum,
+            reason,
+        )
diff --git a/src/_secureaccesstokenauthorizer/_storage_server.py b/src/_secureaccesstokenauthorizer/_storage_server.py
index 0943681..6264b31 100644
--- a/src/_secureaccesstokenauthorizer/_storage_server.py
+++ b/src/_secureaccesstokenauthorizer/_storage_server.py
@@ -123,6 +123,9 @@ class SecureAccessTokenAuthorizerStorageServer(Referenceable):
         self._validate_tokens(tokens)
         return self._original.remote_renew_lease(*a, **kw)
 
+    def remote_advise_corrupt_share(self, *a, **kw):
+        return self._original.remote_advise_corrupt_share(*a, **kw)
+
 # I don't understand why this is required.
 # SecureAccessTokenAuthorizerStorageServer is-a Referenceable.  It seems like
 # the built in adapter should take care of this case.
diff --git a/src/_secureaccesstokenauthorizer/tests/test_storage_protocol.py b/src/_secureaccesstokenauthorizer/tests/test_storage_protocol.py
index 35bd82d..b4f341b 100644
--- a/src/_secureaccesstokenauthorizer/tests/test_storage_protocol.py
+++ b/src/_secureaccesstokenauthorizer/tests/test_storage_protocol.py
@@ -275,6 +275,47 @@ class ImmutableTests(TestCase):
             Equals(int(now + RENEW_INTERVAL)),
         )
 
+    @given(
+        storage_index=storage_indexes(),
+        renew_secret=lease_renew_secrets(),
+        cancel_secret=lease_cancel_secrets(),
+        sharenum=sharenums(),
+        size=sizes(),
+    )
+    def test_advise_corrupt_share(self, storage_index, renew_secret, cancel_secret, sharenum, size):
+        """
+        An advisory of corruption in a share can be sent to the server.
+        """
+        # Hypothesis causes our storage server to be used many times.  Clean
+        # up between iterations.
+        cleanup_storage_server(self.anonymous_storage_server)
+
+        # Create a share we can toy with.
+        _, allocated = self.anonymous_storage_server.remote_allocate_buckets(
+            storage_index,
+            renew_secret,
+            cancel_secret,
+            {sharenum},
+            size,
+            canary=self.canary,
+        )
+        [(_, writer)] = allocated.items()
+        writer.remote_write(0, bytes_for_share(sharenum, size))
+        writer.remote_close()
+
+        extract_result(
+            self.client.advise_corrupt_share(
+                u"immutable",
+                storage_index,
+                sharenum,
+                u"the bits look bad",
+            ),
+        )
+        self.assertThat(
+            FilePath(self.anonymous_storage_server.corruption_advisory_dir).children(),
+            HasLength(1),
+        )
+
 
 def get_leases(storage_server, storage_index):
     """
@@ -304,7 +345,11 @@ def cleanup_storage_server(storage_server):
     :param allmydata.storage.server.StorageServer storage_server: The storage
         server with some on-disk shares to delete.
     """
-    start = FilePath(storage_server.sharedir)
-    for p in start.walk():
-        if p is not start:
-            p.remove()
+    starts = [
+        FilePath(storage_server.sharedir),
+        FilePath(storage_server.corruption_advisory_dir),
+    ]
+    for start in starts:
+        for p in start.walk():
+            if p is not start:
+                p.remove()
-- 
GitLab