From 0c898e11323cf4e5baabecb55d8be2ff2268690d Mon Sep 17 00:00:00 2001 From: SerenaFeng Date: Mon, 23 May 2016 18:34:19 +0800 Subject: add test result/dashboard related unittests in testAPI and refactor its response modification: add unittests for test result/dashboard rename test_results table name in db to results refactor response body JIRA: FUNCTEST-255 Change-Id: I0657e6e95156a8c79072e7333fd8aaeb12d986e5 Signed-off-by: SerenaFeng --- result_collection_api/tests/unit/fake_pymongo.py | 15 +- result_collection_api/tests/unit/test_base.py | 48 +++-- result_collection_api/tests/unit/test_dashboard.py | 71 +++++++ .../tests/unit/test_fake_pymongo.py | 16 ++ result_collection_api/tests/unit/test_result.py | 235 +++++++++++++++++++++ result_collection_api/tests/unit/test_testcase.py | 20 +- 6 files changed, 373 insertions(+), 32 deletions(-) create mode 100644 result_collection_api/tests/unit/test_dashboard.py create mode 100644 result_collection_api/tests/unit/test_result.py (limited to 'result_collection_api/tests/unit') diff --git a/result_collection_api/tests/unit/fake_pymongo.py b/result_collection_api/tests/unit/fake_pymongo.py index 1521bfa..40eb164 100644 --- a/result_collection_api/tests/unit/fake_pymongo.py +++ b/result_collection_api/tests/unit/fake_pymongo.py @@ -1,6 +1,7 @@ from bson.objectid import ObjectId from concurrent.futures import ThreadPoolExecutor + __author__ = 'serena' @@ -42,7 +43,7 @@ class MemDb(object): result = executor.submit(self._find_one, spec_or_id, *args) return result - def _insert(self, doc_or_docs): + def _insert(self, doc_or_docs, check_keys=True): docs = doc_or_docs return_one = False @@ -53,8 +54,8 @@ class MemDb(object): ids = [] for doc in docs: if '_id' not in doc: - doc['_id'] = ObjectId() - if not self._find_one(doc['_id']): + doc['_id'] = str(ObjectId()) + if not check_keys or not self._find_one(doc['_id']): ids.append(doc['_id']) self.contents.append(doc_or_docs) @@ -65,16 +66,16 @@ class MemDb(object): else: return ids - def insert(self, doc_or_docs): + def insert(self, doc_or_docs, check_keys=True): with ThreadPoolExecutor(max_workers=2) as executor: - result = executor.submit(self._insert, doc_or_docs) + result = executor.submit(self._insert, doc_or_docs, check_keys) return result @staticmethod def _in(content, *args): for arg in args: for k, v in arg.iteritems(): - if content.get(k, None) != v: + if k != 'creation_date' and content.get(k, None) != v: return False return True @@ -129,4 +130,4 @@ class MemDb(object): pods = MemDb() projects = MemDb() testcases = MemDb() -test_results = MemDb() +results = MemDb() diff --git a/result_collection_api/tests/unit/test_base.py b/result_collection_api/tests/unit/test_base.py index 57d863c..a06cba9 100644 --- a/result_collection_api/tests/unit/test_base.py +++ b/result_collection_api/tests/unit/test_base.py @@ -50,24 +50,18 @@ class TestBase(AsyncHTTPTestCase): return self.create(self.req_e, *args) def create(self, req=None, *args): + return self.create_help(self.basePath, req, *args) + + def create_help(self, uri, req, *args): if req: req = req.format() - - res = self.fetch(self._get_uri(*args), + res = self.fetch(self._update_uri(uri, *args), method='POST', body=json.dumps(req), headers=self.headers) return self._get_return(res, self.create_res) - def create_help(self, uri, req, cls): - res = self.fetch(uri, - method='POST', - body=json.dumps(req.format()), - headers=self.headers) - - return self._get_return(res, cls) - def get(self, *args): res = self.fetch(self._get_uri(*args), method='GET', @@ -75,9 +69,16 @@ class TestBase(AsyncHTTPTestCase): def inner(): new_args, num = self._get_valid_args(*args) - return self.get_res if num != self._need_arg_num() else self.list_res + return self.get_res \ + if num != self._need_arg_num(self.basePath) else self.list_res return self._get_return(res, inner()) + def query(self, query): + res = self.fetch(self._get_query_uri(query), + method='GET', + headers=self.headers) + return self._get_return(res, self.list_res) + def update(self, new=None, *args): if new: new = new.format() @@ -98,16 +99,22 @@ class TestBase(AsyncHTTPTestCase): new_args = tuple(['%s' % arg for arg in args if arg is not None]) return new_args, len(new_args) - def _need_arg_num(self): - return self.basePath.count('%s') + def _need_arg_num(self, uri): + return uri.count('%s') + + def _get_query_uri(self, query): + return self.basePath + '?' + query def _get_uri(self, *args): + return self._update_uri(self.basePath, *args) + + def _update_uri(self, uri, *args): + r_uri = uri new_args, num = self._get_valid_args(*args) - uri = self.basePath - if num != self._need_arg_num(): - uri += '/%s' + if num != self._need_arg_num(uri): + r_uri += '/%s' - return uri % tuple(['%s' % arg for arg in new_args]) + return r_uri % tuple(['%s' % arg for arg in new_args]) def _get_return(self, res, cls): code = res.code @@ -116,7 +123,10 @@ class TestBase(AsyncHTTPTestCase): @staticmethod def _get_return_body(code, body, cls): - return cls.from_dict(json.loads(body)) if code < 300 else body + return cls.from_dict(json.loads(body)) if code < 300 and cls else body + + def assert_href(self, body): + self.assertIn(self.basePath, body.href) def assert_create_body(self, body, req=None, *args): if not req: @@ -129,4 +139,4 @@ class TestBase(AsyncHTTPTestCase): fake_pymongo.pods.clear() fake_pymongo.projects.clear() fake_pymongo.testcases.clear() - fake_pymongo.test_results.clear() + fake_pymongo.results.clear() diff --git a/result_collection_api/tests/unit/test_dashboard.py b/result_collection_api/tests/unit/test_dashboard.py new file mode 100644 index 0000000..1e0d22b --- /dev/null +++ b/result_collection_api/tests/unit/test_dashboard.py @@ -0,0 +1,71 @@ +import unittest + +from test_result import TestResultBase +from common.constants import HTTP_NOT_FOUND, HTTP_OK + +__author__ = '__serena__' + + +class TestDashboardBase(TestResultBase): + def setUp(self): + super(TestDashboardBase, self).setUp() + self.basePath = '/dashboard' + self.create_help('/results', self.req_d) + self.create_help('/results', self.req_d) + self.list_res = None + + +class TestDashboardQuery(TestDashboardBase): + def test_projectMissing(self): + code, body = self.query(self._set_query(project='missing')) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn('Project name missing', body) + + def test_projectNotReady(self): + code, body = self.query(self._set_query(project='notReadyProject')) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn('Project [notReadyProject] not dashboard ready', body) + + def test_testcaseMissing(self): + code, body = self.query(self._set_query(case='missing')) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn('Test case missing for project [{}]' + .format(self.project), + body) + + def test_testcaseNotReady(self): + code, body = self.query(self._set_query(case='notReadyCase')) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn( + 'Test case [notReadyCase] not dashboard ready for project [%s]' + % self.project, + body) + + def test_success(self): + code, body = self.query(self._set_query()) + self.assertEqual(code, HTTP_OK) + self.assertIn('{"description": "vPing results for Dashboard"}', body) + + def test_caseIsStatus(self): + code, body = self.query(self._set_query(case='status')) + self.assertEqual(code, HTTP_OK) + self.assertIn('{"description": "Functest status"}', body) + + def _set_query(self, project=None, case=None): + uri = '' + for k, v in list(locals().iteritems()): + if k == 'self' or k == 'uri': + continue + if v is None: + v = eval('self.' + k) + if v != 'missing': + uri += '{}={}&'.format(k, v) + uri += 'pod={}&'.format(self.pod) + uri += 'version={}&'.format(self.version) + uri += 'installer={}&'.format(self.installer) + uri += 'period={}&'.format(5) + return uri[0:-1] + + +if __name__ == '__main__': + unittest.main() diff --git a/result_collection_api/tests/unit/test_fake_pymongo.py b/result_collection_api/tests/unit/test_fake_pymongo.py index 228fed7..6920fca 100644 --- a/result_collection_api/tests/unit/test_fake_pymongo.py +++ b/result_collection_api/tests/unit/test_fake_pymongo.py @@ -10,6 +10,7 @@ class MyTest(AsyncHTTPTestCase): def setUp(self): super(MyTest, self).setUp() self.db = fake_pymongo + self.addCleanup(self._clear) self.io_loop.run_sync(self.fixture_setup) def get_app(self): @@ -26,6 +27,7 @@ class MyTest(AsyncHTTPTestCase): def test_find_one(self): user = yield self.db.pods.find_one({'name': 'test1'}) self.assertEqual(user, self.test1) + self.db.pods.remove() @gen_test def test_find(self): @@ -48,5 +50,19 @@ class MyTest(AsyncHTTPTestCase): user = yield self.db.pods.find_one({'_id': '1'}) self.assertIsNone(user) + @gen_test + def test_insert_check_keys(self): + yield self.db.pods.insert({'_id': '1', 'name': 'test1'}, + check_keys=False) + cursor = self.db.pods.find({'_id': '1'}) + names = [] + while (yield cursor.fetch_next): + ob = cursor.next_object() + names.append(ob.get('name')) + self.assertItemsEqual(names, ['test1', 'test1']) + + def _clear(self): + self.db.pods.clear() + if __name__ == '__main__': unittest.main() diff --git a/result_collection_api/tests/unit/test_result.py b/result_collection_api/tests/unit/test_result.py new file mode 100644 index 0000000..2ea1b6c --- /dev/null +++ b/result_collection_api/tests/unit/test_result.py @@ -0,0 +1,235 @@ +import unittest + +from test_base import TestBase +from resources.pod_models import PodCreateRequest +from resources.project_models import ProjectCreateRequest +from resources.testcase_models import TestcaseCreateRequest +from resources.result_models import ResultCreateRequest, \ + TestResult, TestResults +from common.constants import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND + + +__author__ = '__serena__' + + +class Details(object): + def __init__(self, timestart=None, duration=None, status=None): + self.timestart = timestart + self.duration = duration + self.status = status + + def format(self): + return { + "timestart": self.timestart, + "duration": self.duration, + "status": self.status + } + + @staticmethod + def from_dict(a_dict): + + if a_dict is None: + return None + + t = Details() + t.timestart = a_dict.get('timestart') + t.duration = a_dict.get('duration') + t.status = a_dict.get('status') + return t + + +class TestResultBase(TestBase): + def setUp(self): + self.pod = 'zte-pod1' + self.project = 'functest' + self.case = 'vPing' + self.installer = 'fuel' + self.version = 'C' + self.build_tag = 'v3.0' + self.scenario = 'odl-l2' + self.criteria = '10s' + self.trust_indicator = 0.7 + super(TestResultBase, self).setUp() + self.details = Details(timestart='0', duration='9s', status='OK') + self.req_d = ResultCreateRequest(pod_name=self.pod, + project_name=self.project, + case_name=self.case, + installer=self.installer, + version=self.version, + description='vping use ssh', + details=self.details.format(), + build_tag=self.build_tag, + scenario=self.scenario, + criteria=self.criteria, + trust_indicator=self.trust_indicator) + self.get_res = TestResult + self.list_res = TestResults + self.basePath = '/results' + self.req_pod = PodCreateRequest(self.pod, 'metal', 'zte pod 1') + self.req_project = ProjectCreateRequest(self.project, 'vping test') + self.req_testcase = TestcaseCreateRequest('/cases/vping', + self.case, + 'vping-ssh test') + self.create_help('/pods', self.req_pod) + self.create_help('/projects', self.req_project) + self.create_help('/projects/%s/cases', self.req_testcase, self.project) + + def assert_res(self, code, result): + self.assertEqual(code, HTTP_OK) + req = self.req_d + self.assertEqual(result.pod_name, req.pod_name) + self.assertEqual(result.project_name, req.project_name) + self.assertEqual(result.case_name, req.case_name) + self.assertEqual(result.installer, req.installer) + self.assertEqual(result.version, req.version) + self.assertEqual(result.description, req.description) + details_req = Details.from_dict(req.details) + details_res = Details.from_dict(result.details) + self.assertEqual(details_res.duration, details_req.duration) + self.assertEqual(details_res.timestart, details_req.timestart) + self.assertEqual(details_res.status, details_req.status) + self.assertEqual(result.build_tag, req.build_tag) + self.assertEqual(result.scenario, req.scenario) + self.assertEqual(result.criteria, req.criteria) + self.assertEqual(result.trust_indicator, req.trust_indicator) + self.assertIsNotNone(result.creation_date) + self.assertIsNotNone(result._id) + + +class TestResultCreate(TestResultBase): + def test_nobody(self): + (code, body) = self.create(None) + self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertIn('no payload', body) + + def test_podNotProvided(self): + req = self.req_d + req.pod_name = None + (code, body) = self.create(req) + self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertIn('pod is not provided', body) + + def test_projectNotProvided(self): + req = self.req_d + req.project_name = None + (code, body) = self.create(req) + self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertIn('project is not provided', body) + + def test_testcaseNotProvided(self): + req = self.req_d + req.case_name = None + (code, body) = self.create(req) + self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertIn('testcase is not provided', body) + + def test_noPod(self): + req = self.req_d + req.pod_name = 'notExistPod' + (code, body) = self.create(req) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn('Could not find POD', body) + + def test_noProject(self): + req = self.req_d + req.project_name = 'notExistProject' + (code, body) = self.create(req) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn('Could not find project', body) + + def test_noTestcase(self): + req = self.req_d + req.case_name = 'notExistTestcase' + (code, body) = self.create(req) + self.assertEqual(code, HTTP_NOT_FOUND) + self.assertIn('Could not find testcase', body) + + def test_success(self): + (code, body) = self.create_d() + self.assertEqual(code, HTTP_OK) + self.assert_href(body) + + +class TestResultGet(TestResultBase): + def test_getOne(self): + _, res = self.create_d() + _id = res.href.split('/')[-1] + code, body = self.get(_id) + self.assert_res(code, body) + + def test_queryPod(self): + self._query_and_assert(self._set_query('pod')) + + def test_queryProject(self): + self._query_and_assert(self._set_query('project')) + + def test_queryTestcase(self): + self._query_and_assert(self._set_query('case')) + + def test_queryVersion(self): + self._query_and_assert(self._set_query('version')) + + def test_queryInstaller(self): + self._query_and_assert(self._set_query('installer')) + + def test_queryBuildTag(self): + self._query_and_assert(self._set_query('build_tag')) + + def test_queryScenario(self): + self._query_and_assert(self._set_query('scenario')) + + def test_queryTrustIndicator(self): + self._query_and_assert(self._set_query('trust_indicator')) + + def test_queryCriteria(self): + self._query_and_assert(self._set_query('criteria')) + + def test_queryPeriod(self): + self._query_and_assert(self._set_query('period=1')) + + def test_combination(self): + self._query_and_assert(self._set_query('pod', + 'project', + 'case', + 'version', + 'installer', + 'build_tag', + 'scenario', + 'trust_indicator', + 'criteria', + 'period=1')) + + def test_notFound(self): + self._query_and_assert(self._set_query('pod=notExistPod', + 'project', + 'case', + 'version', + 'installer', + 'build_tag', + 'scenario', + 'trust_indicator', + 'criteria', + 'period=1'), + found=False) + + def _query_and_assert(self, query, found=True): + _, res = self.create_d() + code, body = self.query(query) + if not found: + self.assertEqual(code, HTTP_OK) + self.assertEqual(0, len(body.results)) + else: + for result in body.results: + self.assert_res(code, result) + + def _set_query(self, *args): + uri = '' + for arg in args: + if '=' in arg: + uri += arg + '&' + else: + uri += '{}={}&'.format(arg, eval('self.' + arg)) + return uri[0: -1] + +if __name__ == '__main__': + unittest.main() diff --git a/result_collection_api/tests/unit/test_testcase.py b/result_collection_api/tests/unit/test_testcase.py index 4b99837..e44c0b4 100644 --- a/result_collection_api/tests/unit/test_testcase.py +++ b/result_collection_api/tests/unit/test_testcase.py @@ -3,7 +3,7 @@ import unittest from test_base import TestBase from resources.testcase_models import TestcaseCreateRequest, \ Testcase, Testcases, TestcaseUpdateRequest -from resources.project_models import ProjectCreateRequest, Project +from resources.project_models import ProjectCreateRequest from common.constants import HTTP_OK, HTTP_BAD_REQUEST, \ HTTP_FORBIDDEN, HTTP_NOT_FOUND @@ -14,10 +14,18 @@ __author__ = '__serena__' class TestCaseBase(TestBase): def setUp(self): super(TestCaseBase, self).setUp() - self.req_d = TestcaseCreateRequest('/cases/vping_1', 'vping_1', 'vping-ssh test') - self.req_e = TestcaseCreateRequest('/cases/doctor_1', 'doctor_1', 'create doctor') - self.update_d = TestcaseUpdateRequest('vping_1', 'vping-ssh test', 'functest') - self.update_e = TestcaseUpdateRequest('doctor_1', 'create doctor', 'functest') + self.req_d = TestcaseCreateRequest('/cases/vping_1', + 'vping_1', + 'vping-ssh test') + self.req_e = TestcaseCreateRequest('/cases/doctor_1', + 'doctor_1', + 'create doctor') + self.update_d = TestcaseUpdateRequest('vping_1', + 'vping-ssh test', + 'functest') + self.update_e = TestcaseUpdateRequest('doctor_1', + 'create doctor', + 'functest') self.get_res = Testcase self.list_res = Testcases self.update_res = Testcase @@ -44,7 +52,7 @@ class TestCaseBase(TestBase): def create_project(self): req_p = ProjectCreateRequest('functest', 'vping-ssh test') - self.create_help('/projects', req_p, Project) + self.create_help('/projects', req_p) self.project = req_p.name def create_d(self): -- cgit 1.2.3-korg