swagger-ize project-apis of testAPI 23/14723/2
authorSerenaFeng <feng.xiaowei@zte.com.cn>
Thu, 26 May 2016 12:32:02 +0000 (20:32 +0800)
committerSerenaFeng <feng.xiaowei@zte.com.cn>
Thu, 26 May 2016 12:40:13 +0000 (20:40 +0800)
rename pod_handler.py to pod_handlers.py

JIRA: FUNCTEST-264

Change-Id: I8699999776bdb238f680a128b83cea0a098534c5
Signed-off-by: SerenaFeng <feng.xiaowei@zte.com.cn>
utils/test/result_collection_api/resources/handlers.py
utils/test/result_collection_api/resources/pod_handlers.py [moved from utils/test/result_collection_api/resources/pod_handler.py with 51% similarity]
utils/test/result_collection_api/resources/pod_models.py
utils/test/result_collection_api/resources/project_handlers.py [new file with mode: 0644]
utils/test/result_collection_api/resources/project_models.py
utils/test/result_collection_api/result_collection_api.py
utils/test/result_collection_api/tests/unit/test_base.py
utils/test/result_collection_api/tests/unit/test_project.py

index afee1cd..3f9d842 100644 (file)
@@ -25,7 +25,6 @@ from tornado import gen
 from models import CreateResponse
 from resources.result_models import TestResult
 from resources.testcase_models import Testcase
-from resources.project_models import Project
 from common.constants import DEFAULT_REPRESENTATION, HTTP_BAD_REQUEST, \
     HTTP_NOT_FOUND, HTTP_FORBIDDEN
 from common.config import prepare_put_request
@@ -39,15 +38,12 @@ def format_data(data, cls):
 
 
 class GenericApiHandler(RequestHandler):
-    """
-    The purpose of this class is to take benefit of inheritance and prepare
-    a set of common functions for
-    the handlers
-    """
-
-    def initialize(self):
-        """ Prepares the database for the entire class """
+    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
 
     def prepare(self):
         if self.request.method != "GET" and self.request.method != "DELETE":
@@ -60,8 +56,6 @@ class GenericApiHandler(RequestHandler):
                         raise HTTPError(HTTP_BAD_REQUEST,
                                         "Bad Json format [{}]".
                                         format(error))
-                else:
-                    self.json_args = None
 
     def finish_request(self, json_object=None):
         if json_object:
@@ -75,32 +69,57 @@ class GenericApiHandler(RequestHandler):
 
     @asynchronous
     @gen.coroutine
-    def _create(self, table, data, mark):
+    def _create(self, error):
+        if self.json_args is None:
+            raise HTTPError(HTTP_BAD_REQUEST, 'no body')
+
+        data = self.table_cls.from_dict(self.json_args)
+        name = data.name
+        if name is None or name == '':
+            raise HTTPError(HTTP_BAD_REQUEST,
+                            '{} name missing'.format(self.table[:-1]))
+
+        exist_data = yield self._eval_db(self.table, 'find_one',
+                                         {"name": name})
+        if exist_data is not None:
+            raise HTTPError(HTTP_FORBIDDEN,
+                            error.format(name, self.table[:-1]))
         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))
+        yield self._eval_db(self.table, 'insert', data.format())
+        self.finish_request(self._create_response(name))
 
     @asynchronous
     @gen.coroutine
-    def _list(self, table, format_cls, query=None):
+    def _list(self, query=None):
         if query is None:
             query = {}
         res = []
-        cursor = self._eval_db(table, 'find', query)
+        cursor = self._eval_db(self.table, 'find', query)
         while (yield cursor.fetch_next):
-            res.append(format_data(cursor.next_object(), format_cls))
-        self.finish_request({table: res})
+            res.append(format_data(cursor.next_object(), self.table_cls))
+        self.finish_request({self.table: res})
+
+    @asynchronous
+    @gen.coroutine
+    def _get_one(self, query):
+        data = yield self._eval_db(self.table, 'find_one', query)
+        if data is None:
+            raise HTTPError(HTTP_NOT_FOUND,
+                            "[{}] not exist in table [{}]"
+                            .format(query, self.table))
+        self.finish_request(format_data(data, self.table_cls))
 
     @asynchronous
     @gen.coroutine
