Cleaned and made integration tests working
* can be run by tox -epy26 -- fuel_plugin/testing/tests/integration * removed code that mimic nailgun * used requests_mock to mock http requests * added BaseIntegrationTest class that set ups DB * it is possible to pass own session when creating Pecan app for OSTF * added WebTest as a requirement for tests Change-Id: Id73208c3b0a000c017ec44388e3cecc78d2228a5 Partial-Bug: #1404892
This commit is contained in:
parent
47b82d5130
commit
98d0287158
|
@ -38,3 +38,11 @@ def contexted_session(dbpath):
|
|||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
def get_session(dbpath):
|
||||
"""Returns SQLAlchemy scoped session for given DB configuration string."""
|
||||
engine = create_engine(dbpath)
|
||||
session = orm.scoped_session(orm.sessionmaker())
|
||||
session.configure(bind=engine)
|
||||
return session
|
||||
|
|
|
@ -17,6 +17,7 @@ import pecan
|
|||
|
||||
from fuel_plugin.ostf_adapter.wsgi import access_control
|
||||
from fuel_plugin.ostf_adapter.wsgi import hooks
|
||||
from fuel_plugin.ostf_adapter.storage import engine
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
@ -49,13 +50,17 @@ def setup_config(custom_pecan_config):
|
|||
pecan.conf.update(config_to_use)
|
||||
|
||||
|
||||
def setup_app(config=None):
|
||||
def setup_app(config=None, session=None):
|
||||
setup_config(config or {})
|
||||
session = session or engine.get_session(pecan.conf.dbpath)
|
||||
app_hooks = [
|
||||
hooks.CustomTransactionalHook(session),
|
||||
hooks.AddTokenHook()
|
||||
]
|
||||
app = pecan.make_app(
|
||||
pecan.conf.app.root,
|
||||
debug=pecan.conf.debug,
|
||||
force_canonical=True,
|
||||
hooks=[hooks.CustomTransactionalHook(dbpath=pecan.conf.dbpath),
|
||||
hooks.AddTokenHook()]
|
||||
hooks=app_hooks,
|
||||
)
|
||||
return access_control.setup(app)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
# under the License.
|
||||
|
||||
import logging
|
||||
from sqlalchemy import create_engine, orm
|
||||
|
||||
from pecan import hooks
|
||||
|
||||
|
@ -22,10 +21,8 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class CustomTransactionalHook(hooks.TransactionHook):
|
||||
def __init__(self, dbpath):
|
||||
engine = create_engine(dbpath)
|
||||
self.session = orm.scoped_session(orm.sessionmaker())
|
||||
self.session.configure(bind=engine)
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def start():
|
||||
pass
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# Copyright 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
|
@ -1,119 +0,0 @@
|
|||
# Copyright 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from bottle import route, run
|
||||
|
||||
|
||||
cluster_fixture = {
|
||||
1: {
|
||||
'cluster_meta': {
|
||||
'release_id': 1,
|
||||
'mode': 'ha'
|
||||
},
|
||||
'release_data': {
|
||||
'operating_system': 'rhel'
|
||||
},
|
||||
'cluster_attributes': {
|
||||
'editable': {
|
||||
'additional_components': {},
|
||||
'common': {}
|
||||
}
|
||||
}
|
||||
},
|
||||
2: {
|
||||
'cluster_meta': {
|
||||
'release_id': 2,
|
||||
'mode': 'multinode',
|
||||
},
|
||||
'release_data': {
|
||||
'operating_system': 'ubuntu'
|
||||
},
|
||||
'cluster_attributes': {
|
||||
'editable': {
|
||||
'additional_components': {},
|
||||
'common': {}
|
||||
}
|
||||
}
|
||||
},
|
||||
3: {
|
||||
'cluster_meta': {
|
||||
'release_id': 3,
|
||||
'mode': 'ha'
|
||||
},
|
||||
'release_data': {
|
||||
'operating_system': 'rhel'
|
||||
},
|
||||
'cluster_attributes': {
|
||||
'editable': {
|
||||
'additional_components': {
|
||||
'murano': {
|
||||
'value': True
|
||||
},
|
||||
'sahara': {
|
||||
'value': False
|
||||
}
|
||||
},
|
||||
'common': {}
|
||||
}
|
||||
}
|
||||
},
|
||||
4: {
|
||||
'cluster_meta': {
|
||||
'release_id': 4,
|
||||
'mode': 'test_error'
|
||||
},
|
||||
'release_data': {
|
||||
'operating_system': 'none'
|
||||
},
|
||||
'cluster_attributes': {
|
||||
'editable': {
|
||||
'additional_components': {},
|
||||
'common': {}
|
||||
}
|
||||
}
|
||||
},
|
||||
5: {
|
||||
'cluster_meta': {
|
||||
'release_id': 5,
|
||||
'mode': 'dependent_tests'
|
||||
},
|
||||
'release_data': {
|
||||
'operating_system': 'none'
|
||||
},
|
||||
'cluster_attributes': {
|
||||
'editable': {
|
||||
'additional_components': {},
|
||||
'common': {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@route('/api/clusters/<id:int>')
|
||||
def serve_cluster_meta(id):
|
||||
return cluster_fixture[id]['cluster_meta']
|
||||
|
||||
|
||||
@route('/api/releases/<id:int>')
|
||||
def serve_cluster_release_info(id):
|
||||
return cluster_fixture[id]['release_data']
|
||||
|
||||
|
||||
@route('/api/clusters/<id:int>/attributes')
|
||||
def serve_cluster_attributes(id):
|
||||
return cluster_fixture[id]['cluster_attributes']
|
||||
|
||||
|
||||
run(host='localhost', port=8000, debug=True)
|
|
@ -1,236 +0,0 @@
|
|||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Profiled execution.
|
||||
profile=no
|
||||
|
||||
# Add <file or directory> to the black list. It should be a base name, not a
|
||||
# path. You may set this option multiple times.
|
||||
ignore=CVS
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
disable=F0401,R0201,W0311,C0111
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html
|
||||
output-format=parseable
|
||||
|
||||
# Include message's id in output
|
||||
include-ids=yes
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (R0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Add a comment according to your evaluation note. This is used by the global
|
||||
# evaluation report (R0004).
|
||||
comment=no
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=120
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching names used for dummy variables (i.e. not used).
|
||||
dummy-variables-rgx=_|dummy
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of classes names for which member attributes should not be checked
|
||||
# (useful for classes with attributes dynamically set).
|
||||
ignored-classes=SQLObject
|
||||
|
||||
# When zope mode is activated, add a predefined set of Zope acquired attributes
|
||||
# to generated-members.
|
||||
zope=no
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E0201 when accessed.
|
||||
generated-members=REQUEST,acl_users,aq_parent
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Required attributes for module, separated by a comma
|
||||
required-attributes=
|
||||
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=map,filter,apply,input
|
||||
|
||||
# Regular expression which should only match correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression which should only match correct module level names
|
||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression which should only match correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression which should only match correct function names
|
||||
function-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct method names
|
||||
method-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct instance attribute names
|
||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct variable names
|
||||
variable-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct list comprehension /
|
||||
# generator expression variable names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=app,uwsgi,e,i,j,k,ex,Run,_
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Regular expression which should only match functions or classes name which do
|
||||
# not require a docstring
|
||||
no-docstring-rgx=__.*__|[Tt]est.*
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=20
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=10
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branchs=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=10
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=0
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of interface methods to ignore, separated by a comma. This is used for
|
||||
# instance to not check methods defines in Zope's Interface base class.
|
||||
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
|
@ -1,55 +0,0 @@
|
|||
# Copyright 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
processes_pool = None
|
||||
|
||||
|
||||
def setup():
|
||||
global processes_pool
|
||||
|
||||
with open('/dev/null', 'w') as devnull:
|
||||
processes_pool = tuple(
|
||||
[
|
||||
subprocess.Popen(
|
||||
[
|
||||
'python',
|
||||
'fuel_plugin/testing/test_utils/nailgun_mimic.py'
|
||||
],
|
||||
stdout=devnull,
|
||||
stderr=devnull
|
||||
),
|
||||
subprocess.Popen(
|
||||
[
|
||||
'ostf-server',
|
||||
'--debug',
|
||||
('--debug_tests=fuel_plugin/testing/'
|
||||
'fixture/dummy_tests')
|
||||
],
|
||||
stdout=devnull,
|
||||
stderr=devnull
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
def teardown():
|
||||
for process in processes_pool:
|
||||
process.send_signal(signal.SIGINT)
|
||||
process.wait()
|
|
@ -15,15 +15,18 @@
|
|||
# under the License.
|
||||
|
||||
|
||||
import mock
|
||||
import requests_mock
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy import event
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
import unittest2
|
||||
import webtest
|
||||
|
||||
from fuel_plugin.ostf_adapter import config
|
||||
from fuel_plugin.ostf_adapter import mixins
|
||||
from fuel_plugin.ostf_adapter.nose_plugin.nose_discovery import discovery
|
||||
from fuel_plugin.ostf_adapter.nose_plugin import nose_discovery
|
||||
from fuel_plugin.ostf_adapter.storage import models
|
||||
from fuel_plugin.ostf_adapter.wsgi import app
|
||||
|
||||
|
||||
TEST_PATH = 'fuel_plugin/testing/fixture/dummy_tests'
|
||||
|
@ -119,16 +122,77 @@ class BaseUnitTest(unittest2.TestCase):
|
|||
"""Base class for all unit tests."""
|
||||
|
||||
|
||||
class BaseWSGITest(unittest2.TestCase):
|
||||
class BaseIntegrationTest(BaseUnitTest):
|
||||
"""Base class for all integration tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.dbpath = 'postgresql+psycopg2://ostf:ostf@localhost/ostf'
|
||||
cls.Session = sessionmaker()
|
||||
config.init_config([])
|
||||
# db connection
|
||||
cls.dbpath = config.cfg.CONF.adapter.dbpath
|
||||
cls.engine = create_engine(cls.dbpath)
|
||||
|
||||
cls.ext_id = 'fuel_plugin.testing.fixture.dummy_tests.'
|
||||
cls.expected = {
|
||||
# mock http requests
|
||||
cls.requests_mock = requests_mock.Mocker()
|
||||
cls.requests_mock.start()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# stop https requests mocking
|
||||
cls.requests_mock.stop()
|
||||
|
||||
def setUp(self):
|
||||
self.connection = self.engine.connect()
|
||||
self.trans = self.connection.begin()
|
||||
self.session = scoped_session(sessionmaker())
|
||||
self.session.configure(bind=self.connection)
|
||||
|
||||
# supprot tests with rollbacks
|
||||
# start the session in a SAVEPOINT...
|
||||
self.session.begin_nested()
|
||||
|
||||
# # then each time that SAVEPOINT ends, reopen it
|
||||
@event.listens_for(self.session, "after_transaction_end")
|
||||
def restart_savepoint(session, transaction):
|
||||
if transaction.nested and not transaction._parent.nested:
|
||||
session.begin_nested()
|
||||
|
||||
def tearDown(self):
|
||||
# rollback changes to database
|
||||
# made by tests
|
||||
self.trans.rollback()
|
||||
self.session.close()
|
||||
self.connection.close()
|
||||
|
||||
def mock_api_for_cluster(self, cluster_id):
|
||||
"""Mock requests to Nailgun to mimic behavior of
|
||||
Nailgun's API
|
||||
"""
|
||||
cluster = CLUSTERS[cluster_id]
|
||||
release_id = cluster['cluster_meta']['release_id']
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'GET',
|
||||
'/api/clusters/{0}'.format(cluster_id),
|
||||
json=cluster['cluster_meta'])
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'GET',
|
||||
'/api/releases/{0}'.format(release_id),
|
||||
json=cluster['release_data'])
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'GET',
|
||||
'/api/clusters/{0}/attributes'.format(cluster_id),
|
||||
json=cluster['cluster_attributes'])
|
||||
|
||||
|
||||
class BaseWSGITest(BaseIntegrationTest):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseWSGITest, self).setUp()
|
||||
self.ext_id = 'fuel_plugin.testing.fixture.dummy_tests.'
|
||||
self.expected = {
|
||||
'cluster': {
|
||||
'id': 1,
|
||||
'deployment_tags': set(['ha', 'rhel', 'nova_network',
|
||||
|
@ -137,7 +201,7 @@ class BaseWSGITest(unittest2.TestCase):
|
|||
'test_sets': ['general_test',
|
||||
'stopped_test', 'ha_deployment_test',
|
||||
'environment_variables'],
|
||||
'tests': [cls.ext_id + test for test in [
|
||||
'tests': [self.ext_id + test for test in [
|
||||
('deployment_types_tests.ha_deployment_test.'
|
||||
'HATest.test_ha_depl'),
|
||||
('deployment_types_tests.ha_deployment_test.'
|
||||
|
@ -157,51 +221,17 @@ class BaseWSGITest(unittest2.TestCase):
|
|||
]]
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
# orm session wrapping
|
||||
config.init_config([])
|
||||
self.connection = self.engine.connect()
|
||||
self.trans = self.connection.begin()
|
||||
self.discovery()
|
||||
|
||||
self.Session.configure(
|
||||
bind=self.connection
|
||||
)
|
||||
self.session = self.Session()
|
||||
|
||||
test_sets = self.session.query(models.TestSet).all()
|
||||
|
||||
# need this if start unit tests in conjuction with integration
|
||||
if not test_sets:
|
||||
discovery(path=TEST_PATH, session=self.session)
|
||||
|
||||
mixins.cache_test_repository(self.session)
|
||||
|
||||
# mocking
|
||||
# request mocking
|
||||
self.request_mock = mock.MagicMock()
|
||||
|
||||
self.request_patcher = mock.patch(
|
||||
'fuel_plugin.ostf_adapter.wsgi.controllers.request',
|
||||
self.request_mock
|
||||
)
|
||||
self.request_patcher.start()
|
||||
|
||||
# engine.get_session mocking
|
||||
self.request_mock.session = self.session
|
||||
|
||||
def tearDown(self):
|
||||
# rollback changes to database
|
||||
# made by tests
|
||||
self.trans.rollback()
|
||||
self.session.close()
|
||||
self.connection.close()
|
||||
|
||||
# end of test_case patching
|
||||
self.request_patcher.stop()
|
||||
self.app = webtest.TestApp(app.setup_app(session=self.session))
|
||||
|
||||
def discovery(self):
|
||||
"""Discover dummy tests used for testsing."""
|
||||
mixins.TEST_REPOSITORY = []
|
||||
nose_discovery.discovery(path=TEST_PATH, session=self.session)
|
||||
mixins.cache_test_repository(self.session)
|
||||
self.session.flush()
|
||||
|
||||
@property
|
||||
def is_background_working(self):
|
||||
is_working = True
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ from sqlalchemy import create_engine
|
|||
|
||||
from fuel_plugin.testing.tests.functional.base import \
|
||||
BaseAdapterTest, Response
|
||||
from fuel_plugin.ostf_client.client import TestingAdapterClient as adapter
|
||||
from fuel_plugin.ostf_client import client
|
||||
|
||||
|
||||
class AdapterTests(BaseAdapterTest):
|
||||
|
@ -74,7 +74,7 @@ class AdapterTests(BaseAdapterTest):
|
|||
]
|
||||
}
|
||||
|
||||
cls.adapter = adapter(url)
|
||||
cls.adapter = client.TestingAdapterClient(url)
|
||||
cls.client = cls.init_client(url)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -12,39 +12,32 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
from mock import patch, Mock
|
||||
import mock
|
||||
|
||||
from fuel_plugin.ostf_adapter.wsgi import controllers
|
||||
from fuel_plugin.ostf_adapter.storage import models
|
||||
|
||||
from fuel_plugin.testing.tests import base
|
||||
|
||||
|
||||
class TestTestsController(base.BaseWSGITest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTestsController, self).setUp()
|
||||
self.controller = controllers.TestsController()
|
||||
|
||||
def test_get(self):
|
||||
res = self.controller.get(self.expected['cluster']['id'])
|
||||
cluster_id = self.expected['cluster']['id']
|
||||
self.mock_api_for_cluster(cluster_id)
|
||||
resp = self.app.get(
|
||||
'/v1/tests/{0}'.format(cluster_id)
|
||||
)
|
||||
resp_tests = [test['id'] for test in resp.json]
|
||||
|
||||
self.assertTrue(self.is_background_working)
|
||||
|
||||
self.assertTrue(len(res) == len(self.expected['tests']))
|
||||
self.assertTrue(
|
||||
sorted([test['id'] for test in res]),
|
||||
sorted(self.expected['tests'])
|
||||
self.assertItemsEqual(
|
||||
resp_tests,
|
||||
self.expected['tests']
|
||||
)
|
||||
|
||||
|
||||
class TestTestSetsController(base.BaseWSGITest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTestSetsController, self).setUp()
|
||||
self.controller = controllers.TestsetsController()
|
||||
|
||||
def test_get(self):
|
||||
self.expected['test_set_description'] = [
|
||||
'General fake tests',
|
||||
|
@ -52,64 +45,56 @@ class TestTestSetsController(base.BaseWSGITest):
|
|||
'Fake tests for HA deployment',
|
||||
'Test for presence of env variables inside of testrun subprocess'
|
||||
]
|
||||
res = self.controller.get(self.expected['cluster']['id'])
|
||||
|
||||
cluster_id = self.expected['cluster']['id']
|
||||
self.mock_api_for_cluster(cluster_id)
|
||||
|
||||
resp = self.app.get(
|
||||
'/v1/testsets/{0}'.format(cluster_id)
|
||||
)
|
||||
resp_testsets_ids = [testset['id'] for testset in resp.json]
|
||||
|
||||
self.assertTrue(self.is_background_working)
|
||||
|
||||
self.assertTrue(
|
||||
sorted([testset['id'] for testset in res]) ==
|
||||
sorted(self.expected['test_sets'])
|
||||
)
|
||||
self.assertTrue(
|
||||
sorted([testset['name'] for testset in res]) ==
|
||||
sorted(self.expected['test_set_description'])
|
||||
self.assertItemsEqual(
|
||||
resp_testsets_ids,
|
||||
self.expected['test_sets']
|
||||
)
|
||||
|
||||
test_set_order = {
|
||||
'general_test': 0,
|
||||
'stopped_test': 1,
|
||||
'ha_deployment_test': 2,
|
||||
'environment_variables': 3
|
||||
}
|
||||
self.assertItemsEqual(
|
||||
[testset['name'] for testset in resp.json],
|
||||
self.expected['test_set_description']
|
||||
)
|
||||
|
||||
resp_elements = [testset['id'] for testset in res]
|
||||
for test_set in resp_elements:
|
||||
self.assertTrue(
|
||||
test_set_order[test_set] == resp_elements.index(test_set)
|
||||
)
|
||||
test_sets_order = (
|
||||
'general_test',
|
||||
'stopped_test',
|
||||
'ha_deployment_test',
|
||||
'environment_variables',
|
||||
)
|
||||
self.assertSequenceEqual(resp_testsets_ids, test_sets_order)
|
||||
|
||||
|
||||
class TestTestRunsController(base.BaseWSGITest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTestRunsController, self).setUp()
|
||||
|
||||
self.request_mock.body = json.dumps([
|
||||
{
|
||||
'testset': 'ha_deployment_test',
|
||||
'metadata': {'cluster_id': 1}
|
||||
}]
|
||||
)
|
||||
|
||||
self.controller = controllers.TestrunsController()
|
||||
|
||||
self.plugin_mock = Mock()
|
||||
self.plugin_mock = mock.Mock()
|
||||
self.plugin_mock.kill.return_value = True
|
||||
|
||||
self.nose_plugin_patcher = patch(
|
||||
self.nose_plugin_patcher = mock.patch(
|
||||
'fuel_plugin.ostf_adapter.storage.models.nose_plugin.get_plugin',
|
||||
lambda *args: self.plugin_mock
|
||||
)
|
||||
self.nose_plugin_patcher.start()
|
||||
|
||||
self.cluster_id = self.expected['cluster']['id']
|
||||
self.mock_api_for_cluster(self.cluster_id)
|
||||
|
||||
def tearDown(self):
|
||||
super(TestTestRunsController, self).tearDown()
|
||||
|
||||
self.nose_plugin_patcher.stop()
|
||||
|
||||
|
||||
class TestTestRunsPostController(TestTestRunsController):
|
||||
|
||||
def test_post(self):
|
||||
self.expected['testrun_post'] = {
|
||||
'testset': 'ha_deployment_test',
|
||||
|
@ -127,17 +112,25 @@ class TestTestRunsPostController(TestTestRunsController):
|
|||
}
|
||||
}
|
||||
|
||||
res = self.controller.post()[0]
|
||||
resp = self.app.post_json('/v1/testruns/', (
|
||||
{
|
||||
'testset': 'ha_deployment_test',
|
||||
'metadata': {'cluster_id': self.cluster_id}
|
||||
},
|
||||
))
|
||||
|
||||
for key in self.expected['testrun_post'].keys():
|
||||
resp_testrun = resp.json[0]
|
||||
|
||||
for key in self.expected['testrun_post']:
|
||||
if key == 'tests':
|
||||
self.assertTrue(
|
||||
sorted(self.expected['testrun_post'][key]['names']) ==
|
||||
sorted([test['id'] for test in res[key]])
|
||||
self.assertItemsEqual(
|
||||
self.expected['testrun_post'][key]['names'],
|
||||
[test['id'] for test in resp_testrun[key]]
|
||||
)
|
||||
else:
|
||||
self.assertTrue(
|
||||
self.expected['testrun_post'][key] == res[key]
|
||||
self.assertEqual(
|
||||
self.expected['testrun_post'][key],
|
||||
resp_testrun[key]
|
||||
)
|
||||
|
||||
self.session.query(models.TestRun)\
|
||||
|
@ -152,35 +145,29 @@ class TestTestRunsPostController(TestTestRunsController):
|
|||
tests_names = [
|
||||
test.name for test in testrun_tests
|
||||
]
|
||||
self.assertTrue(
|
||||
sorted(tests_names) ==
|
||||
sorted(self.expected['testrun_post']['tests']['names'])
|
||||
self.assertItemsEqual(
|
||||
tests_names,
|
||||
self.expected['testrun_post']['tests']['names']
|
||||
)
|
||||
|
||||
|
||||
class TestTestRunsPutController(TestTestRunsController):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTestRunsPutController, self).setUp()
|
||||
self.test_run = self.controller.post()[0]
|
||||
def test_put_stopped(self):
|
||||
resp = self.app.post_json('/v1/testruns/', (
|
||||
{
|
||||
'testset': 'ha_deployment_test',
|
||||
'metadata': {'cluster_id': self.cluster_id}
|
||||
},
|
||||
))
|
||||
resp_testrun = resp.json[0]
|
||||
|
||||
self.session.query(models.Test)\
|
||||
.filter_by(test_run_id=int(self.test_run['id']))\
|
||||
.filter_by(test_run_id=resp_testrun['id'])\
|
||||
.update({'status': 'running'})
|
||||
|
||||
# flush data which test is depend on into db
|
||||
self.session.commit()
|
||||
|
||||
self.request_mock.body = json.dumps(
|
||||
[{
|
||||
'status': 'stopped',
|
||||
'id': self.test_run['id']
|
||||
}]
|
||||
)
|
||||
|
||||
def test_put_stopped(self):
|
||||
self.expected['testrun_put'] = {
|
||||
'id': int(self.test_run['id']),
|
||||
'id': resp_testrun['id'],
|
||||
'testset': 'ha_deployment_test',
|
||||
'cluster_id': 1,
|
||||
'tests': {
|
||||
|
@ -195,17 +182,23 @@ class TestTestRunsPutController(TestTestRunsController):
|
|||
}
|
||||
}
|
||||
|
||||
res = self.controller.put()[0]
|
||||
resp = self.app.put_json('/v1/testruns/', (
|
||||
{
|
||||
'status': 'stopped',
|
||||
'id': resp_testrun['id']
|
||||
},
|
||||
))
|
||||
resp_testrun = resp.json[0]
|
||||
|
||||
for key in self.expected['testrun_put'].keys():
|
||||
if key == 'tests':
|
||||
self.assertTrue(
|
||||
sorted(self.expected['testrun_put'][key]['names']) ==
|
||||
sorted([test['id'] for test in res[key]])
|
||||
self.assertItemsEqual(
|
||||
self.expected['testrun_put'][key]['names'],
|
||||
[test['id'] for test in resp_testrun[key]]
|
||||
)
|
||||
else:
|
||||
self.assertTrue(
|
||||
self.expected['testrun_put'][key] == res[key]
|
||||
self.assertEqual(
|
||||
self.expected['testrun_put'][key], resp_testrun[key]
|
||||
)
|
||||
|
||||
testrun_tests = self.session.query(models.Test)\
|
||||
|
@ -215,9 +208,9 @@ class TestTestRunsPutController(TestTestRunsController):
|
|||
tests_names = [
|
||||
test.name for test in testrun_tests
|
||||
]
|
||||
self.assertTrue(
|
||||
sorted(tests_names) ==
|
||||
sorted(self.expected['testrun_put']['tests']['names'])
|
||||
self.assertItemsEqual(
|
||||
tests_names,
|
||||
self.expected['testrun_put']['tests']['names']
|
||||
)
|
||||
|
||||
self.assertTrue(
|
||||
|
@ -229,12 +222,14 @@ class TestTestRunsPutController(TestTestRunsController):
|
|||
|
||||
class TestClusterRedeployment(base.BaseWSGITest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestClusterRedeployment, self).setUp()
|
||||
self.controller = controllers.TestsetsController()
|
||||
self.controller.get(self.expected['cluster']['id'])
|
||||
@mock.patch('fuel_plugin.ostf_adapter.mixins._get_cluster_depl_tags')
|
||||
def test_cluster_redeployment_with_different_tags(self, m_get_depl_tags):
|
||||
m_get_depl_tags.return_value = set(
|
||||
['multinode', 'centos']
|
||||
)
|
||||
cluster_id = self.expected['cluster']['id']
|
||||
self.app.get('/v1/testsets/{0}'.format(cluster_id))
|
||||
|
||||
def test_cluster_redeployment_with_different_tags(self):
|
||||
self.expected = {
|
||||
'cluster': {
|
||||
'id': 1,
|
||||
|
@ -265,14 +260,10 @@ class TestClusterRedeployment(base.BaseWSGITest):
|
|||
|
||||
# patch request_to_nailgun function in orded to emulate
|
||||
# redeployment of cluster
|
||||
cluster_data = set(
|
||||
m_get_depl_tags.return_value = set(
|
||||
['multinode', 'ubuntu', 'nova_network']
|
||||
)
|
||||
|
||||
with patch(
|
||||
('fuel_plugin.ostf_adapter.mixins._get_cluster_depl_tags'),
|
||||
lambda *args, **kwargs: cluster_data
|
||||
):
|
||||
self.controller.get(self.expected['cluster']['id'])
|
||||
self.app.get('/v1/testsets/{0}'.format(cluster_id))
|
||||
|
||||
self.assertTrue(self.is_background_working)
|
||||
|
|
|
@ -12,39 +12,23 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
from mock import patch, MagicMock
|
||||
from webtest import TestApp
|
||||
import mock
|
||||
|
||||
from fuel_plugin.ostf_adapter.wsgi import app
|
||||
from fuel_plugin.ostf_adapter.storage import models
|
||||
from fuel_plugin.testing.tests import base
|
||||
|
||||
|
||||
class WsgiInterfaceTests(base.BaseWSGITest):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(WsgiInterfaceTests, cls).setUpClass()
|
||||
|
||||
def setUp(self):
|
||||
super(WsgiInterfaceTests, self).setUp()
|
||||
|
||||
self.app = TestApp(app.setup_app())
|
||||
|
||||
self.fixture = {
|
||||
'cluster_id': 1
|
||||
}
|
||||
|
||||
def tearDown(self):
|
||||
super(WsgiInterfaceTests, self).tearDown()
|
||||
class WsgiInterfaceTest(base.BaseWSGITest):
|
||||
|
||||
def test_get_all_tests(self):
|
||||
self.app.get('/v1/tests/{0}'
|
||||
.format(self.fixture['cluster_id']))
|
||||
cluster_id = 1
|
||||
self.mock_api_for_cluster(cluster_id)
|
||||
self.app.get('/v1/tests/{0}'.format(cluster_id))
|
||||
|
||||
def test_get_all_testsets(self):
|
||||
self.app.get('/v1/testsets/{0}'
|
||||
.format(self.fixture['cluster_id']))
|
||||
cluster_id = 1
|
||||
self.mock_api_for_cluster(cluster_id)
|
||||
self.app.get('/v1/testsets/{0}'.format(cluster_id))
|
||||
|
||||
def test_get_one_testruns(self):
|
||||
self.app.get('/v1/testruns/1')
|
||||
|
@ -52,21 +36,23 @@ class WsgiInterfaceTests(base.BaseWSGITest):
|
|||
def test_get_all_testruns(self):
|
||||
self.app.get('/v1/testruns')
|
||||
|
||||
@patch('fuel_plugin.ostf_adapter.wsgi.controllers.models')
|
||||
def test_post_testruns(self, models):
|
||||
@mock.patch.object(models.TestRun, 'start')
|
||||
def test_post_testruns(self, mstart):
|
||||
self.mock_api_for_cluster(3)
|
||||
self.mock_api_for_cluster(4)
|
||||
|
||||
testruns = [
|
||||
{
|
||||
'testset': 'test_simple',
|
||||
'testset': 'general_test',
|
||||
'metadata': {'cluster_id': 3}
|
||||
},
|
||||
{
|
||||
'testset': 'test_simple',
|
||||
'testset': 'general_test',
|
||||
'metadata': {'cluster_id': 4}
|
||||
}
|
||||
]
|
||||
|
||||
self.request_mock.body = json.dumps(testruns)
|
||||
models.TestRun.start.return_value = {}
|
||||
mstart.return_value = {}
|
||||
self.app.post_json('/v1/testruns', testruns)
|
||||
|
||||
def test_put_testruns(self):
|
||||
|
@ -83,11 +69,9 @@ class WsgiInterfaceTests(base.BaseWSGITest):
|
|||
}
|
||||
]
|
||||
|
||||
self.request_mock.body = json.dumps(testruns)
|
||||
self.request_mock.storage.get_test_run.return_value = \
|
||||
MagicMock(frontend={})
|
||||
self.app.put_json('/v1/testruns', testruns)
|
||||
|
||||
def test_get_last_testruns(self):
|
||||
self.app.get('/v1/testruns/last/{0}'
|
||||
.format(self.fixture['cluster_id']))
|
||||
cluster_id = 1
|
||||
self.mock_api_for_cluster(cluster_id)
|
||||
self.app.get('/v1/testruns/last/{0}'.format(cluster_id))
|
|
@ -1,8 +1,8 @@
|
|||
-r requirements.txt
|
||||
WebTest>=2.0.17
|
||||
mock==1.0.1
|
||||
requests-mock>=0.5.1
|
||||
flake8
|
||||
tox>=1.7.1
|
||||
coverage==3.6
|
||||
fabric
|
||||
bottle
|
||||
|
|
Loading…
Reference in New Issue