Пример #1
0
def test_property_path_on_model(person_model: Model) -> None:
    # complex based property path
    person: ComplexKind = cast(ComplexKind, person_model["Person"])
    person_path = {p.path: p for p in person.resolved_properties()}
    assert len(person_path) == 13
    assert person_path[PropertyPath(["name"])].kind == person_model["string"]
    assert person_path[PropertyPath(["name"])].prop.name == "name"
    assert person_path[PropertyPath(["list[]"])].kind == person_model["string"]
    assert person_path[PropertyPath(["list[]"])].prop.name == "list"
    assert person_path[PropertyPath(["tags",
                                     None])].kind == person_model["string"]
    assert person_path[PropertyPath(["address",
                                     "zip"])].kind == person_model["zip"]
    assert person_path[PropertyPath(["address", "zip"])].prop.name == "zip"
    with pytest.raises(KeyError):
        _ = person_path[PropertyPath(["anything"])]

    # model based property path
    assert person_model.kind_by_path("name") == person_model["string"]
    assert person_model.kind_by_path("list[]") == person_model["string"]
    assert person_model.kind_by_path("tags.foo") == person_model["string"]
    assert person_model.kind_by_path("tags.bla") == person_model["string"]
    assert person_model.kind_by_path(
        "other_addresses.bla.zip") == person_model["zip"]
    assert person_model.kind_by_path("address.zip") == person_model["zip"]
Пример #2
0
def test_update(person_model: Model) -> None:
    with pytest.raises(
            AttributeError) as not_allowed:  # update city with different type
        person_model.update_kinds([
            ComplexKind(
                "Address",
                ["Base"],
                [
                    Property("city", "int32", required=True),
                ],
            )
        ])
    assert (
        str(not_allowed.value) ==
        "Update not possible: following properties would be non unique having the same path but different type: "
        "Address.city (string -> int32)")

    updated = person_model.update_kinds([StringKind("Foo")])
    assert updated["Foo"].fqn == "Foo"
    with pytest.raises(AttributeError) as simple:
        updated.update_kinds([ComplexKind("Foo", [], [])])
    assert str(
        simple.value) == "Update Foo changes an existing property type Foo"
    with pytest.raises(AttributeError) as duplicate:
        updated.update_kinds(
            [ComplexKind("Bla", [], [Property("id", "int32")])])
    assert (
        str(duplicate.value) ==
        "Update not possible: following properties would be non unique having the same path but different type: "
        "Bla.id (string -> int32)")
Пример #3
0
 async def merge_graph(self, db: DbAccess) -> GraphUpdate:  # type: ignore
     model = Model.from_kinds([kind async for kind in db.model_db.all()])
     builder = GraphBuilder(model)
     nxt = self.next_action()
     while isinstance(nxt, ReadElement):
         for element in nxt.jsons():
             builder.add_from_json(element)
         log.debug(f"Read {int(BatchSize / 1000)}K elements in process")
         nxt = self.next_action()
     if isinstance(nxt, PoisonPill):
         log.debug("Got poison pill - going to die.")
         shutdown_process(0)
     elif isinstance(nxt, MergeGraph):
         log.debug("Graph read into memory")
         builder.check_complete()
         graphdb = db.get_graph_db(nxt.graph)
         outer_edge_db = db.get_pending_outer_edge_db()
         _, result = await graphdb.merge_graph(builder.graph, model,
                                               nxt.change_id, nxt.is_batch)
         if nxt.task_id and builder.deferred_edges:
             await outer_edge_db.update(
                 PendingDeferredEdges(nxt.task_id, nxt.graph,
                                      builder.deferred_edges))
             log.debug(
                 f"Updated {len(builder.deferred_edges)} pending outer edges for collect task {nxt.task_id}"
             )
         return result
Пример #4
0
 async def model(self) -> Model:
     async with self.session.get(self.base_path + "/model") as response:
         model_json = await response.json()
         model = Model.from_kinds([
             from_js(kind, Kind) for kind in model_json["kinds"].values()
         ])  # type: ignore
         return model