-    def _get_one(self, table, format_cls, query):
-        data = yield self._eval_db(table, 'find_one', query)
+    def _delete(self, query):
+        data = yield self._eval_db(self.table, 'find_one', query)
         if data is None:
             raise HTTPError(HTTP_NOT_FOUND,
-                            "{} Not Exist".format(query))
-        self.finish_request(format_data(data, format_cls))
+                            "[{}] not exit in table [{}]"
+                            .format(query, self.table))
+
+        yield self._eval_db(self.table, 'remove', query)
+        self.finish_request()
 
     def _eval_db(self, table, method, param):
         return eval('self.db.%s.%s(param)' % (table, method))
@@ -112,143 +131,6 @@ class VersionHandler(GenericApiHandler):
         self.finish_request([{'v1': 'basics'}])
 
 
-class ProjectHandler(GenericApiHandler):
-    """
-    TestProjectHandler Class
-    Handle the requests about the Test projects
-    HTTP Methdods :
-        - GET : Get all test projects and details about a specific one
-        - POST : Add a test project
-        - PUT : Edit test projects information (name and/or description)
-        - DELETE : Remove a test project
-    """
-
-    def initialize(self):
-        """ Prepares the database for the entire class """
-        super(ProjectHandler, self).initialize()
-
-    @asynchronous
-    @gen.coroutine
-    def get(self, project_name=None):
-        """
-        Get Project(s) info
-        :param project_name:
-        """
-
-        query = dict()
-
-        if project_name is not None:
-            query["name"] = project_name
-            answer = yield self.db.projects.find_one(query)
-            if answer is None:
-                raise HTTPError(HTTP_NOT_FOUND,
-                                "{} Not Exist".format(project_name))
-            else:
-                answer = format_data(answer, Project)
-        else:
-            res = []
-            cursor = self.db.projects.find(query)
-            while (yield cursor.fetch_next):
-                res.append(format_data(cursor.next_object(), Project))
-            answer = {'projects': res}
-
-        self.finish_request(answer)
-
-    @asynchronous
-    @gen.coroutine
-    def post(self):
-        """ Create a test project"""
-
-        if self.json_args is None:
-            raise HTTPError(HTTP_BAD_REQUEST)
-
-        query = {"name": self.json_args.get("name")}
-
-        # check for name in db
-        the_project = yield self.db.projects.find_one(query)
-        if the_project is not None:
-            raise HTTPError(HTTP_FORBIDDEN,
-                            "{} already exists as a project".format(
-                                self.json_args.get("name")))
-
-        project = Project.from_dict(self.json_args)
-        project.creation_date = datetime.now()
-
-        yield self.db.projects.insert(project.format())
-        self.finish_request(self._create_response(project.name))
-
-    @asynchronous
-    @gen.coroutine
-    def put(self, project_name):
-        """ Updates the name and description of a test project"""
-
-        if self.json_args is None:
-            raise HTTPError(HTTP_BAD_REQUEST)
-
-        query = {'name': project_name}
-        from_project = yield self.db.projects.find_one(query)
-        if from_project is None:
-            raise HTTPError(HTTP_NOT_FOUND,
-                            "{} could not be found".format(project_name))
-
-        project = Project.from_dict(from_project)
-        new_name = self.json_args.get("name")
-        new_description = self.json_args.get("description")
-
-        # check for payload name parameter in db
-        # avoid a request if the project name has not changed in the payload
-        if new_name != project.name:
-            to_project = yield self.db.projects.find_one(
-                {"name": new_name})
-            if to_project is not None:
-                raise HTTPError(HTTP_FORBIDDEN,
-                                "{} already exists as a project"
-                                .format(new_name))
-
-        # new dict for changes
-        request = dict()
-        request = prepare_put_request(request,
-                                      "name",
-                                      new_name,
-                                      project.name)
-        request = prepare_put_request(request,
-                                      "description",
-                                      new_description,
-                                      project.description)
-
-        """ raise exception if there isn't a change """
-        if not request:
-            raise HTTPError(HTTP_FORBIDDEN, "Nothing to update")
-
-        """ we merge the whole document """
-        edit_request = project.format()
-        edit_request.update(request)
-
-        """ Updating the DB """
-        yield self.db.projects.update({'name': project_name}, edit_request)
-        new_project = yield self.db.projects.find_one({"_id": project._id})
-
-        self.finish_request(format_data(new_project, Project))
-
-    @asynchronous
-    @gen.coroutine
-    def delete(self, project_name):
-        """ Remove a test project"""
-        query = {'name': project_name}
-
-        # check for an existing project to be deleted
-        project = yield self.db.projects.find_one(query)
-        if project is None:
-            raise HTTPError(HTTP_NOT_FOUND,
-                            "{} could not be found as a project to be deleted"
-                            .format(project_name))
-
-        # just delete it, or maybe save it elsewhere in a future
-        yield self.db.projects.remove(query)
-
-        self.finish_request()
-
-
 class TestcaseHandler(GenericApiHandler):
     """
     TestCasesHandler Class
@@ -1,70 +1,56 @@
 from tornado import gen
-from tornado.web import HTTPError, asynchronous
+from tornado.web import 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()
+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
+            @description: list all pods
             @return 200: list all pods, empty list is no pod exist
             @rtype: L{Pods}
         """
