fix bug on period in Test API
[releng.git] / utils / test / result_collection_api / resources / handlers.py
index 35aea0c..6443fc4 100644 (file)
@@ -11,13 +11,17 @@ import json
 
 from tornado.web import RequestHandler, asynchronous, HTTPError
 from tornado import gen
-from datetime import datetime
+from datetime import datetime, timedelta
 
 from models import Pod, TestProject, TestCase, TestResult
 from common.constants import DEFAULT_REPRESENTATION, HTTP_BAD_REQUEST, \
     HTTP_NOT_FOUND, HTTP_FORBIDDEN
 from common.config import prepare_put_request
 
+from dashboard.dashboard_utils import get_dashboard_cases, \
+    check_dashboard_ready_project, check_dashboard_ready_case, \
+    get_dashboard_result
+
 
 class GenericApiHandler(RequestHandler):
     """
@@ -60,6 +64,8 @@ class PodHandler(GenericApiHandler):
     """ Handle the requests about the POD Platforms
     HTTP Methdods :
         - GET : Get PODS
+        - POST : Create a pod
+        - DELETE : DELETE POD
     """
 
     def initialize(self):
@@ -68,19 +74,15 @@ class PodHandler(GenericApiHandler):
 
     @asynchronous
     @gen.coroutine
-    def get(self, pod_id=None):
+    def get(self, pod_name=None):
         """
         Get all pods or a single pod
         :param pod_id:
         """
-
-        if pod_id is None:
-            pod_id = ""
-
         get_request = dict()
 
-        if len(pod_id) > 0:
-            get_request["_id"] = int(pod_id)
+        if pod_name is not None:
+            get_request["name"] = pod_name
 
         res = []
         cursor = self.db.pod.find(get_request)
@@ -98,6 +100,69 @@ class PodHandler(GenericApiHandler):
 
         self.finish_request(answer)
 
+    @asynchronous
+    @gen.coroutine
+    def post(self):
+        """ Create a POD"""
+
+        if self.json_args is None:
+            raise HTTPError(HTTP_BAD_REQUEST)
+
+        query = {"name": self.json_args.get("name")}
+
+        # check for existing name in db
+        mongo_dict = yield self.db.pod.find_one(query)
+        if mongo_dict is not None:
+            raise HTTPError(HTTP_FORBIDDEN,
+                            "{} already exists as a pod".format(
+                                self.json_args.get("name")))
+
+        pod = Pod.pod_from_dict(self.json_args)
+        pod.creation_date = datetime.now()
+
+        future = self.db.pod.insert(pod.format())
+        result = yield future
+        pod._id = result
+
+        meta = dict()
+        meta["success"] = True
+        meta["uri"] = "/pods/{}".format(pod.name)
+
+        answer = dict()
+        answer["pod"] = pod.format_http()
+        answer["meta"] = meta
+
+        self.finish_request(answer)
+
+    @asynchronous
+    @gen.coroutine
+    def delete(self, pod_name):
+        """ Remove a POD
+
+        # check for an existing pod to be deleted
+        mongo_dict = yield self.db.pod.find_one(
+            {'name': pod_name})
+        pod = TestProject.pod(mongo_dict)
+        if pod is None:
+            raise HTTPError(HTTP_NOT_FOUND,
+                            "{} could not be found as a pod to be deleted"
+                            .format(pod_name))
+
+        # just delete it, or maybe save it elsewhere in a future
+        res = yield self.db.test_projects.remove(
+            {'name': pod_name})
+
+        meta = dict()
+        meta["success"] = True
+        meta["deletion-data"] = res
+
+        answer = dict()
+        answer["meta"] = meta
+
+        self.finish_request(answer)
+        """
+        pass
+
 
 class TestProjectHandler(GenericApiHandler):
     """
@@ -440,18 +505,26 @@ class TestResultsHandler(GenericApiHandler):
         Available filters for this request are :
          - project : project name
          - case : case name
