Version for tests added

Fuel releases versions compatibility now included into tests discovering
mechanism.

Change-Id: Ia860cc62d30ef02e7fdff4864eecd16cccf01b1c
Implements: blueprint ostf-tests-versioning
This commit is contained in:
Artem Roma 2015-02-12 16:44:33 +02:00
parent f9c37d0876
commit ad8df61058
11 changed files with 324 additions and 68 deletions

View File

@ -42,12 +42,14 @@ def cache_test_repository(session):
.options(joinedload('tests'))\
.all()
crucial_tests_attrs = ['name', 'deployment_tags']
crucial_tests_attrs = ['name', 'deployment_tags',
'available_since_release']
for test_set in test_repository:
data_elem = dict()
data_elem['test_set_id'] = test_set.id
data_elem['deployment_tags'] = test_set.deployment_tags
data_elem['available_since_release'] = test_set.available_since_release
data_elem['tests'] = []
for test in test_set.tests:
@ -58,27 +60,28 @@ def cache_test_repository(session):
TEST_REPOSITORY.append(data_elem)
def discovery_check(session, cluster, token=None):
cluster_deployment_args = _get_cluster_depl_tags(cluster, token=token)
def discovery_check(session, cluster_id, token=None):
cluster_attrs = _get_cluster_attrs(cluster_id, token=token)
cluster_data = {
'cluster_id': cluster,
'deployment_tags': cluster_deployment_args
'id': cluster_id,
'deployment_tags': cluster_attrs['deployment_tags'],
'release_version': cluster_attrs['release_version'],
}
cluster_state = session.query(models.ClusterState)\
.filter_by(id=cluster_data['cluster_id'])\
.filter_by(id=cluster_data['id'])\
.first()
if not cluster_state:
session.add(
models.ClusterState(
id=cluster_data['cluster_id'],
id=cluster_data['id'],
deployment_tags=list(cluster_data['deployment_tags'])
)
)
# flush data to db, cuz _add_cluster_testing_pattern
# flush data to db, because _add_cluster_testing_pattern
# is dependent on it
session.flush()
@ -100,7 +103,9 @@ def discovery_check(session, cluster, token=None):
session.merge(cluster_state)
def _get_cluster_depl_tags(cluster_id, token=None):
def _get_cluster_attrs(cluster_id, token=None):
cluster_attrs = {}
REQ_SES = requests.Session()
REQ_SES.trust_env = False
@ -130,13 +135,15 @@ def _get_cluster_depl_tags(cluster_id, token=None):
release_data = REQ_SES.get(release_url).json()
if 'version' in release_data:
cluster_attrs['release_version'] = release_data['version']
# info about deployment type and operating system
mode = 'ha' if 'ha' in response['mode'].lower() else response['mode']
deployment_tags.add(mode)
deployment_tags.add(release_data.get(
'operating_system', 'failed to get os'))
if 'version' in release_data:
deployment_tags.add(release_data['version'])
# networks manager
network_type = response.get('net_provider', 'nova_network')
deployment_tags.add(network_type)
@ -175,7 +182,11 @@ def _get_cluster_depl_tags(cluster_id, token=None):
if libvrt_data and libvrt_data.get('value'):
deployment_tags.add(libvrt_data['value'])
return set([tag.lower() for tag in deployment_tags])
cluster_attrs['deployment_tags'] = set(
[tag.lower() for tag in deployment_tags]
)
return cluster_attrs
def _add_cluster_testing_pattern(session, cluster_data):
@ -188,22 +199,15 @@ def _add_cluster_testing_pattern(session, cluster_data):
cache_test_repository(session)
for test_set in TEST_REPOSITORY:
if nose_utils.process_deployment_tags(
cluster_data['deployment_tags'],
test_set['deployment_tags']
):
if nose_utils.is_test_available(cluster_data, test_set):
testing_pattern = dict()
testing_pattern['cluster_id'] = cluster_data['cluster_id']
testing_pattern = {}
testing_pattern['cluster_id'] = cluster_data['id']
testing_pattern['test_set_id'] = test_set['test_set_id']
testing_pattern['tests'] = []
for test in test_set['tests']:
if nose_utils.process_deployment_tags(
cluster_data['deployment_tags'],
test['deployment_tags']
):
if nose_utils.is_test_available(cluster_data, test):
testing_pattern['tests'].append(test['name'])
to_database.append(

View File

@ -81,21 +81,20 @@ class DiscoveryPlugin(plugins.Plugin):
test_id = test.id()
for test_set_id in self.test_sets.keys():
if self.test_belongs_to_testset(test_id, test_set_id):
data = dict()
test_kwargs = {
"title": "",
"description": "",
"duration": "",
"deployment_tags": [],
"available_since_release": "",
"test_set_id": test_set_id,
"name": test_id,
}
(data['title'], data['description'],
data['duration'], data['deployment_tags']) = \
nose_utils.get_description(test)
data.update(
{
'test_set_id': test_set_id,
'name': test_id
}
)
test_kwargs.update(nose_utils.get_description(test))
try:
test_obj = models.Test(**data)
test_obj = models.Test(**test_kwargs)
self.session.merge(test_obj)
# flush tests data into db

View File

@ -70,7 +70,7 @@ class StoragePlugin(plugins.Plugin):
data
)
if data['status'] != 'running':
test_name = nose_utils.get_description(test)[0]
test_name = nose_utils.get_description(test)["title"]
self.results_log.log_results(
test_id,
test_name=test_name,

View File

@ -20,6 +20,8 @@ import os
import re
import traceback
from distutils import version
from nose import case
from nose.suite import ContextSuite
@ -69,6 +71,7 @@ def get_description(test_obj):
if isinstance(test_obj, case.Test):
docstring = test_obj.test._testMethodDoc
test_data = {}
if docstring:
deployment_tags_pattern = r'Deployment tags:.?(?P<tags>.+)?'
docstring, deployment_tags = _process_docstring(
@ -83,21 +86,30 @@ def get_description(test_obj):
deployment_tags = [
tag.strip().lower() for tag in deployment_tags.split(',')
]
else:
deployment_tags = []
test_data['deployment_tags'] = deployment_tags
rel_vers_pattern = "Available since release:.?(?P<rel_vers>.+)"
docstring, rel_vers = _process_docstring(
docstring,
rel_vers_pattern
)
if rel_vers:
test_data["available_since_release"] = rel_vers
duration_pattern = r'Duration:.?(?P<duration>.+)'
docstring, duration = _process_docstring(
docstring,
duration_pattern
)
if duration:
test_data['duration'] = duration
docstring = docstring.split('\n')
name = docstring.pop(0)
description = u'\n'.join(docstring) if docstring else u""
test_data['title'] = docstring.pop(0)
test_data['description'] = \
u'\n'.join(docstring) if docstring else u""
return name, description, duration, deployment_tags
return u"", u"", u"", []
return test_data
def modify_test_name_for_nose(test_path):
@ -163,7 +175,7 @@ def get_tests_to_update(test):
return tests
def process_deployment_tags(cluster_depl_tags, test_depl_tags):
def _process_deployment_tags(cluster_depl_tags, test_depl_tags):
"""Process alternative deployment tags for testsets and tests
and determines whether current test entity (testset or test)
is appropriate for cluster.
@ -179,3 +191,46 @@ def process_deployment_tags(cluster_depl_tags, test_depl_tags):
return True
return False
def _compare_release_versions(cluster_release_version, test_release_version):
cl_openstack_ver, cl_fuel_ver = cluster_release_version.split('-')
test_openstack_ver, test_fuel_ver = test_release_version.split('-')
cond = (
(version.StrictVersion(cl_openstack_ver) >=
version.StrictVersion(test_openstack_ver))
and
(version.StrictVersion(cl_fuel_ver) >=
version.StrictVersion(test_fuel_ver))
)
return cond
def is_test_available(cluster_data, test_entity_data):
is_test_available = False
is_rel_ver_suitable = False
# if 'available_since_release' attritube of test entity
# is empty then this test entity is available for cluster
# in other case execute release comparator logic
if not test_entity_data['available_since_release']:
is_rel_ver_suitable = True
else:
is_rel_ver_suitable = _compare_release_versions(
cluster_data['release_version'],
test_entity_data['available_since_release']
)
# if release version of test entity is suitable for cluster
# then check test entity compatibility with cluster
# by deployment tags
if is_rel_ver_suitable:
is_depl_tags_suitable = _process_deployment_tags(
cluster_data['deployment_tags'],
test_entity_data['deployment_tags']
)
if is_depl_tags_suitable:
is_test_available = True
return is_test_available

View File

@ -0,0 +1,44 @@
# Copyright 2015 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.
"""versioning
Revision ID: 36e3fd684a9e
Revises: 54904076d82d
Create Date: 2015-02-12 15:45:23.885397
"""
# revision identifiers, used by Alembic.
revision = '36e3fd684a9e'
down_revision = '54904076d82d'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('test_sets', sa.Column('available_since_release',
sa.String(64),
default=""))
op.add_column('tests', sa.Column('available_since_release',
sa.String(64),
default=""))
op.add_column('cluster_state', sa.Column('release_version', sa.String(64)))
def downgrade():
op.drop_column('test_sets', 'available_since_release')
op.drop_column('tests', 'available_since_release')
op.drop_column('cluster_state', 'release_version')

View File

@ -48,6 +48,7 @@ class ClusterState(BASE):
id = sa.Column(sa.Integer, primary_key=True, autoincrement=False)
deployment_tags = sa.Column(ARRAY(sa.String(64)))
release_version = sa.Column(sa.String(64))
class ClusterTestingPattern(BASE):
@ -90,6 +91,8 @@ class TestSet(BASE):
# with current test set
exclusive_testsets = sa.Column(ARRAY(sa.String(128)))
available_since_release = sa.Column(sa.String(64), default="")
tests = relationship(
'Test',
backref='test_set',
@ -135,6 +138,7 @@ class Test(BASE):
time_taken = sa.Column(sa.Float())
meta = sa.Column(fields.JsonField())
deployment_tags = sa.Column(ARRAY(sa.String(64)))
available_since_release = sa.Column(sa.String(64), default="")
test_run_id = sa.Column(
sa.Integer(),

View File

@ -0,0 +1,49 @@
# Copyright 2015 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.
__profile__ = {
"id": "test_versioning",
"driver": "nose",
"test_path": "fuel_plugin/tests/functional/dummy_tests/test_versioning.py",
"description": "Test suite that contains fake tests for versioning check",
"deployment_tags": ["releases_comparison"],
"test_runs_ordering_priority": 13,
"exclusive_testsets": [],
"available_since_release": "2015.2-6.0",
}
import unittest2
class TestVersioning(unittest2.TestCase):
def test_simple_fake_first(self):
"""This is simple fake test
for versioning checking.
It should be discovered for
releases == of >= 2015.2-6.0
Available since release: 2015.2-6.0
Deployment tags: releases_comparison
"""
self.assertTrue(True)
def test_simple_fake_second(self):
"""This is simple fake test
for versioning checking.
It should be discovered for
releases == of >= 2015.2-6.1
Available since release: 2015.2-6.1
Deployment tags: releases_comparison
"""
self.assertTrue(True)

View File

@ -39,7 +39,8 @@ CLUSTERS = {
'mode': 'ha'
},
'release_data': {
'operating_system': 'rhel'
'operating_system': 'rhel',
'version': '2015.2-1.0',
},
'cluster_attributes': {
'editable': {
@ -54,7 +55,8 @@ CLUSTERS = {
'mode': 'multinode',
},
'release_data': {
'operating_system': 'ubuntu'
'operating_system': 'ubuntu',
'version': '2015.2-1.0',
},
'cluster_attributes': {
'editable': {
@ -69,7 +71,8 @@ CLUSTERS = {
'mode': 'ha'
},
'release_data': {
'operating_system': 'rhel'
'operating_system': 'rhel',
'version': '2015.2-1.0',
},
'cluster_attributes': {
'editable': {
@ -91,7 +94,8 @@ CLUSTERS = {
'mode': 'test_error'
},
'release_data': {
'operating_system': 'none'
'operating_system': 'none',
'version': '2015.2-1.0',
},
'cluster_attributes': {
'editable': {
@ -106,7 +110,24 @@ CLUSTERS = {
'mode': 'dependent_tests'
},
'release_data': {
'operating_system': 'none'
'operating_system': 'none',
'version': '2015.2-1.0',
},
'cluster_attributes': {
'editable': {
'additional_components': {},
'common': {}
}
}
},
6: {
'cluster_meta': {
'release_id': 6,
'mode': 'releases_comparison'
},
'release_data': {
'operating_system': '',
'version': '2015.2-6.0',
},
'cluster_attributes': {
'editable': {

View File

@ -222,11 +222,14 @@ class TestTestRunsController(base.BaseWSGITest):
class TestClusterRedeployment(base.BaseWSGITest):
@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']
)
@mock.patch('fuel_plugin.ostf_adapter.mixins._get_cluster_attrs')
def test_cluster_redeployment_with_different_tags(self,
m_get_cluster_attrs):
m_get_cluster_attrs.return_value = {
'deployment_tags': set(['multinode', 'centos']),
'release_version': '2015.2-1.0'
}
cluster_id = self.expected['cluster']['id']
self.app.get('/v1/testsets/{0}'.format(cluster_id))
@ -260,10 +263,44 @@ class TestClusterRedeployment(base.BaseWSGITest):
# patch request_to_nailgun function in orded to emulate
# redeployment of cluster
m_get_depl_tags.return_value = set(
['multinode', 'ubuntu', 'nova_network']
)
m_get_cluster_attrs.return_value = {
'deployment_tags': set(['multinode', 'ubuntu', 'nova_network']),
'release_version': '2015.2-1.0'
}
self.app.get('/v1/testsets/{0}'.format(cluster_id))
self.assertTrue(self.is_background_working)
class TestVersioning(base.BaseWSGITest):
def test_discover_tests_with_versions(self):
cluster_id = 6
self.mock_api_for_cluster(cluster_id)
self.app.get('/v1/testsets/{0}'.format(cluster_id))
self.expected = {
'cluster': {
'id': 6,
'deployment_tags': set(['releases_comparison'])
},
'test_sets': ['general_test', 'stopped_test', 'test_versioning',
'environment_variables'],
'tests': [self.ext_id + test for test in [
'general_test.Dummy_test.test_fast_pass',
'general_test.Dummy_test.test_long_pass',
'general_test.Dummy_test.test_fast_fail',
'general_test.Dummy_test.test_fast_error',
'general_test.Dummy_test.test_fail_with_step',
'general_test.Dummy_test.test_skip',
'general_test.Dummy_test.test_skip_directly',
'stopped_test.dummy_tests_stopped.test_really_long',
'stopped_test.dummy_tests_stopped.test_one_no_so_long',
'stopped_test.dummy_tests_stopped.test_not_long_at_all',
('test_environment_variables.TestEnvVariables.'
'test_os_credentials_env_variables'),
'test_versioning.TestVersioning.test_simple_fake_first',
]]
}
self.assertTrue(self.is_background_working)

View File

@ -54,10 +54,16 @@ class TestNoseDiscovery(base.BaseUnitTest):
if isinstance(el[0][0], models.Test)
]
def _find_needed_test(self, test_name):
return next(t for t in self.tests if t.name == test_name)
def _find_needed_test_set(self, test_set_id):
return next(t for t in self.test_sets if t.id == test_set_id)
def test_discovery(self):
expected = {
'test_sets_count': 9,
'tests_count': 27
'test_sets_count': 10,
'tests_count': 29
}
self.assertTrue(
@ -116,11 +122,9 @@ class TestNoseDiscovery(base.BaseUnitTest):
}
}
needed_testset = [testset for testset in self.test_sets
if testset.id == expected['testset']['id']][0]
needed_testset = self._find_needed_test_set(expected['testset']['id'])
needed_test = [test for test in self.tests
if test.name == expected['test']['name']][0]
needed_test = self._find_needed_test(expected['test']['name'])
self.assertEqual(
needed_testset.deployment_tags,
@ -157,3 +161,40 @@ class TestNoseDiscovery(base.BaseUnitTest):
nose_discovery.DiscoveryPlugin.test_belongs_to_testset(
test_id, test_set_id)
)
def test_release_version_attribute(self):
for test_entity in (self.tests, self.test_sets):
self.assertTrue(
all(
[hasattr(t, 'available_since_release')
for t in test_entity]
)
)
expected = {
'test_set': {
'id': 'test_versioning',
'available_since_release': '2015.2-6.0',
},
'tests': [
{'name': ('fuel_plugin.testing.fixture.dummy_tests.'
'test_versioning.TestVersioning.'
'test_simple_fake_first'),
'available_since_release': '2015.2-6.0', },
{'name': ('fuel_plugin.testing.fixture.dummy_tests.'
'test_versioning.TestVersioning.'
'test_simple_fake_second'),
'available_since_release': '2015.2-6.1', },
]
}
needed_test_set = self._find_needed_test_set(
expected['test_set']['id']
)
self.assertEqual(needed_test_set.available_since_release,
expected['test_set']['available_since_release'])
for test in expected['tests']:
needed_test = self._find_needed_test(test['name'])
self.assertEqual(needed_test.available_since_release,
test['available_since_release'])

View File

@ -27,10 +27,12 @@ class TestDeplTagsGetter(base.BaseUnitTest):
def test_get_cluster_depl_tags(self):
expected = {
'cluster_id': 3,
'depl_tags': set(
['ha', 'rhel', 'additional_components',
'murano', 'nova_network', 'public_on_all_nodes']
)
'attrs': {
'deployment_tags': set(
['ha', 'rhel', 'additional_components',
'murano', 'nova_network', 'public_on_all_nodes']),
'release_version': '2015.2-1.0'
}
}
with requests_mock.Mocker() as m:
@ -41,6 +43,6 @@ class TestDeplTagsGetter(base.BaseUnitTest):
json=cluster['cluster_attributes'])
m.register_uri('GET', '/api/releases/3',
json=cluster['release_data'])
res = mixins._get_cluster_depl_tags(expected['cluster_id'])
res = mixins._get_cluster_attrs(expected['cluster_id'])
self.assertEqual(res, expected['depl_tags'])
self.assertEqual(res, expected['attrs'])