neutron/neutron/tests/unit/extensions/test_flavors.py

735 lines
31 KiB
Python

#
# 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 copy
from unittest import mock
import fixtures
from neutron_lib import context
from neutron_lib.db import api as db_api
from neutron_lib.db import constants as db_const
from neutron_lib.exceptions import flavors as flav_exc
from neutron_lib.plugins import constants
from oslo_config import cfg
from oslo_utils import uuidutils
from webob import exc
from neutron.db.models import l3 as l3_models
from neutron.db import servicetype_db
from neutron.extensions import flavors
from neutron.objects import flavor as flavor_obj
from neutron.services.flavors import flavors_plugin
from neutron.services import provider_configuration as provconf
from neutron.tests import base
from neutron.tests.unit.api.v2 import test_base
from neutron.tests.unit.db import test_db_base_plugin_v2
from neutron.tests.unit import dummy_plugin
from neutron.tests.unit.extensions import base as extension
_uuid = uuidutils.generate_uuid
_get_path = test_base._get_path
_driver = ('neutron.tests.unit.extensions.test_flavors.'
'DummyServiceDriver')
_provider = dummy_plugin.RESOURCE_NAME
_long_name = 'x' * (db_const.NAME_FIELD_SIZE + 1)
_long_description = 'x' * (db_const.LONG_DESCRIPTION_FIELD_SIZE + 1)
class FlavorExtensionTestCase(extension.ExtensionTestCase):
def setUp(self):
super(FlavorExtensionTestCase, self).setUp()
self.setup_extension(
'neutron.services.flavors.flavors_plugin.FlavorsPlugin',
constants.FLAVORS, flavors.Flavors, '',
supported_extension_aliases=['flavors'])
def test_create_flavor(self):
tenant_id = uuidutils.generate_uuid()
# Use service_type FLAVORS since plugin must be loaded to validate
data = {'flavor': {'name': 'GOLD',
'service_type': constants.FLAVORS,
'description': 'the best flavor',
'tenant_id': tenant_id,
'project_id': tenant_id,
'enabled': True}}
expected = copy.deepcopy(data)
expected['flavor']['service_profiles'] = []
instance = self.plugin.return_value
instance.create_flavor.return_value = expected['flavor']
res = self.api.post(_get_path('flavors', fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt)
instance.create_flavor.assert_called_with(mock.ANY,
flavor=expected)
res = self.deserialize(res)
self.assertIn('flavor', res)
self.assertEqual(expected, res)
def test_create_flavor_invalid_service_type(self):
tenant_id = uuidutils.generate_uuid()
data = {'flavor': {'name': 'GOLD',
'service_type': 'BROKEN',
'description': 'the best flavor',
'tenant_id': tenant_id,
'enabled': True}}
self.api.post(_get_path('flavors', fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_create_flavor_too_long_name(self):
tenant_id = uuidutils.generate_uuid()
data = {'flavor': {'name': _long_name,
'service_type': constants.FLAVORS,
'description': 'the best flavor',
'tenant_id': tenant_id,
'enabled': True}}
self.api.post(_get_path('flavors', fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_create_flavor_too_long_description(self):
tenant_id = uuidutils.generate_uuid()
data = {'flavor': {'name': _long_name,
'service_type': constants.FLAVORS,
'description': _long_description,
'tenant_id': tenant_id,
'enabled': True}}
self.api.post(_get_path('flavors', fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_create_flavor_invalid_enabled(self):
tenant_id = uuidutils.generate_uuid()
data = {'flavor': {'name': _long_name,
'service_type': constants.FLAVORS,
'description': 'the best flavor',
'tenant_id': tenant_id,
'enabled': 'BROKEN'}}
self.api.post(_get_path('flavors', fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_update_flavor(self):
flavor_id = 'fake_id'
data = {'flavor': {'name': 'GOLD',
'description': 'the best flavor',
'enabled': True}}
expected = copy.copy(data)
expected['flavor']['service_profiles'] = []
instance = self.plugin.return_value
instance.update_flavor.return_value = expected['flavor']
res = self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt)
instance.update_flavor.assert_called_with(mock.ANY,
flavor_id,
flavor=expected)
res = self.deserialize(res)
self.assertIn('flavor', res)
self.assertEqual(expected, res)
def test_update_flavor_too_long_name(self):
flavor_id = 'fake_id'
data = {'flavor': {'name': _long_name,
'description': 'the best flavor',
'enabled': True}}
self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_update_flavor_too_long_description(self):
flavor_id = 'fake_id'
data = {'flavor': {'name': 'GOLD',
'description': _long_description,
'enabled': True}}
self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_update_flavor_invalid_enabled(self):
flavor_id = 'fake_id'
data = {'flavor': {'name': 'GOLD',
'description': _long_description,
'enabled': 'BROKEN'}}
self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_delete_flavor(self):
flavor_id = 'fake_id'
instance = self.plugin.return_value
self.api.delete(_get_path('flavors', id=flavor_id, fmt=self.fmt),
content_type='application/%s' % self.fmt)
instance.delete_flavor.assert_called_with(mock.ANY,
flavor_id)
def test_show_flavor(self):
flavor_id = 'fake_id'
expected = {'flavor': {'id': flavor_id,
'name': 'GOLD',
'description': 'the best flavor',
'enabled': True,
'service_profiles': ['profile-1']}}
instance = self.plugin.return_value
instance.get_flavor.return_value = expected['flavor']
res = self.api.get(_get_path('flavors', id=flavor_id, fmt=self.fmt))
instance.get_flavor.assert_called_with(mock.ANY,
flavor_id,
fields=mock.ANY)
res = self.deserialize(res)
self.assertEqual(expected, res)
def test_get_flavors(self):
data = {'flavors': [{'id': 'id1',
'name': 'GOLD',
'description': 'the best flavor',
'enabled': True,
'service_profiles': ['profile-1']},
{'id': 'id2',
'name': 'GOLD',
'description': 'the best flavor',
'enabled': True,
'service_profiles': ['profile-2', 'profile-1']}]}
instance = self.plugin.return_value
instance.get_flavors.return_value = data['flavors']
res = self.api.get(_get_path('flavors', fmt=self.fmt))
instance.get_flavors.assert_called_with(mock.ANY,
fields=mock.ANY,
filters=mock.ANY)
res = self.deserialize(res)
self.assertEqual(data, res)
def test_create_service_profile(self):
tenant_id = uuidutils.generate_uuid()
expected = {'service_profile': {'description': 'the best sp',
'driver': '',
'tenant_id': tenant_id,
'project_id': tenant_id,
'enabled': True,
'metainfo': '{"data": "value"}'}}
instance = self.plugin.return_value
instance.create_service_profile.return_value = (
expected['service_profile'])
res = self.api.post(_get_path('service_profiles', fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt)
instance.create_service_profile.assert_called_with(
mock.ANY,
service_profile=expected)
res = self.deserialize(res)
self.assertIn('service_profile', res)
self.assertEqual(expected, res)
def test_create_service_profile_too_long_description(self):
tenant_id = uuidutils.generate_uuid()
expected = {'service_profile': {'description': _long_description,
'driver': '',
'tenant_id': tenant_id,
'enabled': True,
'metainfo': '{"data": "value"}'}}
self.api.post(_get_path('service_profiles', fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_create_service_profile_too_long_driver(self):
tenant_id = uuidutils.generate_uuid()
expected = {'service_profile': {'description': 'the best sp',
'driver': _long_description,
'tenant_id': tenant_id,
'enabled': True,
'metainfo': '{"data": "value"}'}}
self.api.post(_get_path('service_profiles', fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_create_service_profile_invalid_enabled(self):
tenant_id = uuidutils.generate_uuid()
expected = {'service_profile': {'description': 'the best sp',
'driver': '',
'tenant_id': tenant_id,
'enabled': 'BROKEN',
'metainfo': '{"data": "value"}'}}
self.api.post(_get_path('service_profiles', fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_update_service_profile(self):
sp_id = "fake_id"
expected = {'service_profile': {'description': 'the best sp',
'enabled': False,
'metainfo': '{"data1": "value3"}'}}
instance = self.plugin.return_value
instance.update_service_profile.return_value = (
expected['service_profile'])
res = self.api.put(_get_path('service_profiles',
id=sp_id, fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt)
instance.update_service_profile.assert_called_with(
mock.ANY,
sp_id,
service_profile=expected)
res = self.deserialize(res)
self.assertIn('service_profile', res)
self.assertEqual(expected, res)
def test_update_service_profile_too_long_description(self):
sp_id = "fake_id"
expected = {'service_profile': {'description': 'the best sp',
'enabled': 'BROKEN',
'metainfo': '{"data1": "value3"}'}}
self.api.put(_get_path('service_profiles',
id=sp_id, fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_update_service_profile_invalid_enabled(self):
sp_id = "fake_id"
expected = {'service_profile': {'description': 'the best sp',
'enabled': 'BROKEN',
'metainfo': '{"data1": "value3"}'}}
self.api.put(_get_path('service_profiles',
id=sp_id, fmt=self.fmt),
self.serialize(expected),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
def test_delete_service_profile(self):
sp_id = 'fake_id'
instance = self.plugin.return_value
self.api.delete(_get_path('service_profiles', id=sp_id, fmt=self.fmt),
content_type='application/%s' % self.fmt)
instance.delete_service_profile.assert_called_with(mock.ANY,
sp_id)
def test_show_service_profile(self):
sp_id = 'fake_id'
expected = {'service_profile': {'id': 'id1',
'driver': _driver,
'description': 'desc',
'metainfo': '{}',
'enabled': True}}
instance = self.plugin.return_value
instance.get_service_profile.return_value = (
expected['service_profile'])
res = self.api.get(_get_path('service_profiles',
id=sp_id, fmt=self.fmt))
instance.get_service_profile.assert_called_with(mock.ANY,
sp_id,
fields=mock.ANY)
res = self.deserialize(res)
self.assertEqual(expected, res)
def test_get_service_profiles(self):
expected = {'service_profiles': [{'id': 'id1',
'driver': _driver,
'description': 'desc',
'metainfo': '{}',
'enabled': True},
{'id': 'id2',
'driver': _driver,
'description': 'desc',
'metainfo': '{}',
'enabled': True}]}
instance = self.plugin.return_value
instance.get_service_profiles.return_value = (
expected['service_profiles'])
res = self.api.get(_get_path('service_profiles', fmt=self.fmt))
instance.get_service_profiles.assert_called_with(mock.ANY,
fields=mock.ANY,
filters=mock.ANY)
res = self.deserialize(res)
self.assertEqual(expected, res)
def test_associate_service_profile_with_flavor(self):
tenant_id = uuidutils.generate_uuid()
expected = {'service_profile': {'id': _uuid(),
'tenant_id': tenant_id,
'project_id': tenant_id}}
instance = self.plugin.return_value
instance.create_flavor_service_profile.return_value = (
expected['service_profile'])
res = self.api.post('/flavors/fl_id/service_profiles',
self.serialize(expected),
content_type='application/%s' % self.fmt)
instance.create_flavor_service_profile.assert_called_with(
mock.ANY, service_profile=expected, flavor_id='fl_id')
res = self.deserialize(res)
self.assertEqual(expected, res)
def test_disassociate_service_profile_with_flavor(self):
instance = self.plugin.return_value
instance.delete_flavor_service_profile.return_value = None
self.api.delete('/flavors/fl_id/service_profiles/%s' % 'fake_spid',
content_type='application/%s' % self.fmt)
instance.delete_flavor_service_profile.assert_called_with(
mock.ANY,
'fake_spid',
flavor_id='fl_id')
def test_update_association_error(self):
"""Confirm that update is not permitted with user error."""
new_id = uuidutils.generate_uuid()
data = {'service_profile': {'id': new_id}}
self.api.put('/flavors/fl_id/service_profiles/%s' % 'fake_spid',
self.serialize(data),
content_type='application/%s' % self.fmt,
status=exc.HTTPBadRequest.code)
class DummyServicePlugin(object):
def driver_loaded(self, driver, service_profile):
pass
@classmethod
def get_plugin_type(cls):
return dummy_plugin.DUMMY_SERVICE_TYPE
def get_plugin_description(self):
return "Dummy service plugin, aware of flavors"
class DummyServiceDriver(object):
@staticmethod
def get_service_type():
return dummy_plugin.DUMMY_SERVICE_TYPE
def __init__(self, plugin):
pass
class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
base.PluginFixture):
def setUp(self):
super(FlavorPluginTestCase, self).setUp()
self.config_parse()
cfg.CONF.set_override(
'service_plugins',
['neutron.tests.unit.extensions.test_flavors.DummyServicePlugin'])
self.useFixture(
fixtures.MonkeyPatch('neutron.manager.NeutronManager._instance'))
self.plugin = flavors_plugin.FlavorsPlugin()
self.ctx = context.get_admin_context()
providers = [DummyServiceDriver.get_service_type() +
":" + _provider + ":" + _driver]
self.service_manager = servicetype_db.ServiceTypeManager.get_instance()
self.service_providers = mock.patch.object(
provconf.NeutronModule, 'service_providers').start()
self.service_providers.return_value = providers
for provider in providers:
self.service_manager.add_provider_configuration(
provider.split(':')[0], provconf.ProviderConfiguration())
db_api.CONTEXT_WRITER.get_engine()
def _create_flavor(self, description=None):
flavor = {'flavor': {'name': 'GOLD',
'service_type': dummy_plugin.DUMMY_SERVICE_TYPE,
'description': description or 'the best flavor',
'enabled': True}}
return self.plugin.create_flavor(self.ctx, flavor), flavor
def test_create_flavor(self):
self._create_flavor()
res = flavor_obj.Flavor.get_objects(self.ctx)
self.assertEqual(1, len(res))
self.assertEqual('GOLD', res[0]['name'])
self.assertEqual(
dummy_plugin.DUMMY_SERVICE_TYPE, res[0]['service_type'])
def test_update_flavor(self):
fl, flavor = self._create_flavor()
flavor = {'flavor': {'name': 'Silver',
'enabled': False}}
self.plugin.update_flavor(self.ctx, fl['id'], flavor)
# don't reuse cached models from previous plugin call
self.ctx.session.expire_all()
res = flavor_obj.Flavor.get_object(self.ctx, id=fl['id'])
self.assertEqual('Silver', res['name'])
self.assertFalse(res['enabled'])
def test_delete_flavor(self):
fl, _ = self._create_flavor()
self.plugin.delete_flavor(self.ctx, fl['id'])
self.assertFalse(flavor_obj.Flavor.objects_exist(self.ctx))
def test_show_flavor(self):
fl, _ = self._create_flavor()
show_fl = self.plugin.get_flavor(self.ctx, fl['id'])
self.assertEqual(fl, show_fl)
def test_get_flavors(self):
fl, flavor = self._create_flavor()
flavor['flavor']['name'] = 'SILVER'
self.plugin.create_flavor(self.ctx, flavor)
show_fl = self.plugin.get_flavors(self.ctx)
self.assertEqual(2, len(show_fl))
def _create_service_profile(self, description=None):
data = {'service_profile':
{'description': description or 'the best sp',
'driver': _driver,
'enabled': True,
'metainfo': '{"data": "value"}'}}
sp = self.plugin.create_service_profile(self.ctx,
data)
return sp, data
def test_create_service_profile(self):
sp, data = self._create_service_profile()
res = flavor_obj.ServiceProfile.get_object(self.ctx, id=sp['id'])
self.assertIsNotNone(res)
self.assertEqual(data['service_profile']['driver'], res.driver)
self.assertEqual(data['service_profile']['metainfo'], res.metainfo)
def test_create_service_profile_empty_driver(self):
data = {'service_profile':
{'description': 'the best sp',
'driver': '',
'enabled': True,
'metainfo': '{"data": "value"}'}}
sp = self.plugin.create_service_profile(self.ctx,
data)
res = flavor_obj.ServiceProfile.get_object(self.ctx, id=sp['id'])
self.assertIsNotNone(res)
self.assertEqual(data['service_profile']['driver'], res.driver)
self.assertEqual(data['service_profile']['metainfo'], res.metainfo)
def test_create_service_profile_invalid_driver(self):
data = {'service_profile':
{'description': 'the best sp',
'driver': "Broken",
'enabled': True,
'metainfo': '{"data": "value"}'}}
self.assertRaises(flav_exc.ServiceProfileDriverNotFound,
self.plugin.create_service_profile,
self.ctx,
data)
def test_create_service_profile_invalid_empty(self):
data = {'service_profile':
{'description': '',
'driver': '',
'enabled': True,
'metainfo': ''}}
self.assertRaises(flav_exc.ServiceProfileEmpty,
self.plugin.create_service_profile,
self.ctx,
data)
def test_update_service_profile(self):
sp, data = self._create_service_profile()
data['service_profile']['metainfo'] = '{"data": "value1"}'
sp = self.plugin.update_service_profile(self.ctx, sp['id'],
data)
# don't reuse cached models from previous plugin call
self.ctx.session.expire_all()
res = flavor_obj.ServiceProfile.get_object(self.ctx, id=sp['id'])
self.assertEqual(data['service_profile']['metainfo'], res['metainfo'])
def test_delete_service_profile(self):
sp, data = self._create_service_profile()
self.plugin.delete_service_profile(self.ctx, sp['id'])
res = flavor_obj.ServiceProfile.get_objects(self.ctx)
self.assertFalse(res)
def test_show_service_profile(self):
sp, data = self._create_service_profile()
sp_show = self.plugin.get_service_profile(self.ctx, sp['id'])
self.assertEqual(sp, sp_show)
def test_get_service_profiles(self):
self._create_service_profile()
self._create_service_profile(description='another sp')
self.assertEqual(2, len(self.plugin.get_service_profiles(self.ctx)))
def test_associate_service_profile_with_flavor(self):
sp, data = self._create_service_profile()
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
binding = flavor_obj.FlavorServiceProfileBinding.get_objects(
self.ctx)[0]
self.assertEqual(fl['id'], binding['flavor_id'])
self.assertEqual(sp['id'], binding['service_profile_id'])
# don't reuse cached models from previous plugin call
self.ctx.session.expire_all()
res = self.plugin.get_flavor(self.ctx, fl['id'])
self.assertEqual(1, len(res['service_profiles']))
self.assertEqual(sp['id'], res['service_profiles'][0])
res = self.plugin.get_service_profile(self.ctx, sp['id'])
self.assertEqual(1, len(res['flavors']))
self.assertEqual(fl['id'], res['flavors'][0])
def test_autodelete_flavor_associations(self):
sp, data = self._create_service_profile()
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
self.plugin.delete_flavor(self.ctx, fl['id'])
self.assertFalse(
flavor_obj.FlavorServiceProfileBinding.objects_exist(self.ctx))
def test_associate_service_profile_with_flavor_exists(self):
sp, data = self._create_service_profile()
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
self.assertRaises(flav_exc.FlavorServiceProfileBindingExists,
self.plugin.create_flavor_service_profile,
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
def test_disassociate_service_profile_with_flavor(self):
sp, data = self._create_service_profile()
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
self.plugin.delete_flavor_service_profile(
self.ctx, sp['id'], fl['id'])
self.assertFalse(
flavor_obj.FlavorServiceProfileBinding.objects_exist(self.ctx))
self.assertRaises(
flav_exc.FlavorServiceProfileBindingNotFound,
self.plugin.delete_flavor_service_profile,
self.ctx, sp['id'], fl['id'])
def test_delete_service_profile_in_use(self):
sp, data = self._create_service_profile()
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
self.assertRaises(
flav_exc.ServiceProfileInUse,
self.plugin.delete_service_profile,
self.ctx,
sp['id'])
def test_delete_flavor_in_use(self):
# make use of router since it has a flavor id
fl, data = self._create_flavor()
with db_api.CONTEXT_WRITER.using(self.ctx):
self.ctx.session.add(l3_models.Router(flavor_id=fl['id']))
self.assertRaises(
flav_exc.FlavorInUse,
self.plugin.delete_flavor,
self.ctx,
fl['id'])
def test_get_flavor_next_provider_no_binding(self):
fl, data = self._create_flavor()
self.assertRaises(
flav_exc.FlavorServiceProfileBindingNotFound,
self.plugin.get_flavor_next_provider,
self.ctx,
fl['id'])
def test_get_flavor_next_provider_disabled(self):
data = {'service_profile':
{'description': 'the best sp',
'driver': _driver,
'enabled': False,
'metainfo': '{"data": "value"}'}}
sp = self.plugin.create_service_profile(self.ctx,
data)
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
self.assertRaises(
flav_exc.ServiceProfileDisabled,
self.plugin.get_flavor_next_provider,
self.ctx,
fl['id'])
def test_get_flavor_next_provider_no_driver(self):
data = {'service_profile':
{'description': 'the best sp',
'driver': '',
'enabled': True,
'metainfo': '{"data": "value"}'}}
sp = self.plugin.create_service_profile(self.ctx,
data)
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
self.assertRaises(
flav_exc.ServiceProfileDriverNotFound,
self.plugin.get_flavor_next_provider,
self.ctx,
fl['id'])
def test_get_flavor_next_provider(self):
sp, data = self._create_service_profile()
fl, data = self._create_flavor()
self.plugin.create_flavor_service_profile(
self.ctx,
{'service_profile': {'id': sp['id']}},
fl['id'])
providers = self.plugin.get_flavor_next_provider(
self.ctx,
fl['id'])
self.assertEqual(_provider, providers[0].get('provider', None))