def test_internal_routing(subject, router): RuleFactory.create('test-rule-filters-pass', subscribe_to="test-type", data={ RuleConst.FILTERS: [ Callable(lambda self: True), ], RuleConst.PROCESSING: [ Callable(lambda self: self.payload.setdefault( RuleConst.PASSED, True)), ], }) RuleFactory.create('test-rule-filters-fails', subscribe_to="test-type", data={ RuleConst.FILTERS: [ Callable(lambda self: False), Callable(lambda self: True), ], RuleConst.PROCESSING: [ Callable(lambda self: self.payload.setdefault( RuleConst.PASSED, False)), ], }) proc_events_rx_factory.subscribe( lambda x: x[RuleConst.RULENAME] == 'test-rule-filters-pass' and _assert(x[RuleConst.PASSED] and len(x[RuleConst.PROCESSING]) > 0 or print("##### LEN ", x[RuleConst.PROCESSING]))) proc_events_rx_factory.subscribe( lambda x: x[RuleConst.RULENAME] == 'test-rule-filters-fails' and _assert(not x[RuleConst.PASSED] and len(x[RuleConst.PROCESSING]) == 0)) router.route("test-type", subject, {})
def test_truth(subject, router, asserted): RuleFactory.create('test-is-true', subscribe_to="event-test-truth", data={ filters: [ IsTrue(lambda payload: payload["it-works"]), ], }) RuleFactory.create( 'test-is-false', subscribe_to="event-test-truth", data={ filters: [ IsFalse(lambda payload: payload["it-works"] is False), ], }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == 'test-is-true' and _assert( 'test-is-true', x[processed] and x[filters][0]["returns"] is True)) proc_events_rx_factory( ).subscribe(lambda x: x[rulename] == 'test-is-false' and _assert( 'test-is-false', x[processed] and x[filters][0]["returns"] is True)) router.route("event-test-truth", subject, {'it-works': True}) assert 'test-is-true' in asserted assert 'test-is-false' in asserted
def test_k8s_subject(api, namespace): RuleFactory.create( 'test-k8s-subject', subscribe_to='test-k8s-subject', data={ RuleConst.FILTERS: [ Filter(lambda: (k8s_subject( resource_path= f"/api/v1/namespaces/{namespace}/pods/test-pod-1").ext_name == "test-pod-1")), Filter( K8sObjectsQuery(returns=lambda obj: (k8s_subject( obj).ext_name == "test-pod-1"))), Filter( K8sObjectsQuery(returns=lambda obj: (k8s_subject( obj.obj).ext_name == "test-pod-1"))) ], RuleConst.PROCESSING: [Process(True)] }) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-subject' and _assert( x[RuleConst.GOT_ERRORS] is False and x[RuleConst.PROCESSED], "test-k8s-subject proc failed")) event_router_factory().route( "test-k8s-subject", f"k8s:/api/v1/namespaces/{namespace}/pods/test-pod-1", {})
def test_with_self(): class WithSelfSet(RuleFunctionBase): def execute(self, arg1, arg2, arg3): self.payload["arg1"] = arg1 self.payload["arg2"] = arg2 self.payload["arg3"] = arg3 RuleFactory.create( "test-with-self", subscribe_to="test-argprocessors-self", data={ processing: [ WithSelfSet(lambda self: self.payload["value_from"], arg2=lambda self: self.subject.get("value_from"), arg3=lambda p: "I'll never be called") ] }) payload = {"value_from": 1} subject = subject_factory("test-1") subject.set("value_from", 2) event_router_factory().route("test-argprocessors-self", subject, payload) proc_events_rx_factory.subscribe(lambda x: x[ rulename] == "test-with-self" and _assert(x[processing][0]["args"][ 0] == 1 and x[processing][0]["kwargs"]["arg2"] == 2 and isinstance( x[processing][0]["kwargs"]["arg3"], str))) assert payload["arg1"] == 1 assert payload["arg2"] == 2 assert inspect.isfunction(payload["arg3"])
def test_extend_jp_match(): import jsonpath_rw_ext as jp from krules_core.arg_processors import processors class JPMatchSet(RuleFunctionBase): def execute(self, values, arg2): self.payload["values"] = values self.payload["elem-2"] = arg2 class JPPayloadMatchBase: def __init__(self, expr): self._expr = expr def match(self, instance): raise NotImplementedError() class jp_match(JPPayloadMatchBase): def match(self, instance): return jp.match(self._expr, instance.payload) class jp_match1(JPPayloadMatchBase): def match(self, instance): return jp.match1(self._expr, instance.payload) class JPProcessor(BaseArgProcessor): @staticmethod def interested_in(arg): return isinstance(arg, JPPayloadMatchBase) def process(self, instance): return self._arg.match(instance) processors.append(JPProcessor) RuleFactory.create("test-with-jp-expr", subscribe_to="test-argprocessors-jp-match", data={ processing: [ JPMatchSet(jp_match("$.elems[*].value"), jp_match1("$.elems[?id==2]")) ] }) payload = {"elems": [{"id": 1, "value": "a"}, {"id": 2, "value": "b"}]} event_router_factory().route("test-argprocessors-jp-match", "test-0", payload) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-with-jp-expr" and _assert(x[processing][ 0]["args"][0] == ['a', 'b'] and x[processing][0]["args"][1] == { "id": 2, "value": "b" })) assert payload["values"] == ['a', 'b'] assert payload["elem-2"]["id"] == 2 and payload["elem-2"]["value"] == "b"
def test_delete(api, namespace): RuleFactory.create( 'test-k8s-delete-in-context', subscribe_to="test-delete-in-context", data={ RuleConst.PROCESSING: [ # update from subject K8sObjectDelete() ] }) objs = pykube.Pod.objects(api).filter(namespace=namespace, selector={"app": "pytest-temp"}) #watch = objs.watch().filter(field_selector={"metadata.name": "test-pod-1"}) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-delete-in-context' and _assert(x[RuleConst.GOT_ERRORS] is False and x[RuleConst.PROCESSED], "test-k8s-delete-in-context proc failed")) event_router_factory().route( "test-delete-in-context", f"k8s:/api/v1/namespaces/{namespace}/pods/test-pod-1", {}) # for ev in watch: # if ev.type == "DELETED": # break # assert len(objs) == 1 RuleFactory.create( 'test-k8s-delete-off-context', subscribe_to="test-delete-off-context", data={ RuleConst.PROCESSING: [ # update from subject K8sObjectDelete(name="test-pod-2", apiversion="v1", kind="Pod", namespace=namespace) ] }) objs = pykube.Pod.objects(api).filter(namespace=namespace, selector={"app": "pytest-temp"}) watch = objs.watch().filter(field_selector={"metadata.name": "test-pod-2"}) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-delete-off-context' and _assert(x[RuleConst.GOT_ERRORS] is False and x[RuleConst.PROCESSED], "test-k8s-delete-off-context proc failed")) event_router_factory().route("test-delete-off-context", f"k8s:/api/v1/namespaces/{namespace}", {}) # for ev in watch: # if ev.type == "DELETED": # break # assert len(objs) == 0 event_router_factory().unregister_all()
def test_payload_functions(subject, router, asserted): payload = {"k1": "val1", "k2": {"k2a": 1, "k2b": {"a": 1, "b": 2}}} RuleFactory.create( "test-alter-payload", subscribe_to="test-alter-payload", data={ processing: [ UpdatePayload({ "k2": { "k2b": { "b": 3, "c": 4 } }, "k3": 3, }), SetPayloadProperties( k1=0, k3=lambda v: v + 1, k4=lambda *args: len(args) and args[0] + 1 or -1), SetPayloadProperty( "k4", lambda *args: len(args) and args[0] + 1 or -1) ] }) proc_events_rx_factory( ).subscribe(lambda x: x[rulename] == "test-alter-payload" and _assert( "test-update-1", get_value_from_payload_diffs("k3", x[processing][0][ "payload_diffs"]) == 3 and "a" in x["payload"]["k2"]["k2b"] and x[ "payload"]["k2"]["k2b"]["a"] == payload["k2"]["k2b"]["a"] and not get_value_from_payload_diffs("k2/k2b/a", x[processing][0][ "payload_diffs"]) and get_value_from_payload_diffs( "k2/k2b/b", x[processing][0]["payload_diffs"]) == 3 and get_value_from_payload_diffs("k2/k2b/c", x[processing][0][ "payload_diffs"]) == 4 and not get_value_from_payload_diffs( "k2", x[processing][0]["payload_diffs"], default_value=None))) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-alter-payload" and _assert( "test-update-2", get_value_from_payload_diffs("k1", x[processing][1][ "payload_diffs"]) == 0 and get_value_from_payload_diffs( "k3", x[processing][1]["payload_diffs"]) == 4 and get_value_from_payload_diffs( "k4", x[processing][1]["payload_diffs"]) == -1)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-alter-payload" and _assert( "test-update-3", get_value_from_payload_diffs("k4", x[processing][1]["payload_diffs" ]) == 0)) router.route("test-alter-payload", subject, payload) assert "test-update-1" in asserted assert "test-update-2" in asserted
def test_pycall(subject, router, asserted): def _func(in_value, raise_error, exc_to_raise=Exception("imbad")): if raise_error: raise exc_to_raise return in_value RuleFactory.create( "test-pycall-with-error", subscribe_to="test-pycall", data={ processing: [ PyCall(_func, ([1, 2], True), on_success=lambda self: lambda x: x.reverse(), on_error=lambda self: lambda x: self.payload.update( {"got_errors": True})) ] }) RuleFactory.create( "test-pycall-no-error", subscribe_to="test-pycall", data={ processing: [ PyCall( _func, ([1, 2], ), kwargs={"raise_error": False}, on_success=lambda self: lambda x: (x.reverse(), self.payload.update({"got_errors": False}))) ] }) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-pycall-no-error" and _assert( x[rulename], get_value_from_payload_diffs("pycall_returns", x[processing][0]["payload_diffs"], default_value=None) == [2, 1] and not get_value_from_payload_diffs("got_errors", x[processing][0]["payload_diffs"], default_value=False))) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-pycall-with-error" and _assert( x[rulename], not get_value_from_payload_diffs( "pycall_returns", x[processing][0]["payload_diffs"], default_value=None) and get_value_from_payload_diffs( "got_errors", x[processing][0]["payload_diffs"], default_value=False))) router.route("test-pycall", subject, {}) assert "test-pycall-no-error" in asserted assert "test-pycall-with-error" in asserted
def load_rules_from_rulesdata(rulesdata): description = "" for el in rulesdata: if type(el) == type(""): description = el elif type(el) == type({}) and RuleConst.RULENAME in el: el[RuleConst.DESCRIPTION] = description if el.get(RuleConst.SUBSCRIBE_TO, None) is None: el[RuleConst.SUBSCRIBE_TO] = "*" RuleFactory.create(**el) description = ""
def load_rules_from_rulesdata(rulesdata): description = "" for el in rulesdata: if type(el) == type(""): description = el elif type(el) == type({}) and RuleConst.RULENAME in el: el[RuleConst.DESCRIPTION] = description if el.get(RuleConst.SUBSCRIBE_TO, None) is None: el[RuleConst.SUBSCRIBE_TO] = os.environ[ "TOPIC"] # TODO: should not rely on this variable. The name of the subscription message should be inferred differently RuleFactory.create(**el) description = ""
def test_return(subject, router, asserted): RuleFactory.create('test-returns', subscribe_to="event-test-returns", data={ filters: [ Returns("something"), ], }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == 'test-returns' and _assert( 'test-returns-something', x[processed] and x[filters][0]["returns"] == "something")) router.route("event-test-returns", subject, {}) assert 'test-returns-something' in asserted
def test_router(): subject = "test-subject" proc_events_rx_factory.queue.clear() start_time = datetime.now() router = event_router_factory() router.unregister_all() RuleFactory.create('test-empty-rule', subscribe_to="some-type", data={}) proc_events_rx_factory.subscribe(lambda x: _assert( x[RuleConst.TYPE] == "some-type" and "key1" in x[RuleConst.PAYLOAD] and x[RuleConst.PAYLOAD]["key1"] == "val1", )) router.route('some-type', subject, {"key1": "val1"}) end_time = datetime.now() logging.getLogger().debug("######### {}".format(end_time - start_time)) assert router.unregister_all() == 1, "Expected 1 element"
def tests_query_foreach(api, namespace): RuleFactory.create( 'test-k8s-query-foreach', subscribe_to="test-query-foreach", data={ RuleConst.PROCESSING: [ K8sObjectsQuery(foreach=lambda obj: (obj.obj["metadata"][ "labels"].update({"updated": "foreach"}), obj.update()), apiversion="v1", kind="Pod", namespace=namespace, selector={"app": "pytest-temp"}), ] }) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-query-foreach' and _assert(x[RuleConst.GOT_ERRORS] is False and x[RuleConst.PROCESSED], "test-k8s-query-foreach proc failed")) watch = pykube.Pod.objects(api).filter(namespace=namespace, selector={ "app": "pytest-temp" }).watch() event_router_factory().route("test-query-foreach", "none", {}) try: updated = 0 for ev in watch: if ev.type == 'ADDED' and ev.object.obj["metadata"]["labels"][ "updated"] == "foreach": updated += 1 if updated == 2: break except: assert False, "query update event failed" assert updated == 2 event_router_factory().unregister_all()
def test_simple_callable(): class SimpleSet(RuleFunctionBase): def execute(self, arg1, arg2, arg3, arg4, arg5): self.payload["arg1"] = arg1 self.payload["arg2"] = arg2 self.payload["arg3"] = arg3 self.payload["arg4"] = arg4 self.payload["arg5"] = arg5 RuleFactory.create( "test-simple-callable", subscribe_to="test-argprocessors-callables", data={ processing: [ SimpleSet(lambda: 1, 2, arg3=lambda: 3, arg4=4, arg5=lambda p: "I'll never be called") ] } ) payload = {} event_router_factory().route("test-argprocessors-callables", "test-0", payload) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-simple-callable" and _assert( x[processing][0]["args"][0] == 1 and x[processing][0]["kwargs"]["arg3"] == 3 and x[processing][0]["kwargs"]["arg4"] == 4 and isinstance(x[processing][0]["kwargs"]["arg5"], str) ) ) assert payload["arg1"] == 1 assert payload["arg2"] == 2 assert payload["arg3"] == 3 assert payload["arg4"] == 4 assert inspect.isfunction(payload["arg5"])
def test_subject_match(router, asserted): user_subject = "user|000001" RuleFactory.create( 'test-subject-match', subscribe_to='event-user-action', data={ filters: [ SubjectNameMatch(r"^user\|(?P<user_id>.+)", payload_dest="user_info"), IsTrue( lambda payload: "user_id" in payload.get("user_info", {})) ] }) RuleFactory.create('test-subject-does-not-match', subscribe_to='event-user-action', data={ filters: [ SubjectNameDoesNotMatch( r"^device\|(?P<device_id>.+)", payload_dest="device_info"), ] }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == 'test-subject-match' and _assert( 'test-subject-match', x[processed] is True)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == 'test-subject-does-not-match' and _assert( 'test-subject-does-not-match', x[processed] is True)) router.route("event-user-action", user_subject, {}) assert 'test-subject-match' in asserted assert 'test-subject-does-not-match' in asserted
def test_with_payload_and_subject(): class WithPayloadSet(RuleFunctionBase): def execute(self, arg1, arg2, arg3): self.payload["arg1"] = arg1 self.payload["arg2"] = arg2 self.payload["arg3"] = arg3 RuleFactory.create( "test-with-payload-and-subject", subscribe_to="test-argprocessors-payload-and-subject", data={ processing: [ WithPayloadSet(lambda payload: payload["value_from"], arg2=lambda subject: subject.get("value_from"), arg3=lambda p: "I'll never be called") ] }) _payload = {"value_from": 1} _subject = subject_factory("test-1") _subject.set("value_from", 2) event_router_factory().route("test-argprocessors-payload-and-subject", _subject, _payload) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-with-payload-and-subject" and _assert(x[ processing][0]["args"][0] == 1 and x[processing][0][ "kwargs"]["arg2"] == 2 and hasattr( x[processing][0]["kwargs"]["arg3"], "__call__"))) assert _payload["arg1"] == 1 assert _payload["arg2"] == 2 assert inspect.isfunction(_payload["arg3"])
def test_filtered(router, subject): os.environ["PUBLISH_PROCEVENTS_LEVEL"] = str(ProcEventsLevel.FULL) os.environ["PUBLISH_PROCEVENTS_MATCHING"] = "passed=true" proc_events_rx_factory.subscribe( on_next=lambda x: publish_proc_events_filtered( x, "passed=true", lambda match: match is not None, debug=True)) RuleFactory.create( 'check-even-value', subscribe_to="event-test-procevents", data={ filters: [ Filter(lambda payload: payload["value"] % 2 == 0), ], processing: [ SetPayloadProperty("isEven", True), ] }) RuleFactory.create( 'check-odd-value', subscribe_to="event-test-procevents", data={ filters: [ Filter(lambda payload: payload["value"] % 2 != 0), ], processing: [ SetPayloadProperty("isEven", False), ] }) RuleFactory.create( 'test-procevents-filter', subscribe_to=RULE_PROC_EVENT, data={ processing: [ Process( lambda payload: subscribed_rules.append(payload["name"])), ], }) router.route("event-test-procevents", subject, {"value": 2}) assert "check-even-value" in subscribed_rules assert "check-odd-value" not in subscribed_rules
def test_on_subject_property_changed(router, subject, asserted): from krules_core import types RuleFactory.create( "test-prop-changed", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged("prop_a"), SubjectPropertyChanged(lambda: "prop_{}".format("a")), SubjectPropertyChanged( lambda prop: re.match("prop_[a-z]", prop)), SubjectPropertyChanged("prop_a", lambda: 1), SubjectPropertyChanged("prop_a", value=lambda value: value > 0), SubjectPropertyChanged("prop_a", value=lambda value, old_value: value == 1 and old_value is None), SubjectPropertyChanged("prop_a", old_value=None), SubjectPropertyChanged( "prop_a", old_value=lambda old_value: old_value is None) ] }) RuleFactory.create("test-prop-changed-fails-1", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={filters: [ SubjectPropertyChanged("prop_b"), ]}) RuleFactory.create("test-prop-changed-fails-2", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged("prop_a", lambda value: value > 1), ] }) RuleFactory.create("test-prop-changed-fails-3", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged( "prop_a", lambda value, old_value: value == 1 and old_value is not None), ] }) RuleFactory.create("test-prop-changed-fails-4", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged( "prop_a", lambda value, old_value: value == 1, lambda old_value: old_value is not None), ] }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-prop-changed" and _assert( x[rulename], x[processed], "{} not processed".format(x[rulename]))) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-prop-changed-fails-1" and _assert( x[rulename], not x[processed], "{} should not be not processed". format(x[rulename]))) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-prop-changed-fails-2" and _assert( x[rulename], not x[processed], "{} should not be not processed". format(x[rulename]))) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-prop-changed-fails-3" and _assert( x[rulename], not x[processed], "{} should not be not processed". format(x[rulename]))) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-prop-changed-fails-4" and _assert( x[rulename], not x[processed], "{} should not be not processed". format(x[rulename]))) subject.prop_a = 1 assert 'test-prop-changed' in asserted assert 'test-prop-changed-fails-1' in asserted assert 'test-prop-changed-fails-2' in asserted assert 'test-prop-changed-fails-3' in asserted assert 'test-prop-changed-fails-4' in asserted
def test_check_payload_match(router, subject, asserted): payload = { "batch_data": [{ "time": "2020-03-10T17:16:16.014673", "value": 100 }, { "time": "2020-03-10T17:21:16.014673", "value": 50 }, { "time": "2020-03-10T17:26:16.014673", "value": 60 }, { "time": "2020-03-10T17:31:16.014673", "value": 105 }, { "time": "2020-03-10T17:36:16.014673", "value": 120 }], "device_info": { "id": "0AFB1110", "disabled": False, } } # just check no empty RuleFactory.create( "test-check-payload-jpmatch-not-empty", subscribe_to="test-check-payload-jpmatch", data={ filters: [ PayloadMatch("$..batch_data[[email protected]>100]" ) # returns two elements - pass ] }) # store result RuleFactory.create( "test-check-payload-jpmatch-store-result", subscribe_to="test-check-payload-jpmatch", data={ filters: [ PayloadMatch("$.batch_data[[email protected]>100]", lambda m: len(m) == 2), PayloadMatch("$.batch_data[[email protected]>100]", payload_dest="jpexpr_match"), IsTrue(lambda payload: len(payload['jpexpr_match']) == 2) ] }) # match one RuleFactory.create( "test-check-payload-jpmatch-one", subscribe_to="test-check-payload-jpmatch", data={ filters: [ PayloadMatchOne("$.device_info.id", "0AFB1110"), PayloadMatchOne("$.device_info.id", payload_dest="device_id"), PayloadMatchOne("$.device.info.disabled", lambda disabled: not disabled), IsTrue(lambda payload: payload["device_id"] == "0AFB1110") ] }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-check-payload-jpmatch-not-empty" and _assert(x[rulename], x[processed])) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-check-payload-jpmatch-store-result" and _assert(x[rulename], x[processed])) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-check-payload-jpmatch-one" and _assert( x[rulename], x[processed] and x[filters][0]["returns"] is True and x[filters][1]["returns"] is True and x[filters][2]["returns" ] is True)) router.route("test-check-payload-jpmatch", subject, payload) assert "test-check-payload-jpmatch-not-empty" in asserted assert "test-check-payload-jpmatch-store-result" in asserted assert "test-check-payload-jpmatch-one" in asserted
def test_check_subject_property(router, subject, asserted): RuleFactory.create("test-simple-subject-property", subscribe_to="test-subject-property", data={ filters: [ CheckSubjectProperty("prop-1", "value-1"), CheckSubjectProperty("prop-2", 2), ] }) RuleFactory.create("test-simple-subject-property-fails", subscribe_to="test-subject-property", data={ filters: [ CheckSubjectProperty("prop-1", "value-1"), CheckSubjectProperty("prop-2", "2"), ] }) import re RuleFactory.create( "test-expr-subject-property", subscribe_to="test-subject-property", data={ filters: [ # one argument (value) CheckSubjectProperty("prop-1"), CheckSubjectProperty( "prop-1", lambda v: v in ("value-1", ) and re.match("value-[0-9]", v)), CheckSubjectProperty("prop-2", lambda v: type(v) is int), CheckSubjectProperty("ext-prop", extended=True) ] }) subject.set("prop-1", "value-1") subject.set("prop-2", 2) subject.set_ext("ext-prop-2", "extprop") proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-simple-subject-property" and _assert( x[rulename], x[processed] is True)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-simple-subject-property-fails" and _assert(x[rulename], x[processed] is False)) router.route("test-subject-property", subject, {}) assert "test-simple-subject-property" in asserted assert "test-simple-subject-property-fails" in asserted # clean up router.unregister_all() proc_events_rx_factory.override( providers.Singleton(rx.subjects.ReplaySubject)) # check direct subject.set("prop-1", "value-2") subject.set_ext("ext-prop-3", 1) # properties are not yet stored, rules should fail RuleFactory.create( "test-subject-property-direct", subscribe_to="test-subject-property-direct", data={ filters: [ CheckSubjectProperty("v-prop-1", "value-2", cached=False), # prop-1 is still value-1 ] }) RuleFactory.create( "test-subject-property-ext-direct", subscribe_to="test-subject-property-direct", data={ filters: [ CheckSubjectProperty( "ext-prop-3", cached=False), # ext-prop-3 does not exists yet ] }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-subject-property-direct" and _assert( x[rulename], not x[processed])) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-subject-property-ext-direct" and _assert(x[rulename], not x[processed])) router.route("test-subject-property-direct", subject, {}) assert "test-subject-property-direct" in asserted assert "test-subject-property-ext-direct" in asserted
def test_update(api, namespace): RuleFactory.create( 'test-k8s-update-in-context', subscribe_to="test-update-in-context", data={ RuleConst.PROCESSING: [ # update from subject K8sObjectUpdate(lambda obj: (obj["metadata"]["labels"].update( {"updated": "pod-1"}))), ] }) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-update-in-context' and _assert(x[RuleConst.PROCESSED] and x[RuleConst.GOT_ERRORS] is False, "test-k8s-update-in-context proc failed")) objs = pykube.Pod.objects(api).filter(namespace=namespace, selector={"app": "pytest-temp"}) watch = objs.watch().filter(field_selector={"metadata.name": "test-pod-1"}) event_router_factory().route( "test-update-in-context", f"k8s:/api/v1/namespaces/{namespace}/pods/test-pod-1", {}) try: for ev in watch: if ev.type == 'ADDED' and ev.object.obj["metadata"]["labels"][ "updated"] == "pod-1": break except: assert False, "update pod-1 event failed" RuleFactory.create( 'test-k8s-update-off-context', subscribe_to="test-update-off-context", data={ RuleConst.PROCESSING: [ # update from subject K8sObjectUpdate( lambda obj: (obj["metadata"]["labels"].update({"updated": "pod-2"})), name="test-pod-2", apiversion="v1", kind="Pod", namespace=namespace), ] }) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-update-off-context' and _assert(x[RuleConst.GOT_ERRORS] is False and x[RuleConst.PROCESSED], "test-k8s-update-off-context proc failed")) objs = pykube.Pod.objects(api).filter(namespace=namespace, selector={"app": "pytest-temp"}) watch = objs.watch().filter(field_selector={"metadata.name": "test-pod-2"}) event_router_factory().route("test-update-off-context", "none", {}) try: for ev in watch: if ev.type == 'ADDED' and ev.object.obj["metadata"]["labels"][ "updated"] == "pod-2": break except: assert False, "update pod-2 event failed" event_router_factory().unregister_all()
def test_subject_functions(subject, router, asserted): class _CheckStoredValue(RuleFunctionBase): def execute(self, prop, expected_value): if not subject_storage_factory( self.subject.name).is_concurrency_safe(): return True # skip test subject = subject_factory(self.subject.name) return subject.get(prop, cached=False) == expected_value from datetime import datetime RuleFactory.create( "test-set-subject-property", subscribe_to="test-set-subject-property", data={ processing: [ SetSubjectProperty( "dt_prop", lambda: datetime.now().isoformat()), # no args SetSubjectProperty("my_prop", 1), SetSubjectProperty("my_prop", lambda v: v + 10), SetSubjectPropertySilently("something_to_say", False), StoreSubjectProperty("my_prop_2", 2), _CheckStoredValue("my_prop_2", 2), StoreSubjectPropertySilently("my_prop_3", 3), _CheckStoredValue("my_prop_3", 3), SetSubjectExtendedProperty("my_ext_prop", "extpropvalue"), SetSubjectProperties({ "my_prop_4": 4, "my_silent_prop_5": 5 }, unmuted=["my_prop_4"]), IncrementSubjectProperty("my_prop_4"), _CheckStoredValue("my_prop_4", 1), # cached property in not considered DecrementSubjectProperty("my_prop_4", amount=1.5), IncrementSubjectPropertySilently("my_silent_prop_6"), DecrementSubjectPropertySilently("my_silent_prop_6"), ] }) from krules_core import types RuleFactory.create( "test-non-muted-property", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged( "my_prop", lambda value, old_value: value == 1 and old_value is None) ] }) RuleFactory.create( "test-muted-property", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={filters: [SubjectPropertyChanged("something_to_say")]}) RuleFactory.create( "test-direct-property", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged( "my_prop_2", lambda value, old_value: value == 2 and old_value is None) ] }) RuleFactory.create("test-muted-direct-property", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={filters: [SubjectPropertyChanged("my_prop_3")]}) RuleFactory.create("test-multi-set-properties-unmuted", subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={filters: [SubjectPropertyChanged("my_prop_4")]}) RuleFactory.create( "test-multi-set-properties-muted", # never processed subscribe_to=types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ SubjectPropertyChanged( lambda p: p in ("my_silent_prop_5", "my_silent_prop_6")) ] }) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-set-subject-property" and _assert( x[rulename], x[processed])) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-non-muted-property" and x[ processed] and _assert(x[rulename], True)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-muted-property" and x[ processed] and _assert(x[rulename], False)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-direct-property" and x[ processed] and _assert(x[rulename], True)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-muted-direct-property" and x[ processed] and _assert(x[rulename], False)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-multi-set-properties-unmuted" and x[ processed] and _assert(x[rulename], True)) proc_events_rx_factory().subscribe( lambda x: x[rulename] == "test-multi-set-properties-muted" and x[ processed] and _assert(x[rulename], False)) router.route("test-set-subject-property", subject, {}) assert subject.get("my_prop") == 11 assert subject.get("dt_prop")[:10] == datetime.now().isoformat()[:10] assert subject.get_ext("my_ext_prop") == "extpropvalue" assert subject.get("my_prop_4") == -.5 assert subject.get("my_silent_prop_5") == 5 assert "test-set-subject-property" in asserted assert "test-non-muted-property" in asserted assert "test-muted-property" not in asserted assert "test-direct-property" in asserted assert "test-multi-set-properties-unmuted" in asserted
def test_create(api, namespace): RuleFactory.create('test-k8s-create', subscribe_to="test-create", data={ RuleConst.PROCESSING: [ K8sObjectCreate({ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "test-pod-1", "labels": { "app": "pytest-temp" } }, "spec": { "containers": [{ "name": "hello", "image": "karthequian/helloworld" }] } }), K8sObjectCreate({ "apiVersion": "v1", "kind": "Pod", "metadata": { "name": "test-pod-2", "labels": { "app": "pytest-temp" } }, "spec": { "containers": [{ "name": "hello", "image": "karthequian/helloworld" }] } }) ] }) proc_events_rx_factory().subscribe( lambda x: x[RuleConst.RULENAME] == 'test-k8s-create' and _assert( not x[RuleConst.GOT_ERRORS] and x[RuleConst.PROCESSED], "test-k8s-create proc failed")) event_router_factory().route("test-create", "some", {}) pykube.Pod.objects(api).filter(namespace=namespace) objs = pykube.Pod.objects(api).filter(namespace=namespace, selector={"app": "pytest-temp"}) # wait for pods ready # watch = objs.watch() # ready = 0 # for ev in watch: # print(ev.type, ev.object.name, ev.object.ready) # if ev.object.ready: # ready += 1 # if ready == 2: # break # assert len(objs) == 2 event_router_factory().unregister_all()