1# (c) 2016, Adrian Likins <alikins@redhat.com> 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17 18# Make coding more python3-ish 19from __future__ import (absolute_import, division, print_function) 20__metaclass__ = type 21 22from units.compat import unittest 23 24from ansible.errors import AnsibleParserError 25from ansible.module_utils.six import string_types 26from ansible.playbook.attribute import FieldAttribute 27from ansible.template import Templar 28from ansible.playbook import base 29from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes, AnsibleUnsafeText 30 31from units.mock.loader import DictDataLoader 32 33 34class TestBase(unittest.TestCase): 35 ClassUnderTest = base.Base 36 37 def setUp(self): 38 self.assorted_vars = {'var_2_key': 'var_2_value', 39 'var_1_key': 'var_1_value', 40 'a_list': ['a_list_1', 'a_list_2'], 41 'a_dict': {'a_dict_key': 'a_dict_value'}, 42 'a_set': set(['set_1', 'set_2']), 43 'a_int': 42, 44 'a_float': 37.371, 45 'a_bool': True, 46 'a_none': None, 47 } 48 self.b = self.ClassUnderTest() 49 50 def _base_validate(self, ds): 51 bsc = self.ClassUnderTest() 52 parent = ExampleParentBaseSubClass() 53 bsc._parent = parent 54 bsc._dep_chain = [parent] 55 parent._dep_chain = None 56 bsc.load_data(ds) 57 fake_loader = DictDataLoader({}) 58 templar = Templar(loader=fake_loader) 59 bsc.post_validate(templar) 60 return bsc 61 62 def test(self): 63 self.assertIsInstance(self.b, base.Base) 64 self.assertIsInstance(self.b, self.ClassUnderTest) 65 66 # dump me doesnt return anything or change anything so not much to assert 67 def test_dump_me_empty(self): 68 self.b.dump_me() 69 70 def test_dump_me(self): 71 ds = {'environment': [], 72 'vars': {'var_2_key': 'var_2_value', 73 'var_1_key': 'var_1_value'}} 74 b = self._base_validate(ds) 75 b.dump_me() 76 77 def _assert_copy(self, orig, copy): 78 self.assertIsInstance(copy, self.ClassUnderTest) 79 self.assertIsInstance(copy, base.Base) 80 self.assertEquals(len(orig._valid_attrs), 81 len(copy._valid_attrs)) 82 83 sentinel = 'Empty DS' 84 self.assertEquals(getattr(orig, '_ds', sentinel), 85 getattr(copy, '_ds', sentinel)) 86 87 def test_copy_empty(self): 88 copy = self.b.copy() 89 self._assert_copy(self.b, copy) 90 91 def test_copy_with_vars(self): 92 ds = {'vars': self.assorted_vars} 93 b = self._base_validate(ds) 94 95 copy = b.copy() 96 self._assert_copy(b, copy) 97 98 def test_serialize(self): 99 ds = {} 100 ds = {'environment': [], 101 'vars': self.assorted_vars 102 } 103 b = self._base_validate(ds) 104 ret = b.serialize() 105 self.assertIsInstance(ret, dict) 106 107 def test_deserialize(self): 108 data = {} 109 110 d = self.ClassUnderTest() 111 d.deserialize(data) 112 self.assertIn('run_once', d._attributes) 113 self.assertIn('check_mode', d._attributes) 114 115 data = {'no_log': False, 116 'remote_user': None, 117 'vars': self.assorted_vars, 118 'environment': [], 119 'run_once': False, 120 'connection': None, 121 'ignore_errors': False, 122 'port': 22, 123 'a_sentinel_with_an_unlikely_name': ['sure, a list']} 124 125 d = self.ClassUnderTest() 126 d.deserialize(data) 127 self.assertNotIn('a_sentinel_with_an_unlikely_name', d._attributes) 128 self.assertIn('run_once', d._attributes) 129 self.assertIn('check_mode', d._attributes) 130 131 def test_serialize_then_deserialize(self): 132 ds = {'environment': [], 133 'vars': self.assorted_vars} 134 b = self._base_validate(ds) 135 copy = b.copy() 136 ret = b.serialize() 137 b.deserialize(ret) 138 c = self.ClassUnderTest() 139 c.deserialize(ret) 140 # TODO: not a great test, but coverage... 141 self.maxDiff = None 142 self.assertDictEqual(b.serialize(), copy.serialize()) 143 self.assertDictEqual(c.serialize(), copy.serialize()) 144 145 def test_post_validate_empty(self): 146 fake_loader = DictDataLoader({}) 147 templar = Templar(loader=fake_loader) 148 ret = self.b.post_validate(templar) 149 self.assertIsNone(ret) 150 151 def test_get_ds_none(self): 152 ds = self.b.get_ds() 153 self.assertIsNone(ds) 154 155 def test_load_data_ds_is_none(self): 156 self.assertRaises(AssertionError, self.b.load_data, None) 157 158 def test_load_data_invalid_attr(self): 159 ds = {'not_a_valid_attr': [], 160 'other': None} 161 162 self.assertRaises(AnsibleParserError, self.b.load_data, ds) 163 164 def test_load_data_invalid_attr_type(self): 165 ds = {'environment': True} 166 167 # environment is supposed to be a list. This 168 # seems like it shouldn't work? 169 ret = self.b.load_data(ds) 170 self.assertEquals(True, ret._attributes['environment']) 171 172 def test_post_validate(self): 173 ds = {'environment': [], 174 'port': 443} 175 b = self._base_validate(ds) 176 self.assertEquals(b.port, 443) 177 self.assertEquals(b.environment, []) 178 179 def test_post_validate_invalid_attr_types(self): 180 ds = {'environment': [], 181 'port': 'some_port'} 182 b = self._base_validate(ds) 183 self.assertEquals(b.port, 'some_port') 184 185 def test_squash(self): 186 data = self.b.serialize() 187 self.b.squash() 188 squashed_data = self.b.serialize() 189 # TODO: assert something 190 self.assertFalse(data['squashed']) 191 self.assertTrue(squashed_data['squashed']) 192 193 def test_vars(self): 194 # vars as a dict. 195 ds = {'environment': [], 196 'vars': {'var_2_key': 'var_2_value', 197 'var_1_key': 'var_1_value'}} 198 b = self._base_validate(ds) 199 self.assertEquals(b.vars['var_1_key'], 'var_1_value') 200 201 def test_vars_list_of_dicts(self): 202 ds = {'environment': [], 203 'vars': [{'var_2_key': 'var_2_value'}, 204 {'var_1_key': 'var_1_value'}] 205 } 206 b = self._base_validate(ds) 207 self.assertEquals(b.vars['var_1_key'], 'var_1_value') 208 209 def test_vars_not_dict_or_list(self): 210 ds = {'environment': [], 211 'vars': 'I am a string, not a dict or a list of dicts'} 212 self.assertRaises(AnsibleParserError, self.b.load_data, ds) 213 214 def test_vars_not_valid_identifier(self): 215 ds = {'environment': [], 216 'vars': [{'var_2_key': 'var_2_value'}, 217 {'1an-invalid identifer': 'var_1_value'}] 218 } 219 self.assertRaises(AnsibleParserError, self.b.load_data, ds) 220 221 def test_vars_is_list_but_not_of_dicts(self): 222 ds = {'environment': [], 223 'vars': ['foo', 'bar', 'this is a string not a dict'] 224 } 225 self.assertRaises(AnsibleParserError, self.b.load_data, ds) 226 227 def test_vars_is_none(self): 228 # If vars is None, we should get a empty dict back 229 ds = {'environment': [], 230 'vars': None 231 } 232 b = self._base_validate(ds) 233 self.assertEquals(b.vars, {}) 234 235 def test_validate_empty(self): 236 self.b.validate() 237 self.assertTrue(self.b._validated) 238 239 def test_getters(self): 240 # not sure why these exist, but here are tests anyway 241 loader = self.b.get_loader() 242 variable_manager = self.b.get_variable_manager() 243 self.assertEquals(loader, self.b._loader) 244 self.assertEquals(variable_manager, self.b._variable_manager) 245 246 247class TestExtendValue(unittest.TestCase): 248 # _extend_value could be a module or staticmethod but since its 249 # not, the test is here. 250 def test_extend_value_list_newlist(self): 251 b = base.Base() 252 value_list = ['first', 'second'] 253 new_value_list = ['new_first', 'new_second'] 254 ret = b._extend_value(value_list, new_value_list) 255 self.assertEquals(value_list + new_value_list, ret) 256 257 def test_extend_value_list_newlist_prepend(self): 258 b = base.Base() 259 value_list = ['first', 'second'] 260 new_value_list = ['new_first', 'new_second'] 261 ret_prepend = b._extend_value(value_list, new_value_list, prepend=True) 262 self.assertEquals(new_value_list + value_list, ret_prepend) 263 264 def test_extend_value_newlist_list(self): 265 b = base.Base() 266 value_list = ['first', 'second'] 267 new_value_list = ['new_first', 'new_second'] 268 ret = b._extend_value(new_value_list, value_list) 269 self.assertEquals(new_value_list + value_list, ret) 270 271 def test_extend_value_newlist_list_prepend(self): 272 b = base.Base() 273 value_list = ['first', 'second'] 274 new_value_list = ['new_first', 'new_second'] 275 ret = b._extend_value(new_value_list, value_list, prepend=True) 276 self.assertEquals(value_list + new_value_list, ret) 277 278 def test_extend_value_string_newlist(self): 279 b = base.Base() 280 some_string = 'some string' 281 new_value_list = ['new_first', 'new_second'] 282 ret = b._extend_value(some_string, new_value_list) 283 self.assertEquals([some_string] + new_value_list, ret) 284 285 def test_extend_value_string_newstring(self): 286 b = base.Base() 287 some_string = 'some string' 288 new_value_string = 'this is the new values' 289 ret = b._extend_value(some_string, new_value_string) 290 self.assertEquals([some_string, new_value_string], ret) 291 292 def test_extend_value_list_newstring(self): 293 b = base.Base() 294 value_list = ['first', 'second'] 295 new_value_string = 'this is the new values' 296 ret = b._extend_value(value_list, new_value_string) 297 self.assertEquals(value_list + [new_value_string], ret) 298 299 def test_extend_value_none_none(self): 300 b = base.Base() 301 ret = b._extend_value(None, None) 302 self.assertEquals(len(ret), 0) 303 self.assertFalse(ret) 304 305 def test_extend_value_none_list(self): 306 b = base.Base() 307 ret = b._extend_value(None, ['foo']) 308 self.assertEquals(ret, ['foo']) 309 310 311class ExampleException(Exception): 312 pass 313 314 315# naming fails me... 316class ExampleParentBaseSubClass(base.Base): 317 _test_attr_parent_string = FieldAttribute(isa='string', default='A string attr for a class that may be a parent for testing') 318 319 def __init__(self): 320 321 super(ExampleParentBaseSubClass, self).__init__() 322 self._dep_chain = None 323 324 def get_dep_chain(self): 325 return self._dep_chain 326 327 328class ExampleSubClass(base.Base): 329 _test_attr_blip = FieldAttribute(isa='string', default='example sub class test_attr_blip', 330 inherit=False, 331 always_post_validate=True) 332 333 def __init__(self): 334 super(ExampleSubClass, self).__init__() 335 336 def get_dep_chain(self): 337 if self._parent: 338 return self._parent.get_dep_chain() 339 else: 340 return None 341 342 343class BaseSubClass(base.Base): 344 _name = FieldAttribute(isa='string', default='', always_post_validate=True) 345 _test_attr_bool = FieldAttribute(isa='bool', always_post_validate=True) 346 _test_attr_int = FieldAttribute(isa='int', always_post_validate=True) 347 _test_attr_float = FieldAttribute(isa='float', default=3.14159, always_post_validate=True) 348 _test_attr_list = FieldAttribute(isa='list', listof=string_types, always_post_validate=True) 349 _test_attr_list_no_listof = FieldAttribute(isa='list', always_post_validate=True) 350 _test_attr_list_required = FieldAttribute(isa='list', listof=string_types, required=True, 351 default=list, always_post_validate=True) 352 _test_attr_string = FieldAttribute(isa='string', default='the_test_attr_string_default_value') 353 _test_attr_string_required = FieldAttribute(isa='string', required=True, 354 default='the_test_attr_string_default_value') 355 _test_attr_percent = FieldAttribute(isa='percent', always_post_validate=True) 356 _test_attr_set = FieldAttribute(isa='set', default=set, always_post_validate=True) 357 _test_attr_dict = FieldAttribute(isa='dict', default=lambda: {'a_key': 'a_value'}, always_post_validate=True) 358 _test_attr_class = FieldAttribute(isa='class', class_type=ExampleSubClass) 359 _test_attr_class_post_validate = FieldAttribute(isa='class', class_type=ExampleSubClass, 360 always_post_validate=True) 361 _test_attr_unknown_isa = FieldAttribute(isa='not_a_real_isa', always_post_validate=True) 362 _test_attr_example = FieldAttribute(isa='string', default='the_default', 363 always_post_validate=True) 364 _test_attr_none = FieldAttribute(isa='string', always_post_validate=True) 365 _test_attr_preprocess = FieldAttribute(isa='string', default='the default for preprocess') 366 _test_attr_method = FieldAttribute(isa='string', default='some attr with a getter', 367 always_post_validate=True) 368 _test_attr_method_missing = FieldAttribute(isa='string', default='some attr with a missing getter', 369 always_post_validate=True) 370 371 def _get_attr_test_attr_method(self): 372 return 'foo bar' 373 374 def _validate_test_attr_example(self, attr, name, value): 375 if not isinstance(value, str): 376 raise ExampleException('_test_attr_example is not a string: %s type=%s' % (value, type(value))) 377 378 def _post_validate_test_attr_example(self, attr, value, templar): 379 after_template_value = templar.template(value) 380 return after_template_value 381 382 def _post_validate_test_attr_none(self, attr, value, templar): 383 return None 384 385 def _get_parent_attribute(self, attr, extend=False, prepend=False): 386 value = None 387 try: 388 value = self._attributes[attr] 389 if self._parent and (value is None or extend): 390 parent_value = getattr(self._parent, attr, None) 391 if extend: 392 value = self._extend_value(value, parent_value, prepend) 393 else: 394 value = parent_value 395 except KeyError: 396 pass 397 398 return value 399 400 401# terrible name, but it is a TestBase subclass for testing subclasses of Base 402class TestBaseSubClass(TestBase): 403 ClassUnderTest = BaseSubClass 404 405 def _base_validate(self, ds): 406 ds['test_attr_list_required'] = [] 407 return super(TestBaseSubClass, self)._base_validate(ds) 408 409 def test_attr_bool(self): 410 ds = {'test_attr_bool': True} 411 bsc = self._base_validate(ds) 412 self.assertEquals(bsc.test_attr_bool, True) 413 414 def test_attr_int(self): 415 MOST_RANDOM_NUMBER = 37 416 ds = {'test_attr_int': MOST_RANDOM_NUMBER} 417 bsc = self._base_validate(ds) 418 self.assertEquals(bsc.test_attr_int, MOST_RANDOM_NUMBER) 419 420 def test_attr_int_del(self): 421 MOST_RANDOM_NUMBER = 37 422 ds = {'test_attr_int': MOST_RANDOM_NUMBER} 423 bsc = self._base_validate(ds) 424 del bsc.test_attr_int 425 self.assertNotIn('test_attr_int', bsc._attributes) 426 427 def test_attr_float(self): 428 roughly_pi = 4.0 429 ds = {'test_attr_float': roughly_pi} 430 bsc = self._base_validate(ds) 431 self.assertEquals(bsc.test_attr_float, roughly_pi) 432 433 def test_attr_percent(self): 434 percentage = '90%' 435 percentage_float = 90.0 436 ds = {'test_attr_percent': percentage} 437 bsc = self._base_validate(ds) 438 self.assertEquals(bsc.test_attr_percent, percentage_float) 439 440 # This method works hard and gives it its all and everything it's got. It doesn't 441 # leave anything on the field. It deserves to pass. It has earned it. 442 def test_attr_percent_110_percent(self): 443 percentage = '110.11%' 444 percentage_float = 110.11 445 ds = {'test_attr_percent': percentage} 446 bsc = self._base_validate(ds) 447 self.assertEquals(bsc.test_attr_percent, percentage_float) 448 449 # This method is just here for the paycheck. 450 def test_attr_percent_60_no_percent_sign(self): 451 percentage = '60' 452 percentage_float = 60.0 453 ds = {'test_attr_percent': percentage} 454 bsc = self._base_validate(ds) 455 self.assertEquals(bsc.test_attr_percent, percentage_float) 456 457 def test_attr_set(self): 458 test_set = set(['first_string_in_set', 'second_string_in_set']) 459 ds = {'test_attr_set': test_set} 460 bsc = self._base_validate(ds) 461 self.assertEquals(bsc.test_attr_set, test_set) 462 463 def test_attr_set_string(self): 464 test_data = ['something', 'other'] 465 test_value = ','.join(test_data) 466 ds = {'test_attr_set': test_value} 467 bsc = self._base_validate(ds) 468 self.assertEquals(bsc.test_attr_set, set(test_data)) 469 470 def test_attr_set_not_string_or_list(self): 471 test_value = 37.1 472 ds = {'test_attr_set': test_value} 473 bsc = self._base_validate(ds) 474 self.assertEquals(bsc.test_attr_set, set([test_value])) 475 476 def test_attr_dict(self): 477 test_dict = {'a_different_key': 'a_different_value'} 478 ds = {'test_attr_dict': test_dict} 479 bsc = self._base_validate(ds) 480 self.assertEquals(bsc.test_attr_dict, test_dict) 481 482 def test_attr_dict_string(self): 483 test_value = 'just_some_random_string' 484 ds = {'test_attr_dict': test_value} 485 self.assertRaisesRegexp(AnsibleParserError, 'is not a dictionary', self._base_validate, ds) 486 487 def test_attr_class(self): 488 esc = ExampleSubClass() 489 ds = {'test_attr_class': esc} 490 bsc = self._base_validate(ds) 491 self.assertIs(bsc.test_attr_class, esc) 492 493 def test_attr_class_wrong_type(self): 494 not_a_esc = ExampleSubClass 495 ds = {'test_attr_class': not_a_esc} 496 bsc = self._base_validate(ds) 497 self.assertIs(bsc.test_attr_class, not_a_esc) 498 499 def test_attr_class_post_validate(self): 500 esc = ExampleSubClass() 501 ds = {'test_attr_class_post_validate': esc} 502 bsc = self._base_validate(ds) 503 self.assertIs(bsc.test_attr_class_post_validate, esc) 504 505 def test_attr_class_post_validate_class_not_instance(self): 506 not_a_esc = ExampleSubClass 507 ds = {'test_attr_class_post_validate': not_a_esc} 508 self.assertRaisesRegexp(AnsibleParserError, 'is not a valid.*got a.*Meta.*instead', 509 self._base_validate, ds) 510 511 def test_attr_class_post_validate_wrong_class(self): 512 not_a_esc = 37 513 ds = {'test_attr_class_post_validate': not_a_esc} 514 self.assertRaisesRegexp(AnsibleParserError, 'is not a valid.*got a.*int.*instead', 515 self._base_validate, ds) 516 517 def test_attr_remote_user(self): 518 ds = {'remote_user': 'testuser'} 519 bsc = self._base_validate(ds) 520 # TODO: attemp to verify we called parent gettters etc 521 self.assertEquals(bsc.remote_user, 'testuser') 522 523 def test_attr_example_undefined(self): 524 ds = {'test_attr_example': '{{ some_var_that_shouldnt_exist_to_test_omit }}'} 525 exc_regex_str = 'test_attr_example.*has an invalid value, which includes an undefined variable.*some_var_that_shouldnt*' 526 self.assertRaises(AnsibleParserError) 527 528 def test_attr_name_undefined(self): 529 ds = {'name': '{{ some_var_that_shouldnt_exist_to_test_omit }}'} 530 bsc = self._base_validate(ds) 531 # the attribute 'name' is special cases in post_validate 532 self.assertEquals(bsc.name, '{{ some_var_that_shouldnt_exist_to_test_omit }}') 533 534 def test_subclass_validate_method(self): 535 ds = {'test_attr_list': ['string_list_item_1', 'string_list_item_2'], 536 'test_attr_example': 'the_test_attr_example_value_string'} 537 # Not throwing an exception here is the test 538 bsc = self._base_validate(ds) 539 self.assertEquals(bsc.test_attr_example, 'the_test_attr_example_value_string') 540 541 def test_subclass_validate_method_invalid(self): 542 ds = {'test_attr_example': [None]} 543 self.assertRaises(ExampleException, self._base_validate, ds) 544 545 def test_attr_none(self): 546 ds = {'test_attr_none': 'foo'} 547 bsc = self._base_validate(ds) 548 self.assertEquals(bsc.test_attr_none, None) 549 550 def test_attr_string(self): 551 the_string_value = "the new test_attr_string_value" 552 ds = {'test_attr_string': the_string_value} 553 bsc = self._base_validate(ds) 554 self.assertEquals(bsc.test_attr_string, the_string_value) 555 556 def test_attr_string_invalid_list(self): 557 ds = {'test_attr_string': ['The new test_attr_string', 'value, however in a list']} 558 self.assertRaises(AnsibleParserError, self._base_validate, ds) 559 560 def test_attr_string_required(self): 561 the_string_value = "the new test_attr_string_required_value" 562 ds = {'test_attr_string_required': the_string_value} 563 bsc = self._base_validate(ds) 564 self.assertEquals(bsc.test_attr_string_required, the_string_value) 565 566 def test_attr_list_invalid(self): 567 ds = {'test_attr_list': {}} 568 self.assertRaises(AnsibleParserError, self._base_validate, ds) 569 570 def test_attr_list(self): 571 string_list = ['foo', 'bar'] 572 ds = {'test_attr_list': string_list} 573 bsc = self._base_validate(ds) 574 self.assertEquals(string_list, bsc._attributes['test_attr_list']) 575 576 def test_attr_list_none(self): 577 ds = {'test_attr_list': None} 578 bsc = self._base_validate(ds) 579 self.assertEquals(None, bsc._attributes['test_attr_list']) 580 581 def test_attr_list_no_listof(self): 582 test_list = ['foo', 'bar', 123] 583 ds = {'test_attr_list_no_listof': test_list} 584 bsc = self._base_validate(ds) 585 self.assertEquals(test_list, bsc._attributes['test_attr_list_no_listof']) 586 587 def test_attr_list_required(self): 588 string_list = ['foo', 'bar'] 589 ds = {'test_attr_list_required': string_list} 590 bsc = self.ClassUnderTest() 591 bsc.load_data(ds) 592 fake_loader = DictDataLoader({}) 593 templar = Templar(loader=fake_loader) 594 bsc.post_validate(templar) 595 self.assertEquals(string_list, bsc._attributes['test_attr_list_required']) 596 597 def test_attr_list_required_empty_string(self): 598 string_list = [""] 599 ds = {'test_attr_list_required': string_list} 600 bsc = self.ClassUnderTest() 601 bsc.load_data(ds) 602 fake_loader = DictDataLoader({}) 603 templar = Templar(loader=fake_loader) 604 self.assertRaisesRegexp(AnsibleParserError, 'cannot have empty values', 605 bsc.post_validate, templar) 606 607 def test_attr_unknown(self): 608 a_list = ['some string'] 609 ds = {'test_attr_unknown_isa': a_list} 610 bsc = self._base_validate(ds) 611 self.assertEquals(bsc.test_attr_unknown_isa, a_list) 612 613 def test_attr_method(self): 614 ds = {'test_attr_method': 'value from the ds'} 615 bsc = self._base_validate(ds) 616 # The value returned by the subclasses _get_attr_test_attr_method 617 self.assertEquals(bsc.test_attr_method, 'foo bar') 618 619 def test_attr_method_missing(self): 620 a_string = 'The value set from the ds' 621 ds = {'test_attr_method_missing': a_string} 622 bsc = self._base_validate(ds) 623 self.assertEquals(bsc.test_attr_method_missing, a_string) 624 625 def test_get_validated_value_string_rewrap_unsafe(self): 626 attribute = FieldAttribute(isa='string') 627 value = AnsibleUnsafeText(u'bar') 628 templar = Templar(None) 629 bsc = self.ClassUnderTest() 630 result = bsc.get_validated_value('foo', attribute, value, templar) 631 self.assertIsInstance(result, AnsibleUnsafeText) 632 self.assertEquals(result, AnsibleUnsafeText(u'bar')) 633