Пример #5
0
 async def load_model(self) -> Model:
     if self.__loaded_model:
         return self.__loaded_model
     else:
         kinds = [kind async for kind in self.db.all()]
         model = Model.from_kinds(list(kinds))
         self.__loaded_model = model
         return model
Пример #6
0
 async def update_configs_model(self, update: List[Kind]) -> Model:
     async with self.session.patch(self.base_path + "/configs/model",
                                   json=to_js(update)) as response:
         model_json = await response.json()
         model = Model.from_kinds([
             from_js(kind, Kind) for kind in model_json["kinds"].values()
         ])  # type: ignore
         return model
def test_ip_range() -> None:
    bind_vars: Json = {}
    model = QueryModel(
        Query.by(IsTerm(["foo"])).on_section("reported"), Model.empty())
    result = in_subnet(
        "crs", bind_vars,
        FunctionTerm("in_subnet", "foo.bla", ["192.168.1.0/24"]), model)
    assert result == "BIT_AND(IPV4_TO_NUMBER(crs.foo.bla), 4294967040) == @0"
    assert bind_vars["0"] == 3232235776
Пример #8
0
 async def get_configs_model(self) -> Model:
     async with self.session.get(self.base_path + f"/configs/model") as r:
         if r.status == 200:
             model_json = await r.json()
             model = Model.from_kinds([
                 from_js(kind, Kind)
                 for kind in model_json["kinds"].values()
             ])  # type: ignore
             return model
         else:
             raise AttributeError(await r.text())
Пример #9
0
def test_any() -> None:
    model = Model.from_kinds(predefined_kinds)
    assert model.check_valid({
        "kind": "any",
        "a": True,
        "b": 12,
        "c": [],
        "d": {
            "a": "b"
        }
    }) is None
def test_has_key() -> None:
    bind_vars: Json = {}
    model = QueryModel(Query.by("foo"), Model.empty())
    result = has_key("crs", bind_vars,
                     FunctionTerm("has_key", "foo.bla", [["a", "b", "c"]]),
                     model)
    assert result == "@fn0 ALL IN ATTRIBUTES(crs.foo.bla, true)"
    assert bind_vars["fn0"] == ["a", "b", "c"]
    bind_vars2: Json = {}
    result = has_key("crs", bind_vars2,
                     FunctionTerm("has_key", "foo.bla", ["a"]), model)
    assert result == "HAS(crs.foo.bla, @fn0)"
    assert bind_vars2["fn0"] == "a"
Пример #11
0
def test_dictionary() -> None:
    model = {k.fqn: k for k in predefined_kinds}
    result = Property.parse_kind("dictionary[string, string]", model)
    assert isinstance(result, DictionaryKind)
    assert result.key_kind is model["string"]
    assert result.value_kind is model["string"]
    result = Property.parse_kind(
        "dictionary[string, dictionary[string, float]]", model)
    assert isinstance(result, DictionaryKind)
    assert result.key_kind is model["string"]
    assert result.value_kind == DictionaryKind(model["string"], model["float"])
    address = ComplexKind("Foo", [], [
        Property("tags", "dictionary[string, string]"),
        Property("anything", "dictionary[string, any]")
    ])
    address_model = Model.from_kinds([address])
    assert address_model.check_valid({
        "kind": "Foo",
        "tags": {
            "a": "b",
            "b": "c"
        }
    }) is None
    expected = 'Kind:Foo Property:tags is not valid: value of dictionary[string, string] is not valid: Expected type string but got int: {"kind": "Foo", "tags": {"a": 1, "b": "c"}}'
    assert expect_error(address_model, {
        "kind": "Foo",
        "tags": {
            "a": 1,
            "b": "c"
        }
    }) == expected
    assert address_model.check_valid({
        "kind": "Foo",
        "anything": {
            "a": 1,
            "b": "c",
            "c": True
        }
    }) is None
    expected = 'Kind:Foo Property:anything is not valid: dictionary requires a json object, but got this: 1: {"kind": "Foo", "anything": 1}'
    assert expect_error(address_model, {
        "kind": "Foo",
        "anything": 1
    }) == expected
