summaryrefslogtreecommitdiffstats
path: root/testapi
diff options
context:
space:
mode:
authorSerenaFeng <feng.xiaowei@zte.com.cn>2017-09-11 12:37:22 +0800
committerSerenaFeng <feng.xiaowei@zte.com.cn>2017-09-12 14:23:18 +0800
commit7479f29b3d0a613d459cd26b31eab38f00a00b22 (patch)
tree2a763a2de3bd25cdddd49d5efb1eacc7036741e8 /testapi
parent28d5b3d14a6354ec170ebaea7f0f6ba342375b61 (diff)
leverage LFID authentication to pod creation
only valid linux foundation user is allowed to create the new pod add owner field in pods to track the pod creator Change-Id: Icada07152069f7c826bfa6122cb86db8c4e3bf68 Signed-off-by: SerenaFeng <feng.xiaowei@zte.com.cn>
Diffstat (limited to 'testapi')
-rw-r--r--testapi/3rd_party/static/testapi-ui/components/pods/pods.html1
-rw-r--r--testapi/opnfv_testapi/common/check.py17
-rw-r--r--testapi/opnfv_testapi/common/message.py8
-rw-r--r--testapi/opnfv_testapi/resources/handlers.py1
-rw-r--r--testapi/opnfv_testapi/resources/pod_models.py3
-rw-r--r--testapi/opnfv_testapi/tests/unit/executor.py33
-rw-r--r--testapi/opnfv_testapi/tests/unit/fake_pymongo.py1
-rw-r--r--testapi/opnfv_testapi/tests/unit/resources/test_base.py25
-rw-r--r--testapi/opnfv_testapi/tests/unit/resources/test_pod.py45
-rw-r--r--testapi/opnfv_testapi/tests/unit/resources/test_result.py17
10 files changed, 128 insertions, 23 deletions
diff --git a/testapi/3rd_party/static/testapi-ui/components/pods/pods.html b/testapi/3rd_party/static/testapi-ui/components/pods/pods.html
index e366670..22f2934 100644
--- a/testapi/3rd_party/static/testapi-ui/components/pods/pods.html
+++ b/testapi/3rd_party/static/testapi-ui/components/pods/pods.html
@@ -54,6 +54,7 @@
<a href="#" ng-click="showPod = !showPod">{{pod.name}}</a>
<div class="show-pod" ng-class="{ 'hidden': ! showPod }" style="margin-left:24px;">
<p>
+ owner: {{pod.owner}}<br>
role: {{pod.role}}<br>
mode: {{pod.mode}}<br>
create_date: {{pod.creation_date}}<br>
diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py
index 9ded48d..e80b1c6 100644
--- a/testapi/opnfv_testapi/common/check.py
+++ b/testapi/opnfv_testapi/common/check.py
@@ -11,11 +11,28 @@ import re
from tornado import gen
+from opnfv_testapi.common import constants
from opnfv_testapi.common import message
from opnfv_testapi.common import raises
from opnfv_testapi.db import api as dbapi
+def is_authorized(method):
+ @functools.wraps(method)
+ def wrapper(self, *args, **kwargs):
+ if self.table in ['pods']:
+ testapi_id = self.get_secure_cookie(constants.TESTAPI_ID)
+ if not testapi_id:
+ raises.Unauthorized(message.not_login())
+ user_info = yield dbapi.db_find_one('users', {'user': testapi_id})
+ if not user_info:
+ raises.Unauthorized(message.not_lfid())
+ kwargs['owner'] = testapi_id
+ ret = yield gen.coroutine(method)(self, *args, **kwargs)
+ raise gen.Return(ret)
+ return wrapper
+
+
def valid_token(method):
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
diff --git a/testapi/opnfv_testapi/common/message.py b/testapi/opnfv_testapi/common/message.py
index 951cbaf..8b5c3fb 100644
--- a/testapi/opnfv_testapi/common/message.py
+++ b/testapi/opnfv_testapi/common/message.py
@@ -42,6 +42,14 @@ def invalid_token():
return 'Invalid Token'
+def not_login():
+ return 'TestAPI id is not provided'
+
+
+def not_lfid():
+ return 'Not a valid Linux Foundation Account'
+
+
def no_update():
return 'Nothing to update'
diff --git a/testapi/opnfv_testapi/resources/handlers.py b/testapi/opnfv_testapi/resources/handlers.py
index 757c817..8e5dab2 100644
--- a/testapi/opnfv_testapi/resources/handlers.py
+++ b/testapi/opnfv_testapi/resources/handlers.py
@@ -75,6 +75,7 @@ class GenericApiHandler(web.RequestHandler):
@web.asynchronous
@gen.coroutine
+ @check.is_authorized
@check.valid_token
@check.no_body
@check.miss_fields
diff --git a/testapi/opnfv_testapi/resources/pod_models.py b/testapi/opnfv_testapi/resources/pod_models.py
index 2c3ea97..415d3d6 100644
--- a/testapi/opnfv_testapi/resources/pod_models.py
+++ b/testapi/opnfv_testapi/resources/pod_models.py
@@ -29,13 +29,14 @@ class PodCreateRequest(models.ModelBase):
class Pod(models.ModelBase):
def __init__(self,
name='', mode='', details='',
- role="", _id='', create_date=''):
+ role="", _id='', create_date='', owner=''):
self.name = name
self.mode = mode
self.details = details
self.role = role
self._id = _id
self.creation_date = create_date
+ self.owner = owner
@swagger.model()
diff --git a/testapi/opnfv_testapi/tests/unit/executor.py b/testapi/opnfv_testapi/tests/unit/executor.py
index b8f696c..aa99b90 100644
--- a/testapi/opnfv_testapi/tests/unit/executor.py
+++ b/testapi/opnfv_testapi/tests/unit/executor.py
@@ -9,6 +9,39 @@
import functools
import httplib
+from concurrent.futures import ThreadPoolExecutor
+import mock
+
+
+O_get_secure_cookie = (
+ 'opnfv_testapi.resources.handlers.GenericApiHandler.get_secure_cookie')
+
+
+def thread_execute(method, *args, **kwargs):
+ with ThreadPoolExecutor(max_workers=2) as executor:
+ result = executor.submit(method, *args, **kwargs)
+ return result
+
+
+def mock_invalid_lfid():
+ def _mock_invalid_lfid(xstep):
+ def wrap(self, *args, **kwargs):
+ with mock.patch(O_get_secure_cookie) as m_cookie:
+ m_cookie.return_value = 'InvalidUser'
+ return xstep(self, *args, **kwargs)
+ return wrap
+ return _mock_invalid_lfid
+
+
+def mock_valid_lfid():
+ def _mock_valid_lfid(xstep):
+ def wrap(self, *args, **kwargs):
+ with mock.patch(O_get_secure_cookie) as m_cookie:
+ m_cookie.return_value = 'ValidUser'
+ return xstep(self, *args, **kwargs)
+ return wrap
+ return _mock_valid_lfid
+
def upload(excepted_status, excepted_response):
def _upload(create_request):
diff --git a/testapi/opnfv_testapi/tests/unit/fake_pymongo.py b/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
index 3320a86..c44a92c 100644
--- a/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
+++ b/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
@@ -288,3 +288,4 @@ testcases = MemDb('testcases')
results = MemDb('results')
scenarios = MemDb('scenarios')
tokens = MemDb('tokens')
+users = MemDb('users')
diff --git a/testapi/opnfv_testapi/tests/unit/resources/test_base.py b/testapi/opnfv_testapi/tests/unit/resources/test_base.py
index 39633e5..89cd7e8 100644
--- a/testapi/opnfv_testapi/tests/unit/resources/test_base.py
+++ b/testapi/opnfv_testapi/tests/unit/resources/test_base.py
@@ -6,13 +6,16 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
+from datetime import datetime
import json
from os import path
+from bson.objectid import ObjectId
import mock
from tornado import testing
from opnfv_testapi.resources import models
+from opnfv_testapi.resources import pod_models
from opnfv_testapi.tests.unit import fake_pymongo
@@ -26,10 +29,32 @@ class TestBase(testing.AsyncHTTPTestCase):
self.get_res = None
self.list_res = None
self.update_res = None
+ self.pod_d = pod_models.Pod(name='zte-pod1',
+ mode='virtual',
+ details='zte pod 1',
+ role='community-ci',
+ _id=str(ObjectId()),
+ owner='ValidUser',
+ create_date=str(datetime.now()))
+ self.pod_e = pod_models.Pod(name='zte-pod2',
+ mode='metal',
+ details='zte pod 2',
+ role='production-ci',
+ _id=str(ObjectId()),
+ owner='ValidUser',
+ create_date=str(datetime.now()))
self.req_d = None
self.req_e = None
self.addCleanup(self._clear)
super(TestBase, self).setUp()
+ fake_pymongo.users.insert({"user": "ValidUser",
+ 'email': 'validuser@lf.com',
+ 'fullname': 'Valid User',
+ 'groups': [
+ 'opnfv-testapi-users',
+ 'opnfv-gerrit-functest-submitters',
+ 'opnfv-gerrit-qtip-contributors']
+ })
def tearDown(self):
self.db_patcher.stop()
diff --git a/testapi/opnfv_testapi/tests/unit/resources/test_pod.py b/testapi/opnfv_testapi/tests/unit/resources/test_pod.py
index d1a19f7..5d9da3a 100644
--- a/testapi/opnfv_testapi/tests/unit/resources/test_pod.py
+++ b/testapi/opnfv_testapi/tests/unit/resources/test_pod.py
@@ -12,24 +12,29 @@ import unittest
from opnfv_testapi.common import message
from opnfv_testapi.resources import pod_models
from opnfv_testapi.tests.unit import executor
+from opnfv_testapi.tests.unit import fake_pymongo
from opnfv_testapi.tests.unit.resources import test_base as base
class TestPodBase(base.TestBase):
def setUp(self):
super(TestPodBase, self).setUp()
- self.req_d = pod_models.PodCreateRequest('zte-1', 'virtual',
- 'zte pod 1', 'ci-pod')
- self.req_e = pod_models.PodCreateRequest('zte-2', 'metal', 'zte pod 2')
- self.req_f = pod_models.PodCreateRequest('Zte-1', 'virtual',
- 'zte pod 1', 'ci-pod')
self.get_res = pod_models.Pod
self.list_res = pod_models.Pods
self.basePath = '/api/v1/pods'
+ self.req_d = pod_models.PodCreateRequest(name=self.pod_d.name,
+ mode=self.pod_d.mode,
+ details=self.pod_d.details,
+ role=self.pod_d.role)
+ self.req_e = pod_models.PodCreateRequest(name=self.pod_e.name,
+ mode=self.pod_e.mode,
+ details=self.pod_e.details,
+ role=self.pod_e.role)
def assert_get_body(self, pod, req=None):
if not req:
req = self.req_d
+ self.assertEqual(pod.owner, 'ValidUser')
self.assertEqual(pod.name, req.name)
self.assertEqual(pod.mode, req.mode)
self.assertEqual(pod.details, req.details)
@@ -39,38 +44,54 @@ class TestPodBase(base.TestBase):
class TestPodCreate(TestPodBase):
+ @executor.create(httplib.BAD_REQUEST, message.not_login())
+ def test_notlogin(self):
+ return self.req_d
+
+ @executor.mock_invalid_lfid()
+ @executor.create(httplib.BAD_REQUEST, message.not_lfid())
+ def test_invalidLfid(self):
+ return self.req_d
+
+ @executor.mock_valid_lfid()
@executor.create(httplib.BAD_REQUEST, message.no_body())
def test_withoutBody(self):
return None
+ @executor.mock_valid_lfid()
@executor.create(httplib.BAD_REQUEST, message.missing('name'))
def test_emptyName(self):
return pod_models.PodCreateRequest('')
+ @executor.mock_valid_lfid()
@executor.create(httplib.BAD_REQUEST, message.missing('name'))
def test_noneName(self):
return pod_models.PodCreateRequest(None)
+ @executor.mock_valid_lfid()
@executor.create(httplib.OK, 'assert_create_body')
def test_success(self):
return self.req_d
+ @executor.mock_valid_lfid()
@executor.create(httplib.FORBIDDEN, message.exist_base)
def test_alreadyExist(self):
- self.create_d()
+ fake_pymongo.pods.insert(self.pod_d.format())
return self.req_d
+ @executor.mock_valid_lfid()
@executor.create(httplib.FORBIDDEN, message.exist_base)
def test_alreadyExistCaseInsensitive(self):
- self.create(self.req_f)
+ fake_pymongo.pods.insert(self.pod_d.format())
+ self.req_d.name = self.req_d.name.upper()
return self.req_d
class TestPodGet(TestPodBase):
def setUp(self):
super(TestPodGet, self).setUp()
- self.create_d()
- self.create_e()
+ fake_pymongo.pods.insert(self.pod_d.format())
+ fake_pymongo.pods.insert(self.pod_e.format())
@executor.get(httplib.NOT_FOUND, message.not_found_base)
def test_notExist(self):
@@ -78,7 +99,7 @@ class TestPodGet(TestPodBase):
@executor.get(httplib.OK, 'assert_get_body')
def test_getOne(self):
- return self.req_d.name
+ return self.pod_d.name
@executor.get(httplib.OK, '_assert_list')
def test_list(self):
@@ -87,10 +108,10 @@ class TestPodGet(TestPodBase):
def _assert_list(self, body):
self.assertEqual(len(body.pods), 2)
for pod in body.pods:
- if self.req_d.name == pod.name:
+ if self.pod_d.name == pod.name:
self.assert_get_body(pod)
else:
- self.assert_get_body(pod, self.req_e)
+ self.assert_get_body(pod, self.pod_e)
if __name__ == '__main__':
diff --git a/testapi/opnfv_testapi/tests/unit/resources/test_result.py b/testapi/opnfv_testapi/tests/unit/resources/test_result.py
index 1e83ed3..f5026c9 100644
--- a/testapi/opnfv_testapi/tests/unit/resources/test_result.py
+++ b/testapi/opnfv_testapi/tests/unit/resources/test_result.py
@@ -7,17 +7,18 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
import copy
+from datetime import datetime
+from datetime import timedelta
import httplib
-import unittest
-from datetime import datetime, timedelta
import json
+import unittest
from opnfv_testapi.common import message
-from opnfv_testapi.resources import pod_models
from opnfv_testapi.resources import project_models
from opnfv_testapi.resources import result_models
from opnfv_testapi.resources import testcase_models
from opnfv_testapi.tests.unit import executor
+from opnfv_testapi.tests.unit import fake_pymongo
from opnfv_testapi.tests.unit.resources import test_base as base
@@ -52,7 +53,8 @@ class Details(object):
class TestResultBase(base.TestBase):
def setUp(self):
- self.pod = 'zte-pod1'
+ super(TestResultBase, self).setUp()
+ self.pod = self.pod_d.name
self.project = 'functest'
self.case = 'vPing'
self.installer = 'fuel'
@@ -65,7 +67,6 @@ class TestResultBase(base.TestBase):
self.stop_date = str(datetime.now() + timedelta(minutes=1))
self.update_date = str(datetime.now() + timedelta(days=1))
self.update_step = -0.05
- super(TestResultBase, self).setUp()
self.details = Details(timestart='0', duration='9s', status='OK')
self.req_d = result_models.ResultCreateRequest(
pod_name=self.pod,
@@ -84,10 +85,6 @@ class TestResultBase(base.TestBase):
self.list_res = result_models.TestResults
self.update_res = result_models.TestResult
self.basePath = '/api/v1/results'
- self.req_pod = pod_models.PodCreateRequest(
- self.pod,
- 'metal',
- 'zte pod 1')
self.req_project = project_models.ProjectCreateRequest(
self.project,
'vping test')
@@ -95,7 +92,7 @@ class TestResultBase(base.TestBase):
self.case,
'/cases/vping',
'vping-ssh test')
- self.create_help('/api/v1/pods', self.req_pod)
+ fake_pymongo.pods.insert(self.pod_d.format())
self.create_help('/api/v1/projects', self.req_project)
self.create_help('/api/v1/projects/%s/cases',
self.req_testcase,