-        self._list('pods', Pod)
+        self._list()
 
-    # @asynchronous
     @gen.coroutine
     @swagger.operation(nickname='create')
     def post(self):
         """
-            @description: Create a POD
-            @param body: pod information to be created
+            @description: create a pod
+            @param body: pod 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
+            @return 200: pod is created.
+            @raise 403: pod already exists
+            @raise 400: post without body
         """
-        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')
+        self._create('{} already exists as a {}')
 
-        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()
 
+class PodGURHandler(GenericPodHandler):
     @swagger.operation(nickname='get-one')
-    def get(self, pod_name=None):
+    def get(self, pod_name):
         """
-            @description: Get a single pod by pod_name
+            @description: get a single pod by pod_name
+            @rtype: L{Pod}
             @return 200: pod exist
             @raise 404: pod not exist
-            @rtype: L{Pod}
         """
         query = dict()
-        query["name"] = pod_name
-        self._get_one('pods', Pod, query)
+        query['name'] = pod_name
+        self._get_one(query)
 
     @asynchronous
     @gen.coroutine
index fcb4ddb..cc98c90 100644 (file)
@@ -27,9 +27,9 @@ class PodCreateRequest(object):
 
 @swagger.model()
 class Pod(PodCreateRequest):
-    """ describes a POD platform """
-    def __init__(self, name='', mode='', details='', role="",
-                 _id='', create_date=''):
+    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
diff --git a/utils/test/result_collection_api/resources/project_handlers.py b/utils/test/result_collection_api/resources/project_handlers.py
new file mode 100644 (file)
index 0000000..69ce3b5
--- /dev/null
@@ -0,0 +1,124 @@
+from tornado import gen
+from tornado.web import HTTPError, asynchronous
+
+from tornado_swagger_ui.tornado_swagger import swagger
+from handlers import GenericApiHandler, prepare_put_request, format_data
+from common.constants import HTTP_BAD_REQUEST, HTTP_FORBIDDEN, HTTP_NOT_FOUND
+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: post without body
+        """
+        self._create('{} already exists as a {}')
+
+
+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})
+
+    @asynchronous
+    @gen.coroutine
+    @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
+        """
+        if self.json_args is None:
+            raise HTTPError(HTTP_BAD_REQUEST)
+
+        query = {'name': project_name}
+        from_project = yield self.db.projects.find_one(query)
+        if from_project is None:
+            raise HTTPError(HTTP_NOT_FOUND,
+                            "{} could not be found".format(project_name))
+
+        project = Project.from_dict(from_project)
+        new_name = self.json_args.get("name")
+        new_description = self.json_args.get("description")
+
+        # check for payload name parameter in db
+        # avoid a request if the project name has not changed in the payload
+        if new_name != project.name:
+            to_project = yield self.db.projects.find_one(
+                {"name": new_name})
+            if to_project is not None:
+                raise HTTPError(HTTP_FORBIDDEN,
+                                "{} already exists as a project"
+                                .format(new_name))
+
+        # new dict for changes
+        request = dict()
+        request = prepare_put_request(request,
+                                      "name",
+                                      new_name,
+                                      project.name)
+        request = prepare_put_request(request,
+                                      "description",
+                                      new_description,
+                                      project.description)
+
+        """ raise exception if there isn't a change """
+        if not request:
+            raise HTTPError(HTTP_FORBIDDEN, "Nothing to update")
+
+        """ we merge the whole document """
+        edit_request = project.format()
+        edit_request.update(request)
+
+        """ Updating the DB """
+        yield self.db.projects.update(query, edit_request)
+        new_project = yield self.db.projects.find_one({"_id": project._id})
+
+        self.finish_request(format_data(new_project, Project))
+
+    @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})
index 895fc3e..a8f8309 100644 (file)
@@ -1,7 +1,23 @@
+from 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
@@ -13,14 +29,14 @@ class ProjectCreateRequest(object):
         }
 
 
