Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / tests / unit / extensions / test_flavors.py
1 #
2 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
3 #    not use this file except in compliance with the License. You may obtain
4 #    a copy of the License at
5 #
6 #         http://www.apache.org/licenses/LICENSE-2.0
7 #
8 #    Unless required by applicable law or agreed to in writing, software
9 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 #    License for the specific language governing permissions and limitations
12 #    under the License.
13 #
14
15
16 import copy
17 import fixtures
18 import mock
19
20 from oslo_config import cfg
21 from oslo_utils import uuidutils
22 from webob import exc
23
24 from neutron.api.v2 import attributes as attr
25 from neutron import context
26 from neutron.db import api as dbapi
27 from neutron.db import flavors_db
28 from neutron.db import servicetype_db
29 from neutron.extensions import flavors
30 from neutron.plugins.common import constants
31 from neutron.services.flavors import flavors_plugin
32 from neutron.services import provider_configuration as provconf
33 from neutron.tests import base
34 from neutron.tests.unit.api.v2 import test_base
35 from neutron.tests.unit.db import test_db_base_plugin_v2
36 from neutron.tests.unit.extensions import base as extension
37
38 _uuid = uuidutils.generate_uuid
39 _get_path = test_base._get_path
40
41 _driver = ('neutron.tests.unit.extensions.test_flavors.'
42            'DummyServiceDriver')
43 _provider = 'dummy'
44 _long_name = 'x' * (attr.NAME_MAX_LEN + 1)
45 _long_description = 'x' * (attr.LONG_DESCRIPTION_MAX_LEN + 1)
46
47
48 class FlavorExtensionTestCase(extension.ExtensionTestCase):
49
50     def setUp(self):
51         super(FlavorExtensionTestCase, self).setUp()
52         self._setUpExtension(
53             'neutron.services.flavors.flavors_plugin.FlavorsPlugin',
54             constants.FLAVORS, flavors.RESOURCE_ATTRIBUTE_MAP,
55             flavors.Flavors, '', supported_extension_aliases='flavors')
56
57     def test_create_flavor(self):
58         tenant_id = uuidutils.generate_uuid()
59         # Use service_type FLAVORS since plugin must be loaded to validate
60         data = {'flavor': {'name': 'GOLD',
61                            'service_type': constants.FLAVORS,
62                            'description': 'the best flavor',
63                            'tenant_id': tenant_id,
64                            'enabled': True}}
65
66         expected = copy.deepcopy(data)
67         expected['flavor']['service_profiles'] = []
68
69         instance = self.plugin.return_value
70         instance.create_flavor.return_value = expected['flavor']
71         res = self.api.post(_get_path('flavors', fmt=self.fmt),
72                             self.serialize(data),
73                             content_type='application/%s' % self.fmt)
74
75         instance.create_flavor.assert_called_with(mock.ANY,
76                                                   flavor=expected)
77         res = self.deserialize(res)
78         self.assertIn('flavor', res)
79         self.assertEqual(expected, res)
80
81     def test_create_flavor_invalid_service_type(self):
82         tenant_id = uuidutils.generate_uuid()
83         data = {'flavor': {'name': 'GOLD',
84                            'service_type': 'BROKEN',
85                            'description': 'the best flavor',
86                            'tenant_id': tenant_id,
87                            'enabled': True}}
88         self.api.post(_get_path('flavors', fmt=self.fmt),
89                       self.serialize(data),
90                       content_type='application/%s' % self.fmt,
91                       status=exc.HTTPBadRequest.code)
92
93     def test_create_flavor_too_long_name(self):
94         tenant_id = uuidutils.generate_uuid()
95         data = {'flavor': {'name': _long_name,
96                            'service_type': constants.FLAVORS,
97                            'description': 'the best flavor',
98                            'tenant_id': tenant_id,
99                            'enabled': True}}
100         self.api.post(_get_path('flavors', fmt=self.fmt),
101                       self.serialize(data),
102                       content_type='application/%s' % self.fmt,
103                       status=exc.HTTPBadRequest.code)
104
105     def test_create_flavor_too_long_description(self):
106         tenant_id = uuidutils.generate_uuid()
107         data = {'flavor': {'name': _long_name,
108                            'service_type': constants.FLAVORS,
109                            'description': _long_description,
110                            'tenant_id': tenant_id,
111                            'enabled': True}}
112         self.api.post(_get_path('flavors', fmt=self.fmt),
113                       self.serialize(data),
114                       content_type='application/%s' % self.fmt,
115                       status=exc.HTTPBadRequest.code)
116
117     def test_create_flavor_invalid_enabled(self):
118         tenant_id = uuidutils.generate_uuid()
119         data = {'flavor': {'name': _long_name,
120                            'service_type': constants.FLAVORS,
121                            'description': 'the best flavor',
122                            'tenant_id': tenant_id,
123                            'enabled': 'BROKEN'}}
124         self.api.post(_get_path('flavors', fmt=self.fmt),
125                       self.serialize(data),
126                       content_type='application/%s' % self.fmt,
127                       status=exc.HTTPBadRequest.code)
128
129     def test_update_flavor(self):
130         flavor_id = 'fake_id'
131         data = {'flavor': {'name': 'GOLD',
132                            'description': 'the best flavor',
133                            'enabled': True}}
134         expected = copy.copy(data)
135         expected['flavor']['service_profiles'] = []
136
137         instance = self.plugin.return_value
138         instance.update_flavor.return_value = expected['flavor']
139         res = self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
140                            self.serialize(data),
141                            content_type='application/%s' % self.fmt)
142
143         instance.update_flavor.assert_called_with(mock.ANY,
144                                                   flavor_id,
145                                                   flavor=expected)
146         res = self.deserialize(res)
147         self.assertIn('flavor', res)
148         self.assertEqual(expected, res)
149
150     def test_update_flavor_too_long_name(self):
151         flavor_id = 'fake_id'
152         data = {'flavor': {'name': _long_name,
153                            'description': 'the best flavor',
154                            'enabled': True}}
155         self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
156                      self.serialize(data),
157                      content_type='application/%s' % self.fmt,
158                      status=exc.HTTPBadRequest.code)
159
160     def test_update_flavor_too_long_description(self):
161         flavor_id = 'fake_id'
162         data = {'flavor': {'name': 'GOLD',
163                            'description': _long_description,
164                            'enabled': True}}
165         self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
166                      self.serialize(data),
167                      content_type='application/%s' % self.fmt,
168                      status=exc.HTTPBadRequest.code)
169
170     def test_update_flavor_invalid_enabled(self):
171         flavor_id = 'fake_id'
172         data = {'flavor': {'name': 'GOLD',
173                            'description': _long_description,
174                            'enabled': 'BROKEN'}}
175         self.api.put(_get_path('flavors', id=flavor_id, fmt=self.fmt),
176                      self.serialize(data),
177                      content_type='application/%s' % self.fmt,
178                      status=exc.HTTPBadRequest.code)
179
180     def test_delete_flavor(self):
181         flavor_id = 'fake_id'
182         instance = self.plugin.return_value
183         self.api.delete(_get_path('flavors', id=flavor_id, fmt=self.fmt),
184                         content_type='application/%s' % self.fmt)
185
186         instance.delete_flavor.assert_called_with(mock.ANY,
187                                                   flavor_id)
188
189     def test_show_flavor(self):
190         flavor_id = 'fake_id'
191         expected = {'flavor': {'id': flavor_id,
192                                'name': 'GOLD',
193                                'description': 'the best flavor',
194                                'enabled': True,
195                                'service_profiles': ['profile-1']}}
196         instance = self.plugin.return_value
197         instance.get_flavor.return_value = expected['flavor']
198         res = self.api.get(_get_path('flavors', id=flavor_id, fmt=self.fmt))
199         instance.get_flavor.assert_called_with(mock.ANY,
200                                                flavor_id,
201                                                fields=mock.ANY)
202         res = self.deserialize(res)
203         self.assertEqual(expected, res)
204
205     def test_get_flavors(self):
206         data = {'flavors': [{'id': 'id1',
207                              'name': 'GOLD',
208                              'description': 'the best flavor',
209                              'enabled': True,
210                              'service_profiles': ['profile-1']},
211                             {'id': 'id2',
212                              'name': 'GOLD',
213                              'description': 'the best flavor',
214                              'enabled': True,
215                              'service_profiles': ['profile-2', 'profile-1']}]}
216         instance = self.plugin.return_value
217         instance.get_flavors.return_value = data['flavors']
218         res = self.api.get(_get_path('flavors', fmt=self.fmt))
219         instance.get_flavors.assert_called_with(mock.ANY,
220                                                 fields=mock.ANY,
221                                                 filters=mock.ANY)
222         res = self.deserialize(res)
223         self.assertEqual(data, res)
224
225     def test_create_service_profile(self):
226         tenant_id = uuidutils.generate_uuid()
227         expected = {'service_profile': {'description': 'the best sp',
228                                         'driver': '',
229                                         'tenant_id': tenant_id,
230                                         'enabled': True,
231                                         'metainfo': '{"data": "value"}'}}
232
233         instance = self.plugin.return_value
234         instance.create_service_profile.return_value = (
235             expected['service_profile'])
236         res = self.api.post(_get_path('service_profiles', fmt=self.fmt),
237                             self.serialize(expected),
238                             content_type='application/%s' % self.fmt)
239         instance.create_service_profile.assert_called_with(
240             mock.ANY,
241             service_profile=expected)
242         res = self.deserialize(res)
243         self.assertIn('service_profile', res)
244         self.assertEqual(expected, res)
245
246     def test_create_service_profile_too_long_description(self):
247         tenant_id = uuidutils.generate_uuid()
248         expected = {'service_profile': {'description': _long_description,
249                                         'driver': '',
250                                         'tenant_id': tenant_id,
251                                         'enabled': True,
252                                         'metainfo': '{"data": "value"}'}}
253         self.api.post(_get_path('service_profiles', fmt=self.fmt),
254                       self.serialize(expected),
255                       content_type='application/%s' % self.fmt,
256                       status=exc.HTTPBadRequest.code)
257
258     def test_create_service_profile_too_long_driver(self):
259         tenant_id = uuidutils.generate_uuid()
260         expected = {'service_profile': {'description': 'the best sp',
261                                         'driver': _long_description,
262                                         'tenant_id': tenant_id,
263                                         'enabled': True,
264                                         'metainfo': '{"data": "value"}'}}
265         self.api.post(_get_path('service_profiles', fmt=self.fmt),
266                       self.serialize(expected),
267                       content_type='application/%s' % self.fmt,
268                       status=exc.HTTPBadRequest.code)
269
270     def test_create_service_profile_invalid_enabled(self):
271         tenant_id = uuidutils.generate_uuid()
272         expected = {'service_profile': {'description': 'the best sp',
273                                         'driver': '',
274                                         'tenant_id': tenant_id,
275                                         'enabled': 'BROKEN',
276                                         'metainfo': '{"data": "value"}'}}
277         self.api.post(_get_path('service_profiles', fmt=self.fmt),
278                       self.serialize(expected),
279                       content_type='application/%s' % self.fmt,
280                       status=exc.HTTPBadRequest.code)
281
282     def test_update_service_profile(self):
283         sp_id = "fake_id"
284         expected = {'service_profile': {'description': 'the best sp',
285                                         'enabled': False,
286                                         'metainfo': '{"data1": "value3"}'}}
287
288         instance = self.plugin.return_value
289         instance.update_service_profile.return_value = (
290             expected['service_profile'])
291         res = self.api.put(_get_path('service_profiles',
292                                      id=sp_id, fmt=self.fmt),
293                            self.serialize(expected),
294                            content_type='application/%s' % self.fmt)
295
296         instance.update_service_profile.assert_called_with(
297             mock.ANY,
298             sp_id,
299             service_profile=expected)
300         res = self.deserialize(res)
301         self.assertIn('service_profile', res)
302         self.assertEqual(expected, res)
303
304     def test_update_service_profile_too_long_description(self):
305         sp_id = "fake_id"
306         expected = {'service_profile': {'description': 'the best sp',
307                                         'enabled': 'BROKEN',
308                                         'metainfo': '{"data1": "value3"}'}}
309         self.api.put(_get_path('service_profiles',
310                                id=sp_id, fmt=self.fmt),
311                      self.serialize(expected),
312                      content_type='application/%s' % self.fmt,
313                      status=exc.HTTPBadRequest.code)
314
315     def test_update_service_profile_invalid_enabled(self):
316         sp_id = "fake_id"
317         expected = {'service_profile': {'description': 'the best sp',
318                                         'enabled': 'BROKEN',
319                                         'metainfo': '{"data1": "value3"}'}}
320         self.api.put(_get_path('service_profiles',
321                                id=sp_id, fmt=self.fmt),
322                      self.serialize(expected),
323                      content_type='application/%s' % self.fmt,
324                      status=exc.HTTPBadRequest.code)
325
326     def test_delete_service_profile(self):
327         sp_id = 'fake_id'
328         instance = self.plugin.return_value
329         self.api.delete(_get_path('service_profiles', id=sp_id, fmt=self.fmt),
330                         content_type='application/%s' % self.fmt)
331         instance.delete_service_profile.assert_called_with(mock.ANY,
332                                                            sp_id)
333
334     def test_show_service_profile(self):
335         sp_id = 'fake_id'
336         expected = {'service_profile': {'id': 'id1',
337                                         'driver': _driver,
338                                         'description': 'desc',
339                                         'metainfo': '{}',
340                                         'enabled': True}}
341         instance = self.plugin.return_value
342         instance.get_service_profile.return_value = (
343             expected['service_profile'])
344         res = self.api.get(_get_path('service_profiles',
345                                      id=sp_id, fmt=self.fmt))
346         instance.get_service_profile.assert_called_with(mock.ANY,
347                                                         sp_id,
348                                                         fields=mock.ANY)
349         res = self.deserialize(res)
350         self.assertEqual(expected, res)
351
352     def test_get_service_profiles(self):
353         expected = {'service_profiles': [{'id': 'id1',
354                                           'driver': _driver,
355                                           'description': 'desc',
356                                           'metainfo': '{}',
357                                           'enabled': True},
358                                          {'id': 'id2',
359                                           'driver': _driver,
360                                           'description': 'desc',
361                                           'metainfo': '{}',
362                                           'enabled': True}]}
363         instance = self.plugin.return_value
364         instance.get_service_profiles.return_value = (
365             expected['service_profiles'])
366         res = self.api.get(_get_path('service_profiles', fmt=self.fmt))
367         instance.get_service_profiles.assert_called_with(mock.ANY,
368                                                          fields=mock.ANY,
369                                                          filters=mock.ANY)
370         res = self.deserialize(res)
371         self.assertEqual(expected, res)
372
373     def test_associate_service_profile_with_flavor(self):
374         tenant_id = uuidutils.generate_uuid()
375         expected = {'service_profile': {'id': _uuid(),
376                                         'tenant_id': tenant_id}}
377         instance = self.plugin.return_value
378         instance.create_flavor_service_profile.return_value = (
379             expected['service_profile'])
380         res = self.api.post('/flavors/fl_id/service_profiles',
381                             self.serialize(expected),
382                             content_type='application/%s' % self.fmt)
383         instance.create_flavor_service_profile.assert_called_with(
384             mock.ANY, service_profile=expected, flavor_id='fl_id')
385         res = self.deserialize(res)
386         self.assertEqual(expected, res)
387
388     def test_disassociate_service_profile_with_flavor(self):
389         instance = self.plugin.return_value
390         instance.delete_flavor_service_profile.return_value = None
391         self.api.delete('/flavors/fl_id/service_profiles/%s' % 'fake_spid',
392                         content_type='application/%s' % self.fmt)
393         instance.delete_flavor_service_profile.assert_called_with(
394             mock.ANY,
395             'fake_spid',
396             flavor_id='fl_id')
397
398     def test_update_association_error(self):
399         """Confirm that update is not permitted with user error."""
400         new_id = uuidutils.generate_uuid()
401         data = {'service_profile': {'id': new_id}}
402         self.api.put('/flavors/fl_id/service_profiles/%s' % 'fake_spid',
403                      self.serialize(data),
404                      content_type='application/%s' % self.fmt,
405                      status=exc.HTTPBadRequest.code)
406
407
408 class DummyCorePlugin(object):
409     pass
410
411
412 class DummyServicePlugin(object):
413
414     def driver_loaded(self, driver, service_profile):
415         pass
416
417     def get_plugin_type(self):
418         return constants.DUMMY
419
420     def get_plugin_description(self):
421         return "Dummy service plugin, aware of flavors"
422
423
424 class DummyServiceDriver(object):
425
426     @staticmethod
427     def get_service_type():
428         return constants.DUMMY
429
430     def __init__(self, plugin):
431         pass
432
433
434 class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
435                            base.PluginFixture):
436     def setUp(self):
437         super(FlavorPluginTestCase, self).setUp()
438
439         self.config_parse()
440         cfg.CONF.set_override(
441             'core_plugin',
442             'neutron.tests.unit.extensions.test_flavors.DummyCorePlugin')
443         cfg.CONF.set_override(
444             'service_plugins',
445             ['neutron.tests.unit.extensions.test_flavors.DummyServicePlugin'])
446
447         self.useFixture(
448             fixtures.MonkeyPatch('neutron.manager.NeutronManager._instance'))
449
450         self.plugin = flavors_plugin.FlavorsPlugin()
451         self.ctx = context.get_admin_context()
452
453         providers = [DummyServiceDriver.get_service_type() +
454                      ":" + _provider + ":" + _driver]
455         self.service_manager = servicetype_db.ServiceTypeManager.get_instance()
456         self.service_providers = mock.patch.object(
457             provconf.NeutronModule, 'service_providers').start()
458         self.service_providers.return_value = providers
459         for provider in providers:
460             self.service_manager.add_provider_configuration(
461                 provider.split(':')[0], provconf.ProviderConfiguration())
462
463         dbapi.get_engine()
464
465     def _create_flavor(self, description=None):
466         flavor = {'flavor': {'name': 'GOLD',
467                              'service_type': constants.DUMMY,
468                              'description': description or 'the best flavor',
469                              'enabled': True}}
470         return self.plugin.create_flavor(self.ctx, flavor), flavor
471
472     def test_create_flavor(self):
473         self._create_flavor()
474         res = self.ctx.session.query(flavors_db.Flavor).all()
475         self.assertEqual(1, len(res))
476         self.assertEqual('GOLD', res[0]['name'])
477         self.assertEqual(constants.DUMMY, res[0]['service_type'])
478
479     def test_update_flavor(self):
480         fl, flavor = self._create_flavor()
481         flavor = {'flavor': {'name': 'Silver',
482                              'enabled': False}}
483         self.plugin.update_flavor(self.ctx, fl['id'], flavor)
484         res = (self.ctx.session.query(flavors_db.Flavor).
485                filter_by(id=fl['id']).one())
486         self.assertEqual('Silver', res['name'])
487         self.assertFalse(res['enabled'])
488
489     def test_delete_flavor(self):
490         fl, data = self._create_flavor()
491         self.plugin.delete_flavor(self.ctx, fl['id'])
492         res = (self.ctx.session.query(flavors_db.Flavor).all())
493         self.assertFalse(res)
494
495     def test_show_flavor(self):
496         fl, data = self._create_flavor()
497         show_fl = self.plugin.get_flavor(self.ctx, fl['id'])
498         self.assertEqual(fl, show_fl)
499
500     def test_get_flavors(self):
501         fl, flavor = self._create_flavor()
502         flavor['flavor']['name'] = 'SILVER'
503         self.plugin.create_flavor(self.ctx, flavor)
504         show_fl = self.plugin.get_flavors(self.ctx)
505         self.assertEqual(2, len(show_fl))
506
507     def _create_service_profile(self, description=None):
508         data = {'service_profile':
509                 {'description': description or 'the best sp',
510                  'driver': _driver,
511                  'enabled': True,
512                  'metainfo': '{"data": "value"}'}}
513         sp = self.plugin.create_service_profile(self.ctx,
514                                                 data)
515         return sp, data
516
517     def test_create_service_profile(self):
518         sp, data = self._create_service_profile()
519         res = (self.ctx.session.query(flavors_db.ServiceProfile).
520                filter_by(id=sp['id']).one())
521         self.assertEqual(data['service_profile']['driver'], res['driver'])
522         self.assertEqual(data['service_profile']['metainfo'], res['metainfo'])
523
524     def test_create_service_profile_empty_driver(self):
525         data = {'service_profile':
526                 {'description': 'the best sp',
527                  'driver': '',
528                  'enabled': True,
529                  'metainfo': '{"data": "value"}'}}
530         sp = self.plugin.create_service_profile(self.ctx,
531                                                 data)
532         res = (self.ctx.session.query(flavors_db.ServiceProfile).
533                filter_by(id=sp['id']).one())
534         self.assertEqual(data['service_profile']['driver'], res['driver'])
535         self.assertEqual(data['service_profile']['metainfo'], res['metainfo'])
536
537     def test_create_service_profile_invalid_driver(self):
538         data = {'service_profile':
539                 {'description': 'the best sp',
540                  'driver': "Broken",
541                  'enabled': True,
542                  'metainfo': '{"data": "value"}'}}
543         self.assertRaises(flavors.ServiceProfileDriverNotFound,
544                           self.plugin.create_service_profile,
545                           self.ctx,
546                           data)
547
548     def test_create_service_profile_invalid_empty(self):
549         data = {'service_profile':
550                 {'description': '',
551                  'driver': '',
552                  'enabled': True,
553                  'metainfo': ''}}
554         self.assertRaises(flavors.ServiceProfileEmpty,
555                           self.plugin.create_service_profile,
556                           self.ctx,
557                           data)
558
559     def test_update_service_profile(self):
560         sp, data = self._create_service_profile()
561         data['service_profile']['metainfo'] = '{"data": "value1"}'
562         sp = self.plugin.update_service_profile(self.ctx, sp['id'],
563                                                 data)
564         res = (self.ctx.session.query(flavors_db.ServiceProfile).
565                filter_by(id=sp['id']).one())
566         self.assertEqual(data['service_profile']['metainfo'], res['metainfo'])
567
568     def test_delete_service_profile(self):
569         sp, data = self._create_service_profile()
570         self.plugin.delete_service_profile(self.ctx, sp['id'])
571         res = self.ctx.session.query(flavors_db.ServiceProfile).all()
572         self.assertFalse(res)
573
574     def test_show_service_profile(self):
575         sp, data = self._create_service_profile()
576         sp_show = self.plugin.get_service_profile(self.ctx, sp['id'])
577         self.assertEqual(sp, sp_show)
578
579     def test_get_service_profiles(self):
580         self._create_service_profile()
581         self._create_service_profile(description='another sp')
582         self.assertEqual(2, len(self.plugin.get_service_profiles(self.ctx)))
583
584     def test_associate_service_profile_with_flavor(self):
585         sp, data = self._create_service_profile()
586         fl, data = self._create_flavor()
587         self.plugin.create_flavor_service_profile(
588             self.ctx,
589             {'service_profile': {'id': sp['id']}},
590             fl['id'])
591         binding = (
592             self.ctx.session.query(flavors_db.FlavorServiceProfileBinding).
593             first())
594         self.assertEqual(fl['id'], binding['flavor_id'])
595         self.assertEqual(sp['id'], binding['service_profile_id'])
596
597         res = self.plugin.get_flavor(self.ctx, fl['id'])
598         self.assertEqual(1, len(res['service_profiles']))
599         self.assertEqual(sp['id'], res['service_profiles'][0])
600
601         res = self.plugin.get_service_profile(self.ctx, sp['id'])
602         self.assertEqual(1, len(res['flavors']))
603         self.assertEqual(fl['id'], res['flavors'][0])
604
605     def test_autodelete_flavor_associations(self):
606         sp, data = self._create_service_profile()
607         fl, data = self._create_flavor()
608         self.plugin.create_flavor_service_profile(
609             self.ctx,
610             {'service_profile': {'id': sp['id']}},
611             fl['id'])
612         self.plugin.delete_flavor(self.ctx, fl['id'])
613         binding = (
614             self.ctx.session.query(flavors_db.FlavorServiceProfileBinding).
615             first())
616         self.assertIsNone(binding)
617
618     def test_associate_service_profile_with_flavor_exists(self):
619         sp, data = self._create_service_profile()
620         fl, data = self._create_flavor()
621         self.plugin.create_flavor_service_profile(
622             self.ctx,
623             {'service_profile': {'id': sp['id']}},
624             fl['id'])
625         self.assertRaises(flavors.FlavorServiceProfileBindingExists,
626                           self.plugin.create_flavor_service_profile,
627                           self.ctx,
628                           {'service_profile': {'id': sp['id']}},
629                           fl['id'])
630
631     def test_disassociate_service_profile_with_flavor(self):
632         sp, data = self._create_service_profile()
633         fl, data = self._create_flavor()
634         self.plugin.create_flavor_service_profile(
635             self.ctx,
636             {'service_profile': {'id': sp['id']}},
637             fl['id'])
638         self.plugin.delete_flavor_service_profile(
639             self.ctx, sp['id'], fl['id'])
640         binding = (
641             self.ctx.session.query(flavors_db.FlavorServiceProfileBinding).
642             first())
643         self.assertIsNone(binding)
644
645         self.assertRaises(
646             flavors.FlavorServiceProfileBindingNotFound,
647             self.plugin.delete_flavor_service_profile,
648             self.ctx, sp['id'], fl['id'])
649
650     def test_delete_service_profile_in_use(self):
651         sp, data = self._create_service_profile()
652         fl, data = self._create_flavor()
653         self.plugin.create_flavor_service_profile(
654             self.ctx,
655             {'service_profile': {'id': sp['id']}},
656             fl['id'])
657         self.assertRaises(
658             flavors.ServiceProfileInUse,
659             self.plugin.delete_service_profile,
660             self.ctx,
661             sp['id'])
662
663     def test_get_flavor_next_provider_no_binding(self):
664         fl, data = self._create_flavor()
665         self.assertRaises(
666             flavors.FlavorServiceProfileBindingNotFound,
667             self.plugin.get_flavor_next_provider,
668             self.ctx,
669             fl['id'])
670
671     def test_get_flavor_next_provider_disabled(self):
672         data = {'service_profile':
673                 {'description': 'the best sp',
674                  'driver': _driver,
675                  'enabled': False,
676                  'metainfo': '{"data": "value"}'}}
677         sp = self.plugin.create_service_profile(self.ctx,
678                                                 data)
679         fl, data = self._create_flavor()
680         self.plugin.create_flavor_service_profile(
681             self.ctx,
682             {'service_profile': {'id': sp['id']}},
683             fl['id'])
684         self.assertRaises(
685             flavors.ServiceProfileDisabled,
686             self.plugin.get_flavor_next_provider,
687             self.ctx,
688             fl['id'])
689
690     def test_get_flavor_next_provider_no_driver(self):
691         data = {'service_profile':
692                 {'description': 'the best sp',
693                  'driver': '',
694                  'enabled': True,
695                  'metainfo': '{"data": "value"}'}}
696         sp = self.plugin.create_service_profile(self.ctx,
697                                                 data)
698         fl, data = self._create_flavor()
699         self.plugin.create_flavor_service_profile(
700             self.ctx,
701             {'service_profile': {'id': sp['id']}},
702             fl['id'])
703         self.assertRaises(
704             flavors.ServiceProfileDriverNotFound,
705             self.plugin.get_flavor_next_provider,
706             self.ctx,
707             fl['id'])
708
709     def test_get_flavor_next_provider(self):
710         sp, data = self._create_service_profile()
711         fl, data = self._create_flavor()
712         self.plugin.create_flavor_service_profile(
713             self.ctx,
714             {'service_profile': {'id': sp['id']}},
715             fl['id'])
716         providers = self.plugin.get_flavor_next_provider(
717             self.ctx,
718             fl['id'])
719         self.assertEqual(_provider, providers[0].get('provider', None))