mirror of
https://github.com/ansible/awx.git
synced 2024-11-02 01:21:21 +03:00
299fa3b6b4
- remove flake8 as an install requirements (it's only used for tests) - vendor toposort, which is Apache 2.0 licensed (and very small) - change websocket-client to a setuptools optional dependency, which you can install via: pip install "./awxkit[websockets]" - add `jq` and `tabulate` under an additional optional setuptools dependency: pip install "./awxkit[formatting]" - remove `cryptography`, which is only used for random RSA generation (unused by the CLI)
690 lines
23 KiB
Python
690 lines
23 KiB
Python
import pytest
|
|
|
|
from awxkit.utils import filter_by_class
|
|
from awxkit.utils.toposort import CircularDependencyError
|
|
from awxkit.api.mixins import has_create
|
|
|
|
|
|
class MockHasCreate(has_create.HasCreate):
|
|
|
|
connection = None
|
|
|
|
def __str__(self):
|
|
return "instance of {0.__class__.__name__} ({1})".format(self, hex(id(self)))
|
|
|
|
def __init__(self, *a, **kw):
|
|
self.cleaned = False
|
|
super(MockHasCreate, self).__init__()
|
|
|
|
def silent_cleanup(self):
|
|
self.cleaned = True
|
|
|
|
|
|
class A(MockHasCreate):
|
|
|
|
def create(self, **kw):
|
|
return self
|
|
|
|
|
|
class B(MockHasCreate):
|
|
|
|
optional_dependencies = [A]
|
|
|
|
def create(self, a=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((a, A)))
|
|
return self
|
|
|
|
|
|
class C(MockHasCreate):
|
|
|
|
dependencies = [A, B]
|
|
|
|
def create(self, a=A, b=B, **kw):
|
|
self.create_and_update_dependencies(b, a)
|
|
return self
|
|
|
|
|
|
class D(MockHasCreate):
|
|
|
|
dependencies = [A]
|
|
optional_dependencies = [B]
|
|
|
|
def create(self, a=A, b=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((a, A), (b, B)))
|
|
return self
|
|
|
|
|
|
class E(MockHasCreate):
|
|
|
|
dependencies = [D, C]
|
|
|
|
def create(self, c=C, d=D, **kw):
|
|
self.create_and_update_dependencies(d, c)
|
|
return self
|
|
|
|
|
|
class F(MockHasCreate):
|
|
|
|
dependencies = [B]
|
|
optional_dependencies = [E]
|
|
|
|
def create(self, b=B, e=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((b, B), (e, E)))
|
|
return self
|
|
|
|
|
|
class G(MockHasCreate):
|
|
|
|
dependencies = [D]
|
|
optional_dependencies = [F, E]
|
|
|
|
def create(self, d=D, f=None, e=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((d, D), (f, F), (e, E)))
|
|
return self
|
|
|
|
|
|
class H(MockHasCreate):
|
|
|
|
optional_dependencies = [E, A]
|
|
|
|
def create(self, a=None, e=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((a, A), (e, E)))
|
|
return self
|
|
|
|
|
|
class MultipleWordClassName(MockHasCreate):
|
|
|
|
def create(self, **kw):
|
|
return self
|
|
|
|
|
|
class AnotherMultipleWordClassName(MockHasCreate):
|
|
|
|
optional_dependencies = [MultipleWordClassName]
|
|
|
|
def create(self, multiple_word_class_name=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((multiple_word_class_name, MultipleWordClassName)))
|
|
return self
|
|
|
|
|
|
def test_dependency_graph_single_page():
|
|
"""confirms that `dependency_graph(Base)` will return a dependency graph
|
|
consisting of only dependencies and dependencies of dependencies (if any)
|
|
"""
|
|
desired = {}
|
|
desired[G] = set([D])
|
|
desired[D] = set([A])
|
|
desired[A] = set()
|
|
assert has_create.dependency_graph(G) == desired
|
|
|
|
|
|
def test_dependency_graph_page_with_optional():
|
|
"""confirms that `dependency_graph(Base, OptionalBase)` will return a dependency
|
|
graph consisting of only dependencies and dependencies of dependencies (if any)
|
|
with the exception that the OptionalBase and its dependencies are included as well.
|
|
"""
|
|
desired = {}
|
|
desired[G] = set([D])
|
|
desired[E] = set([D, C])
|
|
desired[C] = set([A, B])
|
|
desired[D] = set([A])
|
|
desired[B] = set()
|
|
desired[A] = set()
|
|
assert has_create.dependency_graph(G, E) == desired
|
|
|
|
|
|
def test_dependency_graph_page_with_additionals():
|
|
"""confirms that `dependency_graph(Base, AdditionalBaseOne, AdditionalBaseTwo)`
|
|
will return a dependency graph consisting of only dependencies and dependencies
|
|
of dependencies (if any) with the exception that the AdditionalBases
|
|
are treated as a dependencies of Base (when they aren't) and their dependencies
|
|
are included as well.
|
|
"""
|
|
desired = {}
|
|
desired[E] = set([D, C])
|
|
desired[D] = set([A])
|
|
desired[C] = set([A, B])
|
|
desired[F] = set([B])
|
|
desired[G] = set([D])
|
|
desired[A] = set()
|
|
desired[B] = set()
|
|
assert has_create.dependency_graph(E, F, G) == desired
|
|
|
|
|
|
def test_optional_dependency_graph_single_page():
|
|
"""confirms that has_create._optional_dependency_graph(Base) returns a complete dependency tree
|
|
including all optional_dependencies
|
|
"""
|
|
desired = {}
|
|
desired[H] = set([E, A])
|
|
desired[E] = set([D, C])
|
|
desired[D] = set([A, B])
|
|
desired[C] = set([A, B])
|
|
desired[B] = set([A])
|
|
desired[A] = set()
|
|
assert has_create.optional_dependency_graph(H) == desired
|
|
|
|
|
|
def test_optional_dependency_graph_with_additional():
|
|
"""confirms that has_create._optional_dependency_graph(Base) returns a complete dependency tree
|
|
including all optional_dependencies with the AdditionalBases treated as a dependencies
|
|
of Base (when they aren't) and their dependencies and optional_dependencies included as well.
|
|
"""
|
|
desired = {}
|
|
desired[F] = set([B, E])
|
|
desired[H] = set([E, A])
|
|
desired[E] = set([D, C])
|
|
desired[D] = set([A, B])
|
|
desired[C] = set([A, B])
|
|
desired[B] = set([A])
|
|
desired[A] = set()
|
|
assert has_create.optional_dependency_graph(F, H, A) == desired
|
|
|
|
|
|
def test_creation_order():
|
|
"""confirms that `has_create.creation_order()` returns a valid creation order in the desired list of sets format"""
|
|
dependency_graph = dict(eight=set(['seven', 'six']),
|
|
seven=set(['five']),
|
|
six=set(),
|
|
five=set(['two', 'one']),
|
|
four=set(['one']),
|
|
three=set(['two']),
|
|
two=set(['one']),
|
|
one=set())
|
|
desired = [set(['one', 'six']),
|
|
set(['two', 'four']),
|
|
set(['three', 'five']),
|
|
set(['seven']),
|
|
set(['eight'])]
|
|
assert has_create.creation_order(dependency_graph) == desired
|
|
|
|
|
|
def test_creation_order_with_loop():
|
|
"""confirms that `has_create.creation_order()` raises toposort.CircularDependencyError when evaluating
|
|
a cyclic dependency graph
|
|
"""
|
|
dependency_graph = dict(eight=set(['seven', 'six']),
|
|
seven=set(['five']),
|
|
six=set(),
|
|
five=set(['two', 'one']),
|
|
four=set(['one']),
|
|
three=set(['two']),
|
|
two=set(['one']),
|
|
one=set(['eight']))
|
|
with pytest.raises(CircularDependencyError):
|
|
assert has_create.creation_order(dependency_graph)
|
|
|
|
|
|
class One(MockHasCreate):
|
|
pass
|
|
|
|
|
|
class Two(MockHasCreate):
|
|
dependencies = [One]
|
|
|
|
|
|
class Three(MockHasCreate):
|
|
dependencies = [Two, One]
|
|
|
|
|
|
class Four(MockHasCreate):
|
|
optional_dependencies = [Two]
|
|
|
|
|
|
class Five(MockHasCreate):
|
|
dependencies = [Two]
|
|
optional_dependencies = [One]
|
|
|
|
|
|
class IsntAHasCreate(object):
|
|
pass
|
|
|
|
class Six(MockHasCreate, IsntAHasCreate):
|
|
dependencies = [Two]
|
|
|
|
class Seven(MockHasCreate):
|
|
dependencies = [IsntAHasCreate]
|
|
|
|
|
|
def test_separate_async_optionals_none_exist():
|
|
"""confirms that when creation group classes have no async optional dependencies the order is unchanged"""
|
|
order = has_create.creation_order(has_create.optional_dependency_graph(Three, Two, One))
|
|
assert has_create.separate_async_optionals(order) == order
|
|
|
|
|
|
def test_separate_async_optionals_two_exist():
|
|
"""confirms that when two creation group classes have async dependencies
|
|
the class that has shared item as a dependency occurs first in a separate creation group
|
|
"""
|
|
order = has_create.creation_order(has_create.optional_dependency_graph(Four, Three, Two))
|
|
assert has_create.separate_async_optionals(order) == [set([One]), set([Two]), set([Three]), set([Four])]
|
|
|
|
|
|
def test_separate_async_optionals_three_exist():
|
|
"""confirms that when three creation group classes have async dependencies
|
|
the class that has shared item as a dependency occurs first in a separate creation group
|
|
"""
|
|
order = has_create.creation_order(has_create.optional_dependency_graph(Five, Four, Three))
|
|
assert has_create.separate_async_optionals(order) == [set([One]), set([Two]), set([Three]),
|
|
set([Five]), set([Four])]
|
|
|
|
|
|
def test_separate_async_optionals_not_has_create():
|
|
"""confirms that when a dependency isn't a HasCreate has_create.separate_aysnc_optionals doesn't
|
|
unnecessarily move it from the initial creation group
|
|
"""
|
|
order = has_create.creation_order(has_create.optional_dependency_graph(Seven, Six))
|
|
assert has_create.separate_async_optionals(order) == [set([One, IsntAHasCreate]), set([Two, Seven]), set([Six])]
|
|
|
|
|
|
def test_page_creation_order_single_page():
|
|
"""confirms that `has_create.page_creation_order()` returns a valid creation order"""
|
|
desired = [set([A]), set([D]), set([G])]
|
|
assert has_create.page_creation_order(G) == desired
|
|
|
|
|
|
def test_page_creation_order_optionals_provided():
|
|
"""confirms that `has_create.page_creation_order()` returns a valid creation order
|
|
when optional_dependencies are included
|
|
"""
|
|
desired = [set([A]), set([B]), set([C]), set([D]), set([E]), set([H])]
|
|
assert has_create.page_creation_order(H, A, E) == desired
|
|
|
|
|
|
def test_page_creation_order_additionals_provided():
|
|
"""confirms that `has_create.page_creation_order()` returns a valid creation order
|
|
when additional pages are included
|
|
"""
|
|
desired = [set([A]), set([B]), set([D]), set([F, H]), set([G])]
|
|
assert has_create.page_creation_order(F, H, G) == desired
|
|
|
|
|
|
def test_all_instantiated_dependencies_single_page():
|
|
f = F().create()
|
|
b = f._dependency_store[B]
|
|
desired = set([b, f])
|
|
assert set(has_create.all_instantiated_dependencies(f, A, B, C, D, E, F, G, H)) == desired
|
|
|
|
|
|
def test_all_instantiated_dependencies_single_page_are_ordered():
|
|
f = F().create()
|
|
b = f._dependency_store[B]
|
|
desired = [b, f]
|
|
assert has_create.all_instantiated_dependencies(f, A, B, C, D, E, F, G, H) == desired
|
|
|
|
|
|
def test_all_instantiated_dependencies_optionals():
|
|
a = A().create()
|
|
b = B().create(a=a)
|
|
c = C().create(a=a, b=b)
|
|
d = D().create(a=a, b=b)
|
|
e = E().create(c=c, d=d)
|
|
h = H().create(a=a, e=e)
|
|
desired = set([a, b, c, d, e, h])
|
|
assert set(has_create.all_instantiated_dependencies(h, A, B, C, D, E, F, G, H)) == desired
|
|
|
|
|
|
def test_all_instantiated_dependencies_optionals_are_ordered():
|
|
a = A().create()
|
|
b = B().create(a=a)
|
|
c = C().create(a=a, b=b)
|
|
d = D().create(a=a, b=b)
|
|
e = E().create(c=c, d=d)
|
|
h = H().create(a=a, e=e)
|
|
desired = [a, b, c, d, e, h]
|
|
assert has_create.all_instantiated_dependencies(h, A, B, C, D, E, F, G, H) == desired
|
|
|
|
|
|
def test_dependency_resolution_complete():
|
|
h = H().create(a=True, e=True)
|
|
a = h._dependency_store[A]
|
|
e = h._dependency_store[E]
|
|
c = e._dependency_store[C]
|
|
d = e._dependency_store[D]
|
|
b = c._dependency_store[B]
|
|
|
|
for item in (h, a, e, d, c, b):
|
|
if item._dependency_store:
|
|
assert all(item._dependency_store.values()
|
|
), "{0} missing dependency: {0._dependency_store}".format(item)
|
|
|
|
assert a == b._dependency_store[A], "Duplicate dependency detected"
|
|
assert a == c._dependency_store[A], "Duplicate dependency detected"
|
|
assert a == d._dependency_store[A], "Duplicate dependency detected"
|
|
assert b == c._dependency_store[B], "Duplicate dependency detected"
|
|
assert b == d._dependency_store[B], "Duplicate dependency detected"
|
|
|
|
|
|
def test_ds_mapping():
|
|
h = H().create(a=True, e=True)
|
|
a = h._dependency_store[A]
|
|
e = h._dependency_store[E]
|
|
c = e._dependency_store[C]
|
|
d = e._dependency_store[D]
|
|
b = c._dependency_store[B]
|
|
|
|
assert a == h.ds.a
|
|
assert e == h.ds.e
|
|
assert c == e.ds.c
|
|
assert d == e.ds.d
|
|
assert b == c.ds.b
|
|
|
|
|
|
def test_ds_multiple_word_class_and_attribute_name():
|
|
amwcn = AnotherMultipleWordClassName().create(multiple_word_class_name=True)
|
|
mwcn = amwcn._dependency_store[MultipleWordClassName]
|
|
assert amwcn.ds.multiple_word_class_name == mwcn
|
|
|
|
|
|
def test_ds_missing_dependency():
|
|
a = A().create()
|
|
|
|
with pytest.raises(AttributeError):
|
|
a.ds.b
|
|
|
|
|
|
def test_teardown_calls_silent_cleanup():
|
|
g = G().create(f=True, e=True)
|
|
f = g._dependency_store[F]
|
|
e = g._dependency_store[E]
|
|
b = f._dependency_store[B]
|
|
d = e._dependency_store[D]
|
|
c = e._dependency_store[C]
|
|
a = c._dependency_store[A]
|
|
instances = [g, f, e, b, d, c, a]
|
|
|
|
for instance in instances:
|
|
assert not instance.cleaned
|
|
|
|
g.teardown()
|
|
for instance in instances:
|
|
assert instance.cleaned
|
|
|
|
|
|
def test_teardown_dependency_store_cleared():
|
|
g = G().create(f=True, e=True)
|
|
f = g._dependency_store[F]
|
|
e = g._dependency_store[E]
|
|
b = f._dependency_store[B]
|
|
d = e._dependency_store[D]
|
|
c = e._dependency_store[C]
|
|
a = c._dependency_store[A]
|
|
|
|
g.teardown()
|
|
|
|
assert not g._dependency_store[F]
|
|
assert not g._dependency_store[E]
|
|
assert not f._dependency_store[B]
|
|
assert not e._dependency_store[D]
|
|
assert not e._dependency_store[C]
|
|
assert not c._dependency_store[A]
|
|
|
|
|
|
def test_idempotent_teardown_dependency_store_cleared():
|
|
g = G().create(f=True, e=True)
|
|
f = g._dependency_store[F]
|
|
e = g._dependency_store[E]
|
|
b = f._dependency_store[B]
|
|
d = e._dependency_store[D]
|
|
c = e._dependency_store[C]
|
|
a = c._dependency_store[A]
|
|
|
|
for item in (g, f, e, b, d, c, a):
|
|
item.teardown()
|
|
item.teardown()
|
|
|
|
assert not g._dependency_store[F]
|
|
assert not g._dependency_store[E]
|
|
assert not f._dependency_store[B]
|
|
assert not e._dependency_store[D]
|
|
assert not e._dependency_store[C]
|
|
assert not c._dependency_store[A]
|
|
|
|
|
|
def test_teardown_ds_cleared():
|
|
g = G().create(f=True, e=True)
|
|
f = g._dependency_store[F]
|
|
e = g._dependency_store[E]
|
|
b = f._dependency_store[B]
|
|
d = e._dependency_store[D]
|
|
c = e._dependency_store[C]
|
|
a = c._dependency_store[A]
|
|
|
|
g.teardown()
|
|
|
|
for former_dep in ('f', 'e'):
|
|
with pytest.raises(AttributeError):
|
|
getattr(g.ds, former_dep)
|
|
|
|
with pytest.raises(AttributeError):
|
|
getattr(f.ds, 'b')
|
|
|
|
for former_dep in ('d', 'c'):
|
|
with pytest.raises(AttributeError):
|
|
getattr(e.ds, former_dep)
|
|
|
|
with pytest.raises(AttributeError):
|
|
getattr(c.ds, 'a')
|
|
|
|
|
|
class OneWithArgs(MockHasCreate):
|
|
|
|
def create(self, **kw):
|
|
self.kw = kw
|
|
return self
|
|
|
|
|
|
class TwoWithArgs(MockHasCreate):
|
|
|
|
dependencies = [OneWithArgs]
|
|
|
|
def create(self, one_with_args=OneWithArgs, **kw):
|
|
if not one_with_args and kw.pop('make_one_with_args', False):
|
|
one_with_args = (OneWithArgs, dict(a='a', b='b', c='c'))
|
|
self.create_and_update_dependencies(one_with_args)
|
|
self.kw = kw
|
|
return self
|
|
|
|
|
|
class ThreeWithArgs(MockHasCreate):
|
|
|
|
dependencies = [OneWithArgs]
|
|
optional_dependencies = [TwoWithArgs]
|
|
|
|
def create(self, one_with_args=OneWithArgs, two_with_args=None, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((one_with_args, OneWithArgs),
|
|
(two_with_args, TwoWithArgs)))
|
|
self.kw = kw
|
|
return self
|
|
|
|
class FourWithArgs(MockHasCreate):
|
|
|
|
dependencies = [TwoWithArgs, ThreeWithArgs]
|
|
|
|
def create(self, two_with_args=TwoWithArgs, three_with_args=ThreeWithArgs, **kw):
|
|
self.create_and_update_dependencies(*filter_by_class((two_with_args, TwoWithArgs),
|
|
(three_with_args, ThreeWithArgs)))
|
|
self.kw = kw
|
|
return self
|
|
|
|
|
|
def test_single_kwargs_class_in_create_and_update_dependencies():
|
|
two_wa = TwoWithArgs().create(one_with_args=False, make_one_with_args=True, two_with_args_kw_arg=123)
|
|
assert isinstance(two_wa.ds.one_with_args, OneWithArgs)
|
|
assert two_wa.ds.one_with_args.kw == dict(a='a', b='b', c='c')
|
|
assert two_wa.kw == dict(two_with_args_kw_arg=123)
|
|
|
|
|
|
def test_no_tuple_for_class_arg_causes_shared_dependencies_staggered():
|
|
three_wo = ThreeWithArgs().create(two_with_args=True)
|
|
assert isinstance(three_wo.ds.one_with_args, OneWithArgs)
|
|
assert isinstance(three_wo.ds.two_with_args, TwoWithArgs)
|
|
assert isinstance(three_wo.ds.two_with_args.ds.one_with_args, OneWithArgs)
|
|
assert three_wo.ds.one_with_args == three_wo.ds.two_with_args.ds.one_with_args
|
|
|
|
|
|
def test_no_tuple_for_class_arg_causes_shared_dependencies_nested_staggering():
|
|
four_wo = FourWithArgs().create()
|
|
assert isinstance(four_wo.ds.two_with_args, TwoWithArgs)
|
|
assert isinstance(four_wo.ds.three_with_args, ThreeWithArgs)
|
|
assert isinstance(four_wo.ds.two_with_args.ds.one_with_args, OneWithArgs)
|
|
assert isinstance(four_wo.ds.three_with_args.ds.one_with_args, OneWithArgs)
|
|
assert isinstance(four_wo.ds.three_with_args.ds.two_with_args, TwoWithArgs)
|
|
assert four_wo.ds.two_with_args.ds.one_with_args == four_wo.ds.three_with_args.ds.one_with_args
|
|
assert four_wo.ds.two_with_args == four_wo.ds.three_with_args.ds.two_with_args
|
|
|
|
|
|
def test_tuple_for_class_arg_causes_unshared_dependencies_when_downstream():
|
|
"""Confirms that provided arg-tuple for dependency type is applied instead of chained dependency"""
|
|
three_wa = ThreeWithArgs().create(two_with_args=(TwoWithArgs, dict(one_with_args=False,
|
|
make_one_with_args=True,
|
|
two_with_args_kw_arg=234)),
|
|
three_with_args_kw_arg=345)
|
|
assert isinstance(three_wa.ds.one_with_args, OneWithArgs)
|
|
assert isinstance(three_wa.ds.two_with_args, TwoWithArgs)
|
|
assert isinstance(three_wa.ds.two_with_args.ds.one_with_args, OneWithArgs)
|
|
assert three_wa.ds.one_with_args != three_wa.ds.two_with_args.ds.one_with_args
|
|
assert three_wa.ds.one_with_args.kw == dict()
|
|
assert three_wa.ds.two_with_args.kw == dict(two_with_args_kw_arg=234)
|
|
assert three_wa.ds.two_with_args.ds.one_with_args.kw == dict(a='a', b='b', c='c')
|
|
assert three_wa.kw == dict(three_with_args_kw_arg=345)
|
|
|
|
|
|
def test_tuples_for_class_arg_cause_unshared_dependencies_when_downstream():
|
|
"""Confirms that provided arg-tuple for dependency type is applied instead of chained dependency"""
|
|
four_wa = FourWithArgs().create(two_with_args=(TwoWithArgs, dict(one_with_args=False,
|
|
make_one_with_args=True,
|
|
two_with_args_kw_arg=456)),
|
|
# No shared dependencies with four_wa.ds.two_with_args
|
|
three_with_args=(ThreeWithArgs, dict(one_with_args=(OneWithArgs, {}),
|
|
two_with_args=False)),
|
|
four_with_args_kw=567)
|
|
assert isinstance(four_wa.ds.two_with_args, TwoWithArgs)
|
|
assert isinstance(four_wa.ds.three_with_args, ThreeWithArgs)
|
|
assert isinstance(four_wa.ds.two_with_args.ds.one_with_args, OneWithArgs)
|
|
assert isinstance(four_wa.ds.three_with_args.ds.one_with_args, OneWithArgs)
|
|
assert four_wa.ds.three_with_args.ds.one_with_args != four_wa.ds.two_with_args.ds.one_with_args
|
|
with pytest.raises(AttributeError):
|
|
four_wa.ds.three_with_args.ds.two_with_args
|
|
assert four_wa.kw == dict(four_with_args_kw=567)
|
|
|
|
|
|
class NotHasCreate(object):
|
|
|
|
pass
|
|
|
|
|
|
class MixinUserA(MockHasCreate, NotHasCreate):
|
|
|
|
def create(self, **kw):
|
|
return self
|
|
|
|
|
|
class MixinUserB(MockHasCreate, NotHasCreate):
|
|
|
|
def create(self, **kw):
|
|
return self
|
|
|
|
|
|
class MixinUserC(MixinUserB):
|
|
|
|
def create(self, **kw):
|
|
return self
|
|
|
|
|
|
class MixinUserD(MixinUserC):
|
|
|
|
def create(self, **kw):
|
|
return self
|
|
|
|
|
|
class NotHasCreateDependencyHolder(MockHasCreate):
|
|
|
|
dependencies = [NotHasCreate]
|
|
|
|
def create(self, not_has_create=MixinUserA):
|
|
self.create_and_update_dependencies(not_has_create)
|
|
return self
|
|
|
|
|
|
def test_not_has_create_default_dependency():
|
|
"""Confirms that HasCreates that claim non-HasCreates as dependencies claim them by correct kwarg
|
|
class name in _dependency_store
|
|
"""
|
|
dep_holder = NotHasCreateDependencyHolder().create()
|
|
assert isinstance(dep_holder.ds.not_has_create, MixinUserA)
|
|
|
|
|
|
def test_not_has_create_passed_dependency():
|
|
"""Confirms that passed non-HasCreate subclasses are sourced as dependency"""
|
|
dep = MixinUserB().create()
|
|
assert isinstance(dep, MixinUserB)
|
|
dep_holder = NotHasCreateDependencyHolder().create(not_has_create=dep)
|
|
assert dep_holder.ds.not_has_create == dep
|
|
|
|
|
|
class HasCreateParentDependencyHolder(MockHasCreate):
|
|
|
|
dependencies = [MixinUserB]
|
|
|
|
def create(self, mixin_user_b=MixinUserC):
|
|
self.create_and_update_dependencies(mixin_user_b)
|
|
return self
|
|
|
|
|
|
def test_has_create_stored_as_parent_dependency():
|
|
"""Confirms that HasCreate subclasses are sourced as their parent"""
|
|
dep = MixinUserC().create()
|
|
assert isinstance(dep, MixinUserC)
|
|
assert isinstance(dep, MixinUserB)
|
|
dep_holder = HasCreateParentDependencyHolder().create(mixin_user_b=dep)
|
|
assert dep_holder.ds.mixin_user_b == dep
|
|
|
|
|
|
class DynamicallyDeclaresNotHasCreateDependency(MockHasCreate):
|
|
|
|
dependencies = [NotHasCreate]
|
|
|
|
def create(self, not_has_create=MixinUserA):
|
|
dynamic_dependency = dict(mixinusera=MixinUserA,
|
|
mixinuserb=MixinUserB,
|
|
mixinuserc=MixinUserC)
|
|
self.create_and_update_dependencies(dynamic_dependency[not_has_create])
|
|
return self
|
|
|
|
|
|
@pytest.mark.parametrize('dependency,dependency_class',
|
|
[('mixinusera', MixinUserA),
|
|
('mixinuserb', MixinUserB),
|
|
('mixinuserc', MixinUserC)])
|
|
def test_subclass_or_parent_dynamic_not_has_create_dependency_declaration(dependency, dependency_class):
|
|
"""Confirms that dependencies that dynamically declare dependencies subclassed from not HasCreate
|
|
are properly linked
|
|
"""
|
|
dep_holder = DynamicallyDeclaresNotHasCreateDependency().create(dependency)
|
|
assert dep_holder.ds.not_has_create.__class__ == dependency_class
|
|
|
|
|
|
class DynamicallyDeclaresHasCreateDependency(MockHasCreate):
|
|
|
|
dependencies = [MixinUserB]
|
|
|
|
def create(self, mixin_user_b=MixinUserB):
|
|
dynamic_dependency = dict(mixinuserb=MixinUserB,
|
|
mixinuserc=MixinUserC,
|
|
mixinuserd=MixinUserD)
|
|
self.create_and_update_dependencies(dynamic_dependency[mixin_user_b])
|
|
return self
|
|
|
|
|
|
@pytest.mark.parametrize('dependency,dependency_class',
|
|
[('mixinuserb', MixinUserB),
|
|
('mixinuserc', MixinUserC),
|
|
('mixinuserd', MixinUserD)])
|
|
def test_subclass_or_parent_dynamic_has_create_dependency_declaration(dependency, dependency_class):
|
|
"""Confirms that dependencies that dynamically declare dependencies subclassed from not HasCreate
|
|
are properly linked
|
|
"""
|
|
dep_holder = DynamicallyDeclaresHasCreateDependency().create(dependency)
|
|
assert dep_holder.ds.mixin_user_b.__class__ == dependency_class
|