From 85e9411d3def955f34497cffcb2ab2c74915200f Mon Sep 17 00:00:00 2001 From: Sergey Kraynev Date: Tue, 25 Mar 2014 02:12:07 -0400 Subject: [PATCH] Initial validation of functions All template functions contain only 'result' function for resolving snippet of template. Current patch presents initial implementation of validate method and support function 'validate' similar to 'resolve'. Related-Bug: #1273490 Change-Id: Id81493bd72e75da746101c4c741eaf846abd8360 --- heat/engine/function.py | 21 ++++++++++++++++++ heat/tests/test_function.py | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/heat/engine/function.py b/heat/engine/function.py index 2f48ff2e82..f5a091ab83 100644 --- a/heat/engine/function.py +++ b/heat/engine/function.py @@ -36,6 +36,15 @@ class Function(object): self.fn_name = fn_name self.args = args + def validate(self): + """ + Validate arguments without resolving the function. + + Function subclasses must override this method to validate their + args. + """ + validate(self.args) + @abc.abstractmethod def result(self): """ @@ -110,3 +119,15 @@ def resolve(snippet): return [resolve(v) for v in snippet] return snippet + + +def validate(snippet): + if isinstance(snippet, Function): + snippet.validate() + elif isinstance(snippet, collections.Mapping): + for v in snippet.values(): + validate(v) + elif (not isinstance(snippet, basestring) and + isinstance(snippet, collections.Iterable)): + for v in snippet: + validate(v) diff --git a/heat/tests/test_function.py b/heat/tests/test_function.py index e0d2241b3c..885846dce3 100644 --- a/heat/tests/test_function.py +++ b/heat/tests/test_function.py @@ -19,6 +19,10 @@ from heat.engine import function class TestFunction(function.Function): + def validate(self): + if len(self.args) < 2: + raise Exception(_('Need more arguments')) + def result(self): return 'wibble' @@ -80,3 +84,42 @@ class ResolveTest(HeatTestCase): self.assertEqual(['foo', {'bar': ['baz', {'blarg': 'wibble'}]}], result) self.assertIsNot(result, snippet) + + +class ValidateTest(HeatTestCase): + def setUp(self): + super(ValidateTest, self).setUp() + self.func = TestFunction(None, 'foo', ['bar', 'baz']) + + def test_validate_func(self): + self.assertIsNone(function.validate(self.func)) + self.func = TestFunction(None, 'foo', ['bar']) + ex = self.assertRaises(Exception, function.validate, self.func) + self.assertEqual('Need more arguments', str(ex)) + + def test_validate_dict(self): + snippet = {'foo': 'bar', 'blarg': self.func} + function.validate(snippet) + + self.func = TestFunction(None, 'foo', ['bar']) + snippet = {'foo': 'bar', 'blarg': self.func} + ex = self.assertRaises(Exception, function.validate, snippet) + self.assertEqual('Need more arguments', str(ex)) + + def test_validate_list(self): + snippet = ['foo', 'bar', 'baz', 'blarg', self.func] + function.validate(snippet) + + self.func = TestFunction(None, 'foo', ['bar']) + snippet = {'foo': 'bar', 'blarg': self.func} + ex = self.assertRaises(Exception, function.validate, snippet) + self.assertEqual('Need more arguments', str(ex)) + + def test_validate_all(self): + snippet = ['foo', {'bar': ['baz', {'blarg': self.func}]}] + function.validate(snippet) + + self.func = TestFunction(None, 'foo', ['bar']) + snippet = {'foo': 'bar', 'blarg': self.func} + ex = self.assertRaises(Exception, function.validate, snippet) + self.assertEqual('Need more arguments', str(ex))