commit 9c704fb10337a29e8d73c88b50a11a2ff5d9d83b
Author: Jan Pašek <janpasek97@gmail.com>
Date:   Thu Apr 15 11:39:39 2021 +0200

    Re #8571 - RestAPI testing

diff --git a/src/controllers/certificates_controller.py b/src/controllers/certificates_controller.py
index 023f712..1306fd9 100644
--- a/src/controllers/certificates_controller.py
+++ b/src/controllers/certificates_controller.py
@@ -12,7 +12,7 @@ from src.constants import CA_ID, \
 from src.exceptions.database_exception import DatabaseException
 from src.model.subject import Subject
 from src.services.certificate_service import CertificateService, RevocationReasonInvalidException, \
-    CertificateStatusInvalidException
+    CertificateStatusInvalidException, CertificateNotFoundException
 #  responsibility.
 from src.services.key_service import KeyService
 
@@ -31,7 +31,7 @@ VALIDITY_DAYS = "validityDays"
 CA = "CA"
 STATUS = "status"
 REASON = "reason"
-REASON_UNDEFINED = "undefined"
+REASON_UNDEFINED = "unspecified"
 
 E_NO_ISSUER_FOUND = {"success": False, "data": "No certificate authority with such unique ID exists."}
 E_NO_CERTIFICATES_FOUND = {"success": False, "data": "No such certificate found."}
@@ -339,14 +339,12 @@ class CertController:
             reason = request_body.get(REASON, REASON_UNDEFINED)
             try:
                 # set certificate status using certificate_service
-                self.certificate_service.set_certificate_revocation_status(status, reason)
-            except (RevocationReasonInvalidException, CertificateStatusInvalidException):
+                self.certificate_service.set_certificate_revocation_status(identifier, status, reason)
+            except (RevocationReasonInvalidException, CertificateStatusInvalidException, CertificateNotFoundException):
                 # these exceptions are thrown in case invalid status or revocation reason is passed to the controller
                 return E_WRONG_PARAMETERS, C_BAD_REQUEST
-            except DatabaseException:
-                return E_WRONG_PARAMETERS, C_BAD_REQUEST
             return {"success": True,
-                    "data": "Certificate status updated successfully."}, C_CREATED_SUCCESSFULLY
+                    "data": "Certificate status updated successfully."}, C_SUCCESS
         # throw an error in case the request does not contain a json body
         else:
             return E_NOT_JSON_FORMAT, C_BAD_REQUEST
diff --git a/src/services/certificate_service.py b/src/services/certificate_service.py
index aa8c370..4d27786 100644
--- a/src/services/certificate_service.py
+++ b/src/services/certificate_service.py
@@ -279,11 +279,15 @@ class CertificateService:
         if reason not in CERTIFICATE_REVOCATION_REASONS:
             raise RevocationReasonInvalidException(reason)
 
+        updated = False
         if status == STATUS_VALID:
-            self.certificate_repository.clear_certificate_revocation(id)
+            updated = self.certificate_repository.clear_certificate_revocation(id)
         elif status == STATUS_REVOKED:
             revocation_timestamp = int(time.time())
