222 lines
8.7 KiB
Python
222 lines
8.7 KiB
Python
# Copyright (c) 2015 Mirantis, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""Base classes for API tests."""
|
|
import os
|
|
|
|
from oslo_config import fixture as config_fixture
|
|
from oslotest import base
|
|
import pecan.testing
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.engine import reflection
|
|
from sqlalchemy.schema import (
|
|
MetaData,
|
|
Table,
|
|
DropTable,
|
|
ForeignKeyConstraint,
|
|
DropConstraint,
|
|
)
|
|
|
|
from refstack.db import migration
|
|
|
|
|
|
class FunctionalTest(base.BaseTestCase):
|
|
"""Base class for functional test case.
|
|
|
|
Used for functional tests where you need to test your.
|
|
literal application and its integration with the framework.
|
|
"""
|
|
|
|
def setUp(self):
|
|
"""Test setup."""
|
|
super(FunctionalTest, self).setUp()
|
|
|
|
self.connection = os.environ.get("REFSTACK_TEST_MYSQL_URL")
|
|
if self.connection is None:
|
|
raise ValueError("Database connection url was not found. "
|
|
"Environment variable REFSTACK_TEST_MYSQL_URL "
|
|
"is not defined")
|
|
|
|
self.config = {
|
|
'app': {
|
|
'root': 'refstack.api.controllers.root.RootController',
|
|
'modules': ['refstack.api'],
|
|
}
|
|
}
|
|
self.config_fixture = config_fixture.Config()
|
|
self.CONF = self.useFixture(self.config_fixture).conf
|
|
self.CONF.set_override('connection',
|
|
self.connection,
|
|
'database')
|
|
|
|
self.app = pecan.testing.load_test_app(self.config)
|
|
|
|
self.drop_all_tables_and_constraints()
|
|
migration.upgrade('head')
|
|
|
|
def tearDown(self):
|
|
"""Test teardown."""
|
|
super(FunctionalTest, self).tearDown()
|
|
pecan.set_config({}, overwrite=True)
|
|
self.app.reset()
|
|
|
|
def drop_all_tables_and_constraints(self):
|
|
"""Drop tables and cyclical constraints between tables."""
|
|
engine = create_engine(self.connection)
|
|
conn = engine.connect()
|
|
trans = conn.begin()
|
|
|
|
inspector = reflection.Inspector.from_engine(engine)
|
|
metadata = MetaData()
|
|
|
|
tbs = []
|
|
all_fks = []
|
|
|
|
try:
|
|
for table_name in inspector.get_table_names():
|
|
fks = []
|
|
for fk in inspector.get_foreign_keys(table_name):
|
|
if not fk['name']:
|
|
continue
|
|
fks.append(
|
|
ForeignKeyConstraint((), (), name=fk['name']))
|
|
|
|
t = Table(table_name, metadata, *fks)
|
|
tbs.append(t)
|
|
all_fks.extend(fks)
|
|
|
|
for fkc in all_fks:
|
|
conn.execute(DropConstraint(fkc))
|
|
|
|
for table in tbs:
|
|
conn.execute(DropTable(table))
|
|
|
|
trans.commit()
|
|
trans.close()
|
|
conn.close()
|
|
except Exception:
|
|
trans.rollback()
|
|
conn.close()
|
|
raise
|
|
|
|
def delete(self, url, headers=None, extra_environ=None,
|
|
status=None, expect_errors=False, **params):
|
|
"""Send HTTP DELETE request.
|
|
|
|
:param url: url path to target service
|
|
:param headers: a dictionary of extra headers to send
|
|
:param extra_environ: a dictionary of environmental variables that
|
|
should be added to the request
|
|
:param status: integer or string of the HTTP status code you expect
|
|
in response (if not 200 or 3xx). You can also use a
|
|
wildcard, like '3*' or '*'
|
|
:param expect_errors: boolean value, if this is False, then if
|
|
anything is written to environ wsgi.errors it
|
|
will be an error. If it is True, then
|
|
non-200/3xx responses are also okay
|
|
:param params: a query string, or a dictionary that will be encoded
|
|
into a query string. You may also include a URL query
|
|
string on the url
|
|
|
|
"""
|
|
response = self.app.delete(url,
|
|
headers=headers,
|
|
extra_environ=extra_environ,
|
|
status=status,
|
|
expect_errors=expect_errors,
|
|
params=params)
|
|
|
|
return response
|
|
|
|
def get_json(self, url, headers=None, extra_environ=None,
|
|
status=None, expect_errors=False, **params):
|
|
"""Send HTTP GET request.
|
|
|
|
:param url: url path to target service
|
|
:param headers: a dictionary of extra headers to send
|
|
:param extra_environ: a dictionary of environmental variables that
|
|
should be added to the request
|
|
:param status: integer or string of the HTTP status code you expect
|
|
in response (if not 200 or 3xx). You can also use a
|
|
wildcard, like '3*' or '*'
|
|
:param expect_errors: boolean value, if this is False, then if
|
|
anything is written to environ wsgi.errors it
|
|
will be an error. If it is True, then
|
|
non-200/3xx responses are also okay
|
|
:param params: a query string, or a dictionary that will be encoded
|
|
into a query string. You may also include a URL query
|
|
string on the url
|
|
|
|
"""
|
|
response = self.app.get(url,
|
|
headers=headers,
|
|
extra_environ=extra_environ,
|
|
status=status,
|
|
expect_errors=expect_errors,
|
|
params=params)
|
|
|
|
if not expect_errors and response.content_type == 'application/json':
|
|
response = response.json
|
|
return response
|
|
|
|
def post_json(self, url, headers=None, extra_environ=None,
|
|
status=None, expect_errors=False,
|
|
content_type='application/json', **params):
|
|
"""Send HTTP POST request.
|
|
|
|
:param url: url path to target service
|
|
:param headers: a dictionary of extra headers to send
|
|
:param extra_environ: a dictionary of environmental variables that
|
|
should be added to the request
|
|
:param status: integer or string of the HTTP status code you expect
|
|
in response (if not 200 or 3xx). You can also use a
|
|
wildcard, like '3*' or '*'
|
|
:param expect_errors: boolean value, if this is False, then if
|
|
anything is written to environ wsgi.errors it
|
|
will be an error. If it is True, then
|
|
non-200/3xx responses are also okay
|
|
:param params: a query string, or a dictionary that will be encoded
|
|
into a query string. You may also include a URL query
|
|
string on the url
|
|
|
|
"""
|
|
response = self.app.post(url,
|
|
headers=headers,
|
|
extra_environ=extra_environ,
|
|
status=status,
|
|
expect_errors=expect_errors,
|
|
content_type=content_type,
|
|
**params)
|
|
|
|
if not expect_errors and response.content_type == 'application/json':
|
|
response = response.json
|
|
return response
|
|
|
|
def put_json(self, url, headers=None, extra_environ=None,
|
|
status=None, expect_errors=False,
|
|
content_type='application/json', **params):
|
|
"""Send HTTP PUT request. Similar to :meth:`post_json`."""
|
|
response = self.app.put(url,
|
|
headers=headers,
|
|
extra_environ=extra_environ,
|
|
status=status,
|
|
expect_errors=expect_errors,
|
|
content_type=content_type,
|
|
**params)
|
|
|
|
if not expect_errors and response.content_type == 'application/json':
|
|
response = response.json
|
|
return response
|