+@swagger.model()
 class Project:
-    """ Describes a test project"""
-
-    def __init__(self):
-        self._id = None
-        self.name = None
-        self.description = None
-        self.creation_date = None
+    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):
@@ -52,7 +68,11 @@ class Project:
         }
 
 
+@swagger.model()
 class Projects(object):
+    """
+        @ptype projects: C{list} of L{Project}
+    """
     def __init__(self, projects=list()):
         self.projects = projects
 
index afd66f3..344e0d7 100644 (file)
@@ -35,8 +35,9 @@ import tornado.ioloop
 import motor
 
 from resources.handlers import VersionHandler, \
-    ProjectHandler, TestcaseHandler, TestResultsHandler, DashboardHandler
-from resources.pod_handler import PodCLHandler, PodGURHandler
+    TestcaseHandler, TestResultsHandler, DashboardHandler
+from resources.pod_handlers import PodCLHandler, PodGURHandler
+from resources.project_handlers import ProjectCLHandler, ProjectGURHandler
 from common.config import APIConfig
 from tornado_swagger_ui.tornado_swagger import swagger
 
@@ -67,8 +68,8 @@ def make_app():
             # few examples:
             # GET /projects
             # GET /projects/yardstick
-            (r"/api/v1/projects", ProjectHandler),
-            (r"/api/v1/projects/([^/]+)", ProjectHandler),
+            (r"/api/v1/projects", ProjectCLHandler),
+            (r"/api/v1/projects/([^/]+)", ProjectGURHandler),
 
             # few examples
             # GET /projects/qtip/cases => Get cases for qtip
index 16ed07c..44e42b7 100644 (file)
@@ -2,9 +2,10 @@ import json
 from tornado.web import Application
 from tornado.testing import AsyncHTTPTestCase
 
-from resources.pod_handler import PodCLHandler, PodGURHandler
+from resources.pod_handlers import PodCLHandler, PodGURHandler
+from resources.project_handlers import ProjectCLHandler, ProjectGURHandler
 from resources.handlers import VersionHandler, \
-    ProjectHandler, TestcaseHandler, TestResultsHandler, DashboardHandler
+    TestcaseHandler, TestResultsHandler, DashboardHandler
 from resources.models import CreateResponse
 import fake_pymongo
 
@@ -29,8 +30,8 @@ class TestBase(AsyncHTTPTestCase):
                 (r"/versions", VersionHandler),
                 (r"/api/v1/pods", PodCLHandler),
                 (r"/api/v1/pods/([^/]+)", PodGURHandler),
-                (r"/api/v1/projects", ProjectHandler),
-                (r"/api/v1/projects/([^/]+)", ProjectHandler),
+                (r"/api/v1/projects", ProjectCLHandler),
+                (r"/api/v1/projects/([^/]+)", ProjectGURHandler),
                 (r"/api/v1/projects/([^/]+)/cases", TestcaseHandler),
                 (r"/api/v1/projects/([^/]+)/cases/([^/]+)", TestcaseHandler),
                 (r"/api/v1/results", TestResultsHandler),
index c380780..b07cb7a 100644 (file)
@@ -30,6 +30,18 @@ class TestProjectCreate(TestProjectBase):
         (code, body) = self.create()
         self.assertEqual(code, HTTP_BAD_REQUEST)
 
+    def test_emptyName(self):
+        req_empty = ProjectCreateRequest('')
+        (code, body) = self.create(req_empty)
+        self.assertEqual(code, HTTP_BAD_REQUEST)
+        self.assertIn('project name missing', body)
+
+    def test_noneName(self):
+        req_none = ProjectCreateRequest(None)
+        (code, body) = self.create(req_none)
+        self.assertEqual(code, HTTP_BAD_REQUEST)
+        self.assertIn('project name missing', body)
+
     def test_success(self):
         (code, body) = self.create_d()
         self.assertEqual(code, HTTP_OK)