summaryrefslogtreecommitdiffstats
path: root/utils/test/result_collection_api/opnfv_testapi/resources
diff options
context:
space:
mode:
authorSerenaFeng <feng.xiaowei@zte.com.cn>2016-06-01 15:36:17 +0800
committerSerenaFeng <feng.xiaowei@zte.com.cn>2016-06-01 16:21:46 +0800
commita55651eb098da2e1aa90c93294a59857711b48c1 (patch)
tree654e3adace1e4ae1690d9612c5d7b1704a607a5e /utils/test/result_collection_api/opnfv_testapi/resources
parente0d66ea067ea59724c1dc300abe8052d4dcf88d1 (diff)
project-ize testAPI
JIRA: FUNCTEST-284 Change-Id: I219e934bb11f50de84df2aa0345ecc7885223491 Signed-off-by: SerenaFeng <feng.xiaowei@zte.com.cn>
Diffstat (limited to 'utils/test/result_collection_api/opnfv_testapi/resources')
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/__init__.py8
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/dashboard_handlers.py100
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/handlers.py230
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/models.py70
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/pod_handlers.py79
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/pod_models.py79
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/project_handlers.py84
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/project_models.py88
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/result_handlers.py162
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/result_models.py162
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/testcase_handlers.py107
-rw-r--r--utils/test/result_collection_api/opnfv_testapi/resources/testcase_models.py99
12 files changed, 1268 insertions, 0 deletions
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/__init__.py b/utils/test/result_collection_api/opnfv_testapi/resources/__init__.py
new file mode 100644
index 000000000..05c0c9392
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/__init__.py
@@ -0,0 +1,8 @@
+##############################################################################
+# Copyright (c) 2015 Orange
+# guyrodrigue.koffi@orange.com / koffirodrigue@gmail.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/dashboard_handlers.py b/utils/test/result_collection_api/opnfv_testapi/resources/dashboard_handlers.py
new file mode 100644
index 000000000..00abbb92b
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/dashboard_handlers.py
@@ -0,0 +1,100 @@
+from tornado.web import HTTPError
+
+from opnfv_testapi.common.constants import HTTP_NOT_FOUND
+from opnfv_testapi.dashboard.dashboard_utils import \
+ check_dashboard_ready_project, \
+ check_dashboard_ready_case, get_dashboard_result
+from opnfv_testapi.resources.result_handlers import GenericResultHandler
+from opnfv_testapi.resources.result_models import TestResult
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+
+class GenericDashboardHandler(GenericResultHandler):
+ def __init__(self, application, request, **kwargs):
+ super(GenericDashboardHandler, self).__init__(application,
+ request,
+ **kwargs)
+ self.table = self.db_results
+ self.table_cls = TestResult
+
+
+class DashboardHandler(GenericDashboardHandler):
+ @swagger.operation(nickname='query')
+ def get(self):
+ """
+ @description: Retrieve dashboard ready result(s)
+ for a test project
+ @notes: 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)
+
+ GET /dashboard?project=functest&case=vPing&version=Colorado \
+ &pod=pod_name&period=15
+ @rtype: L{string}
+ @param pod: pod name
+ @type pod: L{string}
+ @in pod: query
+ @required pod: False
+ @param project: project name
+ @type project: L{string}
+ @in project: query
+ @required project: True
+ @param case: case name
+ @type case: L{string}
+ @in case: query
+ @required case: True
+ @param version: i.e. Colorado
+ @type version: L{string}
+ @in version: query
+ @required version: False
+ @param installer: fuel/apex/joid/compass
+ @type installer: L{string}
+ @in installer: query
+ @required installer: False
+ @param period: last days
+ @type period: L{string}
+ @in period: query
+ @required period: False
+ @return 200: test result exist
+ @raise 400: period is not in
+ @raise 404: project or case name missing,
+ or project or case is not dashboard ready
+ """
+
+ project_arg = self.get_query_argument("project", None)
+ case_arg = self.get_query_argument("case", None)
+
+ # on /dashboard retrieve the list of projects and testcases
+ # ready for dashboard
+ if project_arg is None:
+ raise HTTPError(HTTP_NOT_FOUND, "Project name missing")
+
+ if not check_dashboard_ready_project(project_arg):
+ raise HTTPError(HTTP_NOT_FOUND,
+ 'Project [{}] not dashboard ready'
+ .format(project_arg))
+
+ if case_arg is None:
+ raise HTTPError(
+ HTTP_NOT_FOUND,
+ 'Test case missing for project [{}]'.format(project_arg))
+
+ if not check_dashboard_ready_case(project_arg, case_arg):
+ raise HTTPError(
+ HTTP_NOT_FOUND,
+ 'Test case [{}] not dashboard ready for project [{}]'
+ .format(case_arg, project_arg))
+
+ # special case of status for project
+ if case_arg == 'status':
+ self.finish_request(get_dashboard_result(project_arg, case_arg))
+ else:
+ def get_result(res, project, case):
+ return get_dashboard_result(project, case, res)
+
+ self._list(self.set_query(), get_result, project_arg, case_arg)
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/handlers.py b/utils/test/result_collection_api/opnfv_testapi/resources/handlers.py
new file mode 100644
index 000000000..4b39b247a
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/handlers.py
@@ -0,0 +1,230 @@
+##############################################################################
+# Copyright (c) 2015 Orange
+# guyrodrigue.koffi@orange.com / koffirodrigue@gmail.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+# feng.xiaowei@zte.com.cn refactor db.pod to db.pods 5-19-2016
+# feng.xiaowei@zte.com.cn refactor test_project to project 5-19-2016
+# feng.xiaowei@zte.com.cn refactor response body 5-19-2016
+# feng.xiaowei@zte.com.cn refactor pod/project response info 5-19-2016
+# feng.xiaowei@zte.com.cn refactor testcase related handler 5-20-2016
+# feng.xiaowei@zte.com.cn refactor result related handler 5-23-2016
+# feng.xiaowei@zte.com.cn refactor dashboard related handler 5-24-2016
+# feng.xiaowei@zte.com.cn add methods to GenericApiHandler 5-26-2016
+# feng.xiaowei@zte.com.cn remove PodHandler 5-26-2016
+# feng.xiaowei@zte.com.cn remove ProjectHandler 5-26-2016
+# feng.xiaowei@zte.com.cn remove TestcaseHandler 5-27-2016
+# feng.xiaowei@zte.com.cn remove ResultHandler 5-29-2016
+# feng.xiaowei@zte.com.cn remove DashboardHandler 5-30-2016
+##############################################################################
+
+import json
+from datetime import datetime
+
+from tornado.web import RequestHandler, asynchronous, HTTPError
+from tornado import gen
+
+from models import CreateResponse
+from opnfv_testapi.common.constants import DEFAULT_REPRESENTATION, \
+ HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_FORBIDDEN
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+
+class GenericApiHandler(RequestHandler):
+ def __init__(self, application, request, **kwargs):
+ super(GenericApiHandler, self).__init__(application, request, **kwargs)
+ self.db = self.settings["db"]
+ self.json_args = None
+ self.table = None
+ self.table_cls = None
+ self.db_projects = 'projects'
+ self.db_pods = 'pods'
+ self.db_testcases = 'testcases'
+ self.db_results = 'results'
+
+ def prepare(self):
+ if self.request.method != "GET" and self.request.method != "DELETE":
+ if self.request.headers.get("Content-Type") is not None:
+ if self.request.headers["Content-Type"].startswith(
+ DEFAULT_REPRESENTATION):
+ try:
+ self.json_args = json.loads(self.request.body)
+ except (ValueError, KeyError, TypeError) as error:
+ raise HTTPError(HTTP_BAD_REQUEST,
+ "Bad Json format [{}]".
+ format(error))
+
+ def finish_request(self, json_object=None):
+ if json_object:
+ self.write(json.dumps(json_object))
+ self.set_header("Content-Type", DEFAULT_REPRESENTATION)
+ self.finish()
+
+ def _create_response(self, resource):
+ href = self.request.full_url() + '/' + str(resource)
+ return CreateResponse(href=href).format()
+
+ def format_data(self, data):
+ cls_data = self.table_cls.from_dict(data)
+ return cls_data.format_http()
+
+ @asynchronous
+ @gen.coroutine
+ def _create(self, miss_checks, db_checks, **kwargs):
+ """
+ :param miss_checks: [miss1, miss2]
+ :param db_checks: [(table, exist, query, error)]
+ """
+ if self.json_args is None:
+ raise HTTPError(HTTP_BAD_REQUEST, "no body")
+
+ data = self.table_cls.from_dict(self.json_args)
+ for miss in miss_checks:
+ miss_data = data.__getattribute__(miss)
+ if miss_data is None or miss_data == '':
+ raise HTTPError(HTTP_BAD_REQUEST,
+ '{} missing'.format(miss))
+
+ for k, v in kwargs.iteritems():
+ data.__setattr__(k, v)
+
+ for table, exist, query, error in db_checks:
+ check = yield self._eval_db_find_one(query(data), table)
+ if (exist and not check) or (not exist and check):
+ code, message = error(data)
+ raise HTTPError(code, message)
+
+ data.creation_date = datetime.now()
+ _id = yield self._eval_db(self.table, 'insert', data.format())
+ if 'name' in self.json_args:
+ resource = data.name
+ else:
+ resource = _id
+ self.finish_request(self._create_response(resource))
+
+ @asynchronous
+ @gen.coroutine
+ def _list(self, query=None, res_op=None, *args):
+ if query is None:
+ query = {}
+ data = []
+ cursor = self._eval_db(self.table, 'find', query)
+ while (yield cursor.fetch_next):
+ data.append(self.format_data(cursor.next_object()))
+ if res_op is None:
+ res = {self.table: data}
+ else:
+ res = res_op(data, *args)
+ self.finish_request(res)
+
+ @asynchronous
+ @gen.coroutine
+ def _get_one(self, query):
+ data = yield self._eval_db_find_one(query)
+ if data is None:
+ raise HTTPError(HTTP_NOT_FOUND,
+ "[{}] not exist in table [{}]"
+ .format(query, self.table))
+ self.finish_request(self.format_data(data))
+
+ @asynchronous
+ @gen.coroutine
+ def _delete(self, query):
+ data = yield self._eval_db_find_one(query)
+ if data is None:
+ raise HTTPError(HTTP_NOT_FOUND,
+ "[{}] not exit in table [{}]"
+ .format(query, self.table))
+
+ yield self._eval_db(self.table, 'remove', query)
+ self.finish_request()
+
+ @asynchronous
+ @gen.coroutine
+ def _update(self, query, db_keys):
+ if self.json_args is None:
+ raise HTTPError(HTTP_BAD_REQUEST, "No payload")
+
+ # check old data exist
+ from_data = yield self._eval_db_find_one(query)
+ if from_data is None:
+ raise HTTPError(HTTP_NOT_FOUND,
+ "{} could not be found in table [{}]"
+ .format(query, self.table))
+
+ data = self.table_cls.from_dict(from_data)
+ # check new data exist
+ equal, new_query = self._update_query(db_keys, data)
+ if not equal:
+ to_data = yield self._eval_db_find_one(new_query)
+ if to_data is not None:
+ raise HTTPError(HTTP_FORBIDDEN,
+ "{} already exists in table [{}]"
+ .format(new_query, self.table))
+
+ # we merge the whole document """
+ edit_request = data.format()
+ edit_request.update(self._update_requests(data))
+
+ """ Updating the DB """
+ yield self._eval_db(self.table, 'update', query, edit_request)
+ edit_request['_id'] = str(data._id)
+ self.finish_request(edit_request)
+
+ def _update_requests(self, data):
+ request = dict()
+ for k, v in self.json_args.iteritems():
+ request = self._update_request(request, k, v,
+ data.__getattribute__(k))
+ if not request:
+ raise HTTPError(HTTP_FORBIDDEN, "Nothing to update")
+ return request
+
+ @staticmethod
+ def _update_request(edit_request, key, new_value, old_value):
+ """
+ This function serves to prepare the elements in the update request.
+ We try to avoid replace the exact values in the db
+ edit_request should be a dict in which we add an entry (key) after
+ comparing values
+ """
+ if not (new_value is None):
+ if len(new_value) > 0:
+ if new_value != old_value:
+ edit_request[key] = new_value
+
+ return edit_request
+
+ def _update_query(self, keys, data):
+ query = dict()
+ equal = True
+ for key in keys:
+ new = self.json_args.get(key)
+ old = data.__getattribute__(key)
+ if new is None:
+ new = old
+ elif new != old:
+ equal = False
+ query[key] = new
+ return equal, query
+
+ def _eval_db(self, table, method, *args):
+ return eval('self.db.%s.%s(*args)' % (table, method))
+
+ def _eval_db_find_one(self, query, table=None):
+ if table is None:
+ table = self.table
+ return self._eval_db(table, 'find_one', query)
+
+
+class VersionHandler(GenericApiHandler):
+ @swagger.operation(nickname='list')
+ def get(self):
+ """
+ @description: list all supported versions
+ @rtype: L{Versions}
+ """
+ versions = [{'version': 'v1.0', 'description': 'basics'}]
+ self.finish_request({'versions': versions})
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/models.py b/utils/test/result_collection_api/opnfv_testapi/resources/models.py
new file mode 100644
index 000000000..881f65dd3
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/models.py
@@ -0,0 +1,70 @@
+##############################################################################
+# Copyright (c) 2015 Orange
+# guyrodrigue.koffi@orange.com / koffirodrigue@gmail.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+# feng.xiaowei@zte.com.cn mv Pod to pod_models.py 5-18-2016
+# feng.xiaowei@zte.com.cn add MetaCreateResponse/MetaGetResponse 5-18-2016
+# feng.xiaowei@zte.com.cn mv TestProject to project_models.py 5-19-2016
+# feng.xiaowei@zte.com.cn delete meta class 5-19-2016
+# feng.xiaowei@zte.com.cn add CreateResponse 5-19-2016
+# feng.xiaowei@zte.com.cn mv TestCase to testcase_models.py 5-20-2016
+# feng.xiaowei@zte.com.cn mv TestResut to result_models.py 5-23-2016
+##############################################################################
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+
+class CreateResponse(object):
+ def __init__(self, href=''):
+ self.href = href
+
+ @staticmethod
+ def from_dict(res_dict):
+ if res_dict is None:
+ return None
+
+ res = CreateResponse()
+ res.href = res_dict.get('href')
+ return res
+
+ def format(self):
+ return {'href': self.href}
+
+
+@swagger.model()
+class Versions(object):
+ """
+ @property versions:
+ @ptype versions: C{list} of L{Version}
+ """
+ def __init__(self):
+ self.versions = list()
+
+ @staticmethod
+ def from_dict(res_dict):
+ if res_dict is None:
+ return None
+
+ res = Versions()
+ for version in res_dict.get('versions'):
+ res.versions.append(Version.from_dict(version))
+ return res
+
+
+@swagger.model()
+class Version(object):
+ def __init__(self, version=None, description=None):
+ self.version = version
+ self.description = description
+
+ @staticmethod
+ def from_dict(a_dict):
+ if a_dict is None:
+ return None
+
+ ver = Version()
+ ver.version = a_dict.get('version')
+ ver.description = str(a_dict.get('description'))
+ return ver
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/pod_handlers.py b/utils/test/result_collection_api/opnfv_testapi/resources/pod_handlers.py
new file mode 100644
index 000000000..5a4b55506
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/pod_handlers.py
@@ -0,0 +1,79 @@
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+from handlers import GenericApiHandler
+from pod_models import Pod
+from opnfv_testapi.common.constants import HTTP_FORBIDDEN
+
+
+class GenericPodHandler(GenericApiHandler):
+ def __init__(self, application, request, **kwargs):
+ super(GenericPodHandler, self).__init__(application, request, **kwargs)
+ self.table = 'pods'
+ self.table_cls = Pod
+
+
+class PodCLHandler(GenericPodHandler):
+ @swagger.operation(nickname='list-all')
+ def get(self):
+ """
+ @description: list all pods
+ @return 200: list all pods, empty list is no pod exist
+ @rtype: L{Pods}
+ """
+ self._list()
+
+ @swagger.operation(nickname='create')
+ def post(self):
+ """
+ @description: create a pod
+ @param body: pod to be created
+ @type body: L{PodCreateRequest}
+ @in body: body
+ @rtype: L{Pod}
+ @return 200: pod is created.
+ @raise 403: pod already exists
+ @raise 400: body or name not provided
+ """
+ def query(data):
+ return {'name': data.name}
+
+ def error(data):
+ message = '{} already exists as a pod'.format(data.name)
+ return HTTP_FORBIDDEN, message
+
+ miss_checks = ['name']
+ db_checks = [(self.table, False, query, error)]
+ self._create(miss_checks, db_checks)
+
+
+class PodGURHandler(GenericPodHandler):
+ @swagger.operation(nickname='get-one')
+ def get(self, pod_name):
+ """
+ @description: get a single pod by pod_name
+ @rtype: L{Pod}
+ @return 200: pod exist
+ @raise 404: pod not exist
+ """
+ query = dict()
+ query['name'] = pod_name
+ self._get_one(query)
+
+ def delete(self, pod_name):
+ """ Remove a POD
+
+ # check for an existing pod to be deleted
+ mongo_dict = yield self.db.pods.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.projects.remove(
+ {'name': pod_name})
+
+ self.finish_request(answer)
+ """
+ pass
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/pod_models.py b/utils/test/result_collection_api/opnfv_testapi/resources/pod_models.py
new file mode 100644
index 000000000..2e645032c
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/pod_models.py
@@ -0,0 +1,79 @@
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+__author__ = '__serena__'
+
+# name: name of the POD e.g. zte-1
+# mode: metal or virtual
+# details: any detail
+# role: ci-pod or community-pod or single-node
+
+
+@swagger.model()
+class PodCreateRequest(object):
+ def __init__(self, name, mode='', details='', role=""):
+ self.name = name
+ self.mode = mode
+ self.details = details
+ self.role = role
+
+ def format(self):
+ return {
+ "name": self.name,
+ "mode": self.mode,
+ "details": self.details,
+ "role": self.role,
+ }
+
+
+@swagger.model()
+class Pod(PodCreateRequest):
+ def __init__(self,
+ name='', mode='', details='',
+ role="", _id='', create_date=''):
+ super(Pod, self).__init__(name, mode, details, role)
+ self._id = _id
+ self.creation_date = create_date
+
+ @staticmethod
+ def from_dict(pod_dict):
+ if pod_dict is None:
+ return None
+
+ p = Pod()
+ p._id = pod_dict.get('_id')
+ p.creation_date = str(pod_dict.get('creation_date'))
+ p.name = pod_dict.get('name')
+ p.mode = pod_dict.get('mode')
+ p.details = pod_dict.get('details')
+ p.role = pod_dict.get('role')
+ return p
+
+ def format(self):
+ f = super(Pod, self).format()
+ f['creation_date'] = str(self.creation_date)
+ return f
+
+ def format_http(self):
+ f = self.format()
+ f['_id'] = str(self._id)
+ return f
+
+
+@swagger.model()
+class Pods(object):
+ """
+ @property pods:
+ @ptype pods: C{list} of L{Pod}
+ """
+ def __init__(self):
+ self.pods = list()
+
+ @staticmethod
+ def from_dict(res_dict):
+ if res_dict is None:
+ return None
+
+ res = Pods()
+ for pod in res_dict.get('pods'):
+ res.pods.append(Pod.from_dict(pod))
+ return res
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/project_handlers.py b/utils/test/result_collection_api/opnfv_testapi/resources/project_handlers.py
new file mode 100644
index 000000000..191a93347
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/project_handlers.py
@@ -0,0 +1,84 @@
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+from handlers import GenericApiHandler
+from opnfv_testapi.common.constants import HTTP_FORBIDDEN
+from project_models import Project
+
+
+class GenericProjectHandler(GenericApiHandler):
+ def __init__(self, application, request, **kwargs):
+ super(GenericProjectHandler, self).__init__(application,
+ request,
+ **kwargs)
+ self.table = 'projects'
+ self.table_cls = Project
+
+
+class ProjectCLHandler(GenericProjectHandler):
+ @swagger.operation(nickname="list-all")
+ def get(self):
+ """
+ @description: list all projects
+ @return 200: return all projects, empty list is no project exist
+ @rtype: L{Projects}
+ """
+ self._list()
+
+ @swagger.operation(nickname="create")
+ def post(self):
+ """
+ @description: create a project
+ @param body: project to be created
+ @type body: L{ProjectCreateRequest}
+ @in body: body
+ @rtype: L{Project}
+ @return 200: project is created.
+ @raise 403: project already exists
+ @raise 400: body or name not provided
+ """
+ def query(data):
+ return {'name': data.name}
+
+ def error(data):
+ message = '{} already exists as a project'.format(data.name)
+ return HTTP_FORBIDDEN, message
+
+ miss_checks = ['name']
+ db_checks = [(self.table, False, query, error)]
+ self._create(miss_checks, db_checks)
+
+
+class ProjectGURHandler(GenericProjectHandler):
+ @swagger.operation(nickname='get-one')
+ def get(self, project_name):
+ """
+ @description: get a single project by project_name
+ @rtype: L{Project}
+ @return 200: project exist
+ @raise 404: project not exist
+ """
+ self._get_one({'name': project_name})
+
+ @swagger.operation(nickname="update")
+ def put(self, project_name):
+ """
+ @description: update a single project by project_name
+ @param body: project to be updated
+ @type body: L{ProjectUpdateRequest}
+ @in body: body
+ @rtype: L{Project}
+ @return 200: update success
+ @raise 404: project not exist
+ @raise 403: new project name already exist or nothing to update
+ """
+ query = {'name': project_name}
+ db_keys = ['name']
+ self._update(query, db_keys)
+
+ @swagger.operation(nickname='delete')
+ def delete(self, project_name):
+ """
+ @description: delete a project by project_name
+ @return 200: delete success
+ @raise 404: project not exist
+ """
+ self._delete({'name': project_name})
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/project_models.py b/utils/test/result_collection_api/opnfv_testapi/resources/project_models.py
new file mode 100644
index 000000000..fbb6beba3
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/project_models.py
@@ -0,0 +1,88 @@
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+__author__ = '__serena__'
+
+
+@swagger.model()
+class ProjectCreateRequest(object):
+ def __init__(self, name, description=''):
+ self.name = name
+ self.description = description
+
+ def format(self):
+ return {
+ "name": self.name,
+ "description": self.description,
+ }
+
+
+@swagger.model()
+class ProjectUpdateRequest(object):
+ def __init__(self, name='', description=''):
+ self.name = name
+ self.description = description
+
+ def format(self):
+ return {
+ "name": self.name,
+ "description": self.description,
+ }
+
+
+@swagger.model()
+class Project(object):
+ def __init__(self,
+ name=None, _id=None, description=None, create_date=None):
+ self._id = _id
+ self.name = name
+ self.description = description
+ self.creation_date = create_date
+
+ @staticmethod
+ def from_dict(res_dict):
+
+ if res_dict is None:
+ return None
+
+ t = Project()
+ t._id = res_dict.get('_id')
+ t.creation_date = res_dict.get('creation_date')
+ t.name = res_dict.get('name')
+ t.description = res_dict.get('description')
+
+ return t
+
+ def format(self):
+ return {
+ "name": self.name,
+ "description": self.description,
+ "creation_date": str(self.creation_date)
+ }
+
+ def format_http(self):
+ return {
+ "_id": str(self._id),
+ "name": self.name,
+ "description": self.description,
+ "creation_date": str(self.creation_date),
+ }
+
+
+@swagger.model()
+class Projects(object):
+ """
+ @property projects:
+ @ptype projects: C{list} of L{Project}
+ """
+ def __init__(self):
+ self.projects = list()
+
+ @staticmethod
+ def from_dict(res_dict):
+ if res_dict is None:
+ return None
+
+ res = Projects()
+ for project in res_dict.get('projects'):
+ res.projects.append(Project.from_dict(project))
+ return res
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/result_handlers.py b/utils/test/result_collection_api/opnfv_testapi/resources/result_handlers.py
new file mode 100644
index 000000000..a9aa17bba
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/result_handlers.py
@@ -0,0 +1,162 @@
+from datetime import datetime, timedelta
+
+from bson.objectid import ObjectId
+from tornado.web import HTTPError
+
+from opnfv_testapi.common.constants import HTTP_BAD_REQUEST, HTTP_NOT_FOUND
+from opnfv_testapi.resources.handlers import GenericApiHandler
+from opnfv_testapi.resources.result_models import TestResult
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+
+class GenericResultHandler(GenericApiHandler):
+ def __init__(self, application, request, **kwargs):
+ super(GenericResultHandler, self).__init__(application,
+ request,
+ **kwargs)
+ self.table = self.db_results
+ self.table_cls = TestResult
+
+ def set_query(self):
+ query = dict()
+ for k in self.request.query_arguments.keys():
+ v = self.get_query_argument(k)
+ if k == 'project' or k == 'pod' or k == 'case':
+ query[k + '_name'] = v
+ elif k == 'period':
+ try:
+ v = int(v)
+ except:
+ raise HTTPError(HTTP_BAD_REQUEST, 'period must be int')
+ if v > 0:
+ period = datetime.now() - timedelta(days=v)
+ obj = {"$gte": str(period)}
+ query['start_date'] = obj
+ elif k == 'trust_indicator':
+ query[k] = float(v)
+ else:
+ query[k] = v
+ return query
+
+
+class ResultsCLHandler(GenericResultHandler):
+ @swagger.operation(nickname="list-all")
+ def get(self):
+ """
+ @description: Retrieve result(s) for a test project
+ on a specific pod.
+ @notes: Retrieve result(s) for a test project on a specific pod.
+ Available filters for this request are :
+ - project : project name
+ - case : case name
+ - 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
+
+ GET /results/project=functest&case=vPing&version=Arno-R1 \
+ &pod=pod_name&period=15
+ @return 200: all test results consist with query,
+ empty list if no result is found
+ @rtype: L{TestResults}
+ @param pod: pod name
+ @type pod: L{string}
+ @in pod: query
+ @required pod: False
+ @param project: project name
+ @type project: L{string}
+ @in project: query
+ @required project: True
+ @param case: case name
+ @type case: L{string}
+ @in case: query
+ @required case: True
+ @param version: i.e. Colorado
+ @type version: L{string}
+ @in version: query
+ @required version: False
+ @param installer: fuel/apex/joid/compass
+ @type installer: L{string}
+ @in installer: query
+ @required installer: False
+ @param build_tag: i.e. v3.0
+ @type build_tag: L{string}
+ @in build_tag: query
+ @required build_tag: False
+ @param scenario: i.e. odl
+ @type scenario: L{string}
+ @in scenario: query
+ @required scenario: False
+ @param criteria: i.e. passed
+ @type criteria: L{string}
+ @in criteria: query
+ @required criteria: False
+ @param period: last days
+ @type period: L{string}
+ @in period: query
+ @required period: False
+ @param trust_indicator: must be int/long/float
+ @type trust_indicator: L{string}
+ @in trust_indicator: query
+ @required trust_indicator: False
+ """
+ self._list(self.set_query())
+
+ @swagger.operation(nickname="create")
+ def post(self):
+ """
+ @description: create a test result
+ @param body: result to be created
+ @type body: L{ResultCreateRequest}
+ @in body: body
+ @rtype: L{TestResult}
+ @return 200: result is created.
+ @raise 404: pod/project/testcase not exist
+ @raise 400: body/pod_name/project_name/case_name not provided
+ """
+ def pod_query(data):
+ return {'name': data.pod_name}
+
+ def pod_error(data):
+ message = 'Could not find pod [{}]'.format(data.pod_name)
+ return HTTP_NOT_FOUND, message
+
+ def project_query(data):
+ return {'name': data.project_name}
+
+ def project_error(data):
+ message = 'Could not find project [{}]'.format(data.project_name)
+ return HTTP_NOT_FOUND, message
+
+ def testcase_query(data):
+ return {'project_name': data.project_name, 'name': data.case_name}
+
+ def testcase_error(data):
+ message = 'Could not find testcase [{}] in project [{}]'\
+ .format(data.case_name, data.project_name)
+ return HTTP_NOT_FOUND, message
+
+ miss_checks = ['pod_name', 'project_name', 'case_name']
+ db_checks = [('pods', True, pod_query, pod_error),
+ ('projects', True, project_query, project_error),
+ ('testcases', True, testcase_query, testcase_error)]
+ self._create(miss_checks, db_checks)
+
+
+class ResultsGURHandler(GenericResultHandler):
+ @swagger.operation(nickname='get-one')
+ def get(self, result_id):
+ """
+ @description: get a single result by result_id
+ @rtype: L{TestResult}
+ @return 200: test result exist
+ @raise 404: test result not exist
+ """
+ query = dict()
+ query["_id"] = ObjectId(result_id)
+ self._get_one(query)
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/result_models.py b/utils/test/result_collection_api/opnfv_testapi/resources/result_models.py
new file mode 100644
index 000000000..cf896735f
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/result_models.py
@@ -0,0 +1,162 @@
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+
+@swagger.model()
+class ResultCreateRequest(object):
+ def __init__(self,
+ pod_name=None,
+ project_name=None,
+ case_name=None,
+ installer=None,
+ version=None,
+ start_date=None,
+ stop_date=None,
+ details=None,
+ build_tag=None,
+ scenario=None,
+ criteria=None,
+ trust_indicator=None):
+ self.pod_name = pod_name
+ self.project_name = project_name
+ self.case_name = case_name
+ self.installer = installer
+ self.version = version
+ self.start_date = start_date
+ self.stop_date = stop_date
+ self.details = details
+ self.build_tag = build_tag
+ self.scenario = scenario
+ self.criteria = criteria
+ self.trust_indicator = trust_indicator
+
+ def format(self):
+ return {
+ "pod_name": self.pod_name,
+ "project_name": self.project_name,
+ "case_name": self.case_name,
+ "installer": self.installer,
+ "version": self.version,
+ "start_date": self.start_date,
+ "stop_date": self.stop_date,
+ "details": self.details,
+ "build_tag": self.build_tag,
+ "scenario": self.scenario,
+ "criteria": self.criteria,
+ "trust_indicator": self.trust_indicator
+ }
+
+
+@swagger.model()
+class TestResult(object):
+ """
+ @property trust_indicator: must be int/long/float
+ @ptype trust_indicator: L{float}
+ """
+ def __init__(self, _id=None, case_name=None, project_name=None,
+ pod_name=None, installer=None, version=None,
+ start_date=None, stop_date=None, details=None,
+ build_tag=None, scenario=None, criteria=None,
+ trust_indicator=None):
+ self._id = _id
+ self.case_name = case_name
+ self.project_name = project_name
+ self.pod_name = pod_name
+ self.installer = installer
+ self.version = version
+ self.start_date = start_date
+ self.stop_date = stop_date
+ self.details = details
+ self.build_tag = build_tag
+ self.scenario = scenario
+ self.criteria = criteria
+ self.trust_indicator = trust_indicator
+
+ @staticmethod
+ def from_dict(a_dict):
+
+ if a_dict is None:
+ return None
+
+ t = TestResult()
+ t._id = a_dict.get('_id')
+ t.case_name = a_dict.get('case_name')
+ t.pod_name = a_dict.get('pod_name')
+ t.project_name = a_dict.get('project_name')
+ t.description = a_dict.get('description')
+ t.start_date = str(a_dict.get('start_date'))
+ t.stop_date = str(a_dict.get('stop_date'))
+ t.details = a_dict.get('details')
+ t.version = a_dict.get('version')
+ t.installer = a_dict.get('installer')
+ t.build_tag = a_dict.get('build_tag')
+ t.scenario = a_dict.get('scenario')
+ t.criteria = a_dict.get('criteria')
+ # 0 < trust indicator < 1
+ # if bad value => set this indicator to 0
+ t.trust_indicator = a_dict.get('trust_indicator')
+ if t.trust_indicator is not None:
+ if isinstance(t.trust_indicator, (int, long, float)):
+ if t.trust_indicator < 0:
+ t.trust_indicator = 0
+ elif t.trust_indicator > 1:
+ t.trust_indicator = 1
+ else:
+ t.trust_indicator = 0
+ else:
+ t.trust_indicator = 0
+ return t
+
+ def format(self):
+ return {
+ "case_name": self.case_name,
+ "project_name": self.project_name,
+ "pod_name": self.pod_name,
+ "description": self.description,
+ "start_date": str(self.start_date),
+ "stop_date": str(self.stop_date),
+ "version": self.version,
+ "installer": self.installer,
+ "details": self.details,
+ "build_tag": self.build_tag,
+ "scenario": self.scenario,
+ "criteria": self.criteria,
+ "trust_indicator": self.trust_indicator
+ }
+
+ def format_http(self):
+ return {
+ "_id": str(self._id),
+ "case_name": self.case_name,
+ "project_name": self.project_name,
+ "pod_name": self.pod_name,
+ "description": self.description,
+ "start_date": str(self.start_date),
+ "stop_date": str(self.stop_date),
+ "version": self.version,
+ "installer": self.installer,
+ "details": self.details,
+ "build_tag": self.build_tag,
+ "scenario": self.scenario,
+ "criteria": self.criteria,
+ "trust_indicator": self.trust_indicator
+ }
+
+
+@swagger.model()
+class TestResults(object):
+ """
+ @property results:
+ @ptype results: C{list} of L{TestResult}
+ """
+ def __init__(self):
+ self.results = list()
+
+ @staticmethod
+ def from_dict(a_dict):
+ if a_dict is None:
+ return None
+
+ res = TestResults()
+ for result in a_dict.get('results'):
+ res.results.append(TestResult.from_dict(result))
+ return res
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/testcase_handlers.py b/utils/test/result_collection_api/opnfv_testapi/resources/testcase_handlers.py
new file mode 100644
index 000000000..dbeebeb98
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/testcase_handlers.py
@@ -0,0 +1,107 @@
+from opnfv_testapi.common.constants import HTTP_FORBIDDEN
+from opnfv_testapi.resources.handlers import GenericApiHandler
+from opnfv_testapi.resources.testcase_models import Testcase
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+
+class GenericTestcaseHandler(GenericApiHandler):
+ def __init__(self, application, request, **kwargs):
+ super(GenericTestcaseHandler, self).__init__(application,
+ request,
+ **kwargs)
+ self.table = self.db_testcases
+ self.table_cls = Testcase
+
+
+class TestcaseCLHandler(GenericTestcaseHandler):
+ @swagger.operation(nickname="list-all")
+ def get(self, project_name):
+ """
+ @description: list all testcases of a project by project_name
+ @return 200: return all testcases of this project,
+ empty list is no testcase exist in this project
+ @rtype: L{TestCases}
+ """
+ query = dict()
+ query['project_name'] = project_name
+ self._list(query)
+
+ @swagger.operation(nickname="create")
+ def post(self, project_name):
+ """
+ @description: create a testcase of a project by project_name
+ @param body: testcase to be created
+ @type body: L{TestcaseCreateRequest}
+ @in body: body
+ @rtype: L{Testcase}
+ @return 200: testcase is created in this project.
+ @raise 403: project not exist
+ or testcase already exists in this project
+ @raise 400: body or name not provided
+ """
+ def p_query(data):
+ return {'name': data.project_name}
+
+ def tc_query(data):
+ return {
+ 'project_name': data.project_name,
+ 'name': data.name
+ }
+
+ def p_error(data):
+ message = 'Could not find project [{}]'.format(data.project_name)
+ return HTTP_FORBIDDEN, message
+
+ def tc_error(data):
+ message = '{} already exists as a testcase in project {}'\
+ .format(data.name, data.project_name)
+ return HTTP_FORBIDDEN, message
+
+ miss_checks = ['name']
+ db_checks = [(self.db_projects, True, p_query, p_error),
+ (self.db_testcases, False, tc_query, tc_error)]
+ self._create(miss_checks, db_checks, project_name=project_name)
+
+
+class TestcaseGURHandler(GenericTestcaseHandler):
+ @swagger.operation(nickname='get-one')
+ def get(self, project_name, case_name):
+ """
+ @description: get a single testcase
+ by case_name and project_name
+ @rtype: L{Testcase}
+ @return 200: testcase exist
+ @raise 404: testcase not exist
+ """
+ query = dict()
+ query['project_name'] = project_name
+ query["name"] = case_name
+ self._get_one(query)
+
+ @swagger.operation(nickname="update")
+ def put(self, project_name, case_name):
+ """
+ @description: update a single testcase
+ by project_name and case_name
+ @param body: testcase to be updated
+ @type body: L{TestcaseUpdateRequest}
+ @in body: body
+ @rtype: L{Project}
+ @return 200: update success
+ @raise 404: testcase or project not exist
+ @raise 403: new testcase name already exist in project
+ or nothing to update
+ """
+ query = {'project_name': project_name, 'name': case_name}
+ db_keys = ['name', 'project_name']
+ self._update(query, db_keys)
+
+ @swagger.operation(nickname='delete')
+ def delete(self, project_name, case_name):
+ """
+ @description: delete a testcase by project_name and case_name
+ @return 200: delete success
+ @raise 404: testcase not exist
+ """
+ query = {'project_name': project_name, 'name': case_name}
+ self._delete(query)
diff --git a/utils/test/result_collection_api/opnfv_testapi/resources/testcase_models.py b/utils/test/result_collection_api/opnfv_testapi/resources/testcase_models.py
new file mode 100644
index 000000000..aa5789e70
--- /dev/null
+++ b/utils/test/result_collection_api/opnfv_testapi/resources/testcase_models.py
@@ -0,0 +1,99 @@
+from opnfv_testapi.tornado_swagger_ui.tornado_swagger import swagger
+
+__author__ = '__serena__'
+
+
+@swagger.model()
+class TestcaseCreateRequest(object):
+ def __init__(self, name, url=None, description=None):
+ self.name = name
+ self.url = url
+ self.description = description
+
+ def format(self):
+ return {
+ "name": self.name,
+ "description": self.description,
+ "url": self.url,
+ }
+
+
+@swagger.model()
+class TestcaseUpdateRequest(object):
+ def __init__(self, name=None, description=None, project_name=None):
+ self.name = name
+ self.description = description
+ self.project_name = project_name
+
+ def format(self):
+ return {
+ "name": self.name,
+ "description": self.description,
+ "project_name": self.project_name,
+ }
+
+
+@swagger.model()
+class Testcase(object):
+ def __init__(self):
+ self._id = None
+ self.name = None
+ self.project_name = None
+ self.description = None
+ self.url = None
+ self.creation_date = None
+
+ @staticmethod
+ def from_dict(a_dict):
+
+ if a_dict is None:
+ return None
+
+ t = Testcase()
+ t._id = a_dict.get('_id')
+ t.project_name = a_dict.get('project_name')
+ t.creation_date = a_dict.get('creation_date')
+ t.name = a_dict.get('name')
+ t.description = a_dict.get('description')
+ t.url = a_dict.get('url')
+
+ return t
+
+ def format(self):
+ return {
+ "name": self.name,
+ "description": self.description,
+ "project_name": self.project_name,
+ "creation_date": str(self.creation_date),
+ "url": self.url
+ }
+
+ def format_http(self):
+ return {
+ "_id": str(self._id),
+ "name": self.name,
+ "project_name": self.project_name,
+ "description": self.description,
+ "creation_date": str(self.creation_date),
+ "url": self.url,
+ }
+
+
+@swagger.model()
+class Testcases(object):
+ """
+ @property testcases:
+ @ptype testcases: C{list} of L{Testcase}
+ """
+ def __init__(self):
+ self.testcases = list()
+
+ @staticmethod
+ def from_dict(res_dict):
+ if res_dict is None:
+ return None
+
+ res = Testcases()
+ for testcase in res_dict.get('testcases'):
+ res.testcases.append(Testcase.from_dict(testcase))
+ return res