From 00355a8df9949edc12c41d5a8475fc17efbb03d3 Mon Sep 17 00:00:00 2001 From: SerenaFeng Date: Thu, 26 May 2016 18:07:35 +0800 Subject: [PATCH] swagger-ize pod-apis of testAPI JIRA: FUNCTEST-263 Change-Id: I293e05f565f882ea39bbf6368405f10241269716 Signed-off-by: SerenaFeng --- .../result_collection_api/resources/handlers.py | 107 ++++++--------------- .../result_collection_api/resources/pod_handler.py | 89 +++++++++++++++++ .../result_collection_api/resources/pod_models.py | 10 +- .../result_collection_api/result_collection_api.py | 20 ++-- .../result_collection_api/tests/unit/test_base.py | 7 +- .../result_collection_api/tests/unit/test_pod.py | 12 +++ 6 files changed, 152 insertions(+), 93 deletions(-) create mode 100644 utils/test/result_collection_api/resources/pod_handler.py diff --git a/utils/test/result_collection_api/resources/handlers.py b/utils/test/result_collection_api/resources/handlers.py index 435334341..afee1cd46 100644 --- a/utils/test/result_collection_api/resources/handlers.py +++ b/utils/test/result_collection_api/resources/handlers.py @@ -12,6 +12,8 @@ # 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 ############################################################################## import json @@ -24,7 +26,6 @@ from models import CreateResponse from resources.result_models import TestResult from resources.testcase_models import Testcase from resources.project_models import Project -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 @@ -72,95 +73,43 @@ class GenericApiHandler(RequestHandler): href = self.request.full_url() + '/' + resource return CreateResponse(href=href).format() - -class VersionHandler(GenericApiHandler): - """ Display a message for the API version """ - def get(self): - self.finish_request([{'v1': 'basics'}]) - - -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): - """ Prepares the database for the entire class """ - super(PodHandler, self).initialize() - @asynchronous @gen.coroutine - def get(self, pod_name=None): - """ - Get all pods or a single pod - :param pod_id: - """ - query = dict() - - if pod_name is not None: - query["name"] = pod_name - answer = yield self.db.pods.find_one(query) - if answer is None: - raise HTTPError(HTTP_NOT_FOUND, - "{} Not Exist".format(pod_name)) - else: - answer = format_data(answer, Pod) - else: - res = [] - cursor = self.db.pods.find(query) - while (yield cursor.fetch_next): - res.append(format_data(cursor.next_object(), Pod)) - answer = {'pods': res} - - self.finish_request(answer) + def _create(self, table, data, mark): + data.creation_date = datetime.now() + _id = yield self._eval_db(table, 'insert', data.format()) + if mark is None: + mark = _id + self.finish_request(self._create_response(mark)) @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 - the_pod = yield self.db.pods.find_one(query) - if the_pod is not None: - raise HTTPError(HTTP_FORBIDDEN, - "{} already exists as a pod".format( - self.json_args.get("name"))) - - pod = Pod.from_dict(self.json_args) - pod.creation_date = datetime.now() - - yield self.db.pods.insert(pod.format()) - self.finish_request(self._create_response(pod.name)) + def _list(self, table, format_cls, query=None): + if query is None: + query = {} + res = [] + cursor = self._eval_db(table, 'find', query) + while (yield cursor.fetch_next): + res.append(format_data(cursor.next_object(), format_cls)) + self.finish_request({table: res}) @asynchronous @gen.coroutine - 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: + def _get_one(self, table, format_cls, query): + data = yield self._eval_db(table, 'find_one', query) + if data is None: raise HTTPError(HTTP_NOT_FOUND, - "{} could not be found as a pod to be deleted" - .format(pod_name)) + "{} Not Exist".format(query)) + self.finish_request(format_data(data, format_cls)) - # just delete it, or maybe save it elsewhere in a future - res = yield self.db.projects.remove( - {'name': pod_name}) + def _eval_db(self, table, method, param): + return eval('self.db.%s.%s(param)' % (table, method)) - self.finish_request(answer) - """ - pass + +class VersionHandler(GenericApiHandler): + """ Display a message for the API version """ + def get(self): + self.finish_request([{'v1': 'basics'}]) class ProjectHandler(GenericApiHandler): diff --git a/utils/test/result_collection_api/resources/pod_handler.py b/utils/test/result_collection_api/resources/pod_handler.py new file mode 100644 index 000000000..718996784 --- /dev/null +++ b/utils/test/result_collection_api/resources/pod_handler.py @@ -0,0 +1,89 @@ +from tornado import gen +from tornado.web import HTTPError, asynchronous + +from tornado_swagger_ui.tornado_swagger import swagger +from handlers import GenericApiHandler +from common.constants import HTTP_BAD_REQUEST, HTTP_FORBIDDEN +from pod_models import Pod + + +class PodCLHandler(GenericApiHandler): + def initialize(self): + super(PodCLHandler, self).initialize() + + @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('pods', Pod) + + # @asynchronous + @gen.coroutine + @swagger.operation(nickname='create') + def post(self): + """ + @description: Create a POD + @param body: pod information to be created + @type body: L{PodCreateRequest} + @in body: body + @return 200: pod is created. + @rtype: L{Pod} + @raise 403: already exists as a pod + @raise 400: bad request + """ + if self.json_args is None: + raise HTTPError(HTTP_BAD_REQUEST, 'no payload') + + pod = Pod.from_dict(self.json_args) + name = pod.name + if name is None or name == '': + raise HTTPError(HTTP_BAD_REQUEST, 'pod name missing') + + the_pod = yield self.db.pods.find_one({'name': name}) + if the_pod is not None: + raise HTTPError(HTTP_FORBIDDEN, + "{} already exists as a pod".format( + self.json_args.get("name"))) + self._create('pods', pod, name) + + +class PodGURHandler(GenericApiHandler): + def initialize(self): + super(PodGURHandler, self).initialize() + + @swagger.operation(nickname='get-one') + def get(self, pod_name=None): + """ + @description: Get a single pod by pod_name + @return 200: pod exist + @raise 404: pod not exist + @rtype: L{Pod} + """ + query = dict() + query["name"] = pod_name + self._get_one('pods', Pod, query) + + @asynchronous + @gen.coroutine + 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/resources/pod_models.py b/utils/test/result_collection_api/resources/pod_models.py index b02e3c222..fcb4ddbbd 100644 --- a/utils/test/result_collection_api/resources/pod_models.py +++ b/utils/test/result_collection_api/resources/pod_models.py @@ -1,3 +1,5 @@ +from tornado_swagger_ui.tornado_swagger import swagger + __author__ = '__serena__' # name: name of the POD e.g. zte-1 @@ -6,8 +8,9 @@ __author__ = '__serena__' # role: ci-pod or community-pod or single-node +@swagger.model() class PodCreateRequest(object): - def __init__(self, name='', mode='', details='', role=""): + def __init__(self, name, mode='', details='', role=""): self.name = name self.mode = mode self.details = details @@ -22,6 +25,7 @@ class PodCreateRequest(object): } +@swagger.model() class Pod(PodCreateRequest): """ describes a POD platform """ def __init__(self, name='', mode='', details='', role="", @@ -55,7 +59,11 @@ class Pod(PodCreateRequest): return f +@swagger.model() class Pods(object): + """ + @ptype pods: C{list} of L{Pod} + """ def __init__(self, pods=list()): self.pods = pods diff --git a/utils/test/result_collection_api/result_collection_api.py b/utils/test/result_collection_api/result_collection_api.py index 97aa58c77..afd66f3fc 100644 --- a/utils/test/result_collection_api/result_collection_api.py +++ b/utils/test/result_collection_api/result_collection_api.py @@ -29,14 +29,16 @@ TODOs : """ +import argparse + import tornado.ioloop import motor -import argparse -from resources.handlers import VersionHandler, PodHandler, \ +from resources.handlers import VersionHandler, \ ProjectHandler, TestcaseHandler, TestResultsHandler, DashboardHandler +from resources.pod_handler import PodCLHandler, PodGURHandler from common.config import APIConfig - +from tornado_swagger_ui.tornado_swagger import swagger # optionally get config file from command line parser = argparse.ArgumentParser() @@ -51,16 +53,16 @@ db = client[CONF.mongo_dbname] def make_app(): - return tornado.web.Application( + return swagger.Application( [ # GET /version => GET API version (r"/versions", VersionHandler), # few examples: - # GET /pods => Get all pods - # GET /pods/1 => Get details on POD 1 - (r"/api/v1/pods", PodHandler), - (r"/api/v1/pods/([^/]+)", PodHandler), + # GET /api/v1/pods => Get all pods + # GET /api/v1/pods/1 => Get details on POD 1 + (r"/api/v1/pods", PodCLHandler), + (r"/api/v1/pods/([^/]+)", PodGURHandler), # few examples: # GET /projects @@ -70,10 +72,8 @@ def make_app(): # few examples # GET /projects/qtip/cases => Get cases for qtip - # (r"/api/v1/projects/([^/]+)/cases", TestcaseHandler), (r"/api/v1/projects/([^/]+)/cases/([^/]+)", TestcaseHandler), - # (r"/test_cases/([^/]+)", TestCasesHandler), # new path to avoid a long depth # GET /results?project=functest&case=keystone.catalog&pod=1 diff --git a/utils/test/result_collection_api/tests/unit/test_base.py b/utils/test/result_collection_api/tests/unit/test_base.py index 99b1de286..16ed07c9c 100644 --- a/utils/test/result_collection_api/tests/unit/test_base.py +++ b/utils/test/result_collection_api/tests/unit/test_base.py @@ -2,7 +2,8 @@ import json from tornado.web import Application from tornado.testing import AsyncHTTPTestCase -from resources.handlers import VersionHandler, PodHandler, \ +from resources.pod_handler import PodCLHandler, PodGURHandler +from resources.handlers import VersionHandler, \ ProjectHandler, TestcaseHandler, TestResultsHandler, DashboardHandler from resources.models import CreateResponse import fake_pymongo @@ -26,8 +27,8 @@ class TestBase(AsyncHTTPTestCase): return Application( [ (r"/versions", VersionHandler), - (r"/api/v1/pods", PodHandler), - (r"/api/v1/pods/([^/]+)", PodHandler), + (r"/api/v1/pods", PodCLHandler), + (r"/api/v1/pods/([^/]+)", PodGURHandler), (r"/api/v1/projects", ProjectHandler), (r"/api/v1/projects/([^/]+)", ProjectHandler), (r"/api/v1/projects/([^/]+)/cases", TestcaseHandler), diff --git a/utils/test/result_collection_api/tests/unit/test_pod.py b/utils/test/result_collection_api/tests/unit/test_pod.py index d7f4c3a63..8a9302738 100644 --- a/utils/test/result_collection_api/tests/unit/test_pod.py +++ b/utils/test/result_collection_api/tests/unit/test_pod.py @@ -32,6 +32,18 @@ class TestPodCreate(TestPodBase): (code, body) = self.create() self.assertEqual(code, HTTP_BAD_REQUEST) + def test_emptyName(self): + req_empty = PodCreateRequest('') + (code, body) = self.create(req_empty) + self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertIn('pod name missing', body) + + def test_noneName(self): + req_none = PodCreateRequest(None) + (code, body) = self.create(req_none) + self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertIn('pod name missing', body) + def test_success(self): code, body = self.create_d() self.assertEqual(code, HTTP_OK) -- 2.16.6