Пример #12
0
def test_load(model_json: str) -> None:
    kinds: List[Kind] = [from_js(a, Kind)
                         for a in json.loads(model_json)]  # type: ignore
    model = Model.from_kinds(kinds)
    assert model.check_valid({
        "kind": "test.EC2",
        "id": "e1",
        "name": "e1",
        "cores": 1,
        "mem": 32,
        "tags": {}
    }) is None

    base: ComplexKind = model["test.Base"]  # type: ignore
    ec2: ComplexKind = model["test.EC2"]  # type: ignore
    assert ec2.kind_hierarchy() == {
        "test.Compound", "test.BaseResource", "test.Base", "test.EC2"
    }
    assert ec2.allow_unknown_props is True
    assert base.allow_unknown_props is False
Пример #13
0
def test_array() -> None:
    foo = ComplexKind("Foo", [], [
        Property("tags", "dictionary[string, string]"),
        Property("kind", "string")
    ])
    complex_kind = ComplexKind(
        "TestArray",
        [],
        [
            Property("kind", "string"),
            Property("los", "string[]"),
            Property("lod", "dictionary[string, string][]"),
            Property("foos", "Foo[]"),
            Property("los_los", "string[][]"),
            Property("los_los_los", "string[][][]"),
        ],
    )
    model = Model.from_kinds([foo, complex_kind])
    assert (model.check_valid({
        "kind":
        "TestArray",
        "los": ["a", "b", "c"],
        "lod": [{
            "a": "b"
        }, {
            "b": "c"
        }],
        "foos": [{
            "kind": "Foo",
            "tags": {
                "a": "b"
            }
        }, {
            "kind": "Foo",
            "tags": {
                "b": "c"
            }
        }],
        "los_los": [["a", "b"], ["c"], ["d", "e"]],
        "los_los_los": [[["a", "b"], ["c"]], [["d", "e"], ["f"]]],
    }) is None)
Пример #14
0
async def test_emit_recurrent_events() -> None:
    message_bus = MessageBus()
    sender = InMemoryEventSender()
    model = ModelHandlerStatic(Model.empty())
    sub = SubscriptionHandler(
        InMemoryDb[Subscriber](Subscriber, lambda x: x.id), message_bus)
    queue = WorkerTaskQueue()
    fast = timedelta(seconds=0.001)
    periodic = emit_recurrent_events(sender, model, sub, queue, message_bus,
                                     fast, fast)
    await periodic.start()
    while len(sender.events) < 3:
        await asyncio.sleep(0.01)
    await periodic.stop()
    model_event, subscriber_event, worker_event = sender.events[0:3]
    assert model_event.kind == CoreEvent.ModelInfo
    assert model_event.counters["model_count"] == 0
    assert subscriber_event.kind == CoreEvent.SubscriberInfo
    assert subscriber_event.counters["subscriber_count"] == 0
    assert worker_event.kind == CoreEvent.WorkerQueueInfo
    assert worker_event.counters["worker_count"] == 0
Пример #15
0
def person_model() -> Model:
    zip = StringKind("zip")
    base = ComplexKind(
        "Base",
        [],
        [
            Property(
                "id", "string", required=True, description="Some identifier"),
            Property("kind",
                     "string",
                     required=True,
                     description="Kind if this node."),
            Property("list", "string[]", description="A list of strings."),
            Property("tags",
                     "dictionary[string, string]",
                     description="Key/value pairs."),
            Property("mtime",
                     "datetime",
                     description="Modification time of this node."),
        ],
    )
    address = ComplexKind(
        "Address",
        ["Base"],
        [
            Property("zip", "zip", description="The zip code."),
            Property("city",
                     "string",
                     required=True,
                     description="The name of the city.\nAnd another line."),
        ],
    )
    person = ComplexKind(
        "Person",
        ["Base"],
        [
            Property("name", "string", description="The name of the person."),
            Property("address",
                     "Address",
                     description="The address of the person."),
            Property("other_addresses",
                     "dictionary[string, Address]",
                     description="Other addresses."),
            Property("addresses",
                     "Address[]",
                     description="The list of addresses."),
            Property("any", "any", description="Some arbitrary value."),
        ],
    )
    any_foo = ComplexKind(
        "any_foo",
        ["Base"],
        [
            Property("foo", "any", description="Some foo value."),
            Property("test", "string", description="Some test value."),
        ],
    )
    cloud = ComplexKind("cloud", ["Base"], [])
    account = ComplexKind("account", ["Base"], [])
    region = ComplexKind("region", ["Base"], [])
    parent = ComplexKind("parent", ["Base"], [])
    child = ComplexKind("child", ["Base"], [])

    return Model.from_kinds([
        zip, person, address, base, any_foo, cloud, account, region, parent,
        child
    ])