-         - pod : pod ID
+         - pod : pod name
+         - version : platform version (Arno-R1, ...)
+         - installer (fuel, ...)
+         - period : x (x last days)
+
 
         :param result_id: Get a result by ID
         :raise HTTPError
 
-        GET /results/project=functest&case=keystone.catalog&pod=1
+        GET /results/project=functest&case=vPing&version=Arno-R1 \
+        &pod=pod_name&period=15
         => get results with optional filters
         """
 
         project_arg = self.get_query_argument("project", None)
         case_arg = self.get_query_argument("case", None)
         pod_arg = self.get_query_argument("pod", None)
+        version_arg = self.get_query_argument("version", None)
+        installer_arg = self.get_query_argument("installer", None)
+        period_arg = self.get_query_argument("period", None)
 
         # prepare request
         get_request = dict()
@@ -463,15 +536,34 @@ class TestResultsHandler(GenericApiHandler):
                 get_request["case_name"] = case_arg
 
             if pod_arg is not None:
-                get_request["pod_id"] = pod_arg
+                get_request["pod_name"] = pod_arg
+
+            if version_arg is not None:
+                get_request["version"] = version_arg
+
+            if installer_arg is not None:
+                get_request["installer"] = installer_arg
+
+            if period_arg is not None:
+                try:
+                    period_arg = int(period_arg)
+                except:
+                    raise HTTPError(HTTP_BAD_REQUEST)
+
+                if period_arg > 0:
+                    period = datetime.now() - timedelta(days=period_arg)
+                    obj = {"$gte": str(period)}
+                    get_request["creation_date"] = obj
         else:
             get_request["_id"] = result_id
 
+        print get_request
         res = []
         # fetching results
         cursor = self.db.test_results.find(get_request)
         while (yield cursor.fetch_next):
-            test_result = TestResult.test_result_from_dict(cursor.next_object())
+            test_result = TestResult.test_result_from_dict(
+                cursor.next_object())
             res.append(test_result.format_http())
 
         # building meta object
@@ -502,7 +594,9 @@ class TestResultsHandler(GenericApiHandler):
             raise HTTPError(HTTP_BAD_REQUEST)
         if self.json_args.get("case_name") is None:
             raise HTTPError(HTTP_BAD_REQUEST)
-        if self.json_args.get("pod_id") is None:
+        # check for pod_name instead of id,
+        # keeping id for current implementations
+        if self.json_args.get("pod_name") is None:
             raise HTTPError(HTTP_BAD_REQUEST)
 
         # TODO : replace checks with jsonschema
@@ -524,18 +618,160 @@ class TestResultsHandler(GenericApiHandler):
 
         # check for pod
         mongo_dict = yield self.db.pod.find_one(
-            {"_id": self.json_args.get("pod_id")})
+            {"name": self.json_args.get("pod_name")})
         if mongo_dict is None:
             raise HTTPError(HTTP_NOT_FOUND,
                             "Could not find POD [{}] "
-                            .format(self.json_args.get("pod_id")))
+                            .format(self.json_args.get("pod_name")))
 
         # convert payload to object
         test_result = TestResult.test_result_from_dict(self.json_args)
         test_result.creation_date = datetime.now()
 
-        future = self.db.test_results.insert(test_result.format())
+        future = self.db.test_results.insert(test_result.format(),
+                                             check_keys=False)
         result = yield future
         test_result._id = result
 
         self.finish_request(test_result.format_http())
+
+
+class DashboardHandler(GenericApiHandler):
+    """
+    DashboardHandler Class
+    Handle the requests about the Test project's results
+    in a dahboard ready format
+    HTTP Methdods :
+        - GET : Get all test results and details about a specific one
+    """
+    def initialize(self):
+        """ Prepares the database for the entire class """
+        super(DashboardHandler, self).initialize()
+        self.name = "dashboard"
+
+    @asynchronous
+    @gen.coroutine
+    def get(self, result_id=None):
+        """
+        Retrieve dashboard ready result(s) for a test project
+        Available filters for this request are :
+         - project : project name
+         - case : case name
+         - pod : pod name
+         - version : platform version (Arno-R1, ...)
+         - installer (fuel, ...)
+         - period : x (x last days)
+
+
+        :param result_id: Get a result by ID
+        :raise HTTPError
+
+        GET /dashboard?project=functest&case=vPing&version=Arno-R1 \
+        &pod=pod_name&period=15
+        => get results with optional filters
+        """
+
+        project_arg = self.get_query_argument("project", None)
+        case_arg = self.get_query_argument("case", None)
+        pod_arg = self.get_query_argument("pod", None)
+        version_arg = self.get_query_argument("version", None)
+        installer_arg = self.get_query_argument("installer", None)
+        period_arg = self.get_query_argument("period", None)
+
+        # prepare request
+        get_request = dict()
+
+        # /dashboard?project=<>&pod=<>...
+        if (result_id is None):
+            if project_arg is not None:
+                get_request["project_name"] = project_arg
+
+            if case_arg is not None:
+                get_request["case_name"] = case_arg
+
+            if pod_arg is not None:
+                get_request["pod_name"] = pod_arg
+
+            if version_arg is not None:
+                get_request["version"] = version_arg
+
+            if installer_arg is not None:
+                get_request["installer"] = installer_arg
+
+            if period_arg is not None:
+                try:
+                    period_arg = int(period_arg)
+                except:
+                    raise HTTPError(HTTP_BAD_REQUEST)
+                if period_arg > 0:
+                    period = datetime.now() - timedelta(days=period_arg)
+                    obj = {"$gte": str(period)}
+                    get_request["creation_date"] = obj
+        else:
+            get_request["_id"] = result_id
+
+        dashboard = []
+
+        # on /dashboard retrieve the list of projects and testcases
+        # ready for dashboard
+        if project_arg is None:
+            raise HTTPError(HTTP_NOT_FOUND,
+                            "error:Project name missing")
+        elif check_dashboard_ready_project(project_arg, "./dashboard"):
+            res = []
+
+            if case_arg is None:
+                raise HTTPError(
+                    HTTP_NOT_FOUND,
+                    "error:Test case missing for project " + project_arg)
+
+            # special case of status for project
+            if case_arg == "status":
+                del get_request["case_name"]
+                # retention time to be agreed
+                # last five days by default?
+                # TODO move to DB
+                period = datetime.now() - timedelta(days=5)
+                get_request["creation_date"] = {"$gte": period}
+
+            # fetching results
+            cursor = self.db.test_results.find(get_request)
+            while (yield cursor.fetch_next):
+                test_result = TestResult.test_result_from_dict(
+                    cursor.next_object())
+                res.append(test_result.format_http())
+
+            if check_dashboard_ready_case(project_arg, case_arg):
+                dashboard = get_dashboard_result(project_arg, case_arg, res)
+            else:
+                raise HTTPError(
+                    HTTP_NOT_FOUND,
+                    "error:" + case_arg +
+                    " test case not case dashboard ready on project " +
+                    project_arg)
+
+        else:
+            dashboard.append(
+                {"error": "Project not recognized or not dashboard ready"})
+            dashboard.append(
+                {"Dashboard-ready-projects":
+                    get_dashboard_cases("./dashboard")})
+            raise HTTPError(
+                HTTP_NOT_FOUND,
+                "error: no dashboard ready data for this project")
+
+        # fetching results
+        # cursor = self.db.test_results.find(get_request)
+        # while (yield cursor.fetch_next):
+        #    test_result = TestResult.test_result_from_dict(
+        #        cursor.next_object())
+        #    res.append(test_result.format_http())
+
+        # building meta object
+        meta = dict()
+
+        # final response object
+        answer = dict()
+        answer["dashboard"] = dashboard
+        answer["meta"] = meta
+        self.finish_request(answer)