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_truth(subject, router, asserted): RuleFactory.create('test-is-true', subscribe_to="event-test-truth", data={ filters: [ Filter(lambda payload: payload["it-works"]), ], }) # RuleFactory.create('test-is-false', # subscribe_to="event-test-truth", # data={ # filters: [ # Filter( # 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[passed] 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[passed] and x[filters][0]["returns"] is True)) router.route("event-test-truth", subject, {'it-works': True}) assert 'test-is-true' in asserted
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_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_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 init(): configs_factory.override(providers.Singleton(lambda: krules_settings)) proc_events_rx_factory.queue.clear() event_router_factory.override(providers.Singleton(lambda: EventRouter())) exceptions_dumpers = exceptions_dumpers_factory() exceptions_dumpers.set(ExceptionDumperBase) exceptions_dumpers.set(RequestsHTTPErrorDumper) # TODO: do it better source = None if "K_SERVICE" in os.environ: source = os.environ["K_SERVICE"] elif "SERVICE" in os.environ: source = os.environ["SERVICE"] else: source = socket.gethostname() from krules_cloudevents.route.dispatcher import CloudEventsDispatcher event_dispatcher_factory.override( providers.Singleton( lambda: CloudEventsDispatcher(_get_dispatch_url, source))) try: import env if "init" in dir(env) and callable(env.init): env.init() except ModuleNotFoundError: logger.warning("No application env.py found!") try: m_rules = importlib.import_module("ruleset") load_rules_from_rulesdata(m_rules.rulesdata) except ModuleNotFoundError as ex: if ex.name == "ruleset": logger.warning("No rules defined!") else: raise ex proc_events_filters = os.environ.get("PUBLISH_PROCEVENTS_MATCHING") if proc_events_filters: proc_events_rx_factory.subscribe( on_next=lambda x: publish_proc_events_filtered( x, proc_events_filters.split(";"), lambda match: match is not None)) else: proc_events_rx_factory.subscribe( on_next=lambda x: publish_proc_events_all(x))
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_return(subject, router, asserted): RuleFactory.create('test-returns', subscribe_to="event-test-returns", data={ filters: [ Filter("something"), ], }) proc_events_rx_factory.subscribe( lambda x: x[rulename] == 'test-returns' and _assert( 'test-returns-something', x[passed] 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 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"), Filter( 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[passed] is True)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == 'test-subject-does-not-match' and _assert( 'test-subject-does-not-match', x[passed] 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_payload_functions(subject, router, asserted): test_payload = {"k1": "val1", "k2": {"k2a": 1, "k2b": {"a": 1, "b": 2}}} RuleFactory.create( "test-alter-payload", subscribe_to="test-alter-payload", data={ processing: [ Process(lambda payload: (payload["k2"]["k2b"].update({ "b": 3, "c": 4 }), payload.update({"k3": 3}))), SetPayloadProperties(k1=0, k3=lambda payload: payload["k3"] + 1, k4=lambda payload: "k4" in payload and payload["k4"] + 1 or -1), SetPayloadProperty( "k4", lambda payload: "k4" in payload and payload["k4"] + 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"] == test_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, test_payload) assert "test-update-1" in asserted assert "test-update-2" in asserted
def test_on_subject_property_changed(router, subject, asserted): from krules_core import event_types RuleFactory.create( "test-prop-changed", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged("prop_a"), OnSubjectPropertyChanged(lambda: "prop_{}".format("a")), OnSubjectPropertyChanged( lambda prop: re.match("prop_[a-z]", prop)), OnSubjectPropertyChanged("prop_a", lambda: 1), OnSubjectPropertyChanged("prop_a", value=lambda value: value > 0), OnSubjectPropertyChanged("prop_a", value=lambda value, old_value: value == 1 and old_value is None), OnSubjectPropertyChanged("prop_a", old_value=None), OnSubjectPropertyChanged( "prop_a", old_value=lambda old_value: old_value is None) ] }) RuleFactory.create("test-prop-changed-fails-1", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={filters: [ OnSubjectPropertyChanged("prop_b"), ]}) RuleFactory.create("test-prop-changed-fails-2", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged( "prop_a", lambda value: value > 1), ] }) RuleFactory.create("test-prop-changed-fails-3", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged( "prop_a", lambda value, old_value: value == 1 and old_value is not None), ] }) RuleFactory.create("test-prop-changed-fails-4", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged( "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[passed], "{} 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[passed], "{} 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[passed], "{} 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[passed], "{} 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[passed], "{} 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"), Filter(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), Filter(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[passed])) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-check-payload-jpmatch-store-result" and _assert(x[rulename], x[passed])) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-check-payload-jpmatch-one" and _assert( x[rulename], x[passed] 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", "extprop") proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-simple-subject-property" and _assert( x[rulename], x[passed] is True)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-simple-subject-property-fails" and _assert(x[rulename], x[passed] is False)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-expr-subject-property" and _assert( x[rulename], x[passed] is True)) router.route("test-subject-property", subject, {}) assert "test-simple-subject-property" in asserted assert "test-simple-subject-property-fails" in asserted assert "test-expr-subject-property" in asserted # clean up router.unregister_all() proc_events_rx_factory.queue.clear() # 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", use_cache=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", use_cache=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[passed])) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-subject-property-ext-direct" and _assert(x[rulename], not x[passed])) router.route("test-subject-property-direct", subject, {}) assert "test-subject-property-direct" in asserted assert "test-subject-property-ext-direct" in asserted
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, use_cache=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), SetSubjectProperty("something_to_say", False, muted=True), SetSubjectPropertyImmediately("my_prop_2", 2), _CheckStoredValue("my_prop_2", 2), SetSubjectPropertyImmediately("my_prop_3", 3, muted=True), _CheckStoredValue("my_prop_3", 3), SetSubjectExtendedProperty("my_ext_prop", "extpropvalue"), SetSubjectProperties({ "my_prop_4": 4, "my_silent_prop_5": 5 }, unmuted=["my_prop_4"]), SetSubjectProperty("my_prop_4", value=lambda x: x is None and 1 or x + 1, use_cache=False), _CheckStoredValue("my_prop_4", 1), # cached property in not considered SetSubjectProperty( "my_prop_4", value=lambda x: x is None and -1.5 or x - 1.5, use_cache=False), SetSubjectProperty("my_silent_prop_6", value=lambda x: x is None and 1 or x - 1, muted=True), ] }) from krules_core import event_types RuleFactory.create( "test-non-muted-property", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged( "my_prop", lambda value, old_value: value == 1 and old_value is None) ] }) RuleFactory.create( "test-muted-property", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={filters: [OnSubjectPropertyChanged("something_to_say")]}) RuleFactory.create( "test-direct-property", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged( "my_prop_2", lambda value, old_value: value == 2 and old_value is None) ] }) RuleFactory.create("test-muted-direct-property", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={filters: [OnSubjectPropertyChanged("my_prop_3")]}) RuleFactory.create("test-multi-set-properties-unmuted", subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={filters: [OnSubjectPropertyChanged("my_prop_4")]}) RuleFactory.create( "test-multi-set-properties-muted", # never processed subscribe_to=event_types.SUBJECT_PROPERTY_CHANGED, data={ filters: [ OnSubjectPropertyChanged( 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[passed])) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-non-muted-property" and x[ passed] and _assert(x[rulename], True)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-muted-property" and x[ passed] and _assert(x[rulename], False)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-direct-property" and x[ passed] and _assert(x[rulename], True)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-muted-direct-property" and x[ passed] and _assert(x[rulename], False)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-multi-set-properties-unmuted" and x[ passed] and _assert(x[rulename], True)) proc_events_rx_factory.subscribe( lambda x: x[rulename] == "test-multi-set-properties-muted" and x[ passed] 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