summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--testapi/.gitignore1
-rw-r--r--testapi/opnfv_testapi/common/check.py22
-rw-r--r--testapi/opnfv_testapi/models/project_models.py6
-rw-r--r--testapi/opnfv_testapi/models/scenario_models.py9
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_pod.py5
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_project.py8
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_result.py5
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py5
-rw-r--r--testapi/testapi-client/.stestr.conf2
-rw-r--r--testapi/testapi-client/test-requirements.txt2
-rw-r--r--testapi/testapi-client/testapiclient/auth.py12
-rw-r--r--testapi/testapi-client/testapiclient/authHandler.py5
-rw-r--r--testapi/testapi-client/testapiclient/httpClient.py12
-rw-r--r--testapi/testapi-client/testapiclient/pods.py49
-rw-r--r--testapi/testapi-client/testapiclient/projects.py74
-rw-r--r--testapi/testapi-client/testapiclient/tests/__init__.py0
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/__init__.py0
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py6
-rw-r--r--testapi/testapi-client/tox.ini8
-rw-r--r--testapi/tox.ini2
20 files changed, 173 insertions, 60 deletions
diff --git a/testapi/.gitignore b/testapi/.gitignore
index 5be8583..869a07a 100644
--- a/testapi/.gitignore
+++ b/testapi/.gitignore
@@ -13,4 +13,5 @@ build
docs/_build
opnfv_testapi/tests/UI/coverage
3rd_party/static/testapi-ui/testapi-ui
+.stestr/
diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py
index 77b48f5..18dc67d 100644
--- a/testapi/opnfv_testapi/common/check.py
+++ b/testapi/opnfv_testapi/common/check.py
@@ -21,7 +21,8 @@ from opnfv_testapi.db import api as dbapi
def is_authorized(method):
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
- if CONF.api_authenticate and self.table in ['pods', 'projects', 'testcases', 'scenarios']:
+ resources = ['pods', 'projects', 'testcases', 'scenarios']
+ if CONF.api_authenticate and self.table in resources:
testapi_id = self.get_secure_cookie(constants.TESTAPI_ID)
if not testapi_id:
raises.Unauthorized(message.not_login())
@@ -51,18 +52,19 @@ def is_reource_tied(method):
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
query_data = {}
- tied_map_tables = {
+ tied_maps = {
'projects': ('testcases', 'project_name'),
'pods': ('results', 'pod_name'),
'testcases': ('results', 'case_name')
}
- if self.table in tied_map_tables:
+ if self.table in tied_maps:
if method.__name__ == '_update':
if 'name' not in self.json_args:
ret = yield gen.coroutine(method)(self, *args, **kwargs)
raise gen.Return(ret)
- query_data[tied_map_tables[self.table][1]] = kwargs.get('query')['name']
- data = yield dbapi.db_find_one(tied_map_tables[self.table][0], query_data)
+ query_data[tied_maps[self.table][1]] = kwargs.get('query')['name']
+ data = yield dbapi.db_find_one(tied_maps[self.table][0],
+ query_data)
if data:
raises.Unauthorized(message.tied_with_resource())
ret = yield gen.coroutine(method)(self, *args, **kwargs)
@@ -159,8 +161,10 @@ def new_not_exists(xstep):
if query:
query_data = query()
if self.table == 'pods':
- if query_data.get('name') is not None:
- query_data['name'] = re.compile('\\b' + query_data.get('name') + '\\b', re.IGNORECASE)
+ if query_data.get('name'):
+ query_data['name'] = re.compile(
+ '\\b{}\\b'.format(query_data.get('name')),
+ re.IGNORECASE)
to_data = yield dbapi.db_find_one(self.table, query_data)
if to_data:
raises.Forbidden(message.exist(self.table, query()))
@@ -188,7 +192,9 @@ def query_by_name(xstep):
def wrap(self, *args, **kwargs):
if 'name' in self.request.query_arguments.keys():
query = kwargs.get('query', {})
- query.update({'name': re.compile(self.get_query_argument('name'), re.IGNORECASE)})
+ query.update({
+ 'name': re.compile(self.get_query_argument('name'),
+ re.IGNORECASE)})
kwargs.update({'query': query})
ret = yield gen.coroutine(xstep)(self, *args, **kwargs)
diff --git a/testapi/opnfv_testapi/models/project_models.py b/testapi/opnfv_testapi/models/project_models.py
index eac2fd3..5c8c048 100644
--- a/testapi/opnfv_testapi/models/project_models.py
+++ b/testapi/opnfv_testapi/models/project_models.py
@@ -27,7 +27,11 @@ class ProjectUpdateRequest(base_models.ModelBase):
@swagger.model()
class Project(base_models.ModelBase):
def __init__(self,
- name=None, creator='', _id=None, description=None, creation_date=None):
+ name=None,
+ creator='',
+ _id=None,
+ description=None,
+ creation_date=None):
self.creator = creator
self._id = _id
self.name = name
diff --git a/testapi/opnfv_testapi/models/scenario_models.py b/testapi/opnfv_testapi/models/scenario_models.py
index 01b5c2b..537650e 100644
--- a/testapi/opnfv_testapi/models/scenario_models.py
+++ b/testapi/opnfv_testapi/models/scenario_models.py
@@ -178,11 +178,16 @@ class Scenario(base_models.ModelBase):
@property installers:
@ptype installers: C{list} of L{ScenarioInstaller}
"""
- def __init__(self, name='', create_date='', _id='', creator='', installers=None):
+ def __init__(self,
+ name='',
+ creation_date='',
+ _id='',
+ creator='',
+ installers=None):
self.name = name
self.creator = creator
self._id = _id
- self.creation_date = create_date
+ self.creation_date = creation_date
self.installers = list_default(installers)
@staticmethod
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py b/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py
index 28d29b5..3a16799 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py
@@ -112,8 +112,9 @@ class TestPodDelete(TestPodBase):
super(TestPodDelete, self).setUp()
fake_pymongo.pods.insert(self.pod_d.format())
fake_pymongo.projects.insert({'name': self.results_d.project_name})
- fake_pymongo.testcases.insert({'name': self.results_d.case_name,
- 'project_name': self.results_d.project_name})
+ fake_pymongo.testcases.insert({
+ 'name': self.results_d.case_name,
+ 'project_name': self.results_d.project_name})
@executor.delete(httplib.BAD_REQUEST, message.not_login())
def test_notlogin(self):
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_project.py b/testapi/opnfv_testapi/tests/unit/handlers/test_project.py
index 884dd68..5903507 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_project.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_project.py
@@ -156,7 +156,9 @@ class TestProjectUpdate(TestProjectBase):
@executor.mock_valid_lfid()
@executor.update(httplib.UNAUTHORIZED, message.tied_with_resource())
def test_updateNotAllowed(self):
- self.create_help('/api/v1/projects/%s/cases', self.testcase_d, self.req_d.name)
+ self.create_help('/api/v1/projects/%s/cases',
+ self.testcase_d,
+ self.req_d.name)
req = project_models.ProjectUpdateRequest('apex', 'apex test')
return req, self.req_d.name
@@ -191,7 +193,9 @@ class TestProjectDelete(TestProjectBase):
@executor.mock_valid_lfid()
@executor.delete(httplib.UNAUTHORIZED, message.tied_with_resource())
def test_deleteNotAllowed(self):
- self.create_help('/api/v1/projects/%s/cases', self.testcase_d, self.req_d.name)
+ self.create_help('/api/v1/projects/%s/cases',
+ self.testcase_d,
+ self.req_d.name)
return self.req_d.name
@executor.mock_valid_lfid()
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py
index c07d792..892256a 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py
@@ -33,8 +33,9 @@ class TestResultBase(base.TestBase):
self.basePath = '/api/v1/results'
fake_pymongo.pods.insert({'name': self.req_d.pod_name})
fake_pymongo.projects.insert({'name': self.req_d.project_name})
- fake_pymongo.testcases.insert({'name': self.req_d.case_name,
- 'project_name': self.req_d.project_name})
+ fake_pymongo.testcases.insert({
+ 'name': self.req_d.case_name,
+ 'project_name': self.req_d.project_name})
def assert_res(self, result, req=None):
if req is None:
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py
index 78f3ab1..97325e2 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py
@@ -181,8 +181,9 @@ class TestCaseDelete(TestCaseBase):
self.create_d()
fake_pymongo.pods.insert(self.pod_d.format())
fake_pymongo.projects.insert({'name': self.results_d.project_name})
- fake_pymongo.testcases.insert({'name': self.results_d.case_name,
- 'project_name': self.results_d.project_name})
+ fake_pymongo.testcases.insert({
+ 'name': self.results_d.case_name,
+ 'project_name': self.results_d.project_name})
@executor.delete(httplib.NOT_FOUND, message.not_found_base)
def test_notFound(self):
diff --git a/testapi/testapi-client/.stestr.conf b/testapi/testapi-client/.stestr.conf
new file mode 100644
index 0000000..cdadb67
--- /dev/null
+++ b/testapi/testapi-client/.stestr.conf
@@ -0,0 +1,2 @@
+[DEFAULT]
+test_path=${TEST_PATH:-./testapiclient/tests/unit}
diff --git a/testapi/testapi-client/test-requirements.txt b/testapi/testapi-client/test-requirements.txt
new file mode 100644
index 0000000..4c62871
--- /dev/null
+++ b/testapi/testapi-client/test-requirements.txt
@@ -0,0 +1,2 @@
+stestr>=1.0.0 # Apache-2.0
+testtools>=2.2.0 # MIT \ No newline at end of file
diff --git a/testapi/testapi-client/testapiclient/auth.py b/testapi/testapi-client/testapiclient/auth.py
index 7799d60..6f51231 100644
--- a/testapi/testapi-client/testapiclient/auth.py
+++ b/testapi/testapi-client/testapiclient/auth.py
@@ -10,13 +10,19 @@ class Auth(Command):
def get_parser(self, prog_name):
parser = super(Auth, self).get_parser(prog_name)
- parser.add_argument('-u', type=str, required=True, help='Username for authentication')
- parser.add_argument('-p', type=str, required=True, help='Password for authentication')
+ parser.add_argument('-u',
+ type=str,
+ required=True,
+ help='Username for authentication')
+ parser.add_argument('-p',
+ type=str,
+ required=True,
+ help='Password for authentication')
return parser
def take_action(self, parsed_args):
response = AuthHandler.authenticate(parsed_args.u, parsed_args.p)
if "login" in response.text:
- print "Authentication has failed. Please check your username and password."
+ print "Authentication has failed."
else:
print "Authentication has been successful!"
diff --git a/testapi/testapi-client/testapiclient/authHandler.py b/testapi/testapi-client/testapiclient/authHandler.py
index a421cf8..baa1088 100644
--- a/testapi/testapi-client/testapiclient/authHandler.py
+++ b/testapi/testapi-client/testapiclient/authHandler.py
@@ -9,7 +9,10 @@ class AuthHandler:
@staticmethod
def authenticate(username, password):
session = requests.Session()
- hostname = Config.config.get("cas", "auth_url") + urllib.quote(Config.config.get("api", "url")) + Config.config.get("cas", "signin_return")
+ hostname = '{}{}{}'.format(
+ Config.config.get("cas", "auth_url"),
+ urllib.quote(Config.config.get("api", "url")),
+ Config.config.get("cas", "signin_return"))
data = {'name': username, 'pass': password, 'form_id': 'user_login'}
response = session.post(hostname, data)
User.session = session
diff --git a/testapi/testapi-client/testapiclient/httpClient.py b/testapi/testapi-client/testapiclient/httpClient.py
index bc45f36..69d94a4 100644
--- a/testapi/testapi-client/testapiclient/httpClient.py
+++ b/testapi/testapi-client/testapiclient/httpClient.py
@@ -29,16 +29,22 @@ class HTTPClient():
return r.text
def post(self, url, session, data):
- r = session.post(url, data=json.dumps(data), headers=HTTPClient.headers)
+ r = session.post(url,
+ data=json.dumps(data),
+ headers=HTTPClient.headers)
return r
def put(self, url, session, data):
- r = session.put(url, data=json.dumps(data), headers=HTTPClient.headers)
+ r = session.put(url,
+ data=json.dumps(data),
+ headers=HTTPClient.headers)
return r.text
def delete(self, url, session, *args):
if(args.__len__ > 0):
- r = session.delete(url, data=json.dumps(args[0]), headers=HTTPClient.headers)
+ r = session.delete(url,
+ data=json.dumps(args[0]),
+ headers=HTTPClient.headers)
else:
r = session.delete(url)
return r.text
diff --git a/testapi/testapi-client/testapiclient/pods.py b/testapi/testapi-client/testapiclient/pods.py
index f5e2fe9..6c8aaed 100644
--- a/testapi/testapi-client/testapiclient/pods.py
+++ b/testapi/testapi-client/testapiclient/pods.py
@@ -16,7 +16,9 @@ class PodGet(PodBase):
def get_parser(self, prog_name):
parser = super(PodGet, self).get_parser(prog_name)
- parser.add_argument('-name', default='', help='Search pods using name')
+ parser.add_argument('-name',
+ default='',
+ help='Search pods using name')
return parser
def take_action(self, parsed_args):
@@ -33,7 +35,10 @@ class PodGetOne(PodBase):
def get_parser(self, prog_name):
parser = super(PodGetOne, self).get_parser(prog_name)
- parser.add_argument('-name', default='', help='Find pod using name', required=True)
+ parser.add_argument('-name',
+ default='',
+ help='Find pod using name',
+ required=True)
return parser
def take_action(self, parsed_args):
@@ -47,9 +52,19 @@ class PodCreate(PodBase):
def get_parser(self, prog_name):
parser = super(PodCreate, self).get_parser(prog_name)
- parser.add_argument('-u', type=str, help='Username for authentication')
- parser.add_argument('-p', type=str, help='Password for authentication')
- parser.add_argument('pod', type=json.loads, help='Pod create request format :\n\'{ "role": "", "name": "", "details": "", "mode": ""}\',\n role should be either "community-ci" or "production-ci", and mode should be either "metal" or "virtual.')
+ parser.add_argument('-u',
+ type=str,
+ help='Username for authentication')
+ parser.add_argument('-p',
+ type=str,
+ help='Password for authentication')
+ parser.add_argument('pod',
+ type=json.loads,
+ help='Pod create request format :\n'
+ '\'{"role": "", "name": "", "details": "", '
+ '"mode": ""}\',\n role should be either '
+ '"community-ci" or "production-ci", and '
+ 'mode should be either "metal" or "virtual.')
return parser
def take_action(self, parsed_args):
@@ -57,9 +72,11 @@ class PodCreate(PodBase):
if(parsed_args.u and parsed_args.p):
response = AuthHandler.authenticate(parsed_args.u, parsed_args.p)
if "login" in response.text:
- print "Authentication has failed. Please check your username and password."
+ print "Authentication has failed."
return
- response = http_client.post(PodCreate.pods_url, User.session, parsed_args.pod)
+ response = http_client.post(PodCreate.pods_url,
+ User.session,
+ parsed_args.pod)
if response.status_code == 200:
print "Pod has been successfully created!"
else:
@@ -71,9 +88,16 @@ class PodDelete(PodBase):
def get_parser(self, prog_name):
parser = super(PodDelete, self).get_parser(prog_name)
- parser.add_argument('-u', type=str, help='Username for authentication')
- parser.add_argument('-p', type=str, help='Password for authentication')
- parser.add_argument('-name', type=str, required=True, help='Delete pods using name')
+ parser.add_argument('-u',
+ type=str,
+ help='Username for authentication')
+ parser.add_argument('-p',
+ type=str,
+ help='Password for authentication')
+ parser.add_argument('-name',
+ type=str,
+ required=True,
+ help='Delete pods using name')
return parser
def take_action(self, parsed_args):
@@ -81,7 +105,8 @@ class PodDelete(PodBase):
if(parsed_args.u and parsed_args.p):
response = AuthHandler.authenticate(parsed_args.u, parsed_args.p)
if "login" in response.text:
- print "Authentication has failed. Please check your username and password."
+ print "Authentication has failed."
return
- pods = http_client.delete(PodDelete.pods_url + "/" + parsed_args.name, User.session)
+ pods = http_client.delete(PodDelete.pods_url + "/" + parsed_args.name,
+ User.session)
print pods
diff --git a/testapi/testapi-client/testapiclient/projects.py b/testapi/testapi-client/testapiclient/projects.py
index 57def5d..eedfa3d 100644
--- a/testapi/testapi-client/testapiclient/projects.py
+++ b/testapi/testapi-client/testapiclient/projects.py
@@ -14,7 +14,9 @@ class ProjectGet(ProjectBase):
def get_parser(self, prog_name):
parser = super(ProjectGet, self).get_parser(prog_name)
- parser.add_argument('-name', default='', help='Search projects by name')
+ parser.add_argument('-name',
+ default='',
+ help='Search projects by name')
return parser
def take_action(self, parsed_args):
@@ -30,7 +32,10 @@ class ProjectGetOne(ProjectBase):
def get_parser(self, prog_name):
parser = super(ProjectGetOne, self).get_parser(prog_name)
- parser.add_argument('-name', default='', required=True, help='Search project by name')
+ parser.add_argument('-name',
+ default='',
+ required=True,
+ help='Search project by name')
return parser
def take_action(self, parsed_args):
@@ -44,9 +49,17 @@ class ProjectCreate(ProjectBase):
def get_parser(self, prog_name):
parser = super(ProjectCreate, self).get_parser(prog_name)
- parser.add_argument('-u', type=str, help='Username for authentication')
- parser.add_argument('-p', type=str, help='Password for authentication')
- parser.add_argument('project', type=json.loads, help='Project create request format :{ "name": (required)"", "description": (optional)""}')
+ parser.add_argument('-u',
+ type=str,
+ help='Username for authentication')
+ parser.add_argument('-p',
+ type=str,
+ help='Password for authentication')
+ parser.add_argument('project',
+ type=json.loads,
+ help='Project create request format :{'
+ ' "name": (required)"", '
+ '"description": (optional)""}')
return parser
def take_action(self, parsed_args):
@@ -54,9 +67,11 @@ class ProjectCreate(ProjectBase):
if(parsed_args.u and parsed_args.p):
response = AuthHandler.authenticate(parsed_args.u, parsed_args.p)
if "login" in response.text:
- print "Authentication has failed. Please check your username and password."
+ print "Authentication has failed."
return
- response = httpClient.post(ProjectCreate.projects_url, User.session, parsed_args.project)
+ response = httpClient.post(ProjectCreate.projects_url,
+ User.session,
+ parsed_args.project)
if response.status_code == 200:
print "Project has been successfully created!"
else:
@@ -67,9 +82,16 @@ class ProjectDelete(ProjectBase):
def get_parser(self, prog_name):
parser = super(ProjectDelete, self).get_parser(prog_name)
- parser.add_argument('-u', type=str, help='Username for authentication')
- parser.add_argument('-p', type=str, help='Password for authentication')
- parser.add_argument('-name', type=str, required=True, help='Delete project by name')
+ parser.add_argument('-u',
+ type=str,
+ help='Username for authentication')
+ parser.add_argument('-p',
+ type=str,
+ help='Password for authentication')
+ parser.add_argument('-name',
+ type=str,
+ required=True,
+ help='Delete project by name')
return parser
def take_action(self, parsed_args):
@@ -77,9 +99,11 @@ class ProjectDelete(ProjectBase):
if(parsed_args.u and parsed_args.p):
response = AuthHandler.authenticate(parsed_args.u, parsed_args.p)
if "login" in response.text:
- print "Authentication has failed. Please check your username and password."
+ print "Authentication has failed."
return
- projects = httpClient.delete(ProjectDelete.projects_url + "/" + parsed_args.name, User.session)
+ projects = httpClient.delete(
+ ProjectDelete.projects_url + "/" + parsed_args.name,
+ User.session)
print projects
@@ -87,10 +111,21 @@ class ProjectPut(ProjectBase):
def get_parser(self, prog_name):
parser = super(ProjectPut, self).get_parser(prog_name)
- parser.add_argument('-u', type=str, help='Username for authentication')
- parser.add_argument('-p', type=str, help='Password for authentication')
- parser.add_argument('-name', type=str, required=True, help='Update project by name')
- parser.add_argument('project', type=json.loads, help='Project Update request format :{ "name": (required)"", "description": (optional)""}')
+ parser.add_argument('-u',
+ type=str,
+ help='Username for authentication')
+ parser.add_argument('-p',
+ type=str,
+ help='Password for authentication')
+ parser.add_argument('-name',
+ type=str,
+ required=True,
+ help='Update project by name')
+ parser.add_argument('project',
+ type=json.loads,
+ help='Project Update request format :{'
+ '"name": (required)"", '
+ '"description": (optional)""}')
return parser
def take_action(self, parsed_args):
@@ -98,7 +133,10 @@ class ProjectPut(ProjectBase):
if(parsed_args.u and parsed_args.p):
response = AuthHandler.authenticate(parsed_args.u, parsed_args.p)
if "login" in response.text:
- print "Authentication has failed. Please check your username and password."
+ print "Authentication has failed."
return
- projects = httpClient.put(ProjectPut.projects_url + "/" + parsed_args.name, User.session, parsed_args.project)
+ projects = httpClient.put(
+ ProjectPut.projects_url + "/" + parsed_args.name,
+ User.session,
+ parsed_args.project)
print projects
diff --git a/testapi/testapi-client/testapiclient/tests/__init__.py b/testapi/testapi-client/testapiclient/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/__init__.py
diff --git a/testapi/testapi-client/testapiclient/tests/unit/__init__.py b/testapi/testapi-client/testapiclient/tests/unit/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/__init__.py
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py b/testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py
new file mode 100644
index 0000000..2b7ad46
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py
@@ -0,0 +1,6 @@
+import testtools
+
+
+class TestPlaceHolder(testtools.TestCase):
+ def test_placeholder(self):
+ self.assertEqual(1, 1)
diff --git a/testapi/testapi-client/tox.ini b/testapi/testapi-client/tox.ini
index cf73b91..51c3d57 100644
--- a/testapi/testapi-client/tox.ini
+++ b/testapi/testapi-client/tox.ini
@@ -12,11 +12,13 @@ sitepackages = True
usedevelop = True
install_command = pip install -U {opts} {packages}
deps =
- -rrequirements.txt
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/test-requirements.txt
setenv=
HOME = {envtmpdir}
PYTHONPATH = {toxinidir}
-
+commands = stestr run {posargs}
+whitelist_externals = stestr
[testenv:pep8]
deps = flake8
@@ -27,6 +29,6 @@ commands = flake8 {toxinidir}
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
-ignore = E123,E125,H803,E501
+ignore = E123,E125,H803
builtins = _
exclude = bin, build, dist, lib, local, .git, .eggs, .tox, .venv, venv, testapi_client.egg-info \ No newline at end of file
diff --git a/testapi/tox.ini b/testapi/tox.ini
index 13b197c..e15deea 100644
--- a/testapi/tox.ini
+++ b/testapi/tox.ini
@@ -38,7 +38,7 @@ commands = flake8 {toxinidir}
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
-ignore = E123,E125,H803,E501
+ignore = E123,E125,H803
builtins = _
exclude = build,dist,doc,legacy,.eggs,.git,.tox,.venv,testapi_venv,venv