Source code for glance.tests.unit.test_glare_type_definition_framework

# Copyright (c) 2015 Mirantis, Inc.
#
# 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 datetime
import functools

import mock
import six

import glance.common.exception as exc
from glance.common.glare import declarative
import glance.common.glare.definitions as defs
from glance.common.glare import serialization
import glance.tests.utils as test_utils


BASE = declarative.get_declarative_base()


[docs]class TestDeclarativeProperties(test_utils.BaseTestCase):
[docs] def test_artifact_type_properties(self): class SomeTypeWithNoExplicitName(BASE): some_attr = declarative.AttributeDefinition() class InheritedType(SomeTypeWithNoExplicitName): __type_version__ = '1.0' __type_name__ = 'ExplicitName' __type_description__ = 'Type description' __type_display_name__ = 'EXPLICIT_NAME' __endpoint__ = 'some_endpoint' some_attr = declarative.AttributeDefinition(display_name='NAME') base_type = SomeTypeWithNoExplicitName base_instance = SomeTypeWithNoExplicitName() self.assertIsNotNone(base_type.metadata) self.assertIsNotNone(base_instance.metadata) self.assertEqual(base_type.metadata, base_instance.metadata) self.assertEqual("SomeTypeWithNoExplicitName", base_type.metadata.type_name) self.assertEqual("SomeTypeWithNoExplicitName", base_type.metadata.type_display_name) self.assertEqual("1.0", base_type.metadata.type_version) self.assertIsNone(base_type.metadata.type_description) self.assertEqual('sometypewithnoexplicitname', base_type.metadata.endpoint) self.assertIsNone(base_instance.some_attr) self.assertIsNotNone(base_type.some_attr) self.assertEqual(base_type.some_attr, base_instance.metadata.attributes.all['some_attr']) self.assertEqual('some_attr', base_type.some_attr.name) self.assertEqual('some_attr', base_type.some_attr.display_name) self.assertIsNone(base_type.some_attr.description) derived_type = InheritedType derived_instance = InheritedType() self.assertIsNotNone(derived_type.metadata) self.assertIsNotNone(derived_instance.metadata) self.assertEqual(derived_type.metadata, derived_instance.metadata) self.assertEqual('ExplicitName', derived_type.metadata.type_name) self.assertEqual('EXPLICIT_NAME', derived_type.metadata.type_display_name) self.assertEqual('1.0', derived_type.metadata.type_version) self.assertEqual('Type description', derived_type.metadata.type_description) self.assertEqual('some_endpoint', derived_type.metadata.endpoint) self.assertIsNone(derived_instance.some_attr) self.assertIsNotNone(derived_type.some_attr) self.assertEqual(derived_type.some_attr, derived_instance.metadata.attributes.all['some_attr']) self.assertEqual('some_attr', derived_type.some_attr.name) self.assertEqual('NAME', derived_type.some_attr.display_name)
[docs] def test_wrong_type_definition(self): def declare_wrong_type_version(): class WrongType(BASE): __type_version__ = 'abc' # not a semver return WrongType def declare_wrong_type_name(): class WrongType(BASE): __type_name__ = 'a' * 256 # too long return WrongType self.assertRaises(exc.InvalidArtifactTypeDefinition, declare_wrong_type_version) self.assertRaises(exc.InvalidArtifactTypeDefinition, declare_wrong_type_name)
[docs] def test_base_declarative_attributes(self): class TestType(BASE): defaulted = declarative.PropertyDefinition(default=42) read_only = declarative.PropertyDefinition(readonly=True) required_attr = declarative.PropertyDefinition(required=True) e = self.assertRaises(exc.InvalidArtifactPropertyValue, TestType) self.assertEqual('required_attr', e.name) self.assertIsNone(e.value) tt = TestType(required_attr="universe") self.assertEqual('universe', tt.required_attr) self.assertEqual(42, tt.defaulted) self.assertIsNone(tt.read_only) tt = TestType(required_attr="universe", defaulted=0, read_only="Hello") self.assertEqual(0, tt.defaulted) self.assertEqual("Hello", tt.read_only) tt.defaulted = 5 self.assertEqual(5, tt.defaulted) tt.required_attr = 'Foo' self.assertEqual('Foo', tt.required_attr) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'read_only', 'some_val') self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'required_attr', None) # no type checks in base AttributeDefinition o = object() tt.required_attr = o self.assertEqual(o, tt.required_attr)
[docs] def test_generic_property(self): class TestType(BASE): simple_prop = declarative.PropertyDefinition() immutable_internal = declarative.PropertyDefinition(mutable=False, internal=True) prop_with_allowed = declarative.PropertyDefinition( allowed_values=["Foo", True, 42]) class DerivedType(TestType): prop_with_allowed = declarative.PropertyDefinition( allowed_values=["Foo", True, 42], required=True, default=42) tt = TestType() self.assertEqual(True, tt.metadata.attributes.all['simple_prop'].mutable) self.assertEqual(False, tt.metadata.attributes.all['simple_prop'].internal) self.assertEqual(False, tt.metadata.attributes.all[ 'immutable_internal'].mutable) self.assertEqual(True, tt.metadata.attributes.all[ 'immutable_internal'].internal) self.assertIsNone(tt.prop_with_allowed) tt = TestType(prop_with_allowed=42) self.assertEqual(42, tt.prop_with_allowed) tt = TestType(prop_with_allowed=True) self.assertEqual(True, tt.prop_with_allowed) tt = TestType(prop_with_allowed='Foo') self.assertEqual('Foo', tt.prop_with_allowed) tt.prop_with_allowed = 42 self.assertEqual(42, tt.prop_with_allowed) tt.prop_with_allowed = 'Foo' self.assertEqual('Foo', tt.prop_with_allowed) tt.prop_with_allowed = True self.assertEqual(True, tt.prop_with_allowed) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'prop_with_allowed', 'bar') # ensure that wrong assignment didn't change the value self.assertEqual(True, tt.prop_with_allowed) self.assertRaises(exc.InvalidArtifactPropertyValue, TestType, prop_with_allowed=False) dt = DerivedType() self.assertEqual(42, dt.prop_with_allowed)
[docs] def test_default_violates_allowed(self): def declare_wrong_type(): class WrongType(BASE): prop = declarative.PropertyDefinition( allowed_values=['foo', 'bar'], default='baz') return WrongType self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_type)
[docs] def test_string_property(self): class TestType(BASE): simple = defs.String() with_length = defs.String(max_length=10, min_length=5) with_pattern = defs.String(pattern='^\\d+$', default='42') tt = TestType() tt.simple = 'foo' self.assertEqual('foo', tt.simple) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'simple', 42) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'simple', 'x' * 256) self.assertRaises(exc.InvalidArtifactPropertyValue, TestType, simple='x' * 256) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'with_length', 'x' * 11) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'with_length', 'x' * 4) tt.simple = 'x' * 5 self.assertEqual('x' * 5, tt.simple) tt.simple = 'x' * 10 self.assertEqual('x' * 10, tt.simple) self.assertEqual("42", tt.with_pattern) tt.with_pattern = '0' self.assertEqual('0', tt.with_pattern) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'with_pattern', 'abc') self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'with_pattern', '.123.')
[docs] def test_binary_object_mutable(self): def declare_blob(mutable): class BLOB(BASE): prop = defs.BinaryObject(mutable=mutable) return BLOB blob = declare_blob(False)() self.assertFalse(blob.metadata.attributes.all['prop'].mutable) self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, functools.partial(declare_blob, True))
[docs] def test_default_and_allowed_violates_string_constrains(self): def declare_wrong_default(): class WrongType(BASE): prop = defs.String(min_length=4, default='foo') return WrongType def declare_wrong_allowed(): class WrongType(BASE): prop = defs.String(min_length=4, allowed_values=['foo', 'bar']) return WrongType self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_default) self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_allowed)
[docs] def test_integer_property(self): class TestType(BASE): simple = defs.Integer() constrained = defs.Integer(min_value=10, max_value=50) tt = TestType() self.assertIsNone(tt.simple) self.assertIsNone(tt.constrained) tt.simple = 0 tt.constrained = 10 self.assertEqual(0, tt.simple) self.assertEqual(10, tt.constrained) tt.constrained = 50 self.assertEqual(50, tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'constrained', 1) self.assertEqual(50, tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'constrained', 51) self.assertEqual(50, tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'simple', '11') self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'simple', 10.5)
[docs] def test_default_and_allowed_violates_int_constrains(self): def declare_wrong_default(): class WrongType(BASE): prop = defs.Integer(min_value=4, default=1) return WrongType def declare_wrong_allowed(): class WrongType(BASE): prop = defs.Integer(min_value=4, max_value=10, allowed_values=[1, 15]) return WrongType self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_default) self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_allowed)
[docs] def test_numeric_values(self): class TestType(BASE): simple = defs.Numeric() constrained = defs.Numeric(min_value=3.14, max_value=4.1) tt = TestType(simple=0.1, constrained=4) self.assertEqual(0.1, tt.simple) self.assertEqual(4.0, tt.constrained) tt.simple = 1 self.assertEqual(1, tt.simple) tt.constrained = 3.14 self.assertEqual(3.14, tt.constrained) tt.constrained = 4.1 self.assertEqual(4.1, tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'simple', 'qwerty') self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'constrained', 3) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, 'constrained', 5)
[docs] def test_default_and_allowed_violates_numeric_constrains(self): def declare_wrong_default(): class WrongType(BASE): prop = defs.Numeric(min_value=4.0, default=1.1) return WrongType def declare_wrong_allowed(): class WrongType(BASE): prop = defs.Numeric(min_value=4.0, max_value=10.0, allowed_values=[1.0, 15.5]) return WrongType self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_default) self.assertRaises(exc.InvalidArtifactTypePropertyDefinition, declare_wrong_allowed)
[docs] def test_same_item_type_array(self): class TestType(BASE): simple = defs.Array() unique = defs.Array(unique=True) simple_with_allowed_values = defs.Array( defs.String(allowed_values=["Foo", "Bar"])) defaulted = defs.Array(defs.Boolean(), default=[True, False]) constrained = defs.Array(item_type=defs.Numeric(min_value=0), min_size=3, max_size=5, unique=True) tt = TestType(simple=[]) self.assertEqual([], tt.simple) tt.simple.append("Foo") self.assertEqual(["Foo"], tt.simple) tt.simple.append("Foo") self.assertEqual(["Foo", "Foo"], tt.simple) self.assertEqual(2, len(tt.simple)) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.simple.append, 42) tt.simple.pop(1) self.assertEqual(["Foo"], tt.simple) del tt.simple[0] self.assertEqual(0, len(tt.simple)) tt.simple_with_allowed_values = ["Foo"] tt.simple_with_allowed_values.insert(0, "Bar") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.simple_with_allowed_values.append, "Baz") self.assertEqual([True, False], tt.defaulted) tt.defaulted.pop() self.assertEqual([True], tt.defaulted) tt2 = TestType() self.assertEqual([True, False], tt2.defaulted) self.assertIsNone(tt.constrained) tt.constrained = [10, 5, 4] self.assertEqual([10, 5, 4], tt.constrained) tt.constrained[1] = 15 self.assertEqual([10, 15, 4], tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained.__setitem__, 1, -5) self.assertEqual([10, 15, 4], tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained.remove, 15) self.assertEqual([10, 15, 4], tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained.__delitem__, 1) self.assertEqual([10, 15, 4], tt.constrained) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained.append, 15) self.assertEqual([10, 15, 4], tt.constrained) tt.unique = [] tt.unique.append("foo") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.unique.append, "foo")
[docs] def test_tuple_style_array(self): class TestType(BASE): address = defs.Array( item_type=[defs.String(20), defs.Integer(min_value=1), defs.Boolean()]) tt = TestType(address=["Hope Street", 1234, True]) self.assertEqual("Hope Street", tt.address[0]) self.assertEqual(1234, tt.address[1]) self.assertEqual(True, tt.address[2]) # On Python 3, sort() fails because int (1) and string ("20") are not # comparable if six.PY2: self.assertRaises(exc.InvalidArtifactPropertyValue, tt.address.sort) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.address.pop, 0) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.address.pop, 1) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.address.pop) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.address.append, "Foo")
[docs] def test_same_item_type_dict(self): class TestType(BASE): simple_props = defs.Dict() constrained_props = defs.Dict( properties=defs.Integer(min_value=1, allowed_values=[1, 2]), min_properties=2, max_properties=3) tt = TestType() self.assertIsNone(tt.simple_props) self.assertIsNone(tt.constrained_props) tt.simple_props = {} self.assertEqual({}, tt.simple_props) tt.simple_props["foo"] = "bar" self.assertEqual({"foo": "bar"}, tt.simple_props) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.simple_props.__setitem__, 42, "foo") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.simple_props.setdefault, "bar", 42) tt.constrained_props = {"foo": 1, "bar": 2} self.assertEqual({"foo": 1, "bar": 2}, tt.constrained_props) tt.constrained_props["baz"] = 1 self.assertEqual({"foo": 1, "bar": 2, "baz": 1}, tt.constrained_props) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained_props.__setitem__, "foo", 3) self.assertEqual(1, tt.constrained_props["foo"]) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained_props.__setitem__, "qux", 2) tt.constrained_props.pop("foo") self.assertEqual({"bar": 2, "baz": 1}, tt.constrained_props) tt.constrained_props['qux'] = 2 self.assertEqual({"qux": 2, "bar": 2, "baz": 1}, tt.constrained_props) tt.constrained_props.popitem() dict_copy = tt.constrained_props.copy() self.assertRaises(exc.InvalidArtifactPropertyValue, tt.constrained_props.popitem) self.assertEqual(dict_copy, tt.constrained_props)
[docs] def test_composite_dict(self): class TestType(BASE): props = defs.Dict(properties={"foo": defs.String(), "bar": defs.Boolean()}) fixed = defs.Dict(properties={"name": defs.String(min_length=2), "age": defs.Integer(min_value=0, max_value=99)}) tt = TestType() tt.props = {"foo": "FOO", "bar": False} self.assertRaises(exc.InvalidArtifactPropertyValue, tt.props.__setitem__, "bar", 123) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.props.__setitem__, "extra", "value") tt.fixed = {"name": "Alex", "age": 42} self.assertRaises(exc.InvalidArtifactPropertyValue, tt.fixed.__setitem__, "age", 120)
[docs] def test_immutables(self): class TestType(BASE): activated = defs.Boolean(required=True, default=False) name = defs.String(mutable=False) def __is_mutable__(self): return not self.activated tt = TestType() self.assertEqual(False, tt.activated) self.assertIsNone(tt.name) tt.name = "Foo" self.assertEqual("Foo", tt.name) tt.activated = True self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, "name", "Bar") self.assertEqual("Foo", tt.name) tt.activated = False tt.name = "Bar" self.assertEqual("Bar", tt.name)
[docs] def test_readonly_array_dict(self): class TestType(BASE): arr = defs.Array(readonly=True) dict = defs.Dict(readonly=True) tt = TestType(arr=["Foo", "Bar"], dict={"qux": "baz"}) self.assertEqual(["Foo", "Bar"], tt.arr) self.assertEqual({"qux": "baz"}, tt.dict) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.append, "Baz") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.insert, 0, "Baz") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.__setitem__, 0, "Baz") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.remove, "Foo") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.pop) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.dict.pop, "qux") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.dict.__setitem__, "qux", "foo")
[docs] def test_mutable_array_dict(self): class TestType(BASE): arr = defs.Array(mutable=False) dict = defs.Dict(mutable=False) activated = defs.Boolean() def __is_mutable__(self): return not self.activated tt = TestType() tt.arr = [] tt.dict = {} tt.arr.append("Foo") tt.arr.insert(0, "Bar") tt.dict["baz"] = "qux" tt.activated = True self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.append, "Baz") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.insert, 0, "Baz") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.__setitem__, 0, "Baz") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.remove, "Foo") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.pop) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.dict.pop, "qux") self.assertRaises(exc.InvalidArtifactPropertyValue, tt.dict.__setitem__, "qux", "foo")
[docs] def test_readonly_as_write_once(self): class TestType(BASE): prop = defs.String(readonly=True) arr = defs.Array(readonly=True) tt = TestType() self.assertIsNone(tt.prop) tt.prop = "Foo" self.assertEqual("Foo", tt.prop) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt, "prop", "bar") tt2 = TestType() self.assertIsNone(tt2.prop) tt2.prop = None self.assertIsNone(tt2.prop) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt2, "prop", None) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, tt2, "prop", "foo") self.assertIsNone(tt.arr) tt.arr = ["foo", "bar"] self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.append, 'baz') self.assertIsNone(tt2.arr) tt2.arr = None self.assertRaises(exc.InvalidArtifactPropertyValue, tt.arr.append, 'baz')
[docs]class TestArtifactType(test_utils.BaseTestCase):
[docs] def test_create_artifact(self): a = defs.ArtifactType(**get_artifact_fixture()) self.assertIsNotNone(a) self.assertEqual("123", a.id) self.assertEqual("ArtifactType", a.type_name) self.assertEqual("1.0", a.type_version) self.assertEqual("11.2", a.version) self.assertEqual("Foo", a.name) self.assertEqual("private", a.visibility) self.assertEqual("creating", a.state) self.assertEqual("my_tenant", a.owner) self.assertEqual(a.created_at, a.updated_at) self.assertIsNone(a.description) self.assertIsNone(a.published_at) self.assertIsNone(a.deleted_at) self.assertIsNone(a.description) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "id", "foo") self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "state", "active") self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "owner", "some other") self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "created_at", datetime.datetime.now()) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "deleted_at", datetime.datetime.now()) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "updated_at", datetime.datetime.now()) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "published_at", datetime.datetime.now()) self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, a, "visibility", "wrong")
[docs] def test_dependency_prop(self): class DerivedType(defs.ArtifactType): depends_on_any = defs.ArtifactReference() depends_on_self = defs.ArtifactReference(type_name='DerivedType') depends_on_self_version = defs.ArtifactReference( type_name='DerivedType', type_version='1.0') class DerivedTypeV11(DerivedType): __type_name__ = 'DerivedType' __type_version__ = '1.1' depends_on_self_version = defs.ArtifactReference( type_name='DerivedType', type_version='1.1') d1 = DerivedType(**get_artifact_fixture()) d2 = DerivedTypeV11(**get_artifact_fixture()) a = defs.ArtifactType(**get_artifact_fixture()) d1.depends_on_any = a self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, d1, 'depends_on_self', a) d1.depends_on_self = d2 d2.depends_on_self = d1 d1.depends_on_self_version = d1 d2.depends_on_self_version = d2 self.assertRaises(exc.InvalidArtifactPropertyValue, setattr, d1, 'depends_on_self_version', d2)
[docs] def test_dependency_list(self): class FooType(defs.ArtifactType): pass class BarType(defs.ArtifactType): pass class TestType(defs.ArtifactType): depends_on = defs.ArtifactReferenceList() depends_on_self_or_foo = defs.ArtifactReferenceList( references=defs.ArtifactReference(['FooType', 'TestType'])) a = defs.ArtifactType(**get_artifact_fixture(id="1")) a_copy = defs.ArtifactType(**get_artifact_fixture(id="1")) b = defs.ArtifactType(**get_artifact_fixture(id="2")) tt = TestType(**get_artifact_fixture(id="3")) foo = FooType(**get_artifact_fixture(id='4')) bar = BarType(**get_artifact_fixture(id='4')) tt.depends_on.append(a) tt.depends_on.append(b) self.assertEqual([a, b], tt.depends_on) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.depends_on.append, a) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.depends_on.append, a_copy) tt.depends_on_self_or_foo.append(tt) tt.depends_on_self_or_foo.append(foo) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.depends_on_self_or_foo.append, bar) self.assertEqual([tt, foo], tt.depends_on_self_or_foo)
[docs] def test_blob(self): class TestType(defs.ArtifactType): image_file = defs.BinaryObject(max_file_size=201054, min_locations=1, max_locations=5) screen_shots = defs.BinaryObjectList( objects=defs.BinaryObject(min_file_size=100), min_count=1) tt = TestType(**get_artifact_fixture()) blob = defs.Blob() blob.size = 1024 blob.locations.append("file://some.file.path") tt.image_file = blob self.assertEqual(1024, tt.image_file.size) self.assertEqual(["file://some.file.path"], tt.image_file.locations)
[docs] def test_pre_publish_blob_validation(self): class TestType(defs.ArtifactType): required_blob = defs.BinaryObject(required=True) optional_blob = defs.BinaryObject() tt = TestType(**get_artifact_fixture()) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.__pre_publish__) tt.required_blob = defs.Blob(size=0) tt.__pre_publish__()
[docs] def test_pre_publish_dependency_validation(self): class TestType(defs.ArtifactType): required_dependency = defs.ArtifactReference(required=True) optional_dependency = defs.ArtifactReference() tt = TestType(**get_artifact_fixture()) self.assertRaises(exc.InvalidArtifactPropertyValue, tt.__pre_publish__) tt.required_dependency = defs.ArtifactType(**get_artifact_fixture()) tt.__pre_publish__()
[docs] def test_default_value_of_immutable_field_in_active_state(self): class TestType(defs.ArtifactType): foo = defs.String(default='Bar', mutable=False) tt = TestType(**get_artifact_fixture(state='active')) self.assertEqual('Bar', tt.foo)
[docs]class SerTestType(defs.ArtifactType): some_string = defs.String() some_text = defs.Text() some_version = defs.SemVerString() some_int = defs.Integer() some_numeric = defs.Numeric() some_bool = defs.Boolean() some_array = defs.Array() another_array = defs.Array( item_type=[defs.Integer(), defs.Numeric(), defs.Boolean()]) some_dict = defs.Dict() another_dict = defs.Dict( properties={'foo': defs.Integer(), 'bar': defs.Boolean()}) some_ref = defs.ArtifactReference() some_ref_list = defs.ArtifactReferenceList() some_blob = defs.BinaryObject() some_blob_list = defs.BinaryObjectList()
[docs]class TestSerialization(test_utils.BaseTestCase):
[docs] def test_serialization_to_db(self): ref1 = defs.ArtifactType(**get_artifact_fixture(id="1")) ref2 = defs.ArtifactType(**get_artifact_fixture(id="2")) ref3 = defs.ArtifactType(**get_artifact_fixture(id="3")) blob1 = defs.Blob(size=100, locations=['http://example.com/blob1'], item_key='some_key', checksum='abc') blob2 = defs.Blob(size=200, locations=['http://example.com/blob2'], item_key='another_key', checksum='fff') blob3 = defs.Blob(size=300, locations=['http://example.com/blob3'], item_key='third_key', checksum='123') fixture = get_artifact_fixture() tt = SerTestType(**fixture) tt.some_string = 'bar' tt.some_text = 'bazz' tt.some_version = '11.22.33-beta' tt.some_int = 50 tt.some_numeric = 10.341 tt.some_bool = True tt.some_array = ['q', 'w', 'e', 'r', 't', 'y'] tt.another_array = [1, 1.2, False] tt.some_dict = {'foobar': "FOOBAR", 'baz': "QUX"} tt.another_dict = {'foo': 1, 'bar': True} tt.some_ref = ref1 tt.some_ref_list = [ref2, ref3] tt.some_blob = blob1 tt.some_blob_list = [blob2, blob3] results = serialization.serialize_for_db(tt) expected = fixture expected['type_name'] = 'SerTestType' expected['type_version'] = '1.0' expected['properties'] = { 'some_string': { 'type': 'string', 'value': 'bar' }, 'some_text': { 'type': 'text', 'value': 'bazz' }, 'some_version': { 'type': 'string', 'value': '11.22.33-beta' }, 'some_int': { 'type': 'int', 'value': 50 }, 'some_numeric': { 'type': 'numeric', 'value': 10.341 }, 'some_bool': { 'type': 'bool', 'value': True }, 'some_array': { 'type': 'array', 'value': [ { 'type': 'string', 'value': 'q' }, { 'type': 'string', 'value': 'w' }, { 'type': 'string', 'value': 'e' }, { 'type': 'string', 'value': 'r' }, { 'type': 'string', 'value': 't' }, { 'type': 'string', 'value': 'y' } ] }, 'another_array': { 'type': 'array', 'value': [ { 'type': 'int', 'value': 1 }, { 'type': 'numeric', 'value': 1.2 }, { 'type': 'bool', 'value': False } ] }, 'some_dict.foobar': { 'type': 'string', 'value': 'FOOBAR' }, 'some_dict.baz': { 'type': 'string', 'value': 'QUX' }, 'another_dict.foo': { 'type': 'int', 'value': 1 }, 'another_dict.bar': { 'type': 'bool', 'value': True } } expected['dependencies'] = { 'some_ref': ['1'], 'some_ref_list': ['2', '3'] } expected['blobs'] = { 'some_blob': [ { 'size': 100, 'checksum': 'abc', 'item_key': 'some_key', 'locations': ['http://example.com/blob1'] }], 'some_blob_list': [ { 'size': 200, 'checksum': 'fff', 'item_key': 'another_key', 'locations': ['http://example.com/blob2'] }, { 'size': 300, 'checksum': '123', 'item_key': 'third_key', 'locations': ['http://example.com/blob3'] } ] } self.assertEqual(expected, results)
[docs] def test_deserialize_from_db(self): ts = datetime.datetime.now() db_dict = { "type_name": 'SerTestType', "type_version": '1.0', "id": "123", "version": "11.2", "description": None, "name": "Foo", "visibility": "private", "state": "creating", "owner": "my_tenant", "created_at": ts, "updated_at": ts, "deleted_at": None, "published_at": None, "tags": ["test", "fixture"], "properties": { 'some_string': { 'type': 'string', 'value': 'bar' }, 'some_text': { 'type': 'text', 'value': 'bazz' }, 'some_version': { 'type': 'string', 'value': '11.22.33-beta' }, 'some_int': { 'type': 'int', 'value': 50 }, 'some_numeric': { 'type': 'numeric', 'value': 10.341 }, 'some_bool': { 'type': 'bool', 'value': True }, 'some_array': { 'type': 'array', 'value': [ { 'type': 'string', 'value': 'q' }, { 'type': 'string', 'value': 'w' }, { 'type': 'string', 'value': 'e' }, { 'type': 'string', 'value': 'r' }, { 'type': 'string', 'value': 't' }, { 'type': 'string', 'value': 'y' } ] }, 'another_array': { 'type': 'array', 'value': [ { 'type': 'int', 'value': 1 }, { 'type': 'numeric', 'value': 1.2 }, { 'type': 'bool', 'value': False } ] }, 'some_dict.foobar': { 'type': 'string', 'value': 'FOOBAR' }, 'some_dict.baz': { 'type': 'string', 'value': 'QUX' }, 'another_dict.foo': { 'type': 'int', 'value': 1 }, 'another_dict.bar': { 'type': 'bool', 'value': True } }, 'blobs': { 'some_blob': [ { 'size': 100, 'checksum': 'abc', 'item_key': 'some_key', 'locations': ['http://example.com/blob1'] }], 'some_blob_list': [ { 'size': 200, 'checksum': 'fff', 'item_key': 'another_key', 'locations': ['http://example.com/blob2'] }, { 'size': 300, 'checksum': '123', 'item_key': 'third_key', 'locations': ['http://example.com/blob3'] } ] }, 'dependencies': { 'some_ref': [ { "type_name": 'ArtifactType', "type_version": '1.0', "id": "1", "version": "11.2", "description": None, "name": "Foo", "visibility": "private", "state": "creating", "owner": "my_tenant", "created_at": ts, "updated_at": ts, "deleted_at": None, "published_at": None, "tags": ["test", "fixture"], "properties": {}, "blobs": {}, "dependencies": {} } ], 'some_ref_list': [ { "type_name": 'ArtifactType', "type_version": '1.0', "id": "2", "version": "11.2", "description": None, "name": "Foo", "visibility": "private", "state": "creating", "owner": "my_tenant", "created_at": ts, "updated_at": ts, "deleted_at": None, "published_at": None, "tags": ["test", "fixture"], "properties": {}, "blobs": {}, "dependencies": {} }, { "type_name": 'ArtifactType', "type_version": '1.0', "id": "3", "version": "11.2", "description": None, "name": "Foo", "visibility": "private", "state": "creating", "owner": "my_tenant", "created_at": ts, "updated_at": ts, "deleted_at": None, "published_at": None, "tags": ["test", "fixture"], "properties": {}, "blobs": {}, "dependencies": {} } ] } } plugins_dict = {'SerTestType': [SerTestType], 'ArtifactType': [defs.ArtifactType]} def _retrieve_plugin(name, version): return next((p for p in plugins_dict.get(name, []) if version and p.version == version), plugins_dict.get(name, [None])[0]) plugins = mock.Mock() plugins.get_class_by_typename = _retrieve_plugin art = serialization.deserialize_from_db(db_dict, plugins) self.assertEqual('123', art.id) self.assertEqual('11.2', art.version) self.assertIsNone(art.description) self.assertEqual('Foo', art.name) self.assertEqual('private', art.visibility) self.assertEqual('private', art.visibility)
[docs]def get_artifact_fixture(**kwargs): ts = datetime.datetime.now() fixture = { "id": "123", "version": "11.2", "description": None, "name": "Foo", "visibility": "private", "state": "creating", "owner": "my_tenant", "created_at": ts, "updated_at": ts, "deleted_at": None, "published_at": None, "tags": ["test", "fixture"] } fixture.update(kwargs) return fixture

Project Source