Repository: LifeguardSystem/lifeguard (language: python)

Issue:
Endpoint to return global status



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index a38b1d5..d7fa664 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,74 @@ To see all settings avaiable run command:
 
 `lifeguard -d`
 
+## Builtin Endpoints 
+
+### Recover Status
+
+__To get global status and all validations.__
+
+`GET /lifeguard/status/complete`
+
+```json
+{
+
+    "status": "NORMAL",
+    "validations": [
+        {
+            "validation_name": "pudim",
+            "status": "NORMAL",
+            "details": {
+                "NORMAL": 200
+            },
+            "settings": {
+                "notification": {
+                    "notify": true
+                }
+            },
+            "last_execution": "2021-06-15T10:46"
+        },
+        {
+            "validation_name": "my site",
+            "status": "NORMAL",
+            "details": {
+                "NORMAL": 200
+            },
+            "settings": {
+                "notification": {
+                    "notify": true
+                }
+            },
+            "last_execution": "2021-06-15T10:46"
+        }
+    ]
+}
+```
+
+__To get global status and only non normal validations.__
+
+`GET /lifeguard/status`
+
+```json
+{
+
+    "status": "PROBLEM",
+    "validations": [
+        {
+            "validation_name": "my site",
+            "status": "PROBLEM",
+            "details": {
+                "NORMAL": 200
+            },
+            "settings": {
+                "notification": {
+                    "notify": true
+                }
+            },
+            "last_execution": "2021-06-15T10:46"
+        }
+    ]
+}
+```
 
 ## Authentication
 
diff --git a/lifeguard/server.py b/lifeguard/server.py
index a44ab9d..89dcd07 100644
--- a/lifeguard/server.py
+++ b/lifeguard/server.py
@@ -4,6 +4,7 @@
 
 from flask import Flask, make_response
 
+from lifeguard import NORMAL, PROBLEM, change_status
 from lifeguard.controllers import custom_controllers, login_required
 from lifeguard.logger import lifeguard_logger as logger
 from lifeguard.repositories import ValidationRepository
@@ -13,11 +14,52 @@
 
 
 def make_json_response(content):
+    """
+    Make default json response
+    """
     response = make_response(content)
     response.headers["Content-Type"] = "application/json"
     return response
 
 
+def build_global_status(complete=False):
+    """
+    Build global status method
+    """
+    try:
+        response = {"status": NORMAL, "validations": []}
+        repository = ValidationRepository()
+        for validation in repository.fetch_all_validation_results():
+            response["status"] = change_status(response["status"], validation.status)
+            if complete or validation.status != NORMAL:
+                response["validations"].append(validation)
+        return make_json_response(ValidationResponseEncoder().encode(response))
+    except Exception:
+        logger.error(
+            "error on execute get status",
+            extra={"traceback": traceback.format_exc()},
+        )
+        return make_json_response(json.dumps({"error": traceback.format_exc()}))
+
+
+@APP.route("/lifeguard/status", methods=["GET"])
+@login_required
+def get_status():
+    """
+    Return global status
+    """
+    return build_global_status()
+
+
+@APP.route("/lifeguard/status/complete", methods=["GET"])
+@login_required
+def get_status_complete():
+    """
+    Return global status with details
+    """
+    return build_global_status(True)
+
+
 @APP.route("/lifeguard/validations/<validation>", methods=["GET"])
 @login_required
 def get_validation(validation):
diff --git a/setup.py b/setup.py
index 84f32e9..d855fb3 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 
 setup(
     name="lifeguard",
-    version="0.0.22",
+    version="0.0.23",
     url="https://github.com/LifeguardSystem/lifeguard",
     author="Diego Rubin",
     author_email="contact@diegorubin.dev",


Test patch:
diff --git a/tests/test_server.py b/tests/test_server.py
index 54fc21e..e238caa 100644
--- a/tests/test_server.py
+++ b/tests/test_server.py
@@ -2,8 +2,13 @@
 import unittest
 from unittest.mock import MagicMock, patch
 
-from lifeguard import NORMAL
-from lifeguard.server import execute_validation, get_validation
+from lifeguard import NORMAL, PROBLEM
+from lifeguard.server import (
+    execute_validation,
+    get_validation,
+    get_status,
+    get_status_complete,
+)
 from lifeguard.validations import ValidationResponse
 
 test_validation = MagicMock(name="test_validation")
@@ -57,3 +62,77 @@ def test_get_validation_result(
 
         response = get_validation("test_validation")
         self.assertEqual(response, mock_response)
+
+    @patch("lifeguard.server.make_response")
+    @patch("lifeguard.server.ValidationRepository")
+    def test_get_status(self, mock_validation_repository, mock_make_response):
+
+        mock_response = MagicMock(name="mock_response")
+        mock_make_response.return_value = mock_response
+
+        mock_repository_instance = MagicMock(name="mock_repository_instance")
+        mock_validation_repository.return_value = mock_repository_instance
+        mock_repository_instance.fetch_all_validation_results.return_value = [
+            ValidationResponse("test_validation", PROBLEM, {})
+        ]
+
+        response = get_status()
+        mock_make_response.assert_called_with(
+            '{"status": "PROBLEM", "validations": [{"validation_name": "test_validation", "status": "PROBLEM", "details": {}, "settings": null}]}'
+        )
+        self.assertEqual(response, mock_response)
+
+    @patch("lifeguard.server.make_response")
+    @patch("lifeguard.server.ValidationRepository")
+    def test_get_status_validations_empty_when_normal(
+        self, mock_validation_repository, mock_make_response
+    ):
+
+        mock_response = MagicMock(name="mock_response")
+        mock_make_response.return_value = mock_response
+
+        mock_repository_instance = MagicMock(name="mock_repository_instance")
+        mock_validation_repository.return_value = mock_repository_instance
+        mock_repository_instance.fetch_all_validation_results.return_value = [
+            ValidationResponse("test_validation", NORMAL, {})
+        ]
+
+        response = get_status()
+        mock_make_response.assert_called_with('{"status": "NORMAL", "validations": []}')
+        self.assertEqual(response, mock_response)
+
+    @patch("lifeguard.server.make_response")
+    @patch("lifeguard.server.ValidationRepository")
+    def test_get_status_complete(self, mock_validation_repository, mock_make_response):
+
+        mock_response = MagicMock(name="mock_response")
+        mock_make_response.return_value = mock_response
+
+        mock_repository_instance = MagicMock(name="mock_repository_instance")
+        mock_validation_repository.return_value = mock_repository_instance
+        mock_repository_instance.fetch_all_validation_results.return_value = [
+            ValidationResponse("test_validation", NORMAL, {})
+        ]
+
+        response = get_status_complete()
+        mock_make_response.assert_called_with(
+            '{"status": "NORMAL", "validations": [{"validation_name": "test_validation", "status": "NORMAL", "details": {}, "settings": null}]}'
+        )
+        self.assertEqual(response, mock_response)
+
+    @patch("lifeguard.server.make_response")
+    @patch("lifeguard.server.ValidationRepository")
+    @patch("lifeguard.server.traceback")
+    def test_get_status_on_exception(
+        self, mock_traceback, mock_validation_repository, mock_make_response
+    ):
+
+        mock_traceback.format_exc.return_value = "traceback"
+
+        mock_response = MagicMock(name="mock_response")
+        mock_make_response.return_value = mock_response
+
+        mock_validation_repository.side_effect = [Exception("error")]
+
+        response = get_status_complete()
+        self.assertEqual(response, mock_response)