Add unit tests for untested code
Add unit tests and '# pragma: no cover' for exclude some code that doesn't require test. Change-Id: Ib071208bd38c7b1102aa341be0d6bf803b647596
This commit is contained in:
parent
7fb06e8317
commit
49f1efc773
@ -23,7 +23,6 @@ from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_log import loggers
|
||||
import pecan
|
||||
from pecan import hooks
|
||||
import webob
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
@ -71,7 +70,7 @@ CONF.register_opts(API_OPTS, opt_group)
|
||||
log.register_options(CONF)
|
||||
|
||||
|
||||
class JSONErrorHook(hooks.PecanHook):
|
||||
class JSONErrorHook(pecan.hooks.PecanHook):
|
||||
"""
|
||||
A pecan hook that translates webob HTTP errors into a JSON format.
|
||||
"""
|
||||
@ -134,7 +133,7 @@ def setup_app(config):
|
||||
debug=CONF.api.app_dev_mode,
|
||||
static_root=static_root,
|
||||
template_path=template_path,
|
||||
hooks=[JSONErrorHook(), hooks.RequestViewerHook(
|
||||
hooks=[JSONErrorHook(), pecan.hooks.RequestViewerHook(
|
||||
{'items': ['status', 'method', 'controller', 'path', 'body']},
|
||||
headers=False, writer=loggers.WritableLogger(LOG, logging.DEBUG)
|
||||
)]
|
||||
|
@ -37,11 +37,11 @@ class RestControllerWithValidation(rest.RestController):
|
||||
def __init__(self, validator):
|
||||
self.validator = validator
|
||||
|
||||
def get_item(self, item_id):
|
||||
def get_item(self, item_id): # pragma: no cover
|
||||
"""Handler for getting item"""
|
||||
raise NotImplemented
|
||||
|
||||
def store_item(self, item_in_json):
|
||||
def store_item(self, item_in_json): # pragma: no cover
|
||||
"""Handler for storing item. Should return new item id"""
|
||||
raise NotImplemented
|
||||
|
||||
|
@ -32,11 +32,11 @@ class PluggableBackend(object):
|
||||
def __get_backend(self):
|
||||
if not self.__backend:
|
||||
backend_name = CONF[self.__pivot]
|
||||
if backend_name not in self.__backends:
|
||||
if backend_name not in self.__backends: # pragma: no cover
|
||||
raise Exception('Invalid backend: %s' % backend_name)
|
||||
|
||||
backend = self.__backends[backend_name]
|
||||
if isinstance(backend, tuple):
|
||||
if isinstance(backend, tuple): # pragma: no cover
|
||||
name = backend[0]
|
||||
fromlist = backend[1]
|
||||
else:
|
||||
|
159
refstack/tests/unit/test_api.py
Normal file
159
refstack/tests/unit/test_api.py
Normal file
@ -0,0 +1,159 @@
|
||||
# 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.
|
||||
|
||||
"""Tests for API's controllers"""
|
||||
|
||||
import mock
|
||||
from oslotest import base
|
||||
|
||||
from refstack.api.controllers import root
|
||||
from refstack.api.controllers import v1
|
||||
|
||||
|
||||
class RootControllerTestCase(base.BaseTestCase):
|
||||
|
||||
def test_index(self):
|
||||
controller = root.RootController()
|
||||
result = controller.index()
|
||||
self.assertEqual(result, {'Root': 'OK'})
|
||||
|
||||
|
||||
class ResultsControllerTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ResultsControllerTestCase, self).setUp()
|
||||
self.validator = mock.Mock()
|
||||
self.controller = v1.ResultsController(self.validator)
|
||||
|
||||
@mock.patch('refstack.db.get_test')
|
||||
@mock.patch('refstack.db.get_test_results')
|
||||
def test_get(self, mock_get_test_res, mock_get_test):
|
||||
self.validator.assert_id.return_value = True
|
||||
|
||||
test_info = mock.Mock()
|
||||
test_info.cpid = 'foo'
|
||||
test_info.created_at = 'bar'
|
||||
test_info.duration_seconds = 999
|
||||
mock_get_test.return_value = test_info
|
||||
|
||||
mock_get_test_res.return_value = [('test1',), ('test2',), ('test3',)]
|
||||
|
||||
actual_result = self.controller.get_one('fake_arg')
|
||||
expected_result = {
|
||||
'cpid': 'foo',
|
||||
'created_at': 'bar',
|
||||
'duration_seconds': 999,
|
||||
'results': ['test1', 'test2', 'test3']
|
||||
}
|
||||
|
||||
self.assertEqual(actual_result, expected_result)
|
||||
mock_get_test_res.assert_called_once_with('fake_arg')
|
||||
mock_get_test.assert_called_once_with('fake_arg')
|
||||
self.validator.assert_id.assert_called_once_with('fake_arg')
|
||||
|
||||
@mock.patch('refstack.db.store_results')
|
||||
@mock.patch('pecan.response')
|
||||
@mock.patch('refstack.common.validators.safe_load_json_body')
|
||||
def test_post(self, mock_safe_load, mock_response, mock_store_results):
|
||||
mock_safe_load.return_value = 'fake_item'
|
||||
mock_store_results.return_value = 'fake_test_id'
|
||||
|
||||
result = self.controller.post()
|
||||
|
||||
self.assertEqual(result, {'test_id': 'fake_test_id'})
|
||||
self.assertEqual(mock_response.status, 201)
|
||||
mock_safe_load.assert_called_once_with(self.validator)
|
||||
mock_store_results.assert_called_once_with('fake_item')
|
||||
|
||||
@mock.patch('pecan.abort')
|
||||
@mock.patch('refstack.db.get_test')
|
||||
def test_get_item_failed(self, mock_get_test, mock_abort):
|
||||
mock_get_test.return_value = None
|
||||
mock_abort.side_effect = Exception()
|
||||
self.assertRaises(Exception,
|
||||
self.controller.get_item,
|
||||
'fake_id')
|
||||
|
||||
@mock.patch('refstack.db.get_test')
|
||||
@mock.patch('refstack.db.get_test_results')
|
||||
def test_get_item(self, mock_get_test_res, mock_get_test):
|
||||
test_info = mock.Mock()
|
||||
test_info.cpid = 'foo'
|
||||
test_info.created_at = 'bar'
|
||||
test_info.duration_seconds = 999
|
||||
mock_get_test.return_value = test_info
|
||||
|
||||
mock_get_test_res.return_value = [('test1',), ('test2',), ('test3',)]
|
||||
|
||||
actual_result = self.controller.get_item('fake_id')
|
||||
expected_result = {
|
||||
'cpid': 'foo',
|
||||
'created_at': 'bar',
|
||||
'duration_seconds': 999,
|
||||
'results': ['test1', 'test2', 'test3']
|
||||
}
|
||||
self.assertEqual(actual_result, expected_result)
|
||||
mock_get_test_res.assert_called_once_with('fake_id')
|
||||
mock_get_test.assert_called_once_with('fake_id')
|
||||
|
||||
@mock.patch('refstack.db.store_results')
|
||||
def test_store_item(self, mock_store_item):
|
||||
mock_store_item.return_value = 'fake_result'
|
||||
result = self.controller.store_item('fake_item')
|
||||
self.assertEqual(result, {'test_id': 'fake_result'})
|
||||
mock_store_item.assert_called_once_with('fake_item')
|
||||
|
||||
|
||||
class RestControllerWithValidationTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(RestControllerWithValidationTestCase, self).setUp()
|
||||
self.validator = mock.Mock()
|
||||
self.controller = v1.RestControllerWithValidation(self.validator)
|
||||
|
||||
@mock.patch('pecan.response')
|
||||
@mock.patch('refstack.common.validators.safe_load_json_body')
|
||||
def test_post(self, mock_safe_load, mock_response):
|
||||
mock_safe_load.return_value = 'fake_item'
|
||||
self.controller.store_item = mock.Mock(return_value='fake_id')
|
||||
|
||||
result = self.controller.post()
|
||||
|
||||
self.assertEqual(result, 'fake_id')
|
||||
self.assertEqual(mock_response.status, 201)
|
||||
mock_safe_load.assert_called_once_with(self.validator)
|
||||
self.controller.store_item.assert_called_once_with('fake_item')
|
||||
|
||||
def test_get_one_return_item(self):
|
||||
self.validator.assert_id.return_value = True
|
||||
self.controller.get_item = mock.Mock(return_value='fake_item')
|
||||
|
||||
result = self.controller.get_one('fake_arg')
|
||||
|
||||
self.assertEqual(result, 'fake_item')
|
||||
self.validator.assert_id.assert_called_once_with('fake_arg')
|
||||
self.controller.get_item.assert_called_once_with(item_id='fake_arg')
|
||||
|
||||
def test_get_one_return_schema(self):
|
||||
self.validator.assert_id.return_value = False
|
||||
self.validator.schema = 'fake_schema'
|
||||
result = self.controller.get_one('schema')
|
||||
self.assertEqual(result, 'fake_schema')
|
||||
|
||||
@mock.patch('pecan.abort')
|
||||
def test_get_one_aborut(self, mock_abort):
|
||||
self.validator.assert_id.return_value = False
|
||||
self.controller.get_one('fake_arg')
|
||||
mock_abort.assert_called_once_with(404)
|
163
refstack/tests/unit/test_app.py
Normal file
163
refstack/tests/unit/test_app.py
Normal file
@ -0,0 +1,163 @@
|
||||
# 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.
|
||||
|
||||
"""Tests for API's utility"""
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
from oslo_config import fixture as config_fixture
|
||||
from oslotest import base
|
||||
import webob
|
||||
|
||||
from refstack.api import app
|
||||
|
||||
|
||||
class JSONErrorHookTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(JSONErrorHookTestCase, self).setUp()
|
||||
self.config_fixture = config_fixture.Config()
|
||||
self.CONF = self.useFixture(self.config_fixture).conf
|
||||
|
||||
def test_on_error_with_webob_instance(self):
|
||||
self.CONF.set_override('app_dev_mode',
|
||||
False,
|
||||
'api')
|
||||
exc = mock.Mock(spec=webob.exc.HTTPError)
|
||||
exc.status_int = 999
|
||||
exc.status = 111
|
||||
exc.title = 'fake_title'
|
||||
|
||||
with mock.patch.object(webob, 'Response') as response:
|
||||
response.return_value = 'fake_value'
|
||||
|
||||
hook = app.JSONErrorHook()
|
||||
result = hook.on_error(mock.Mock(), exc)
|
||||
|
||||
self.assertEqual(result, 'fake_value')
|
||||
body = {'code': exc.status_int, 'title': exc.title}
|
||||
response.assert_called_once_with(body=json.dumps(body),
|
||||
status=exc.status,
|
||||
content_type='application/json')
|
||||
|
||||
def test_on_error_with_webob_instance_with_debug(self):
|
||||
self.CONF.set_override('app_dev_mode',
|
||||
True,
|
||||
'api')
|
||||
exc = mock.Mock(spec=webob.exc.HTTPError)
|
||||
exc.status_int = 999
|
||||
exc.status = 111
|
||||
exc.title = 'fake_title'
|
||||
|
||||
with mock.patch.object(webob, 'Response') as response:
|
||||
response.return_value = 'fake_value'
|
||||
|
||||
hook = app.JSONErrorHook()
|
||||
result = hook.on_error(mock.Mock(), exc)
|
||||
|
||||
self.assertEqual(result, 'fake_value')
|
||||
body = {
|
||||
'code': exc.status_int,
|
||||
'title': exc.title,
|
||||
'detail': str(exc)
|
||||
}
|
||||
response.assert_called_once_with(body=json.dumps(body),
|
||||
status=exc.status,
|
||||
content_type='application/json')
|
||||
|
||||
@mock.patch.object(webob, 'Response')
|
||||
def test_on_error_not_webob_instance(self, response):
|
||||
self.CONF.set_override('app_dev_mode',
|
||||
False,
|
||||
'api')
|
||||
response.return_value = 'fake_value'
|
||||
exc = mock.Mock()
|
||||
|
||||
hook = app.JSONErrorHook()
|
||||
result = hook.on_error(mock.Mock(), exc)
|
||||
|
||||
self.assertEqual(result, 'fake_value')
|
||||
body = {'code': 500, 'title': 'Internal Server Error'}
|
||||
response.assert_called_once_with(body=json.dumps(body),
|
||||
status=500,
|
||||
content_type='application/json')
|
||||
|
||||
@mock.patch.object(webob, 'Response')
|
||||
def test_on_error_not_webob_instance_with_debug(self, response):
|
||||
self.CONF.set_override('app_dev_mode',
|
||||
True,
|
||||
'api')
|
||||
response.return_value = 'fake_value'
|
||||
exc = mock.Mock()
|
||||
|
||||
hook = app.JSONErrorHook()
|
||||
result = hook.on_error(mock.Mock(), exc)
|
||||
|
||||
self.assertEqual(result, 'fake_value')
|
||||
body = {
|
||||
'code': 500,
|
||||
'title': 'Internal Server Error',
|
||||
'detail': str(exc)
|
||||
}
|
||||
response.assert_called_once_with(body=json.dumps(body),
|
||||
status=500,
|
||||
content_type='application/json')
|
||||
|
||||
|
||||
class SetupAppTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SetupAppTestCase, self).setUp()
|
||||
self.config_fixture = config_fixture.Config()
|
||||
self.CONF = self.useFixture(self.config_fixture).conf
|
||||
|
||||
@mock.patch('pecan.hooks')
|
||||
@mock.patch.object(app, 'JSONErrorHook')
|
||||
@mock.patch('os.path.join')
|
||||
@mock.patch('pecan.make_app')
|
||||
def test_setup_app(self, make_app, os_join,
|
||||
json_error_hook, pecan_hooks):
|
||||
|
||||
self.CONF.set_override('app_dev_mode',
|
||||
True,
|
||||
'api')
|
||||
self.CONF.set_override('template_path',
|
||||
'fake_template_path',
|
||||
'api')
|
||||
self.CONF.set_override('static_root',
|
||||
'fake_static_root',
|
||||
'api')
|
||||
|
||||
os_join.return_value = 'fake_project_root'
|
||||
|
||||
json_error_hook.return_value = 'json_error_hook'
|
||||
pecan_hooks.RequestViewerHook.return_value = 'request_viewer_hook'
|
||||
pecan_config = mock.Mock()
|
||||
pecan_config.app = {'root': 'fake_pecan_config'}
|
||||
make_app.return_value = 'fake_app'
|
||||
|
||||
result = app.setup_app(pecan_config)
|
||||
|
||||
self.assertEqual(result, 'fake_app')
|
||||
|
||||
app_conf = dict(pecan_config.app)
|
||||
make_app.assert_called_once_with(
|
||||
app_conf.pop('root'),
|
||||
debug=True,
|
||||
static_root='fake_static_root',
|
||||
template_path='fake_template_path',
|
||||
hooks=['json_error_hook', 'request_viewer_hook']
|
||||
)
|
@ -13,7 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for database API."""
|
||||
"""Tests for database."""
|
||||
|
||||
import six
|
||||
import mock
|
||||
@ -21,6 +21,26 @@ from oslotest import base
|
||||
|
||||
from refstack import db
|
||||
from refstack.db.sqlalchemy import api
|
||||
from refstack.db.sqlalchemy import models
|
||||
|
||||
|
||||
class RefStackBaseTestCase(base.BaseTestCase):
|
||||
"""Test case for RefStackBase model."""
|
||||
|
||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||
def test_delete(self, utcnow):
|
||||
utcnow.return_value = '123'
|
||||
|
||||
base_model = models.RefStackBase()
|
||||
base_model.id = 'fake_id'
|
||||
base_model.save = mock.Mock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
base_model.delete(session)
|
||||
|
||||
self.assertEqual(base_model.deleted, 'fake_id')
|
||||
self.assertEqual(base_model.deleted_at, '123')
|
||||
base_model.save.assert_called_once_with(session=session)
|
||||
|
||||
|
||||
class DBAPITestCase(base.BaseTestCase):
|
||||
@ -67,6 +87,12 @@ class DBHelpersTestCase(base.BaseTestCase):
|
||||
facade.get_session.assert_called_once_with(**fake_kwargs)
|
||||
self.assertEqual(result, 'fake_session')
|
||||
|
||||
@mock.patch('oslo_db.sqlalchemy.session.EngineFacade.from_config')
|
||||
def test_create_facade_lazily(self, session):
|
||||
session.return_value = 'fake_session'
|
||||
result = api._create_facade_lazily()
|
||||
self.assertEqual(result, 'fake_session')
|
||||
|
||||
|
||||
class DBBackendTestCase(base.BaseTestCase):
|
||||
"""Test case for database backend."""
|
||||
|
@ -20,6 +20,19 @@ import mock
|
||||
from oslotest import base
|
||||
|
||||
from refstack.db import migration
|
||||
from refstack.db.migrations.alembic import migration as alembic_migration
|
||||
|
||||
|
||||
class AlembicConfigTestCase(base.BaseTestCase):
|
||||
|
||||
@mock.patch('alembic.config.Config')
|
||||
@mock.patch('os.path.join')
|
||||
def test_alembic_config(self, os_join, alembic_config):
|
||||
os_join.return_value = 'fake_path'
|
||||
alembic_config.return_value = 'fake_config'
|
||||
result = alembic_migration._alembic_config()
|
||||
self.assertEqual(result, 'fake_config')
|
||||
alembic_config.assert_called_once_with('fake_path')
|
||||
|
||||
|
||||
class MigrationTestCase(base.BaseTestCase):
|
||||
|
@ -33,6 +33,13 @@ class ValidatorsTestCase(base.BaseTestCase):
|
||||
def test_is_uuid_fail(self):
|
||||
self.assertFalse(validators.is_uuid('some_string'))
|
||||
|
||||
def test_checker_uuid(self):
|
||||
value = validators.checker_uuid('12345678123456781234567812345678')
|
||||
self.assertTrue(value)
|
||||
|
||||
def test_checker_uuid_fail(self):
|
||||
self.assertFalse(validators.checker_uuid('some_string'))
|
||||
|
||||
|
||||
class TestResultValidatorTestCase(base.BaseTestCase):
|
||||
"""Test case for database TestResultValidator."""
|
||||
@ -50,6 +57,13 @@ class TestResultValidatorTestCase(base.BaseTestCase):
|
||||
super(TestResultValidatorTestCase, self).setUp()
|
||||
self.validator = validators.TestResultValidator()
|
||||
|
||||
def test_assert_id(self):
|
||||
value = self.validator.assert_id('12345678123456781234567812345678')
|
||||
self.assertTrue(value)
|
||||
|
||||
def test_assert_id_fail(self):
|
||||
self.assertFalse(self.validator.assert_id('some_string'))
|
||||
|
||||
def test_validation(self):
|
||||
with mock.patch('jsonschema.validate') as mock_validate:
|
||||
self.validator.validate(self.FAKE_TESTS_RESULTS_JSON)
|
||||
@ -64,12 +78,6 @@ class TestResultValidatorTestCase(base.BaseTestCase):
|
||||
self.validator.validate,
|
||||
wrong_tests_result)
|
||||
|
||||
def test_assert_id(self):
|
||||
self.assertTrue(validators.is_uuid('12345678123456781234567812345678'))
|
||||
|
||||
def test_assert_id_fail(self):
|
||||
self.assertFalse(validators.is_uuid('some_string'))
|
||||
|
||||
@mock.patch('pecan.request')
|
||||
def test_safe_load_json_body(self, mock_request):
|
||||
mock_request.body = self.FAKE_TESTS_RESULTS_JSON
|
||||
|
4
tox.ini
4
tox.ini
@ -44,7 +44,9 @@ commands =
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:py27-cover]
|
||||
commands = python setup.py testr --coverage --omit='*/tests*' --testr-args='{posargs}'
|
||||
commands = python setup.py testr --coverage \
|
||||
--omit='{toxinidir}/refstack/tests*,{toxinidir}/refstack/api/config.py,{toxinidir}/refstack/db/migrations/alembic/env.py,{toxinidir}/refstack/opts.py' \
|
||||
--testr-args='{posargs}'
|
||||
|
||||
[tox:jenkins]
|
||||
downloadcache = ~/cache/pip
|
||||
|
Loading…
Reference in New Issue
Block a user