diff --git a/core/_tests/models/fuel_client/__init__.py b/core/_tests/models/fuel_client/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/core/_tests/models/fuel_client/test_adapter.py b/core/_tests/models/fuel_client/test_adapter.py new file mode 100644 index 000000000..2b810a395 --- /dev/null +++ b/core/_tests/models/fuel_client/test_adapter.py @@ -0,0 +1,115 @@ +# Copyright 2016 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 __future__ import absolute_import +from __future__ import unicode_literals + +import unittest + +# pylint: disable=import-error +from mock import Mock +# pylint: enable=import-error + +from core.models.fuel_client import base_client + +# pylint: disable=no-self-use + + +class TestAdapter(unittest.TestCase): + def test_init_default(self): + session = Mock(spec='keystoneauth1.session.Session') + obj = base_client.Adapter(session=session) + + self.assertEqual(obj.service_type, 'fuel') + self.assertEqual(obj.session, session) + + self.assertEqual( + repr(obj), + ( + "{cls}(" + "session=," + "service_type={svc}" + ") id={id}".format( + cls=base_client.Adapter.__name__, + sess_id=hex(id(session)), + svc=obj.service_type, + id=hex(id(obj)) + )) + ) + + def test_init_svc(self): + session = Mock(spec='keystoneauth1.session.Session') + + service_type = 'ostf' + obj = base_client.Adapter(session=session, service_type=service_type) + + self.assertEqual(obj.service_type, service_type) + self.assertEqual(obj.session, session) + + self.assertEqual( + repr(obj), + ( + "{cls}(" + "session=," + "service_type={svc}" + ") id={id}".format( + cls=base_client.Adapter.__name__, + sess_id=hex(id(session)), + svc=obj.service_type, + id=hex(id(obj)) + )) + ) + + def test_methods(self): + session = Mock(spec='keystoneauth1.session.Session') + get = Mock(name='get') + post = Mock(name='post') + put = Mock(name='put') + delete = Mock(name='delete') + + session.attach_mock(get, 'get') + session.attach_mock(post, 'post') + session.attach_mock(put, 'put') + session.attach_mock(delete, 'delete') + + url = 'test' + + obj = base_client.Adapter(session=session) + + obj.get(url=url) + obj.post(url=url) + obj.put(url=url) + obj.delete(url=url) + + get.assert_called_once_with( + connect_retries=1, + endpoint_filter={'service_type': obj.service_type}, + url=url) + + post.assert_called_once_with( + connect_retries=1, + endpoint_filter={'service_type': obj.service_type}, + url=url) + + put.assert_called_once_with( + connect_retries=1, + endpoint_filter={'service_type': obj.service_type}, + url=url) + + delete.assert_called_once_with( + connect_retries=1, + endpoint_filter={'service_type': obj.service_type}, + url=url) diff --git a/core/_tests/models/fuel_client/test_client.py b/core/_tests/models/fuel_client/test_client.py new file mode 100644 index 000000000..5d92d21be --- /dev/null +++ b/core/_tests/models/fuel_client/test_client.py @@ -0,0 +1,52 @@ +# Copyright 2016 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 __future__ import absolute_import +from __future__ import unicode_literals + +import unittest + +# pylint: disable=import-error +from mock import call +from mock import Mock +from mock import patch +# pylint: enable=import-error + +from core.models.fuel_client import client + +# pylint: disable=no-self-use + + +@patch('core.models.fuel_client.client.logger', autospec=True) +@patch('core.models.fuel_client.base_client.Adapter', autospec=True) +class TestClient(unittest.TestCase): + def test_init(self, adapter, logger): + session = Mock(spec='keystoneauth1.session.Session') + session.attach_mock(Mock(), 'auth') + session.auth.auth_url = 'http://127.0.0.1' + + obj = client.Client(session=session) + + self.assertIn( + call(service_type=u'ostf', session=session), + adapter.mock_calls + ) + + logger.assert_has_calls(( + call.info( + 'Initialization of NailgunClient using shared session \n' + '(auth_url={})'.format(session.auth.auth_url)), + )) + + self.assertIn('ostf', dir(obj)) diff --git a/core/_tests/models/fuel_client/test_ostf_client.py b/core/_tests/models/fuel_client/test_ostf_client.py new file mode 100644 index 000000000..914cfbdd1 --- /dev/null +++ b/core/_tests/models/fuel_client/test_ostf_client.py @@ -0,0 +1,128 @@ +# Copyright 2016 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 __future__ import absolute_import +from __future__ import unicode_literals + +import unittest + +# pylint: disable=import-error +from mock import Mock +from mock import patch +# pylint: enable=import-error + +from core.models.fuel_client.ostf_client import OSTFClient + +# pylint: disable=no-self-use + + +@patch('core.models.fuel_client.ostf_client.logwrap', autospec=True) +class TestOSTFClient(unittest.TestCase): + @staticmethod + def prepare_session(): + session = Mock(spec='keystoneauth1.session.Session') + session.attach_mock(Mock(), 'auth') + session.auth.auth_url = 'http://127.0.0.1' + get = Mock(name='get') + post = Mock(name='post') + put = Mock(name='put') + delete = Mock(name='delete') + + session.attach_mock(get, 'get') + session.attach_mock(post, 'post') + session.attach_mock(put, 'put') + session.attach_mock(delete, 'delete') + + return session + + def test_basic(self, logwrap): + session = self.prepare_session() + client = OSTFClient(session) + + cluster_id = 0 + + client.get_test_sets(cluster_id=cluster_id) + + session.get.assert_called_once_with( + url="/testsets/{}".format(cluster_id)) + + session.reset_mock() + + client.get_tests(cluster_id=cluster_id) + + session.get.assert_called_once_with( + url="/tests/{}".format(cluster_id)) + + session.reset_mock() + + client.get_test_runs() + + session.get.assert_called_once_with(url="/testruns") + + def test_test_runs(self, logwrap): + session = self.prepare_session() + client = OSTFClient(session) + + cluster_id = 0 + testrun_id = 0xff + + client.get_test_runs(testrun_id=testrun_id) + session.get.assert_called_once_with( + url="/testruns/{}".format(testrun_id)) + + session.reset_mock() + + client.get_test_runs(testrun_id=testrun_id, cluster_id=cluster_id) + + session.get.assert_called_once_with( + url="/testruns/{}/{}".format(testrun_id, cluster_id)) + + session.reset_mock() + + client.get_test_runs(cluster_id=cluster_id) + + session.get.assert_called_once_with( + url="/testruns/last/{}".format(cluster_id)) + + def test_run_tests(self, logwrap): + session = self.prepare_session() + client = OSTFClient(session) + + cluster_id = 0 + + test_sets = ['smoke'] + + test_name = 'test' + + client.run_tests(cluster_id=cluster_id, test_sets=test_sets) + + json = [ + {'metadata': {'cluster_id': str(cluster_id), 'config': {}}, + 'testset': test_sets[0]}] + + session.post.assert_called_once_with( + "/testruns", json=json + ) + + session.reset_mock() + + # noinspection PyTypeChecker + client.run_tests( + cluster_id=cluster_id, test_sets=test_sets, test_name=test_name) + + json[0]['tests'] = [test_name] + + session.post.assert_called_once_with( + "/testruns", json=json + ) diff --git a/core/models/fuel_client/__init__.py b/core/models/fuel_client/__init__.py new file mode 100644 index 000000000..17c2cdb6b --- /dev/null +++ b/core/models/fuel_client/__init__.py @@ -0,0 +1,17 @@ +# Copyright 2016 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 core.models.fuel_client.client import Client + +__all__ = ['Client'] diff --git a/core/models/fuel_client/base_client.py b/core/models/fuel_client/base_client.py new file mode 100644 index 000000000..03f59472b --- /dev/null +++ b/core/models/fuel_client/base_client.py @@ -0,0 +1,59 @@ +# Copyright 2016 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 __future__ import unicode_literals + + +class Adapter(object): + def __init__(self, session, service_type='fuel'): + self.session = session + self.service_type = service_type + + def __repr__(self): + return ( + "{cls}(" + "session=," + "service_type={svc}" + ") id={id}".format( + cls=self.__class__.__name__, + sess_id=hex(id(self.session)), + svc=self.service_type, + id=hex(id(self)) + )) + + def get(self, url, **kwargs): + kwargs.setdefault( + 'endpoint_filter', {'service_type': self.service_type}) + return self.session.get(url=url, connect_retries=1, **kwargs) + + def delete(self, url, **kwargs): + kwargs.setdefault( + 'endpoint_filter', {'service_type': self.service_type}) + return self.session.delete(url=url, connect_retries=1, **kwargs) + + def post(self, url, **kwargs): + kwargs.setdefault( + 'endpoint_filter', {'service_type': self.service_type}) + return self.session.post(url=url, connect_retries=1, **kwargs) + + def put(self, url, **kwargs): + kwargs.setdefault( + 'endpoint_filter', {'service_type': self.service_type}) + return self.session.put(url=url, connect_retries=1, **kwargs) + + +class BaseClient(object): + def __init__(self, client): + self._client = client diff --git a/core/models/fuel_client/client.py b/core/models/fuel_client/client.py new file mode 100644 index 000000000..b4dacb056 --- /dev/null +++ b/core/models/fuel_client/client.py @@ -0,0 +1,34 @@ +# Copyright 2016 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 __future__ import unicode_literals + +from core import logger +from core.models.fuel_client import base_client +from core.models.fuel_client import ostf_client + + +class Client(object): + def __init__(self, session): + logger.info( + 'Initialization of NailgunClient using shared session \n' + '(auth_url={})'.format(session.auth.auth_url)) + + ostf_clnt = base_client.Adapter(session=session, service_type='ostf') + # TODO(astepanov): use for FUEL functionality: + # clnt = base_client.Adapter(session=session) + + self.ostf = ostf_client.OSTFClient(ostf_clnt) + +__all__ = ['Client'] diff --git a/core/models/fuel_client/ostf_client.py b/core/models/fuel_client/ostf_client.py new file mode 100644 index 000000000..2fa9f031b --- /dev/null +++ b/core/models/fuel_client/ostf_client.py @@ -0,0 +1,79 @@ +# Copyright 2016 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 __future__ import unicode_literals + +from core.helpers.log_helpers import logwrap +from core.models.fuel_client import base_client + + +class OSTFClient(base_client.BaseClient): + @logwrap + def get_test_sets(self, cluster_id): + """get all test sets for a cluster + + :type cluster_id: int + """ + return self._client.get( + url="/testsets/{}".format(cluster_id), + ).json() + + @logwrap + def get_tests(self, cluster_id): + """get all tests for a cluster + + :type cluster_id: int + """ + return self._client.get( + url="/tests/{}".format(cluster_id), + ).json() + + @logwrap + def get_test_runs(self, testrun_id=None, cluster_id=None): + """get test runs results + + :type testrun_id: int + :type cluster_id: int + """ + url = '/testruns' + if testrun_id is not None: + url += '/{}'.format(testrun_id) + if cluster_id is not None: + url += '/{}'.format(cluster_id) + elif cluster_id is not None: + url += '/last/{}'.format(cluster_id) + return self._client.get(url=url).json() + + @logwrap + def run_tests(self, cluster_id, test_sets, test_name=None): + """run tests on specified cluster + + :type cluster_id: int + :type test_sets: list + :type test_name: str + """ + # get tests otherwise 500 error will be thrown6^40 + self.get_tests(cluster_id) + json = [] + for test_set in test_sets: + record = { + 'metadata': {'cluster_id': str(cluster_id), 'config': {}}, + 'testset': test_set + } + if test_name is not None: + record['tests'] = [test_name] + + json.append(record) + + return self._client.post("/testruns", json=json).json() diff --git a/fuelweb_test/models/fuel_web_client.py b/fuelweb_test/models/fuel_web_client.py index c453114e5..819063947 100644 --- a/fuelweb_test/models/fuel_web_client.py +++ b/fuelweb_test/models/fuel_web_client.py @@ -46,6 +46,7 @@ import yaml from core.helpers.log_helpers import logwrap from core.helpers.log_helpers import QuietLogger +from core.models.fuel_client import Client as FuelClient from fuelweb_test import logger from fuelweb_test import ostf_test_mapping @@ -123,6 +124,8 @@ class FuelWebClient29(object): self._session = KeystoneSession(auth=auth, verify=False) self.client = NailgunClient(session=self._session) + self.fuel_client = FuelClient(session=self._session) + self.security = SecurityChecks(self.client, self._environment) super(FuelWebClient29, self).__init__() @@ -146,13 +149,15 @@ class FuelWebClient29(object): logger.info('Wait OSTF tests at cluster #%s for %s seconds', cluster_id, timeout) wait( - lambda: all([run['status'] == 'finished' - for run in - self.client.get_ostf_test_run(cluster_id)]), + lambda: all( + [ + run['status'] == 'finished' for run + in self.fuel_client.ostf.get_test_runs( + cluster_id=cluster_id)]), timeout=timeout, timeout_msg='OSTF tests run timeout ' '(cluster_id={})'.format(cluster_id)) - return self.client.get_ostf_test_run(cluster_id) + return self.fuel_client.ostf.get_test_runs(cluster_id=cluster_id) @logwrap def _tasks_wait(self, tasks, timeout): @@ -1326,7 +1331,7 @@ class FuelWebClient29(object): test_sets = test_sets or ['smoke', 'sanity'] timeout = timeout or 30 * 60 - self.client.ostf_run_tests(cluster_id, test_sets) + self.fuel_client.ostf.run_tests(cluster_id, test_sets) if tests_must_be_passed: self.assert_ostf_run_certain( cluster_id, @@ -1362,7 +1367,7 @@ class FuelWebClient29(object): retries=None, timeout=15 * 60): """Run a single OSTF test""" - self.client.ostf_run_singe_test(cluster_id, test_sets, test_name) + self.fuel_client.ostf.run_tests(cluster_id, test_sets, test_name) if retries: return self.return_ostf_results(cluster_id, timeout=timeout, test_sets=test_sets) @@ -2900,7 +2905,7 @@ class FuelWebClient29(object): @logwrap def get_all_ostf_set_names(self, cluster_id): - sets = self.client.get_ostf_test_sets(cluster_id) + sets = self.fuel_client.ostf.get_test_sets(cluster_id=cluster_id) return [s['id'] for s in sets] @logwrap diff --git a/fuelweb_test/models/nailgun_client.py b/fuelweb_test/models/nailgun_client.py index e0a9d1e18..57b45e780 100644 --- a/fuelweb_test/models/nailgun_client.py +++ b/fuelweb_test/models/nailgun_client.py @@ -15,6 +15,7 @@ from warnings import warn from core.helpers.log_helpers import logwrap +from core.models.fuel_client import Client as FuelClient from fuelweb_test import logger @@ -28,6 +29,7 @@ class NailgunClient(object): logger.info( 'Initialization of NailgunClient using shared session \n' '(auth_url={})'.format(session.auth.auth_url)) + self.client = FuelClient(session=session) self.session = session def __repr__(self): @@ -278,62 +280,41 @@ class NailgunClient(object): # ## OSTF ### @logwrap def get_ostf_test_sets(self, cluster_id): - return self._get( - url="/testsets/{}".format(cluster_id), - endpoint_filter={'service_type': 'ostf'} - ).json() + warn('get_ostf_test_sets has been moved to ' + 'core.models.fuel_client.Client.ostf.get_test_sets', + DeprecationWarning) + return self.client.ostf.get_test_sets(cluster_id=cluster_id) @logwrap def get_ostf_tests(self, cluster_id): - return self._get( - url="/tests/{}".format(cluster_id), - endpoint_filter={'service_type': 'ostf'} - ).json() + warn('get_ostf_tests has been moved to ' + 'core.models.fuel_client.Client.ostf.get_tests', + DeprecationWarning) + return self.client.ostf.get_tests(cluster_id=cluster_id) @logwrap def get_ostf_test_run(self, cluster_id): - return self._get( - url="/testruns/last/{}".format(cluster_id), - endpoint_filter={'service_type': 'ostf'} - ).json() + warn('get_ostf_test_run has been moved to ' + 'core.models.fuel_client.Client.ostf.get_test_runs', + DeprecationWarning) + return self.client.ostf.get_test_runs(cluster_id=cluster_id) @logwrap def ostf_run_tests(self, cluster_id, test_sets_list): - logger.info('Run OSTF tests at cluster #%s: %s', - cluster_id, test_sets_list) - data = [] - for test_set in test_sets_list: - data.append( - { - 'metadata': {'cluster_id': str(cluster_id), 'config': {}}, - 'testset': test_set - } - ) - # get tests otherwise 500 error will be thrown - self.get_ostf_tests(cluster_id) - return self._post( - "/testruns", - json=data, - endpoint_filter={'service_type': 'ostf'}) + warn('ostf_run_tests has been moved to ' + 'core.models.fuel_client.Client.ostf.run_tests', + DeprecationWarning) + return self.client.ostf.run_tests( + cluster_id=cluster_id, test_sets=test_sets_list) @logwrap def ostf_run_singe_test(self, cluster_id, test_sets_list, test_name): - # get tests otherwise 500 error will be thrown - self.get_ostf_tests(cluster_id) - logger.info('Get tests finish with success') - data = [] - for test_set in test_sets_list: - data.append( - { - 'metadata': {'cluster_id': str(cluster_id), 'config': {}}, - 'tests': [test_name], - 'testset': test_set - } - ) - return self._post( - "/testruns", - json=data, - endpoint_filter={'service_type': 'ostf'}).json() + warn('ostf_run_singe_test has been moved to ' + 'core.models.fuel_client.Client.ostf.run_tests', + DeprecationWarning) + return self.client.ostf.run_tests( + cluster_id=cluster_id, test_sets=test_sets_list, + test_name=test_name) # ## /OSTF ### @logwrap diff --git a/fuelweb_test/tests/test_services.py b/fuelweb_test/tests/test_services.py index 9c3a17ac8..89547ca36 100644 --- a/fuelweb_test/tests/test_services.py +++ b/fuelweb_test/tests/test_services.py @@ -432,8 +432,9 @@ class OSTFCeilometerHelper(TestBasic): test_classes.append('{0}.{1}'.format(test_class_main, test_name)) - all_tests = [test['id'] for test - in self.fuel_web.client.get_ostf_tests(cluster_id)] + all_tests = [ + test['id'] for test + in self.fuel_web.fuel_client.ostf.get_tests(cluster_id)] for test_id in test_classes: if test_id in all_tests: @@ -445,7 +446,7 @@ class OSTFCeilometerHelper(TestBasic): test_name = next( test['name'] for test - in self.fuel_web.client.get_ostf_tests(cluster_id) + in self.fuel_web.fuel_client.ostf.get_tests(cluster_id) if test['id'] == test_id) status = next(test.values()[0]