rally/tests/unit/verification/test_config.py
Yaroslav Lobankov 2d9ceb5a34 [Verify] Adding 'add-options' arg to rally verify genconfig cmd
Tempest supports a mechanism that allows us to plug in various tests as
a Tempest plugin. Each plugin needs to be configured in the proper way.
Rally cannot configure all plugins on the planet. We should add some
option that will allow us to add extra configuration for plugins to
Tempest config file.

For example, if we want to run Ceilometer tests, the workflow will be
as follows:

$ rally verify install
$ rally verify installplugin --source https://github.com/openstack/ceilometer.git
$ rally verify genconfig --add-options /path/to/config/file/for/ceilometer/tests
$ rally verify start --regex ceilometer

where config file for Ceilometer tests is something like this:

...
[service_available]

ceilometer = True
event_enabled = True
...

Change-Id: Ida02a36e2757a742ca91919cc756846f137a23d3
2016-08-19 10:32:38 +00:00

481 lines
20 KiB
Python

# Copyright 2014: 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.
import os
import ddt
import mock
from oslo_config import cfg
import requests
import six
from six.moves.urllib import parse
from rally import exceptions
from rally.verification.tempest import config
from tests.unit import fakes
from tests.unit import test
CONF = cfg.CONF
CREDS = {
"admin": {
"username": "admin",
"tenant_name": "admin",
"password": "admin-12345",
"auth_url": "http://test:5000/v2.0/",
"permission": "admin",
"region_name": "test",
"admin_domain_name": "Default",
"https_insecure": False,
"https_cacert": "/path/to/cacert/file"
}
}
@ddt.ddt
class TempestConfigTestCase(test.TestCase):
def setUp(self):
super(TempestConfigTestCase, self).setUp()
mock.patch("rally.common.objects.deploy.db.deployment_get",
return_value=CREDS).start()
mock.patch("rally.osclients.Clients").start()
self.mock_isfile = mock.patch("os.path.isfile",
return_value=True).start()
self.tempest_conf = config.TempestConfig("fake_deployment")
@mock.patch("os.rename")
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open())
@mock.patch("requests.get", return_value=mock.MagicMock(status_code=200))
def test__download_image_success(self, mock_get,
mock_open, mock_rename):
self.mock_isfile.return_value = False
self.tempest_conf._download_image()
mock_get.assert_called_once_with(
CONF.tempest.img_url, stream=True)
@mock.patch("requests.get")
@ddt.data(404, 500)
def test__download_image_failure(self, status_code, mock_get):
self.mock_isfile.return_value = False
mock_get.return_value = mock.MagicMock(status_code=status_code)
self.assertRaises(exceptions.TempestConfigCreationFailure,
self.tempest_conf._download_image)
@mock.patch("requests.get", side_effect=requests.ConnectionError())
def test__download_image_connection_error(self, mock_requests_get):
self.mock_isfile.return_value = False
self.assertRaises(exceptions.TempestConfigCreationFailure,
self.tempest_conf._download_image)
@ddt.data({"publicURL": "test_url"},
{"interface": "public", "url": "test_url"})
def test__get_service_url(self, endpoint):
mock_catalog = mock.MagicMock()
mock_catalog.get_endpoints.return_value = {
"test_service_type": [endpoint]}
self.tempest_conf.keystone.service_catalog = mock_catalog
self.tempest_conf.clients.services.return_value = {
"test_service_type": "test_service"}
self.assertEqual(
self.tempest_conf._get_service_url("test_service"), "test_url")
def test__configure_auth(self):
self.tempest_conf._configure_auth()
expected = (
("admin_username", CREDS["admin"]["username"]),
("admin_password", CREDS["admin"]["password"]),
("admin_project_name", CREDS["admin"]["tenant_name"]),
("admin_domain_name", CREDS["admin"]["admin_domain_name"]))
result = self.tempest_conf.conf.items("auth")
for item in expected:
self.assertIn(item, result)
@ddt.data("data_processing", "data-processing")
def test__configure_data_processing(self, service_type):
self.tempest_conf.available_services = ["sahara"]
self.tempest_conf.clients.services.return_value = {
service_type: "sahara"}
self.tempest_conf._configure_data_processing()
self.assertEqual(
self.tempest_conf.conf.get(
"data-processing", "catalog_type"), service_type)
def test__configure_identity(self):
self.tempest_conf._configure_identity()
expected = (
("region", CREDS["admin"]["region_name"]),
("auth_version", "v2"),
("uri", CREDS["admin"]["auth_url"][:-1]),
("uri_v3", CREDS["admin"]["auth_url"].replace("/v2.0/", "/v3")),
("disable_ssl_certificate_validation",
str(CREDS["admin"]["https_insecure"])),
("ca_certificates_file", CREDS["admin"]["https_cacert"]))
result = self.tempest_conf.conf.items("identity")
for item in expected:
self.assertIn(item, result)
def test__configure_network_if_neutron(self):
self.tempest_conf.available_services = ["neutron"]
client = self.tempest_conf.clients.neutron()
client.list_networks.return_value = {
"networks": [
{
"status": "ACTIVE",
"id": "test_id",
"router:external": True
}
]
}
self.tempest_conf._configure_network()
self.assertEqual(
self.tempest_conf.conf.get("network",
"public_network_id"), "test_id")
def test__configure_network_if_nova(self):
self.tempest_conf.available_services = ["nova"]
client = self.tempest_conf.clients.nova()
client.networks.list.return_value = [
mock.MagicMock(human_id="fake-network")]
self.tempest_conf._configure_network()
expected = {"compute": ("fixed_network_name", "fake-network"),
"validation": ("network_for_ssh", "fake-network")}
for section, option in six.iteritems(expected):
result = self.tempest_conf.conf.items(section)
self.assertIn(option, result)
@ddt.data({}, {"version": "4.1.0", "args": ("extensions", "/extensions"),
"kwargs": {"retrieve_all": True}})
@ddt.unpack
def test__configure_network_feature_enabled(
self, version="4.0.0", args=("/extensions",), kwargs={}):
self.tempest_conf.available_services = ["neutron"]
client = self.tempest_conf.clients.neutron()
client.list_ext.return_value = {
"extensions": [
{"alias": "dvr"},
{"alias": "extra_dhcp_opt"},
{"alias": "extraroute"}
]
}
mock.patch("neutronclient.version.__version__", version).start()
self.tempest_conf._configure_network_feature_enabled()
client.list_ext.assert_called_once_with(*args, **kwargs)
self.assertEqual(self.tempest_conf.conf.get(
"network-feature-enabled", "api_extensions"),
"dvr,extra_dhcp_opt,extraroute")
@mock.patch("os.makedirs")
@mock.patch("os.path.exists", return_value=False)
def test__configure_oslo_concurrency(self, mock_exists, mock_makedirs):
self.tempest_conf._configure_oslo_concurrency()
lock_path = os.path.join(
self.tempest_conf.data_dir, "lock_files_fake_deployment")
mock_makedirs.assert_called_with(lock_path)
self.assertEqual(
self.tempest_conf.conf.get(
"oslo_concurrency", "lock_path"), lock_path)
def test__configure_object_storage(self):
self.tempest_conf._configure_object_storage()
expected = (
("operator_role", CONF.tempest.swift_operator_role),
("reseller_admin_role", CONF.tempest.swift_reseller_admin_role))
result = self.tempest_conf.conf.items("object-storage")
for item in expected:
self.assertIn(item, result)
def test__configure_orchestration(self):
self.tempest_conf._configure_orchestration()
expected = (
("stack_owner_role", CONF.tempest.heat_stack_owner_role),
("stack_user_role", CONF.tempest.heat_stack_user_role))
result = self.tempest_conf.conf.items("orchestration")
for item in expected:
self.assertIn(item, result)
def test__configure_scenario(self):
self.tempest_conf._configure_scenario()
image_name = parse.urlparse(
config.CONF.tempest.img_url).path.split("/")[-1]
expected = (("img_dir", self.tempest_conf.data_dir),
("img_file", image_name))
result = self.tempest_conf.conf.items("scenario")
for item in expected:
self.assertIn(item, result)
def test__configure_service_available(self):
available_services = ("nova", "cinder", "glance", "sahara")
self.tempest_conf.available_services = available_services
self.tempest_conf._configure_service_available()
expected = (
("neutron", "False"), ("heat", "False"), ("nova", "True"),
("swift", "False"), ("cinder", "True"), ("sahara", "True"),
("glance", "True"))
result = self.tempest_conf.conf.items("service_available")
for item in expected:
self.assertIn(item, result)
@ddt.data({}, {"service": "neutron", "connect_method": "floating"})
@ddt.unpack
def test__configure_validation(self, service="nova",
connect_method="fixed"):
self.tempest_conf.available_services = [service]
self.tempest_conf._configure_validation()
expected = (("run_validation", "True"),
("connect_method", connect_method))
result = self.tempest_conf.conf.items("validation")
for item in expected:
self.assertIn(item, result)
@mock.patch("rally.verification.tempest.config._write_config")
@mock.patch("inspect.getmembers")
def test_generate(self, mock_inspect_getmembers, mock__write_config):
configure_something_method = mock.MagicMock()
mock_inspect_getmembers.return_value = [("_configure_something",
configure_something_method)]
fake_extra_conf = mock.MagicMock()
fake_extra_conf.sections.return_value = ["section"]
fake_extra_conf.items.return_value = [("option", "value")]
self.tempest_conf.generate("/path/to/fake/conf", fake_extra_conf)
self.assertEqual(configure_something_method.call_count, 1)
self.assertIn(("option", "value"),
self.tempest_conf.conf.items("section"))
self.assertEqual(mock__write_config.call_count, 1)
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open())
def test__write_config(self, mock_open):
conf_path = "/path/to/fake/conf"
conf_data = mock.Mock()
config._write_config(conf_path, conf_data)
mock_open.assert_called_once_with(conf_path, "w+")
conf_data.write.assert_called_once_with(mock_open.side_effect())
class TempestResourcesContextTestCase(test.TestCase):
def setUp(self):
super(TempestResourcesContextTestCase, self).setUp()
mock.patch("rally.common.objects.deploy.db.deployment_get",
return_value=CREDS).start()
mock.patch("rally.osclients.Clients").start()
fake_verification = {"uuid": "uuid"}
self.context = config.TempestResourcesContext("fake_deployment",
fake_verification,
"/fake/path/to/config")
self.context.conf.add_section("compute")
self.context.conf.add_section("orchestration")
@mock.patch("rally.plugins.openstack.wrappers."
"network.NeutronWrapper.create_network")
@mock.patch("six.moves.builtins.open", side_effect=mock.mock_open())
def test_options_configured_manually(
self, mock_open, mock_neutron_wrapper_create_network):
self.context.available_services = ["glance", "heat", "nova", "neutron"]
self.context.conf.set("compute", "image_ref", "id1")
self.context.conf.set("compute", "image_ref_alt", "id2")
self.context.conf.set("compute", "flavor_ref", "id3")
self.context.conf.set("compute", "flavor_ref_alt", "id4")
self.context.conf.set("compute", "fixed_network_name", "name1")
self.context.conf.set("orchestration", "instance_type", "id5")
self.context.__enter__()
glanceclient = self.context.clients.glance()
novaclient = self.context.clients.nova()
self.assertEqual(glanceclient.images.create.call_count, 0)
self.assertEqual(novaclient.flavors.create.call_count, 0)
self.assertEqual(mock_neutron_wrapper_create_network.call_count, 0)
def test__create_tempest_roles(self):
role1 = CONF.tempest.swift_operator_role
role2 = CONF.tempest.swift_reseller_admin_role
role3 = CONF.tempest.heat_stack_owner_role
role4 = CONF.tempest.heat_stack_user_role
client = self.context.clients.verified_keystone()
client.roles.list.return_value = [fakes.FakeRole(name=role1),
fakes.FakeRole(name=role2)]
client.roles.create.side_effect = [fakes.FakeFlavor(name=role3),
fakes.FakeFlavor(name=role4)]
self.context._create_tempest_roles()
self.assertEqual(client.roles.create.call_count, 2)
created_roles = [role.name for role in self.context._created_roles]
self.assertIn(role3, created_roles)
self.assertIn(role4, created_roles)
# We can choose any option to test the '_configure_option' method. So let's
# configure the 'flavor_ref' option.
def test__configure_option(self):
create_method = mock.MagicMock()
create_method.side_effect = [fakes.FakeFlavor(id="id1")]
self.context.conf.set("compute", "flavor_ref", "")
self.context._configure_option("compute",
"flavor_ref", create_method, 64)
self.assertEqual(create_method.call_count, 1)
result = self.context.conf.get("compute", "flavor_ref")
self.assertEqual("id1", result)
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
def test__discover_or_create_image_when_image_exists(self, mock_wrap):
client = mock_wrap.return_value
client.list_images.return_value = [fakes.FakeImage(name="CirrOS")]
image = self.context._discover_or_create_image()
self.assertEqual("CirrOS", image.name)
self.assertEqual(0, client.create_image.call_count)
self.assertEqual(0, len(self.context._created_images))
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
def test__discover_or_create_image(self, mock_wrap):
client = mock_wrap.return_value
image = self.context._discover_or_create_image()
self.assertEqual(image, client.create_image.return_value)
self.assertEqual(self.context._created_images[0],
client.create_image.return_value)
mock_wrap.assert_called_once_with(self.context.clients.glance,
self.context)
client.create_image.assert_called_once_with(
container_format=CONF.tempest.img_container_format,
image_location=mock.ANY,
disk_format=CONF.tempest.img_disk_format,
name=mock.ANY,
visibility="public")
def test__discover_or_create_flavor_when_flavor_exists(self):
client = self.context.clients.nova()
client.flavors.list.return_value = [fakes.FakeFlavor(id="id1", ram=64,
vcpus=1, disk=0)]
flavor = self.context._discover_or_create_flavor(64)
self.assertEqual("id1", flavor.id)
self.assertEqual(0, len(self.context._created_flavors))
def test__discover_or_create_flavor(self):
client = self.context.clients.nova()
client.flavors.create.side_effect = [fakes.FakeFlavor(id="id1")]
flavor = self.context._discover_or_create_flavor(64)
self.assertEqual("id1", flavor.id)
self.assertEqual("id1", self.context._created_flavors[0].id)
def test__create_network_resources(self):
client = self.context.clients.neutron()
fake_network = {
"id": "nid1",
"name": "network",
"status": "status"}
client.create_network.side_effect = [{"network": fake_network}]
client.create_router.side_effect = [{"router": {"id": "rid1"}}]
client.create_subnet.side_effect = [{"subnet": {"id": "subid1"}}]
network = self.context._create_network_resources()
self.assertEqual("nid1", network["id"])
self.assertEqual("nid1", self.context._created_networks[0]["id"])
self.assertEqual("rid1",
self.context._created_networks[0]["router_id"])
self.assertEqual("subid1",
self.context._created_networks[0]["subnets"][0])
def test__cleanup_tempest_roles(self):
self.context._created_roles = [fakes.FakeRole(), fakes.FakeRole()]
self.context._cleanup_tempest_roles()
client = self.context.clients.keystone()
self.assertEqual(client.roles.delete.call_count, 2)
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
def test__cleanup_images(self, mock_wrap):
self.context._created_images = [fakes.FakeImage(id="id1"),
fakes.FakeImage(id="id2")]
self.context.conf.set("compute", "image_ref", "id1")
self.context.conf.set("compute", "image_ref_alt", "id2")
wrapper = mock_wrap.return_value
wrapper.get_image.side_effect = [
fakes.FakeImage(id="id1", status="DELETED"),
fakes.FakeImage(id="id2"),
fakes.FakeImage(id="id2", status="DELETED")]
self.context._cleanup_images()
client = self.context.clients.glance()
client.images.delete.assert_has_calls([mock.call("id1"),
mock.call("id2")])
self.assertEqual("", self.context.conf.get("compute", "image_ref"))
self.assertEqual("", self.context.conf.get("compute", "image_ref_alt"))
def test__cleanup_flavors(self):
self.context._created_flavors = [fakes.FakeFlavor(id="id1"),
fakes.FakeFlavor(id="id2"),
fakes.FakeFlavor(id="id3")]
self.context.conf.set("compute", "flavor_ref", "id1")
self.context.conf.set("compute", "flavor_ref_alt", "id2")
self.context.conf.set("orchestration", "instance_type", "id3")
self.context._cleanup_flavors()
client = self.context.clients.nova()
self.assertEqual(client.flavors.delete.call_count, 3)
self.assertEqual("", self.context.conf.get("compute", "flavor_ref"))
self.assertEqual("", self.context.conf.get("compute",
"flavor_ref_alt"))
self.assertEqual("", self.context.conf.get("orchestration",
"instance_type"))
@mock.patch("rally.plugins.openstack.wrappers."
"network.NeutronWrapper.delete_network")
def test__cleanup_network_resources(
self, mock_neutron_wrapper_delete_network):
self.context._created_networks = [{"name": "net-12345"}]
self.context.conf.set("compute", "fixed_network_name", "net-12345")
self.context._cleanup_network_resources()
self.assertEqual(mock_neutron_wrapper_delete_network.call_count, 1)
self.assertEqual("", self.context.conf.get("compute",
"fixed_network_name"))