~ubuntu-branches/ubuntu/trusty/heat/trusty

« back to all changes in this revision

Viewing changes to heat/tests/test_resource.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Chuck Short, Adam Gandelman
  • Date: 2013-09-08 21:51:19 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130908215119-r939tu4aumqgdrkx
Tags: 2013.2~b3-0ubuntu1
[ Chuck Short ]
* New upstream release.
* debian/control: Add python-netaddr as build-dep.
* debian/heat-common.install: Remove heat-boto and associated man-page
* debian/heat-common.install: Remove heat-cfn and associated man-page
* debian/heat-common.install: Remove heat-watch and associated man-page
* debian/patches/fix-sqlalchemy-0.8.patch: Dropped

[ Adam Gandelman ]
* debian/patches/default-kombu.patch: Dropped.
* debian/patches/default-sqlite.patch: Refreshed.
* debian/*.install, rules: Install heat.conf.sample as common
  config file in heat-common. Drop other per-package configs, they
  are no longer used.
* debian/rules: Clean pbr .egg from build dir if it exists.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#    under the License.
14
14
 
15
15
import itertools
16
 
from eventlet.support import greenlets as greenlet
17
16
 
18
17
from heat.common import exception
 
18
from heat.engine import dependencies
19
19
from heat.engine import parser
20
20
from heat.engine import resource
21
21
from heat.engine import scheduler
 
22
from heat.engine import template
 
23
from heat.engine import environment
22
24
from heat.openstack.common import uuidutils
23
25
import heat.db.api as db_api
24
26
 
25
27
from heat.tests import generic_resource as generic_rsrc
26
28
from heat.tests.common import HeatTestCase
27
 
from heat.tests.utils import dummy_context
28
 
from heat.tests.utils import setup_dummy_db
 
29
from heat.tests import utils
29
30
 
30
31
 
31
32
class ResourceTest(HeatTestCase):
32
33
    def setUp(self):
33
34
        super(ResourceTest, self).setUp()
34
 
        setup_dummy_db()
35
 
        self.stack = parser.Stack(dummy_context(), 'test_stack',
36
 
                                  parser.Template({}),
 
35
        utils.setup_dummy_db()
 
36
 
 
37
        resource._register_class('GenericResourceType',
 
38
                                 generic_rsrc.GenericResource)
 
39
 
 
40
        env = environment.Environment()
 
41
        env.load({u'resource_registry':
 
42
                  {u'OS::Test::GenericResource': u'GenericResourceType'}})
 
43
 
 
44
        self.stack = parser.Stack(utils.dummy_context(), 'test_stack',
 
45
                                  parser.Template({}), env=env,
37
46
                                  stack_id=uuidutils.generate_uuid())
38
47
 
39
 
        resource._register_class('GenericResourceType',
40
 
                                 generic_rsrc.GenericResource)
41
 
 
42
48
    def test_get_class_ok(self):
43
49
        cls = resource.get_class('GenericResourceType')
44
50
        self.assertEqual(cls, generic_rsrc.GenericResource)
91
97
        res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
92
98
        self.assertEqual(res.type(), 'Foo')
93
99
 
 
100
    def test_has_interface_direct_match(self):
 
101
        tmpl = {'Type': 'GenericResourceType'}
 
102
        res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
 
103
        self.assertTrue(res.has_interface('GenericResourceType'))
 
104
 
 
105
    def test_has_interface_no_match(self):
 
106
        tmpl = {'Type': 'GenericResourceType'}
 
107
        res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
 
108
        self.assertFalse(res.has_interface('LookingForAnotherType'))
 
109
 
 
110
    def test_has_interface_mapping(self):
 
111
        tmpl = {'Type': 'OS::Test::GenericResource'}
 
112
        res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
 
113
        self.assertTrue(res.has_interface('GenericResourceType'))
 
114
 
94
115
    def test_created_time(self):
95
116
        tmpl = {'Type': 'Foo'}
96
117
        res = generic_rsrc.GenericResource('test_res_new', tmpl, self.stack)
158
179
        tmpl1 = {'Type': 'Foo'}
159
180
        tmpl2 = {'Type': 'Foo'}
160
181
        tmpl3 = {'Type': 'Bar'}
161
 
        stack2 = parser.Stack(dummy_context(), 'test_stack',
 
182
        stack2 = parser.Stack(utils.dummy_context(), 'test_stack',
162
183
                              parser.Template({}), stack_id=-1)
163
184
        res1 = generic_rsrc.GenericResource('test_resource', tmpl1, self.stack)
164
185
        res2 = generic_rsrc.GenericResource('test_resource', tmpl2, stack2)
281
302
        self.assertRaises(exception.ResourceFailure, create)
282
303
        self.assertEqual((res.CREATE, res.FAILED), res.state)
283
304
 
 
305
    def test_create_fail_metadata_parse_error(self):
 
306
        tmpl = {'Type': 'GenericResourceType', 'Properties': {},
 
307
                'Metadata': {"Fn::GetAtt": ["ResourceA", "abc"]}}
 
308
        rname = 'test_resource'
 
309
        res = generic_rsrc.ResourceWithProps(rname, tmpl, self.stack)
 
310
 
 
311
        create = scheduler.TaskRunner(res.create)
 
312
        self.assertRaises(exception.ResourceFailure, create)
 
313
        self.assertEqual((res.CREATE, res.FAILED), res.state)
 
314
 
284
315
    def test_create_resource_after_destroy(self):
285
316
        tmpl = {'Type': 'GenericResourceType'}
286
317
        rname = 'test_res_id_none'
288
319
        res.id = 'test_res_id'
289
320
        (res.action, res.status) = (res.INIT, res.DELETE)
290
321
        self.assertRaises(exception.ResourceFailure, res.create)
291
 
        res.destroy()
 
322
        scheduler.TaskRunner(res.destroy)()
292
323
        res.state_reset()
293
324
        scheduler.TaskRunner(res.create)()
294
325
        self.assertEqual((res.CREATE, res.COMPLETE), res.state)
304
335
        utmpl = {'Type': 'GenericResourceType', 'Properties': {'Foo': 'xyz'}}
305
336
        tmpl_diff = {'Properties': {'Foo': 'xyz'}}
306
337
        prop_diff = {'Foo': 'xyz'}
307
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_update')
308
 
        generic_rsrc.GenericResource.handle_update(
 
338
        self.m.StubOutWithMock(generic_rsrc.ResourceWithProps, 'handle_update')
 
339
        generic_rsrc.ResourceWithProps.handle_update(
309
340
            utmpl, tmpl_diff, prop_diff).AndReturn(None)
310
341
        self.m.ReplayAll()
311
342
 
312
 
        self.assertEqual(None, res.update(utmpl))
 
343
        scheduler.TaskRunner(res.update, utmpl)()
313
344
        self.assertEqual((res.UPDATE, res.COMPLETE), res.state)
314
345
        self.m.VerifyAll()
315
346
 
322
353
        self.assertEqual((res.CREATE, res.COMPLETE), res.state)
323
354
 
324
355
        utmpl = {'Type': 'GenericResourceType', 'Properties': {'Foo': 'xyz'}}
325
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_update')
 
356
        self.m.StubOutWithMock(generic_rsrc.ResourceWithProps, 'handle_update')
326
357
        tmpl_diff = {'Properties': {'Foo': 'xyz'}}
327
358
        prop_diff = {'Foo': 'xyz'}
328
 
        generic_rsrc.GenericResource.handle_update(
 
359
        generic_rsrc.ResourceWithProps.handle_update(
329
360
            utmpl, tmpl_diff, prop_diff).AndRaise(resource.UpdateReplace())
330
361
        self.m.ReplayAll()
331
362
        # should be re-raised so parser.Stack can handle replacement
332
 
        self.assertRaises(resource.UpdateReplace, res.update, utmpl)
 
363
        updater = scheduler.TaskRunner(res.update, utmpl)
 
364
        self.assertRaises(resource.UpdateReplace, updater)
333
365
        self.m.VerifyAll()
334
366
 
335
367
    def test_update_fail_missing_req_prop(self):
343
375
 
344
376
        utmpl = {'Type': 'GenericResourceType', 'Properties': {}}
345
377
 
346
 
        self.assertRaises(exception.ResourceFailure, res.update, utmpl)
 
378
        updater = scheduler.TaskRunner(res.update, utmpl)
 
379
        self.assertRaises(exception.ResourceFailure, updater)
347
380
        self.assertEqual((res.UPDATE, res.FAILED), res.state)
348
381
 
349
382
    def test_update_fail_prop_typo(self):
356
389
 
357
390
        utmpl = {'Type': 'GenericResourceType', 'Properties': {'Food': 'xyz'}}
358
391
 
359
 
        self.assertRaises(exception.ResourceFailure, res.update, utmpl)
 
392
        updater = scheduler.TaskRunner(res.update, utmpl)
 
393
        self.assertRaises(exception.ResourceFailure, updater)
360
394
        self.assertEqual((res.UPDATE, res.FAILED), res.state)
361
395
 
362
396
    def test_update_not_implemented(self):
370
404
        utmpl = {'Type': 'GenericResourceType', 'Properties': {'Foo': 'xyz'}}
371
405
        tmpl_diff = {'Properties': {'Foo': 'xyz'}}
372
406
        prop_diff = {'Foo': 'xyz'}
373
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_update')
374
 
        generic_rsrc.GenericResource.handle_update(utmpl, tmpl_diff, prop_diff
375
 
                                                   ).AndRaise(NotImplemented)
 
407
        self.m.StubOutWithMock(generic_rsrc.ResourceWithProps, 'handle_update')
 
408
        generic_rsrc.ResourceWithProps.handle_update(
 
409
            utmpl, tmpl_diff, prop_diff).AndRaise(NotImplemented)
376
410
        self.m.ReplayAll()
377
 
        self.assertRaises(exception.ResourceFailure, res.update, utmpl)
 
411
        updater = scheduler.TaskRunner(res.update, utmpl)
 
412
        self.assertRaises(exception.ResourceFailure, updater)
378
413
        self.assertEqual((res.UPDATE, res.FAILED), res.state)
379
414
        self.m.VerifyAll()
380
415
 
422
457
            resume = scheduler.TaskRunner(res.resume)
423
458
            self.assertRaises(exception.ResourceFailure, resume)
424
459
 
425
 
    def test_suspend_fail_exit(self):
426
 
        tmpl = {'Type': 'GenericResourceType', 'Properties': {'Foo': 'abc'}}
427
 
        res = generic_rsrc.ResourceWithProps('test_resource', tmpl, self.stack)
428
 
        scheduler.TaskRunner(res.create)()
429
 
        self.assertEqual((res.CREATE, res.COMPLETE), res.state)
430
 
 
431
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_suspend')
432
 
        generic_rsrc.GenericResource.handle_suspend().AndRaise(
433
 
            greenlet.GreenletExit())
434
 
        self.m.ReplayAll()
435
 
 
436
 
        suspend = scheduler.TaskRunner(res.suspend)
437
 
        self.assertRaises(greenlet.GreenletExit, suspend)
438
 
        self.assertEqual((res.SUSPEND, res.FAILED), res.state)
439
 
 
440
 
    def test_resume_fail_exit(self):
441
 
        tmpl = {'Type': 'GenericResourceType', 'Properties': {'Foo': 'abc'}}
442
 
        res = generic_rsrc.ResourceWithProps('test_resource', tmpl, self.stack)
443
 
        scheduler.TaskRunner(res.create)()
444
 
        self.assertEqual((res.CREATE, res.COMPLETE), res.state)
445
 
 
446
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_resume')
447
 
        generic_rsrc.GenericResource.handle_resume().AndRaise(
448
 
            greenlet.GreenletExit())
449
 
        self.m.ReplayAll()
450
 
 
451
 
        res.state_set(res.SUSPEND, res.COMPLETE)
452
 
 
453
 
        resume = scheduler.TaskRunner(res.resume)
454
 
        self.assertRaises(greenlet.GreenletExit, resume)
455
 
        self.assertEqual((res.RESUME, res.FAILED), res.state)
456
 
 
457
460
    def test_suspend_fail_exception(self):
458
461
        tmpl = {'Type': 'GenericResourceType', 'Properties': {'Foo': 'abc'}}
459
462
        res = generic_rsrc.ResourceWithProps('test_resource', tmpl, self.stack)
460
463
        scheduler.TaskRunner(res.create)()
461
464
        self.assertEqual((res.CREATE, res.COMPLETE), res.state)
462
465
 
463
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_suspend')
464
 
        generic_rsrc.GenericResource.handle_suspend().AndRaise(Exception())
 
466
        self.m.StubOutWithMock(generic_rsrc.ResourceWithProps,
 
467
                               'handle_suspend')
 
468
        generic_rsrc.ResourceWithProps.handle_suspend().AndRaise(Exception())
465
469
        self.m.ReplayAll()
466
470
 
467
471
        suspend = scheduler.TaskRunner(res.suspend)
474
478
        scheduler.TaskRunner(res.create)()
475
479
        self.assertEqual((res.CREATE, res.COMPLETE), res.state)
476
480
 
477
 
        self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_resume')
478
 
        generic_rsrc.GenericResource.handle_resume().AndRaise(Exception())
 
481
        self.m.StubOutWithMock(generic_rsrc.ResourceWithProps, 'handle_resume')
 
482
        generic_rsrc.ResourceWithProps.handle_resume().AndRaise(Exception())
479
483
        self.m.ReplayAll()
480
484
 
481
485
        res.state_set(res.SUSPEND, res.COMPLETE)
563
567
                         )
564
568
 
565
569
 
 
570
class ResourceDependenciesTest(HeatTestCase):
 
571
    def setUp(self):
 
572
        super(ResourceDependenciesTest, self).setUp()
 
573
        utils.setup_dummy_db()
 
574
 
 
575
        resource._register_class('GenericResourceType',
 
576
                                 generic_rsrc.GenericResource)
 
577
        resource._register_class('ResourceWithPropsType',
 
578
                                 generic_rsrc.ResourceWithProps)
 
579
 
 
580
        self.deps = dependencies.Dependencies()
 
581
 
 
582
    def test_no_deps(self):
 
583
        tmpl = template.Template({
 
584
            'Resources': {
 
585
                'foo': {'Type': 'GenericResourceType'},
 
586
            }
 
587
        })
 
588
        stack = parser.Stack(None, 'test', tmpl)
 
589
 
 
590
        res = stack['foo']
 
591
        res.add_dependencies(self.deps)
 
592
        graph = self.deps.graph()
 
593
 
 
594
        self.assertIn(res, graph)
 
595
 
 
596
    def test_ref(self):
 
597
        tmpl = template.Template({
 
598
            'Resources': {
 
599
                'foo': {'Type': 'GenericResourceType'},
 
600
                'bar': {
 
601
                    'Type': 'ResourceWithPropsType',
 
602
                    'Properties': {
 
603
                        'Foo': {'Ref': 'foo'},
 
604
                    }
 
605
                }
 
606
            }
 
607
        })
 
608
        stack = parser.Stack(None, 'test', tmpl)
 
609
 
 
610
        res = stack['bar']
 
611
        res.add_dependencies(self.deps)
 
612
        graph = self.deps.graph()
 
613
 
 
614
        self.assertIn(res, graph)
 
615
        self.assertIn(stack['foo'], graph[res])
 
616
 
 
617
    def test_ref_nested_dict(self):
 
618
        tmpl = template.Template({
 
619
            'Resources': {
 
620
                'foo': {'Type': 'GenericResourceType'},
 
621
                'bar': {
 
622
                    'Type': 'ResourceWithPropsType',
 
623
                    'Properties': {
 
624
                        'Foo': {'Fn::Base64': {'Ref': 'foo'}},
 
625
                    }
 
626
                }
 
627
            }
 
628
        })
 
629
        stack = parser.Stack(None, 'test', tmpl)
 
630
 
 
631
        res = stack['bar']
 
632
        res.add_dependencies(self.deps)
 
633
        graph = self.deps.graph()
 
634
 
 
635
        self.assertIn(res, graph)
 
636
        self.assertIn(stack['foo'], graph[res])
 
637
 
 
638
    def test_ref_nested_deep(self):
 
639
        tmpl = template.Template({
 
640
            'Resources': {
 
641
                'foo': {'Type': 'GenericResourceType'},
 
642
                'bar': {
 
643
                    'Type': 'ResourceWithPropsType',
 
644
                    'Properties': {
 
645
                        'Foo': {'Fn::Join': [",", ["blarg",
 
646
                                                   {'Ref': 'foo'},
 
647
                                                   "wibble"]]},
 
648
                    }
 
649
                }
 
650
            }
 
651
        })
 
652
        stack = parser.Stack(None, 'test', tmpl)
 
653
 
 
654
        res = stack['bar']
 
655
        res.add_dependencies(self.deps)
 
656
        graph = self.deps.graph()
 
657
 
 
658
        self.assertIn(res, graph)
 
659
        self.assertIn(stack['foo'], graph[res])
 
660
 
 
661
    def test_ref_fail(self):
 
662
        tmpl = template.Template({
 
663
            'Resources': {
 
664
                'foo': {'Type': 'GenericResourceType'},
 
665
                'bar': {
 
666
                    'Type': 'ResourceWithPropsType',
 
667
                    'Properties': {
 
668
                        'Foo': {'Ref': 'baz'},
 
669
                    }
 
670
                }
 
671
            }
 
672
        })
 
673
        ex = self.assertRaises(exception.InvalidTemplateReference,
 
674
                               parser.Stack,
 
675
                               None, 'test', tmpl)
 
676
        self.assertIn('"baz" (in bar.Properties.Foo)', str(ex))
 
677
 
 
678
    def test_getatt(self):
 
679
        tmpl = template.Template({
 
680
            'Resources': {
 
681
                'foo': {'Type': 'GenericResourceType'},
 
682
                'bar': {
 
683
                    'Type': 'ResourceWithPropsType',
 
684
                    'Properties': {
 
685
                        'Foo': {'Fn::GetAtt': ['foo', 'bar']},
 
686
                    }
 
687
                }
 
688
            }
 
689
        })
 
690
        stack = parser.Stack(None, 'test', tmpl)
 
691
 
 
692
        res = stack['bar']
 
693
        res.add_dependencies(self.deps)
 
694
        graph = self.deps.graph()
 
695
 
 
696
        self.assertIn(res, graph)
 
697
        self.assertIn(stack['foo'], graph[res])
 
698
 
 
699
    def test_getatt_nested_dict(self):
 
700
        tmpl = template.Template({
 
701
            'Resources': {
 
702
                'foo': {'Type': 'GenericResourceType'},
 
703
                'bar': {
 
704
                    'Type': 'ResourceWithPropsType',
 
705
                    'Properties': {
 
706
                        'Foo': {'Fn::Base64': {'Fn::GetAtt': ['foo', 'bar']}},
 
707
                    }
 
708
                }
 
709
            }
 
710
        })
 
711
        stack = parser.Stack(None, 'test', tmpl)
 
712
 
 
713
        res = stack['bar']
 
714
        res.add_dependencies(self.deps)
 
715
        graph = self.deps.graph()
 
716
 
 
717
        self.assertIn(res, graph)
 
718
        self.assertIn(stack['foo'], graph[res])
 
719
 
 
720
    def test_getatt_nested_deep(self):
 
721
        tmpl = template.Template({
 
722
            'Resources': {
 
723
                'foo': {'Type': 'GenericResourceType'},
 
724
                'bar': {
 
725
                    'Type': 'ResourceWithPropsType',
 
726
                    'Properties': {
 
727
                        'Foo': {'Fn::Join': [",", ["blarg",
 
728
                                                   {'Fn::GetAtt': ['foo',
 
729
                                                                   'bar']},
 
730
                                                   "wibble"]]},
 
731
                    }
 
732
                }
 
733
            }
 
734
        })
 
735
        stack = parser.Stack(None, 'test', tmpl)
 
736
 
 
737
        res = stack['bar']
 
738
        res.add_dependencies(self.deps)
 
739
        graph = self.deps.graph()
 
740
 
 
741
        self.assertIn(res, graph)
 
742
        self.assertIn(stack['foo'], graph[res])
 
743
 
 
744
    def test_getatt_fail(self):
 
745
        tmpl = template.Template({
 
746
            'Resources': {
 
747
                'foo': {'Type': 'GenericResourceType'},
 
748
                'bar': {
 
749
                    'Type': 'ResourceWithPropsType',
 
750
                    'Properties': {
 
751
                        'Foo': {'Fn::GetAtt': ['baz', 'bar']},
 
752
                    }
 
753
                }
 
754
            }
 
755
        })
 
756
        ex = self.assertRaises(exception.InvalidTemplateReference,
 
757
                               parser.Stack,
 
758
                               None, 'test', tmpl)
 
759
        self.assertIn('"baz" (in bar.Properties.Foo)', str(ex))
 
760
 
 
761
    def test_getatt_fail_nested_deep(self):
 
762
        tmpl = template.Template({
 
763
            'Resources': {
 
764
                'foo': {'Type': 'GenericResourceType'},
 
765
                'bar': {
 
766
                    'Type': 'ResourceWithPropsType',
 
767
                    'Properties': {
 
768
                        'Foo': {'Fn::Join': [",", ["blarg",
 
769
                                                   {'Fn::GetAtt': ['foo',
 
770
                                                                   'bar']},
 
771
                                                   "wibble",
 
772
                                                   {'Fn::GetAtt': ['baz',
 
773
                                                                   'bar']}]]},
 
774
                    }
 
775
                }
 
776
            }
 
777
        })
 
778
        ex = self.assertRaises(exception.InvalidTemplateReference,
 
779
                               parser.Stack,
 
780
                               None, 'test', tmpl)
 
781
        self.assertIn('"baz" (in bar.Properties.Foo.Fn::Join[1][3])', str(ex))
 
782
 
 
783
    def test_dependson(self):
 
784
        tmpl = template.Template({
 
785
            'Resources': {
 
786
                'foo': {'Type': 'GenericResourceType'},
 
787
                'bar': {
 
788
                    'Type': 'GenericResourceType',
 
789
                    'DependsOn': 'foo',
 
790
                }
 
791
            }
 
792
        })
 
793
        stack = parser.Stack(None, 'test', tmpl)
 
794
 
 
795
        res = stack['bar']
 
796
        res.add_dependencies(self.deps)
 
797
        graph = self.deps.graph()
 
798
 
 
799
        self.assertIn(res, graph)
 
800
        self.assertIn(stack['foo'], graph[res])
 
801
 
 
802
    def test_dependson_fail(self):
 
803
        tmpl = template.Template({
 
804
            'Resources': {
 
805
                'foo': {
 
806
                    'Type': 'GenericResourceType',
 
807
                    'DependsOn': 'wibble',
 
808
                }
 
809
            }
 
810
        })
 
811
        ex = self.assertRaises(exception.InvalidTemplateReference,
 
812
                               parser.Stack,
 
813
                               None, 'test', tmpl)
 
814
        self.assertIn('"wibble" (in foo)', str(ex))
 
815
 
 
816
 
566
817
class MetadataTest(HeatTestCase):
567
818
    def setUp(self):
568
819
        super(MetadataTest, self).setUp()
570
821
            'Type': 'Foo',
571
822
            'Metadata': {'Test': 'Initial metadata'}
572
823
        }
573
 
        setup_dummy_db()
574
 
        self.stack = parser.Stack(dummy_context(),
 
824
        utils.setup_dummy_db()
 
825
        self.stack = parser.Stack(utils.dummy_context(),
575
826
                                  'test_stack', parser.Template({}))
576
827
        self.stack.store()
577
828
        self.res = generic_rsrc.GenericResource('metadata_resource',