Files
deb-python-fuelclient/fuelclient/tests/test_plugins_object.py
Evgeniy L 218abd03d0 Fix exception when plugin is being installed with --force
"put_request" does not return the request object,
it returns dict ready to use dict.

Change-Id: I4f2a18274e70e8687e2e9c83fc91081b0fa7bf2c
Implements: blueprint plugins-security-fixes-delivery
2015-03-04 16:54:09 +03:00

410 lines
16 KiB
Python

# -*- coding: utf-8 -*-
#
# 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.
import mock
from mock import MagicMock
from mock import patch
from fuelclient.cli import error
from fuelclient.objects.plugins import Plugins
from fuelclient.objects.plugins import PluginV1
from fuelclient.objects.plugins import PluginV2
from fuelclient.tests import base
@patch('fuelclient.objects.plugins.raise_error_if_not_master')
class TestPluginV1(base.UnitTestCase):
fake_meta = """
name: 'plugin_name'
version: 'version'
"""
def setUp(self):
super(TestPluginV1, self).setUp()
self.plugin = PluginV1
self.path = '/tmp/plugin/path'
self.name = 'plugin_name'
self.version = 'version'
@patch('fuelclient.objects.plugins.tarfile')
def test_install(self, tar_mock, master_only_mock):
tar_obj = MagicMock()
tar_mock.open.return_value = tar_obj
self.plugin.install(self.path)
master_only_mock.assert_called_once_with()
tar_obj.extractall.assert_called_once_with('/var/www/nailgun/plugins/')
tar_obj.close.assert_called_once_with()
@patch('fuelclient.objects.plugins.shutil.rmtree')
def test_remove(self, rmtree_mock, master_only_mock):
self.plugin.remove(self.name, self.version)
master_only_mock.assert_called_once_with()
rmtree_mock.assert_called_once_with(
'/var/www/nailgun/plugins/plugin_name-version')
def test_update(self, _):
self.assertRaisesRegexp(
error.BadDataException,
'Update action is not supported for old plugins with '
'package version "1.0.0", you can install your plugin '
'or use newer plugin format.',
self.plugin.update, 'some_string')
def test_downgrade(self, _):
self.assertRaisesRegexp(
error.BadDataException,
'Downgrade action is not supported for old plugins with '
'package version "1.0.0", you can install your plugin '
'or use newer plugin format.',
self.plugin.downgrade, 'some_string')
def mock_tar(self, tar_mock):
tar_obj = MagicMock()
tar_mock.open.return_value = tar_obj
tar_file = MagicMock()
tar_obj.getnames.return_value = ['metadata.yaml']
tar_obj.extractfile.return_value = tar_file
tar_file.read.return_value = self.fake_meta
@patch('fuelclient.objects.plugins.tarfile')
def test_name_from_file(self, tar_mock, _):
self.mock_tar(tar_mock)
self.assertEqual(
self.plugin.name_from_file(self.path),
self.name)
@patch('fuelclient.objects.plugins.tarfile')
def test_version_from_file(self, tar_mock, _):
self.mock_tar(tar_mock)
self.assertEqual(
self.plugin.version_from_file(self.path),
self.version)
@patch('fuelclient.objects.plugins.raise_error_if_not_master')
class TestPluginV2(base.UnitTestCase):
def setUp(self):
super(TestPluginV2, self).setUp()
self.plugin = PluginV2
self.path = '/tmp/plugin/path'
self.name = 'plugin_name'
self.version = '1.2.3'
@patch('fuelclient.objects.plugins.utils.exec_cmd')
def test_install(self, exec_mock, master_only_mock):
self.plugin.install(self.path)
exec_mock.assert_called_once_with('yum -y install /tmp/plugin/path')
master_only_mock.assert_called_once_with()
@patch('fuelclient.objects.plugins.utils.exec_cmd')
def test_install_w_force(self, exec_mock, master_only_mock):
self.plugin.install(self.path, force=True)
exec_mock.assert_called_once_with('yum -y reinstall /tmp/plugin/path')
master_only_mock.assert_called_once_with()
@patch('fuelclient.objects.plugins.utils.exec_cmd')
def test_remove(self, exec_mock, master_only_mock):
self.plugin.remove(self.name, self.version)
exec_mock.assert_called_once_with('yum -y remove plugin_name-1.2')
master_only_mock.assert_called_once_with()
@patch('fuelclient.objects.plugins.utils.exec_cmd')
def test_update(self, exec_mock, master_only_mock):
self.plugin.update(self.path)
exec_mock.assert_called_once_with('yum -y update /tmp/plugin/path')
master_only_mock.assert_called_once_with()
@patch('fuelclient.objects.plugins.utils.exec_cmd')
def test_downgrade(self, exec_mock, master_only_mock):
self.plugin.downgrade(self.path)
exec_mock.assert_called_once_with('yum -y downgrade /tmp/plugin/path')
master_only_mock.assert_called_once_with()
@patch('fuelclient.objects.plugins.utils.exec_cmd_iterator',
return_value=['plugin_name-1.2'])
def test_name_from_file(self, exec_mock, _):
self.assertEqual(
self.plugin.name_from_file(self.path),
self.name)
exec_mock.assert_called_once_with(
"rpm -qp --queryformat '%{name}' /tmp/plugin/path")
@patch('fuelclient.objects.plugins.utils.exec_cmd_iterator',
return_value=['1.2.3'])
def test_version_from_file(self, exec_mock, _):
self.assertEqual(
self.plugin.version_from_file(self.path),
self.version)
exec_mock.assert_called_once_with(
"rpm -qp --queryformat '%{version}' /tmp/plugin/path")
class TestPluginsObject(base.UnitTestCase):
def setUp(self):
super(TestPluginsObject, self).setUp()
self.plugin = Plugins
self.path = '/tmp/plugin/path'
self.name = 'plugin_name'
self.version = 'version'
def mock_make_obj_by_file(self, make_obj_by_file_mock):
plugin_obj = MagicMock()
plugin_obj.name_from_file.return_value = 'retrieved_name'
plugin_obj.version_from_file.return_value = 'retrieved_version'
make_obj_by_file_mock.return_value = plugin_obj
return plugin_obj
@patch('fuelclient.utils.glob_and_parse_yaml',
return_value=[
{'name': 'name1', 'version': 'version1'},
{'name': 'name2', 'version': 'version2'},
{'name': 'name3', 'version': 'version3'}])
@patch.object(Plugins, 'update_or_create')
def test_register(self, up_or_create_mock, glob_parse_mock):
self.plugin.register('name3', 'version3')
glob_parse_mock.assert_called_once_with(
'/var/www/nailgun/plugins/*/metadata.yaml')
up_or_create_mock.assert_called_once_with(
{'name': 'name3', 'version': 'version3'},
force=False)
@patch('fuelclient.utils.glob_and_parse_yaml', return_value=[])
def test_register_raises_error(self, glob_parse_mock):
self.assertRaisesRegexp(
error.BadDataException,
'Plugin name3 with version version3 does '
'not exist, install it and try again',
self.plugin.register, 'name3', 'version3')
glob_parse_mock.assert_called_once_with(
'/var/www/nailgun/plugins/*/metadata.yaml')
@patch.object(Plugins, 'get_plugin', return_value={'id': 123})
@patch.object(Plugins.connection, 'delete_request')
def test_unregister(self, del_mock, get_mock):
self.plugin.unregister(self.name, self.version)
get_mock.assert_called_once_with(self.name, self.version)
del_mock.assert_called_once_with('plugins/123')
@patch.object(Plugins, 'register')
@patch.object(Plugins, 'make_obj_by_file')
def test_install(self, make_obj_by_file_mock, register_mock):
plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock)
self.plugin.install(self.path)
plugin_obj.install.assert_called_once_with(self.path, force=False)
register_mock.assert_called_once_with(
'retrieved_name', 'retrieved_version', force=False)
@patch.object(Plugins, 'unregister')
@patch.object(Plugins, 'make_obj_by_name')
def test_remove(self, make_obj_by_name_mock, unregister_mock):
plugin_obj = MagicMock()
make_obj_by_name_mock.return_value = plugin_obj
self.plugin.remove(self.name, self.version)
plugin_obj.remove.assert_called_once_with(self.name, self.version)
unregister_mock.assert_called_once_with(self.name, self.version)
@patch('fuelclient.utils.glob_and_parse_yaml',
return_value=['meta1', 'meta2'])
@patch.object(Plugins, 'update_or_create')
def test_sync(self, up_or_create_mock, glob_and_parse_mock):
self.plugin.sync()
glob_and_parse_mock.assert_called_once_with(
'/var/www/nailgun/plugins/*/metadata.yaml')
self.assertEqual(
up_or_create_mock.call_args_list,
[mock.call('meta1', force=True),
mock.call('meta2', force=True)])
@patch.object(Plugins, 'register')
@patch.object(Plugins, 'make_obj_by_file')
def test_update(self, make_obj_by_file_mock, register_mock):
plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock)
self.plugin.update(self.path)
plugin_obj.update.assert_called_once_with(self.path)
register_mock.assert_called_once_with(
'retrieved_name', 'retrieved_version')
@patch.object(Plugins, 'register')
@patch.object(Plugins, 'make_obj_by_file')
def test_downgrade(self, make_obj_by_file_mock, register_mock):
plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock)
self.plugin.downgrade(self.path)
plugin_obj.downgrade.assert_called_once_with(self.path)
register_mock.assert_called_once_with(
'retrieved_name', 'retrieved_version')
@patch.object(Plugins, 'get_plugin')
def test_make_obj_by_name_v1(self, get_mock):
plugins = [{'package_version': '1.0.0'},
{'package_version': '1.0.1'},
{'package_version': '1.99.99'}]
for plugin in plugins:
get_mock.return_value = plugin
self.assertEqual(
self.plugin.make_obj_by_name(self.name, self.version),
PluginV1)
@patch.object(Plugins, 'get_plugin')
def test_make_obj_by_name_v2(self, get_mock):
plugins = [{'package_version': '2.0.0'},
{'package_version': '2.0.1'},
{'package_version': '3.0.0'}]
for plugin in plugins:
get_mock.return_value = plugin
self.assertEqual(
self.plugin.make_obj_by_name(self.name, self.version),
PluginV2)
@patch.object(Plugins, 'get_plugin')
def test_make_obj_by_name_v2_raises_error(self, get_mock):
get_mock.return_value = {'package_version': '0.0.1'}
self.assertRaisesRegexp(
error.BadDataException,
'Plugin plugin_name==version has '
'unsupported package version 0.0.1',
self.plugin.make_obj_by_name, self.name, self.version)
def test_make_obj_by_file_v1(self):
self.assertEqual(
self.plugin.make_obj_by_file('file-name-1.2.3.fp'),
PluginV1)
def test_make_obj_by_file_v2(self):
self.assertEqual(
self.plugin.make_obj_by_file('file-name-1.2-1.2.3-0.noarch.rpm'),
PluginV2)
def test_make_obj_by_file_raises_error(self):
self.assertRaisesRegexp(
error.BadDataException,
'Plugin file-name.ext has unsupported format .ext',
self.plugin.make_obj_by_file, 'file-name.ext')
@patch.object(Plugins, 'get_plugin_for_update', return_value={'id': 99})
@patch.object(Plugins.connection, 'put_request', return_value={'id': 99})
def test_update_or_create_updates(self, put_mock, get_for_update_mock):
meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0'}
self.plugin.update_or_create(meta)
put_mock.assert_called_once_with('plugins/99', meta)
@patch.object(Plugins, 'get_plugin_for_update', return_value=None)
@patch.object(Plugins.connection, 'post_request_raw',
return_value=MagicMock(status_code=201))
@patch.object(Plugins.connection, 'put_request')
def test_update_or_create_creates(
self, put_mock, post_mock, get_for_update_mock):
meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0'}
self.plugin.update_or_create(meta)
post_mock.assert_called_once_with('plugins/', meta)
get_for_update_mock.assert_called_once_with(meta)
self.assertFalse(put_mock.called)
@patch.object(Plugins, 'get_plugin_for_update', return_value=None)
@patch.object(Plugins.connection, 'post_request_raw',
return_value=MagicMock(
status_code=409,
**{'json.return_value': {'id': 99}}))
@patch.object(Plugins.connection, 'put_request', return_value='put_return')
def test_update_or_create_updates_with_force(
self, put_mock, post_mock, get_for_update_mock):
meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0'}
self.assertEqual(
self.plugin.update_or_create(meta, force=True),
'put_return')
post_mock.assert_called_once_with('plugins/', meta)
get_for_update_mock.assert_called_once_with(meta)
put_mock.assert_called_once_with('plugins/99', meta)
@patch.object(Plugins, 'get_all_data')
def test_get_plugin_for_update(self, get_mock):
plugin_to_be_found = {'name': 'name', 'version': '2.2.0',
'package_version': '2.0.0'}
get_mock.return_value = [
# Different major version
{'name': 'name', 'version': '2.3.0',
'package_version': '2.0.0'},
{'name': 'name', 'version': '2.1.0',
'package_version': '2.0.0'},
# Different name
{'name': 'different_name', 'version': '2.2.99',
'package_version': '2.0.0'},
# Package version is not updatable
{'name': 'name', 'version': '2.2.100',
'package_version': '1.0.0'},
plugin_to_be_found]
self.assertEqual(
self.plugin.get_plugin_for_update(
{'name': 'name',
'version': '2.2.99',
'package_version': '2.0.0'}),
plugin_to_be_found)
# Required plugin has not updatable package version
self.assertIsNone(self.plugin.get_plugin_for_update(
{'name': 'name', 'version': '2.2.99', 'package_version': '1.0.0'}))
# Plugin does not exist
self.assertIsNone(self.plugin.get_plugin_for_update(
{'name': 'name2', 'version': '2.2.9', 'package_version': '2.0.0'}))
def test_is_updatable(self):
for updatable in ['2.0.0', '2.0.1', '99.99.99']:
self.assertTrue(self.plugin.is_updatable(updatable))
for is_not_updatable in ['0.0.1', '1.0.0', '1.99.99']:
self.assertFalse(self.plugin.is_updatable(is_not_updatable))
@patch.object(Plugins, 'get_all_data',
return_value=[{'name': 'name1', 'version': '1.0.0'},
{'name': 'name2', 'version': '1.0.1'},
{'name': 'name2', 'version': '1.0.0'}])
def test_get_plugin(self, get_mock):
self.assertEqual(self.plugin.get_plugin('name2', '1.0.0'),
{'name': 'name2', 'version': '1.0.0'})
get_mock.assert_called_once_with()