Merge "Modify YARDSTICK_DB_BACKEND value on zte-pod1."
[releng.git] / utils / test / result_collection_api / resources / handlers.py
index 64f75c2..fff1662 100644 (file)
@@ -11,13 +11,18 @@ 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 models import TestProject, TestCase, TestResult
+from resources.pod_models import Pod
 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):
     """
@@ -32,7 +37,7 @@ class GenericApiHandler(RequestHandler):
 
     def prepare(self):
         if not (self.request.method == "GET"):
-            if not (self.request.headers.get("Content-Type") is None):
+            if self.request.headers.get("Content-Type") is not None:
                 if self.request.headers["Content-Type"].startswith(
                         DEFAULT_REPRESENTATION):
                     try:
@@ -60,6 +65,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 +75,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 +101,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):
     """
@@ -159,7 +225,7 @@ class TestProjectHandler(GenericApiHandler):
 
         # check for name in db
         mongo_dict = yield self.db.test_projects.find_one(query)
-        if not (mongo_dict is None):
+        if mongo_dict is not None:
             raise HTTPError(HTTP_FORBIDDEN,
                             "{} already exists as a project".format(
                                 self.json_args.get("name")))
@@ -195,7 +261,7 @@ class TestProjectHandler(GenericApiHandler):
         if new_name != test_project.name:
             mongo_dict = yield self.db.test_projects.find_one(
                 {"name": new_name})
-            if not (mongo_dict is None):
+            if mongo_dict is not None:
                 raise HTTPError(HTTP_FORBIDDEN,
                                 "{} already exists as a project"
                                 .format(new_name))
@@ -235,9 +301,9 @@ class TestProjectHandler(GenericApiHandler):
 
         print "DELETE request for : {}".format(project_name)
 
-        # check for an existing case to be deleted
-        mongo_dict = yield self.db.test_cases.find_one(
-            {'project_name': project_name})
+        # check for an existing project to be deleted
+        mongo_dict = yield self.db.test_projects.find_one(
+            {'name': project_name})
         test_project = TestProject.testproject_from_dict(mongo_dict)
         if test_project is None:
             raise HTTPError(HTTP_NOT_FOUND,
@@ -246,7 +312,7 @@ class TestProjectHandler(GenericApiHandler):
 
         # just delete it, or maybe save it elsewhere in a future
         res = yield self.db.test_projects.remove(
-            {'project_name': project_name})
+            {'name': project_name})
         print res
 
         self.finish_request({"message": "success"})
@@ -358,7 +424,7 @@ class TestCasesHandler(GenericApiHandler):
         # with the name provided in the json payload
         mongo_dict = yield self.db.test_cases.find_one(
             {'project_name': new_project_name, 'name': new_name})
-        if not (mongo_dict is None):
+        if mongo_dict is not None:
             raise HTTPError(HTTP_FORBIDDEN,
                             "{} already exists as a project"
                             .format(new_name))
@@ -440,49 +506,96 @@ 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, ...)
+         - build_tag : Jenkins build tag name
+         - period : x (x last days)
+         - scenario : the test scenario (previously version)
+         - criteria : the global criteria status passed or failed
+         - trust_indicator : evaluate the stability of the test case to avoid
+         running systematically long and stable test case
+
 
         :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_arguments("case", None)
-        pod_arg = self.get_query_arguments("pod", 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)
+        build_tag_arg = self.get_query_argument("build_tag", None)
+        scenario_arg = self.get_query_argument("scenario", None)
+        criteria_arg = self.get_query_argument("criteria", None)
+        period_arg = self.get_query_argument("period", None)
+        trust_indicator_arg = self.get_query_argument("trust_indicator", None)
 
         # prepare request
         get_request = dict()
         if result_id is None:
-            if not (project_arg is None):
+            if project_arg is not None:
                 get_request["project_name"] = project_arg
 
-            if not (case_arg is None):
+            if case_arg is not None:
                 get_request["case_name"] = case_arg
 
-            if not (pod_arg is None):
-                get_request["pod_id"] = pod_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 build_tag_arg is not None:
+                get_request["build_tag"] = build_tag_arg
+
+            if scenario_arg is not None:
+                get_request["scenario"] = scenario_arg
+
+            if criteria_arg is not None:
+                get_request["criteria_tag"] = criteria_arg
+
+            if trust_indicator_arg is not None:
+                get_request["trust_indicator_arg"] = trust_indicator_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_cases.find(get_request)
+        cursor = self.db.test_results.find(get_request)
         while (yield cursor.fetch_next):
-            test_case = TestCase.test_case_from_dict(cursor.next_object)
-            res.append(test_case.format_http())
+            test_result = TestResult.test_result_from_dict(
+                cursor.next_object())
+            res.append(test_result.format_http())
 
         # building meta object
         meta = dict()
-        meta["total"] = res.count()
+        meta["total"] = len(res)
 
         # final response object
         answer = dict()
         answer["test_results"] = res
         answer["meta"] = meta
-
         self.finish_request(answer)
 
     @asynchronous
@@ -503,14 +616,16 @@ 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
         # check for project
         mongo_dict = yield self.db.test_projects.find_one(
             {"name": self.json_args.get("project_name")})
-        if not (mongo_dict is None):
+        if mongo_dict is None:
             raise HTTPError(HTTP_NOT_FOUND,
                             "Could not find project [{}] "
                             .format(self.json_args.get("project_name")))
@@ -518,25 +633,167 @@ class TestResultsHandler(GenericApiHandler):
         # check for case
         mongo_dict = yield self.db.test_cases.find_one(
             {"name": self.json_args.get("case_name")})
-        if not (mongo_dict is None):
+        if mongo_dict is None:
             raise HTTPError(HTTP_NOT_FOUND,
                             "Could not find case [{}] "
                             .format(self.json_args.get("case_name")))
 
         # check for pod
         mongo_dict = yield self.db.pod.find_one(
-            {"_id": self.json_args.get("pod_id")})
-        if not (mongo_dict is None):
+            {"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)