diff --git a/tuskar/api/controllers/v2/models.py b/tuskar/api/controllers/v2/models.py index 9f838a3f..fecb24e7 100644 --- a/tuskar/api/controllers/v2/models.py +++ b/tuskar/api/controllers/v2/models.py @@ -20,11 +20,12 @@ the internal Tuskar domain model. import datetime import logging +import six from wsme import types as wtypes +from tuskar.api.controllers.v2 import types as v2types from tuskar.manager import models as manager_models - LOG = logging.getLogger(__name__) @@ -72,10 +73,10 @@ class PlanParameter(Base): name = wtypes.text label = wtypes.text - default = wtypes.text + default = v2types.MultiType(wtypes.text, six.integer_types, list, dict) description = wtypes.text hidden = bool - value = wtypes.text + value = v2types.MultiType(wtypes.text, six.integer_types, list, dict) @classmethod def from_tuskar_model(cls, param): diff --git a/tuskar/api/controllers/v2/types.py b/tuskar/api/controllers/v2/types.py new file mode 100644 index 00000000..7a36040b --- /dev/null +++ b/tuskar/api/controllers/v2/types.py @@ -0,0 +1,40 @@ +# 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 wsme +from wsme import types as wtypes + + +class MultiType(wtypes.UserType): + """A complex type that represents one or more types. + + Used for validating that a value is an instance of one of the types. + + :param *types: Variable-length list of types. + + """ + def __init__(self, *types): + self.types = types + + def __str__(self): + return ' | '.join(map(str, self.types)) + + def validate(self, value): + for t in self.types: + if t is wsme.types.text and isinstance(value, wsme.types.bytes): + value = value.decode() + if isinstance(value, t): + return value + else: + raise ValueError( + _("Wrong type. Expected '%(type)s', got '%(value)s'") + % {'type': self.types, 'value': type(value)}) diff --git a/tuskar/tests/api/controllers/v2/test_plans.py b/tuskar/tests/api/controllers/v2/test_plans.py index 1ed9987c..2007d74b 100644 --- a/tuskar/tests/api/controllers/v2/test_plans.py +++ b/tuskar/tests/api/controllers/v2/test_plans.py @@ -98,6 +98,33 @@ class PlansTests(base.TestCase): mock_retrieve.assert_called_once_with('qwerty12345') self.assertEqual(response.status_int, 404) + @mock.patch('tuskar.manager.plan.PlansManager.retrieve_plan') + def test_get_one_with_parameters(self, mock_retrieve): + # Setup + p = manager_models.DeploymentPlan('a', 'n', 'd') + p.add_parameters( + manager_models.PlanParameter( + name="Param 1", label="1", default=2, hidden=False, + description="1", value=1, param_type=int), + manager_models.PlanParameter( + name="Param 2", label="2", default=['a', ], hidden=False, + description="2", value=['a', 'b'], param_type=list), + manager_models.PlanParameter( + name="Param 3", label="3", default={'a': 2}, hidden=False, + description="3", value={'a': 1}, param_type=dict), + ) + mock_retrieve.return_value = p + + # Test + url = URL_PLANS + '/' + 'qwerty12345' + response = self.app.get(url) + result = response.json + + # Verify + mock_retrieve.assert_called_once_with('qwerty12345') + self.assertEqual(response.status_int, 200) + self.assertEqual(result['name'], 'n') + @mock.patch('tuskar.manager.plan.PlansManager.delete_plan') def test_delete(self, mock_delete): # Test