← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/lp-signing:refactor-webapi-tests into lp-signing:master

 

Colin Watson has proposed merging ~cjwatson/lp-signing:refactor-webapi-tests into lp-signing:master.

Commit message:
Refactor some repetitive webapi tests

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/lp-signing/+git/lp-signing/+merge/381501

TestClient.post now handles the setup of encrypted data a bit more flexibly, and the various post_* methods have better defaults.  This allows most of the tests to specify just how they differ from a working request rather than having to repeat lots of things, which is more concise and easier to read.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/lp-signing:refactor-webapi-tests into lp-signing:master.
diff --git a/lp_signing/tests/test_webapi.py b/lp_signing/tests/test_webapi.py
index 84b5a9d..0201740 100644
--- a/lp_signing/tests/test_webapi.py
+++ b/lp_signing/tests/test_webapi.py
@@ -137,54 +137,41 @@ class TestGenerateView(TestCase):
         self.nonce = Nonce.generate().nonce
         store.commit()
 
+    def post_generate(self, json_data=None, **kwargs):
+        kwargs.setdefault("private_key", self.private_key)
+        kwargs.setdefault("nonce", self.nonce)
+        return self.fixture.client.post(
+            "/generate", json_data=json_data, **kwargs)
+
     def test_unauthenticated(self):
-        resp = self.fixture.client.post("/generate")
+        resp = self.post_generate(private_key=None)
         self.assertThat(resp, HasAPIError("Request not authenticated"))
 
     def test_undecodable_client_public_key(self):
-        resp = self.fixture.client.post(
-            "/generate",
-            headers={
-                "X-Client-Public-Key": "nonsense key",
-                "X-Nonce": base64.b64encode(self.nonce).decode("UTF-8"),
-                })
+        resp = self.post_generate(
+            headers={"X-Client-Public-Key": "nonsense key"})
         self.assertThat(resp, HasAPIError("Cannot decode client public key"))
 
     def test_undecodable_nonce(self):
-        resp = self.fixture.client.post(
-            "/generate",
-            headers={
-                "X-Client-Public-Key": self.private_key.public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": "nonsense nonce",
-                })
+        resp = self.post_generate(headers={"X-Nonce": "nonsense nonce"})
         self.assertThat(resp, HasAPIError("Cannot decode nonce"))
 
     def test_nonce_already_used(self):
         Nonce.check(self.nonce)
-        resp = self.fixture.client.post(
-            "/generate", private_key=self.private_key, nonce=self.nonce)
+        resp = self.post_generate()
         self.assertThat(resp, HasAPIError("Invalid nonce"))
 
     def assertNonceConsumed(self):
         self.assertRaises(InvalidNonce, Nonce.check, self.nonce)
 
     def test_unboxable_data(self):
-        resp = self.fixture.client.post(
-            "/generate",
-            headers={
-                "X-Client-Public-Key": self.private_key.public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": base64.b64encode(self.nonce).decode("UTF-8"),
-                },
-            data=b"data")
+        resp = self.post_generate(encrypted_data=b"data")
         self.assertThat(resp, HasAPIError("Authentication failed"))
         self.assertNonceConsumed()
 
     def test_unregistered_private_key(self):
         private_key = PrivateKey.generate()
-        resp = self.fixture.client.post(
-            "/generate", private_key=private_key, nonce=self.nonce)
+        resp = self.post_generate(private_key=private_key)
         self.assertThat(resp, HasAPIError("Unregistered client public key"))
         self.assertNonceConsumed()
 
@@ -192,28 +179,15 @@ class TestGenerateView(TestCase):
         private_key = PrivateKey.generate()
         box = Box(self.private_key, private_key.public_key)
         message = box.encrypt(b"{}", self.nonce, encoder=Base64Encoder)
-        resp = self.fixture.client.post(
-            "/generate",
-            headers={
-                "X-Client-Public-Key": self.private_key.public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": message.nonce.decode("UTF-8"),
-                },
-            data=message.ciphertext)
+        resp = self.post_generate(encrypted_data=message.ciphertext)
         self.assertThat(resp, HasAPIError("Authentication failed"))
         self.assertNonceConsumed()
 
     def test_no_json(self):
-        resp = self.fixture.client.post(
-            "/generate", private_key=self.private_key, nonce=self.nonce)
+        resp = self.post_generate()
         self.assertThat(resp, HasAPIError("Error decoding JSON request body"))
         self.assertNonceConsumed()
 