Пример #16
0
def test_graph(person_model: Model) -> None:
    graph: DiGraph = person_model.graph()
    assert len(graph.nodes()) == 11
    assert len(graph.edges()) == 8
Пример #17
0
 async def update_model(self, kinds: List[Kind]) -> Model:
     self.model = Model.from_kinds(kinds)
     return self.model
Пример #18
0
def test_model_checking(person_model: Model) -> None:
    assert person_model.check_valid({"kind": "Base", "id": "32"}) is None
    assert person_model.check_valid({
        "kind": "Base",
        "id": "32",
        "list": ["one", "two"]
    }) is None
    expected = 'Kind:Base Property:list is not valid: Expected type string but got int: {"kind": "Base", "id": "32", "list": [1, 2]}'
    assert expect_error(person_model, {
        "kind": "Base",
        "id": "32",
        "list": [1, 2]
    }) == expected
    expected = 'Kind:Base Property:list is not valid: Expected property is not an array!: {"kind": "Base", "id": "32", "list": "not iterable"}'
    assert expect_error(person_model, {
        "kind": "Base",
        "id": "32",
        "list": "not iterable"
    }) == expected
    expected = 'Kind:Base Property:id is not valid: Expected type string but got int: {"kind": "Base", "id": 32}'
    assert expect_error(person_model, {"kind": "Base", "id": 32}) == expected
    expected = 'Kind:Base Property:id is required and missing in {"kind": "Base"}'
    assert expect_error(person_model, {"kind": "Base"}) == expected
    expected = "Kind:Base Property:unknown is not defined in model!"
    assert expect_error(person_model, {
        "kind": "Base",
        "id": "bla",
        "unknown": 1
    }) == expected
    expected = (
        'Kind:Address Property:id is required and missing in {"kind": "Address", "zip": "12345", "city": "gotham"}'
    )
    assert expect_error(person_model, {
        "kind": "Address",
        "zip": "12345",
        "city": "gotham"
    }) == expected
    nested = {
        "id": "batman",
        "kind": "Person",
        "name": "batman",
        "address": {
            "kind": "Address",
            "id": "foo",
            "city": "gotham"
        },
    }
    assert person_model.check_valid(nested) is None
    nested = {
        "id": "batman",
        "kind": "Person",
        "name": "batman",
        "address": {
            "kind": "Address",
            "city": "gotham"
        }
    }
    expected = 'Kind:Person Property:address is not valid: Kind:Address Property:id is required and missing in {"kind": "Address", "city": "gotham"}: {"id": "batman", "kind": "Person", "name": "batman", "address": {"kind": "Address", "city": "gotham"}}'
    assert expect_error(person_model, nested) == expected
    assert person_model.check_valid({
        "kind": "Base",
        "id": "32",
        "mtime": "2008-09-03T20:56:35+20:00"
    })["mtime"] == "2008-09-03T00:56:35Z"  # type: ignore
    anything = {
        "kind": "any",
        "some": [1, 2, 3],
        "not": "defined",
        "props": True
    }
    assert person_model.check_valid(anything) is None
    any_foo = {
        "kind": "any_foo",
        "id": "foo",
        "foo": {
            "a": [1, 2, 3]
        },
        "test": "hallo"
    }
    assert person_model.check_valid(any_foo) is None
Пример #19
0
def foo_model(foo_kinds: List[Kind]) -> Model:
    return Model.from_kinds(foo_kinds)
Пример #20
0
 async def get_configs_model(self) -> Model:
     kinds = [kind async for kind in self.model_db.all()]
     return Model.from_kinds(list(kinds))