-            self.certificate_repository.set_certificate_revoked(id, str(revocation_timestamp), reason)
+            updated = self.certificate_repository.set_certificate_revoked(id, str(revocation_timestamp), reason)
+
+        if not updated:
+            raise CertificateNotFoundException(id)
 
     def get_subject_from_certificate(self, certificate: Certificate) -> Subject:
         """
@@ -348,3 +352,16 @@ class CertificateStatusInvalidException(Exception):
 
     def __str__(self):
         return f"Certificate status '{self.status}' is not valid."
+
+
+class CertificateNotFoundException(Exception):
+    """
+    Exception that denotes that the caller was trying to set
+    a certificate to an invalid state
+    """
+
+    def __init__(self, id):
+        self.id = id
+
+    def __str__(self):
+        return f"Certificate id '{self.id}' does not exist."
diff --git a/tests/integration_tests/rest_api/certificates_test.py b/tests/integration_tests/rest_api/certificates_test.py
index c17fc6e..9e6f751 100644
--- a/tests/integration_tests/rest_api/certificates_test.py
+++ b/tests/integration_tests/rest_api/certificates_test.py
@@ -591,3 +591,103 @@ def test_get_cert_public_key_incorrect_id(server):
         assert "success" in ret.json
         assert not ret.json["success"]
         assert "No such certificate found." == ret.json["data"]
+
+def test_set_certificate_status(server):
+    # Create certificate to be revoked later
+    certificate = {
+        "CA": 1,
+        "subject": {
+            "C": "EN",
+            "CN": "Certificate to be revoked",
+            "L": "Revokeland",
+            "O": "Revoked organization",
+            "OU": "Revocation dep"
+        },
+        "usage": {
+            "CA": False,
+            "SSL": False,
+            "authentication": False,
+            "digitalSignature": True
+        },
+        "validityDays": 60
+    }
+    created_ret = server.post("/api/certificates", content_type="application/json", json=certificate)
+
+    assert created_ret.status_code == 201
+
+    assert "data" in created_ret.json
+    assert "success" in created_ret.json
+    assert created_ret.json["success"]
+
+    d = created_ret.json
+    cert_id = d["data"]
+
+    # revoke the certificate
+    revocation_body = {
+        "status":  "revoked",
+        "reason": "keyCompromise"
+    }
+    revoke_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=revocation_body)
+
+    assert revoke_ret.status_code == 200
+    assert "data" in revoke_ret.json
+    assert "success" in revoke_ret.json
+    assert revoke_ret.json["success"]
+
+    # set to valid again
+    valid_body = {
+        "status":  "valid"
+    }
+    valid_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=valid_body)
+
+    assert valid_ret.status_code == 200
+    assert "data" in valid_ret.json
+    assert "success" in valid_ret.json
+    assert valid_ret.json["success"]
+
+    # wrong status
+    revocation_body = {
+        "status": "something",
+        "reason": "keyCompromise"
+    }
+    revoke_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=revocation_body)
+
+    assert revoke_ret.status_code == 400
+    assert "data" in revoke_ret.json
+    assert "success" in revoke_ret.json
+    assert not revoke_ret.json["success"]
+
+    # wrong reason
+    revocation_body = {
+        "status": "revoked",
+        "reason": "something"
+    }
+    revoke_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=revocation_body)
+
+    assert revoke_ret.status_code == 400
+    assert "data" in revoke_ret.json
+    assert "success" in revoke_ret.json
+    assert not revoke_ret.json["success"]
+
+    # missing status
+    revocation_body = {
+        "reason": "unspecified"
+    }
+    revoke_ret = server.patch(f"/api/certificates/{cert_id}", content_type="application/json", json=revocation_body)
+
+    assert revoke_ret.status_code == 400
+    assert "data" in revoke_ret.json
+    assert "success" in revoke_ret.json
+    assert not revoke_ret.json["success"]
+
+    # invalid id
+    revocation_body = {
+        "status": "revoked",
+        "reason": "keyCompromise"
+    }
+    revoke_ret = server.patch(f"/api/certificates/54791", content_type="application/json", json=revocation_body)
+
+    assert revoke_ret.status_code == 400
+    assert "data" in revoke_ret.json
+    assert "success" in revoke_ret.json
+    assert not revoke_ret.json["success"]
diff --git a/tests/integration_tests/services/certificate_service_test.py b/tests/integration_tests/services/certificate_service_test.py
index c0ca5eb..88cb13c 100644
--- a/tests/integration_tests/services/certificate_service_test.py
+++ b/tests/integration_tests/services/certificate_service_test.py
@@ -4,7 +4,8 @@ from sympy.testing import pytest
 
 from src.constants import SSL_ID, CA_ID, AUTHENTICATION_ID, INTERMEDIATE_CA_ID, ROOT_CA_ID, CERTIFICATE_ID, SIGNATURE_ID
 from src.model.subject import Subject
-from src.services.certificate_service import RevocationReasonInvalidException, CertificateStatusInvalidException
+from src.services.certificate_service import RevocationReasonInvalidException, CertificateStatusInvalidException, \
+    CertificateNotFoundException
 
 
 def export_crt(crt):
@@ -317,3 +318,6 @@ def test_set_certificate_revoked_errors(certificate_service_unique, private_key_
 
     with pytest.raises(CertificateStatusInvalidException) as e:
         certificate_service_unique.set_certificate_revocation_status(root_ca_cert.certificate_id, "bar", "unspecified")
+
+    with pytest.raises(CertificateNotFoundException) as e:
+        certificate_service_unique.set_certificate_revocation_status(5974, "revoked", "unspecified")