-    def post_generate(self, json_data=None):
-        return self.fixture.client.post(
-            "/generate", json_data=json_data,
-            private_key=self.private_key, nonce=self.nonce)
-
     def test_missing_key_type(self):
         resp = self.post_generate({"description": ""})
         self.assertThat(
@@ -564,54 +538,39 @@ class TestSignView(TestCase):
         self.nonce = Nonce.generate().nonce
         store.commit()
 
+    def post_sign(self, json_data=None, **kwargs):
+        kwargs.setdefault("private_key", self.private_key)
+        kwargs.setdefault("nonce", self.nonce)
+        return self.fixture.client.post("/sign", json_data=json_data, **kwargs)
+
     def test_unauthenticated(self):
-        resp = self.fixture.client.post("/sign")
+        resp = self.post_sign(private_key=None)
         self.assertThat(resp, HasAPIError("Request not authenticated"))
 
     def test_undecodable_client_public_key(self):
-        resp = self.fixture.client.post(
-            "/sign",
-            headers={
-                "X-Client-Public-Key": "nonsense key",
-                "X-Nonce": base64.b64encode(self.nonce).decode("UTF-8"),
-                })
+        resp = self.post_sign(headers={"X-Client-Public-Key": "nonsense key"})
         self.assertThat(resp, HasAPIError("Cannot decode client public key"))
 
     def test_undecodable_nonce(self):
-        resp = self.fixture.client.post(
-            "/sign",
-            headers={
-                "X-Client-Public-Key": self.private_key.public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": "nonsense nonce",
-                })
+        resp = self.post_sign(headers={"X-Nonce": "nonsense nonce"})
         self.assertThat(resp, HasAPIError("Cannot decode nonce"))
 
     def test_nonce_already_used(self):
         Nonce.check(self.nonce)
-        resp = self.fixture.client.post(
-            "/sign", private_key=self.private_key, nonce=self.nonce)
+        resp = self.post_sign()
         self.assertThat(resp, HasAPIError("Invalid nonce"))
 
     def assertNonceConsumed(self):
         self.assertRaises(InvalidNonce, Nonce.check, self.nonce)
 
     def test_unboxable_data(self):
-        resp = self.fixture.client.post(
-            "/sign",
-            headers={
-                "X-Client-Public-Key": self.private_key.public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": base64.b64encode(self.nonce).decode("UTF-8"),
-                },
-            data=b"data")
+        resp = self.post_sign(encrypted_data=b"data")
         self.assertThat(resp, HasAPIError("Authentication failed"))
         self.assertNonceConsumed()
 
     def test_unregistered_private_key(self):
         private_key = PrivateKey.generate()
-        resp = self.fixture.client.post(
-            "/sign", private_key=private_key, nonce=self.nonce)
+        resp = self.post_sign(private_key=private_key)
         self.assertThat(resp, HasAPIError("Unregistered client public key"))
         self.assertNonceConsumed()
 
@@ -619,28 +578,15 @@ class TestSignView(TestCase):
         private_key = PrivateKey.generate()
         box = Box(self.private_key, private_key.public_key)
         message = box.encrypt(b"{}", self.nonce, encoder=Base64Encoder)
-        resp = self.fixture.client.post(
-            "/sign",
-            headers={
-                "X-Client-Public-Key": self.private_key.public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": message.nonce.decode("UTF-8"),
-                },
-            data=message.ciphertext)
+        resp = self.post_sign(encrypted_data=message.ciphertext)
         self.assertThat(resp, HasAPIError("Authentication failed"))
         self.assertNonceConsumed()
 
     def test_no_json(self):
-        resp = self.fixture.client.post(
-            "/sign", private_key=self.private_key, nonce=self.nonce)
+        resp = self.post_sign()
         self.assertThat(resp, HasAPIError("Error decoding JSON request body"))
         self.assertNonceConsumed()
 
-    def post_sign(self, json_data=None):
-        return self.fixture.client.post(
-            "/sign", json_data=json_data,
-            private_key=self.private_key, nonce=self.nonce)
-
     def test_missing_key_type(self):
         resp = self.post_sign(
             {
@@ -1099,54 +1045,41 @@ class TestInjectView(TestCase):
 
         store.commit()
 
+    def post_inject(self, json_data=None, index=0, **kwargs):
+        kwargs.setdefault("private_key", self.private_keys[index])
+        kwargs.setdefault("nonce", self.nonces[index])
+        return self.fixture.client.post(
+            "/inject", json_data=json_data, **kwargs)
+
     def test_unauthenticated(self):
-        resp = self.fixture.client.post("/inject")
+        resp = self.post_inject(private_key=None)
         self.assertThat(resp, HasAPIError("Request not authenticated"))
 
     def test_undecodable_client_public_key(self):
-        resp = self.fixture.client.post(
-            "/inject",
-            headers={
-                "X-Client-Public-Key": "nonsense key",
-                "X-Nonce": base64.b64encode(self.nonces[0]).decode("UTF-8"),
-                })
+        resp = self.post_inject(
+            headers={"X-Client-Public-Key": "nonsense key"})
         self.assertThat(resp, HasAPIError("Cannot decode client public key"))
 
     def test_undecodable_nonce(self):
-        resp = self.fixture.client.post(
-            "/inject",
-            headers={
-                "X-Client-Public-Key": self.private_keys[0].public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": "nonsense nonce",
-                })
+        resp = self.post_inject(headers={"X-Nonce": "nonsense nonce"})
         self.assertThat(resp, HasAPIError("Cannot decode nonce"))
 
     def test_nonce_already_used(self):
         Nonce.check(self.nonces[0])
-        resp = self.fixture.client.post(
-            "/inject", private_key=self.private_keys[0], nonce=self.nonces[0])
+        resp = self.post_inject()
         self.assertThat(resp, HasAPIError("Invalid nonce"))
 
     def assertNonceConsumed(self):
         self.assertRaises(InvalidNonce, Nonce.check, self.nonces[0])
 
     def test_unboxable_data(self):
-        resp = self.fixture.client.post(
-            "/inject",
-            headers={
-                "X-Client-Public-Key": self.private_keys[0].public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": base64.b64encode(self.nonces[0]).decode("UTF-8"),
-                },
-            data=b"data")
+        resp = self.post_inject(encrypted_data=b"data")
         self.assertThat(resp, HasAPIError("Authentication failed"))
         self.assertNonceConsumed()
 
     def test_unregistered_private_key(self):
         private_key = PrivateKey.generate()
-        resp = self.fixture.client.post(
-            "/inject", private_key=private_key, nonce=self.nonces[0])
+        resp = self.post_inject(private_key=private_key)
         self.assertThat(resp, HasAPIError("Unregistered client public key"))
         self.assertNonceConsumed()
 
@@ -1154,28 +1087,15 @@ class TestInjectView(TestCase):
         private_key = PrivateKey.generate()
         box = Box(self.private_keys[0], private_key.public_key)
         message = box.encrypt(b"{}", self.nonces[0], encoder=Base64Encoder)
-        resp = self.fixture.client.post(
-            "/inject",
-            headers={
-                "X-Client-Public-Key": self.private_keys[0].public_key.encode(
-                    encoder=Base64Encoder).decode("UTF-8"),
-                "X-Nonce": message.nonce.decode("UTF-8"),
-                },
-            data=message.ciphertext)
+        resp = self.post_inject(encrypted_data=message.ciphertext)
         self.assertThat(resp, HasAPIError("Authentication failed"))
         self.assertNonceConsumed()
 
     def test_no_json(self):
-        resp = self.fixture.client.post(
-            "/inject", private_key=self.private_keys[0], nonce=self.nonces[0])
+        resp = self.post_inject()
         self.assertThat(resp, HasAPIError("Error decoding JSON request body"))
         self.assertNonceConsumed()
 
-    def post_inject(self, json_data=None, index=0):
-        return self.fixture.client.post(
-            "/inject", json_data=json_data,
-            private_key=self.private_keys[index], nonce=self.nonces[index])
-
     def test_missing_key_type(self):
         resp = self.post_inject({"private-key": "",
                                  "public-key": "",
diff --git a/lp_signing/tests/testfixtures.py b/lp_signing/tests/testfixtures.py
index 433b0b8..8cfb84d 100644
--- a/lp_signing/tests/testfixtures.py
+++ b/lp_signing/tests/testfixtures.py
@@ -75,7 +75,7 @@ class TestClient(FlaskClient):
     """A Flask client that understands JSON and boxed authentication."""
 
     def post(self, *args, headers=None, data=None, json_data=None,
-             private_key=None, nonce=None, **kwargs):
+             encrypted_data=None, private_key=None, nonce=None, **kwargs):
         headers = dict(headers) if headers else {}
         if json_data is not None:
             if data is not None:
@@ -84,18 +84,27 @@ class TestClient(FlaskClient):
             if "Content-Type" not in headers:
                 headers["Content-Type"] = "application/json"
             data = json.dumps(json_data).encode("UTF-8")
-        if private_key is not None and nonce is not None:
+        if private_key is not None:
+            headers.setdefault(
+                "X-Client-Public-Key",
+                private_key.public_key.encode(
+                    encoder=Base64Encoder).decode("UTF-8"))
+        if nonce is not None:
+            headers.setdefault(
+                "X-Nonce", Base64Encoder.encode(nonce).decode("UTF-8"))
+        if (private_key is not None and nonce is not None and
+                encrypted_data is None):
             data = data or b""
-            headers["X-Client-Public-Key"] = private_key.public_key.encode(
-                encoder=Base64Encoder).decode("UTF-8")
             box = Box(
                 private_key,
                 boxed_authentication.service_private_keys[0].public_key)
             message = box.encrypt(data, nonce, encoder=Base64Encoder)
-            headers["X-Nonce"] = message.nonce.decode("UTF-8")
             headers["Content-Type"] = "application/x-boxed-json"
-            data = message.ciphertext
-        resp = super().post(*args, headers=headers, data=data, **kwargs)
+            encrypted_data = message.ciphertext
+        else:
+            encrypted_data = data
+        resp = super().post(
+            *args, headers=headers, data=encrypted_data, **kwargs)
         # If there's a current transaction, roll it back.  The POST may have
         # committed a transaction in another thread, so anything we try to
         # commit might otherwise conflict with that.