From f33e28af6d56e05aef4a0efe14e636d5d4a47753 Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Sun, 26 Sep 2021 10:48:24 +0800 Subject: [PATCH] fix(rules): update test cases for emqx_rule_engine_SUITE --- apps/emqx_rule_engine/src/emqx_rule_funcs.erl | 11 +- .../test/emqx_rule_engine_SUITE.erl | 1626 ++++------------- .../test/emqx_rule_registry_SUITE.erl | 148 -- 3 files changed, 365 insertions(+), 1420 deletions(-) delete mode 100644 apps/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl diff --git a/apps/emqx_rule_engine/src/emqx_rule_funcs.erl b/apps/emqx_rule_engine/src/emqx_rule_funcs.erl index 3f60d97c9..bc3ef6f24 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_funcs.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_funcs.erl @@ -333,8 +333,10 @@ republish(Topic, Payload, Qos, Retain) -> '+'(X, Y) when is_number(X), is_number(Y) -> X + Y; -%% concat 2 strings -'+'(X, Y) when is_binary(X), is_binary(Y) -> +%% string concatenation +%% this requires one of the arguments is string, the other argument will be converted +%% to string automatically (implicit conversion) +'+'(X, Y) when is_binary(X); is_binary(Y) -> concat(X, Y). '-'(X, Y) when is_number(X), is_number(Y) -> @@ -635,8 +637,9 @@ tokens(S, Separators) -> tokens(S, Separators, <<"nocrlf">>) -> [list_to_binary(R) || R <- string:lexemes(binary_to_list(S), binary_to_list(Separators) ++ [$\r,$\n,[$\r,$\n]])]. -concat(S1, S2) when is_binary(S1), is_binary(S2) -> - unicode:characters_to_binary([S1, S2], unicode). +%% implicit convert args to strings, and then do concatenation +concat(S1, S2) -> + unicode:characters_to_binary([str(S1), str(S2)], unicode). sprintf_s(Format, Args) when is_list(Args) -> erlang:iolist_to_binary(io_lib:format(binary_to_list(Format), Args)). diff --git a/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl index 0b46d07c4..3b949baa3 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl @@ -26,17 +26,15 @@ -include_lib("common_test/include/ct.hrl"). %%-define(PROPTEST(M,F), true = proper:quickcheck(M:F())). +-define(TMP_RULEID, atom_to_binary(?FUNCTION_NAME)). all() -> [ {group, engine} - , {group, actions} -%% , {group, api} - , {group, cli} + , {group, api} , {group, funcs} , {group, registry} , {group, runtime} , {group, events} - , {group, multi_actions} , {group, bugs} ]. @@ -45,49 +43,21 @@ suite() -> groups() -> [{engine, [sequence], - [t_register_provider, - t_unregister_provider, - t_create_rule, - t_create_resource - ]}, - {actions, [], - [t_inspect_action - ,t_republish_action - ]}, -%% TODO: V5 API -%% {api, [], -%% [t_crud_rule_api, -%% t_list_actions_api, -%% t_show_action_api, -%% t_crud_resources_api, -%% t_list_resource_types_api, -%% t_show_resource_type_api -%% ]}, - {cli, [], - [t_rules_cli, - t_actions_cli, - t_resources_cli, - t_resource_types_cli + [t_create_rule ]}, + {api, [], + [t_crud_rule_api + ]}, {funcs, [], - [t_topic_func, - t_kv_store + [t_kv_store ]}, {registry, [sequence], [t_add_get_remove_rule, t_add_get_remove_rules, t_create_existing_rule, - t_update_rule, - t_disable_rule, t_get_rules_for_topic, t_get_rules_for_topic_2, - t_get_rules_with_same_event, - t_add_get_remove_action, - t_add_get_remove_actions, - t_remove_actions_of, - t_get_resources, - t_add_get_remove_resource, - t_resource_types + t_get_rules_with_same_event ]}, {runtime, [], [t_match_atom_and_binary, @@ -97,9 +67,6 @@ groups() -> t_sqlselect_02, t_sqlselect_1, t_sqlselect_2, - t_sqlselect_2_1, - t_sqlselect_2_2, - t_sqlselect_2_3, t_sqlselect_3, t_sqlparse_event_1, t_sqlparse_event_2, @@ -132,14 +99,6 @@ groups() -> {bugs, [], [t_sqlparse_payload_as, t_sqlparse_nested_get - ]}, - {multi_actions, [], - [t_sqlselect_multi_actoins_1, - t_sqlselect_multi_actoins_1_1, - t_sqlselect_multi_actoins_2, - t_sqlselect_multi_actoins_3, - t_sqlselect_multi_actoins_3_1, - t_sqlselect_multi_actoins_4 ]} ]. @@ -151,7 +110,7 @@ init_per_suite(Config) -> application:load(emqx_machine), ok = ekka_mnesia:start(), ok = emqx_rule_registry:mnesia(boot), - ok = emqx_ct_helpers:start_apps([emqx_rule_engine], fun set_special_configs/1), + ok = emqx_ct_helpers:start_apps([emqx_rule_engine]), Config. end_per_suite(_Config) -> @@ -182,16 +141,8 @@ end_per_group(_Groupname, _Config) -> %%------------------------------------------------------------------------------ init_per_testcase(t_events, Config) -> - {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), - ok = emqx_rule_engine:load_providers(), init_events_counters(), - ok = emqx_rule_registry:register_resource_types([make_simple_resource_type(simple_resource_type)]), - ok = emqx_rule_registry:add_action( - #action{name = 'hook-metrics-action', app = ?APP, - module = ?MODULE, on_create = hook_metrics_action, - types=[], params_spec = #{}, - title = #{en => <<"Hook metrics action">>}, - description = #{en => <<"Hook metrics action">>}}), + {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), SQL = "SELECT * FROM \"$events/client_connected\", " "\"$events/client_disconnected\", " "\"$events/session_subscribed\", " @@ -202,320 +153,82 @@ init_per_testcase(t_events, Config) -> "\"t1\"", {ok, Rule} = emqx_rule_engine:create_rule( #{id => <<"rule:t_events">>, - rawsql => SQL, - actions => [#{id => <<"action:inspect">>, name => 'inspect', args => #{}}, - #{id => <<"action:hook-metrics-action">>, name => 'hook-metrics-action', args => #{}}], - description => <<"Debug rule">>}), + sql => SQL, + outputs => [console, fun ?MODULE:output_record_triggered_events/2], + description => <<"to console and record triggered events">>}), ?assertMatch(#rule{id = <<"rule:t_events">>}, Rule), [{hook_points_rules, Rule} | Config]; -init_per_testcase(Test, Config) - when Test =:= t_sqlselect_multi_actoins_1 - ;Test =:= t_sqlselect_multi_actoins_1_1 - ;Test =:= t_sqlselect_multi_actoins_2 - ;Test =:= t_sqlselect_multi_actoins_3 - ;Test =:= t_sqlselect_multi_actoins_3_1 - ;Test =:= t_sqlselect_multi_actoins_4 - -> - emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), - ok = emqx_rule_engine:load_providers(), - ok = emqx_rule_registry:add_action( - #action{name = 'crash_action', app = ?APP, - module = ?MODULE, on_create = crash_action, - types=[], params_spec = #{}, - title = #{en => <<"Crash Action">>}, - description = #{en => <<"This action will always fail!">>}}), - ok = emqx_rule_registry:add_action( - #action{name = 'failure_action', app = ?APP, - module = ?MODULE, on_create = failure_action, - types=[], params_spec = #{}, - title = #{en => <<"Crash Action">>}, - description = #{en => <<"This action will always fail!">>}}), - ok = emqx_rule_registry:add_action( - #action{name = 'plus_by_one', app = ?APP, - module = ?MODULE, on_create = plus_by_one_action, - types=[], params_spec = #{}, - title = #{en => <<"Plus an integer by 1">>} - }), - init_plus_by_one_action(), - SQL = "SELECT * " - "FROM \"$events/client_connected\" " - "WHERE username = 'emqx1'", - {ok, SubClient} = emqtt:start_link([{clientid, <<"emqx0">>}, {username, <<"emqx0">>}]), - {ok, _} = emqtt:connect(SubClient), - {ok, _, _} = emqtt:subscribe(SubClient, <<"t2">>, 0), - ct:sleep(100), - - {ok, ConnClient} = emqtt:start_link([{clientid, <<"c_emqx1">>}, {username, <<"emqx1">>}]), - TriggerConnEvent = fun() -> - {ok, _} = emqtt:connect(ConnClient) - end, - [{subclient, SubClient}, - {connclient, ConnClient}, - {conn_event, TriggerConnEvent}, - {connsql, SQL} - | Config]; init_per_testcase(_TestCase, Config) -> emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), - ok = emqx_rule_registry:register_resource_types( - [#resource_type{ - name = built_in, - provider = ?APP, - params_spec = #{}, - on_create = {?MODULE, on_resource_create}, - on_destroy = {?MODULE, on_resource_destroy}, - on_status = {?MODULE, on_get_resource_status}, - title = #{en => <<"Built-In Resource Type (debug)">>}, - description = #{en => <<"The built in resource type for debug purpose">>}}]), - %ct:pal("============ ~p", [ets:tab2list(emqx_resource_type)]), Config. - end_per_testcase(t_events, Config) -> ets:delete(events_record_tab), - ok = emqx_rule_registry:remove_rule(?config(hook_points_rules, Config)), - ok = emqx_rule_registry:remove_action('hook-metrics-action'); -end_per_testcase(Test, Config) - when Test =:= t_sqlselect_multi_actoins_1, - Test =:= t_sqlselect_multi_actoins_2 - -> - emqtt:stop(?config(subclient, Config)), - emqtt:stop(?config(connclient, Config)), - Config; + ok = emqx_rule_registry:remove_rule(?config(hook_points_rules, Config)); end_per_testcase(_TestCase, _Config) -> ok. %%------------------------------------------------------------------------------ %% Test cases for rule engine %%------------------------------------------------------------------------------ - -t_register_provider(_Config) -> - ok = emqx_rule_engine:load_providers(), - ?assert(length(emqx_rule_registry:get_actions()) >= 2), - ok. - -t_unregister_provider(_Config) -> - ok = emqx_rule_engine:unload_providers(), - ?assert(length(emqx_rule_registry:get_actions()) == 0), - ok. - t_create_rule(_Config) -> - ok = emqx_rule_engine:load_providers(), {ok, #rule{id = Id}} = emqx_rule_engine:create_rule( - #{rawsql => <<"select * from \"t/a\"">>, - actions => [#{name => 'inspect', args => #{arg1 => 1}}], + #{sql => <<"select * from \"t/a\"">>, + id => <<"t_create_rule">>, + outputs => [console], description => <<"debug rule">>}), - %ct:pal("======== emqx_rule_registry:get_rules :~p", [emqx_rule_registry:get_rules()]), - ?assertMatch({ok,#rule{id = Id, for = [<<"t/a">>]}}, emqx_rule_registry:get_rule(Id)), - ok = emqx_rule_engine:unload_providers(), + ct:pal("======== emqx_rule_registry:get_rules :~p", [emqx_rule_registry:get_rules()]), + ?assertMatch({ok, #rule{id = Id, info = #{from := [<<"t/a">>]}}}, + emqx_rule_registry:get_rule(Id)), emqx_rule_registry:remove_rule(Id), ok. -t_create_resource(_Config) -> - ok = emqx_rule_engine:load_providers(), - {ok, #resource{id = ResId}} = emqx_rule_engine:create_resource( - #{type => built_in, - config => #{}, - description => <<"debug resource">>}), - ?assert(true, is_binary(ResId)), - ok = emqx_rule_engine:unload_providers(), - emqx_rule_registry:remove_resource(ResId), - ok. - -%%------------------------------------------------------------------------------ -%% Test cases for rule actions -%%------------------------------------------------------------------------------ - -t_inspect_action(_Config) -> - ok = emqx_rule_engine:load_providers(), - {ok, #resource{id = ResId}} = emqx_rule_engine:create_resource( - #{type => built_in, - config => #{}, - description => <<"debug resource">>}), - {ok, #rule{id = Id}} = emqx_rule_engine:create_rule( - #{rawsql => "select clientid as c, username as u " - "from \"t1\" ", - actions => [#{name => 'inspect', - args => #{'$resource' => ResId, a=>1, b=>2}}], - type => built_in, - description => <<"Inspect rule">> - }), - {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), - {ok, _} = emqtt:connect(Client), - emqtt:publish(Client, <<"t1">>, <<"{\"id\": 1, \"name\": \"ha\"}">>, 0), - emqtt:stop(Client), - emqx_rule_registry:remove_rule(Id), - emqx_rule_registry:remove_resource(ResId), - ok. - -t_republish_action(_Config) -> - Qos0Received = emqx_metrics:val('messages.qos0.received'), - Received = emqx_metrics:val('messages.received'), - ok = emqx_rule_engine:load_providers(), - {ok, #rule{id = Id, for = [<<"t1">>]}} = - emqx_rule_engine:create_rule( - #{rawsql => <<"select topic, payload, qos from \"t1\"">>, - actions => [#{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"${payload}">>}}], - description => <<"builtin-republish-rule">>}), - {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), - {ok, _} = emqtt:connect(Client), - {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), - - Msg = <<"{\"id\": 1, \"name\": \"ha\"}">>, - emqtt:publish(Client, <<"t1">>, Msg, 0), - receive {publish, #{topic := <<"t2">>, payload := Payload}} -> - ?assertEqual(Msg, Payload) - after 1000 -> - ct:fail(wait_for_t2) - end, - emqtt:stop(Client), - emqx_rule_registry:remove_rule(Id), - ?assertEqual(2, emqx_metrics:val('messages.qos0.received') - Qos0Received), - ?assertEqual(2, emqx_metrics:val('messages.received') - Received), - ok. - %%------------------------------------------------------------------------------ %% Test cases for rule engine api %%------------------------------------------------------------------------------ t_crud_rule_api(_Config) -> - {ok, #{code := 0, data := Rule}} = - emqx_rule_engine_api:create_rule(#{}, - [{<<"name">>, <<"debug-rule">>}, - {<<"rawsql">>, <<"select * from \"t/a\"">>}, - {<<"actions">>, [[{<<"name">>,<<"inspect">>}, - {<<"params">>,[{<<"arg1">>,1}]}]]}, - {<<"description">>, <<"debug rule">>}]), - RuleID = maps:get(id, Rule), - %ct:pal("RCreated : ~p", [Rule]), + RuleID = <<"my_rule">>, + Params0 = #{ + <<"description">> => <<"A simple rule">>, + <<"enable">> => true, + <<"id">> => RuleID, + <<"outputs">> => [ <<"console">> ], + <<"sql">> => <<"SELECT * from \"t/1\"">> + }, + {201, Rule} = emqx_rule_engine_api:crud_rules(post, #{body => Params0}), - {ok, #{code := 0, data := Rules}} = emqx_rule_engine_api:list_rules(#{}, []), - %ct:pal("RList : ~p", [Rules]), + ?assertEqual(RuleID, maps:get(id, Rule)), + {ok, Rules} = emqx_rule_engine_api:crud_rules(get, #{}), + ct:pal("RList : ~p", [Rules]), ?assert(length(Rules) > 0), - {ok, #{code := 0, data := Rule1}} = emqx_rule_engine_api:show_rule(#{id => RuleID}, []), - %ct:pal("RShow : ~p", [Rule1]), + {200, Rule1} = emqx_rule_engine_api:crud_rules_by_id(get, #{bindings => #{id => RuleID}}), + ct:pal("RShow : ~p", [Rule1]), ?assertEqual(Rule, Rule1), - {ok, #{code := 0, data := Rule2}} = emqx_rule_engine_api:update_rule(#{id => RuleID}, - [{<<"rawsql">>, <<"select * from \"t/b\"">>}]), + {200, Rule2} = emqx_rule_engine_api:crud_rules_by_id(put, #{ + bindings => #{id => RuleID}, + body => Params0#{<<"sql">> => <<"select * from \"t/b\"">>} + }), - {ok, #{code := 0, data := Rule3}} = emqx_rule_engine_api:show_rule(#{id => RuleID}, []), - %ct:pal("RShow : ~p", [Rule1]), + {200, Rule3} = emqx_rule_engine_api:crud_rules_by_id(get, #{bindings => #{id => RuleID}}), + %ct:pal("RShow : ~p", [Rule3]), ?assertEqual(Rule3, Rule2), - ?assertEqual(<<"select * from \"t/b\"">>, maps:get(rawsql, Rule3)), + ?assertEqual(<<"select * from \"t/b\"">>, maps:get(sql, Rule3)), - {ok, #{code := 0, data := Rule4}} = emqx_rule_engine_api:update_rule(#{id => RuleID}, - [{<<"actions">>, - [[ - {<<"name">>,<<"republish">>}, - {<<"params">>,[ - {<<"arg1">>,1}, - {<<"target_topic">>, <<"t2">>}, - {<<"target_qos">>, -1}, - {<<"payload_tmpl">>, <<"${payload}">>} - ]} - ]] - }]), + ?assertMatch({200}, emqx_rule_engine_api:crud_rules_by_id(delete, + #{bindings => #{id => RuleID}})), - {ok, #{code := 0, data := Rule5}} = emqx_rule_engine_api:show_rule(#{id => RuleID}, []), - %ct:pal("RShow : ~p", [Rule1]), - ?assertEqual(Rule5, Rule4), - ?assertMatch([#{name := republish }], maps:get(actions, Rule5)), - - ?assertMatch({ok, #{code := 0}}, emqx_rule_engine_api:delete_rule(#{id => RuleID}, [])), - - NotFound = emqx_rule_engine_api:show_rule(#{id => RuleID}, []), %ct:pal("Show After Deleted: ~p", [NotFound]), - ?assertMatch({ok, #{code := 404, message := _Message}}, NotFound), - ok. - -t_list_actions_api(_Config) -> - {ok, #{code := 0, data := Actions}} = emqx_rule_engine_api:list_actions(#{}, []), - %ct:pal("RList : ~p", [Actions]), - ?assert(length(Actions) > 0), - ok. - -t_show_action_api(_Config) -> - {ok, #{code := 0, data := Actions}} = emqx_rule_engine_api:show_action(#{name => 'inspect'}, []), - ?assertEqual('inspect', maps:get(name, Actions)), - ok. - -t_crud_resources_api(_Config) -> - {ok, #{code := 0, data := Resources1}} = - emqx_rule_engine_api:create_resource(#{}, - [{<<"name">>, <<"Simple Resource">>}, - {<<"type">>, <<"built_in">>}, - {<<"config">>, [{<<"a">>, 1}]}, - {<<"description">>, <<"Simple Resource">>}]), - ResId = maps:get(id, Resources1), - {ok, #{code := 0, data := Resources}} = emqx_rule_engine_api:list_resources(#{}, []), - ?assert(length(Resources) > 0), - {ok, #{code := 0, data := Resources2}} = emqx_rule_engine_api:show_resource(#{id => ResId}, []), - ?assertEqual(ResId, maps:get(id, Resources2)), - % - {ok, #{code := 0}} = emqx_rule_engine_api:update_resource(#{id => ResId}, - [{<<"config">>, [{<<"a">>, 2}]}, - {<<"description">>, <<"2">>}]), - {ok, #{code := 0, data := Resources3}} = emqx_rule_engine_api:show_resource(#{id => ResId}, []), - ?assertEqual(ResId, maps:get(id, Resources3)), - ?assertEqual(#{<<"a">> => 2}, maps:get(config, Resources3)), - ?assertEqual(<<"2">>, maps:get(description, Resources3)), - % - {ok, #{code := 0}} = emqx_rule_engine_api:update_resource(#{id => ResId}, - [{<<"config">>, [{<<"a">>, 3}]}]), - {ok, #{code := 0, data := Resources4}} = emqx_rule_engine_api:show_resource(#{id => ResId}, []), - ?assertEqual(ResId, maps:get(id, Resources4)), - ?assertEqual(#{<<"a">> => 3}, maps:get(config, Resources4)), - ?assertEqual(<<"2">>, maps:get(description, Resources4)), - % Only config - {ok, #{code := 0}} = emqx_rule_engine_api:update_resource(#{id => ResId}, - [{<<"config">>, [{<<"a">>, 1}, - {<<"b">>, 2}, - {<<"c">>, 3}]}]), - {ok, #{code := 0, data := Resources5}} = emqx_rule_engine_api:show_resource(#{id => ResId}, []), - ?assertEqual(ResId, maps:get(id, Resources5)), - ?assertEqual(#{<<"a">> => 1, <<"b">> => 2, <<"c">> => 3}, maps:get(config, Resources5)), - ?assertEqual(<<"2">>, maps:get(description, Resources5)), - % Only description - {ok, #{code := 0}} = emqx_rule_engine_api:update_resource(#{id => ResId}, - [{<<"description">>, <<"new5">>}]), - {ok, #{code := 0, data := Resources6}} = emqx_rule_engine_api:show_resource(#{id => ResId}, []), - ?assertEqual(ResId, maps:get(id, Resources6)), - ?assertEqual(#{<<"a">> => 1, <<"b">> => 2, <<"c">> => 3}, maps:get(config, Resources6)), - ?assertEqual(<<"new5">>, maps:get(description, Resources6)), - % None - {ok, #{code := 0}} = emqx_rule_engine_api:update_resource(#{id => ResId}, []), - {ok, #{code := 0, data := Resources7}} = emqx_rule_engine_api:show_resource(#{id => ResId}, []), - ?assertEqual(ResId, maps:get(id, Resources7)), - ?assertEqual(#{<<"a">> => 1, <<"b">> => 2, <<"c">> => 3}, maps:get(config, Resources7)), - ?assertEqual(<<"new5">>, maps:get(description, Resources7)), - % - ?assertMatch({ok, #{code := 0}}, emqx_rule_engine_api:delete_resource(#{id => ResId},#{})), - ?assertMatch({ok, #{code := 404}}, emqx_rule_engine_api:show_resource(#{id => ResId}, [])), - ok. - -t_list_resource_types_api(_Config) -> - {ok, #{code := 0, data := ResourceTypes}} = emqx_rule_engine_api:list_resource_types(#{}, []), - ?assert(length(ResourceTypes) > 0), - ok. - -t_show_resource_type_api(_Config) -> - {ok, #{code := 0, data := RShow}} = emqx_rule_engine_api:show_resource_type(#{name => 'built_in'}, []), - %ct:pal("RShow : ~p", [RShow]), - ?assertEqual(built_in, maps:get(name, RShow)), + ?assertMatch({404, #{code := _, message := _Message}}, + emqx_rule_engine_api:crud_rules_by_id(get, #{bindings => #{id => RuleID}})), ok. %%------------------------------------------------------------------------------ %% Test cases for rule funcs %%------------------------------------------------------------------------------ -t_topic_func(_Config) -> - %%TODO: - ok. - t_kv_store(_) -> undefined = emqx_rule_funcs:kv_store_get(<<"abc">>), <<"not_found">> = emqx_rule_funcs:kv_store_get(<<"abc">>, <<"not_found">>), @@ -529,7 +242,6 @@ t_kv_store(_) -> %%------------------------------------------------------------------------------ t_add_get_remove_rule(_Config) -> - mock_print(), RuleId0 = <<"rule-debug-0">>, ok = emqx_rule_registry:add_rule(make_simple_rule(RuleId0)), ?assertMatch({ok, #rule{id = RuleId0}}, emqx_rule_registry:get_rule(RuleId0)), @@ -542,7 +254,6 @@ t_add_get_remove_rule(_Config) -> ?assertMatch({ok, #rule{id = RuleId1}}, emqx_rule_registry:get_rule(RuleId1)), ok = emqx_rule_registry:remove_rule(Rule1), ?assertEqual(not_found, emqx_rule_registry:get_rule(RuleId1)), - unmock_print(), ok. t_add_get_remove_rules(_Config) -> @@ -566,90 +277,16 @@ t_create_existing_rule(_Config) -> %% create a rule using given rule id {ok, _} = emqx_rule_engine:create_rule( #{id => <<"an_existing_rule">>, - rawsql => <<"select * from \"t/#\"">>, - actions => [ - #{name => 'inspect', args => #{}} - ] + sql => <<"select * from \"t/#\"">>, + outputs => [console] }), - {ok, #rule{rawsql = SQL}} = emqx_rule_registry:get_rule(<<"an_existing_rule">>), + {ok, #rule{info = #{sql := SQL}}} = emqx_rule_registry:get_rule(<<"an_existing_rule">>), ?assertEqual(<<"select * from \"t/#\"">>, SQL), ok = emqx_rule_engine:delete_rule(<<"an_existing_rule">>), ?assertEqual(not_found, emqx_rule_registry:get_rule(<<"an_existing_rule">>)), ok. -t_update_rule(_Config) -> - {ok, #rule{actions = [#action_instance{id = ActInsId0}]}} = emqx_rule_engine:create_rule( - #{id => <<"an_existing_rule">>, - rawsql => <<"select * from \"t/#\"">>, - actions => [ - #{name => 'inspect', args => #{}} - ] - }), - ?assertMatch({ok, #action_instance_params{apply = _}}, - emqx_rule_registry:get_action_instance_params(ActInsId0)), - %% update the rule and verify the old action instances has been cleared - %% and the new action instances has been created. - emqx_rule_engine:update_rule(#{ id => <<"an_existing_rule">>, - actions => [ - #{name => 'do_nothing', args => #{}} - ]}), - - {ok, #rule{actions = [#action_instance{id = ActInsId1}]}} - = emqx_rule_registry:get_rule(<<"an_existing_rule">>), - - ?assertMatch(not_found, - emqx_rule_registry:get_action_instance_params(ActInsId0)), - - ?assertMatch({ok, #action_instance_params{apply = _}}, - emqx_rule_registry:get_action_instance_params(ActInsId1)), - - ok = emqx_rule_engine:delete_rule(<<"an_existing_rule">>), - ?assertEqual(not_found, emqx_rule_registry:get_rule(<<"an_existing_rule">>)), - ok. - -t_disable_rule(_Config) -> - ets:new(simple_action_2, [named_table, set, public]), - ets:insert(simple_action_2, {created, 0}), - ets:insert(simple_action_2, {destroyed, 0}), - Now = erlang:timestamp(), - emqx_rule_registry:add_action( - #action{name = 'simple_action_2', app = ?APP, - module = ?MODULE, - on_create = simple_action_2_create, - on_destroy = simple_action_2_destroy, - types=[], params_spec = #{}, - title = #{en => <<"Simple Action">>}, - description = #{en => <<"Simple Action">>}}), - {ok, #rule{actions = [#action_instance{}]}} = emqx_rule_engine:create_rule( - #{id => <<"simple_rule_2">>, - rawsql => <<"select * from \"t/#\"">>, - actions => [#{name => 'simple_action_2', args => #{}}] - }), - [{_, CAt}] = ets:lookup(simple_action_2, created), - ?assert(CAt > Now), - [{_, DAt}] = ets:lookup(simple_action_2, destroyed), - ?assert(DAt < Now), - - %% disable the rule and verify the old action instances has been cleared - Now2 = erlang:timestamp(), - emqx_rule_engine:update_rule(#{ id => <<"simple_rule_2">>, - enabled => false}), - [{_, CAt2}] = ets:lookup(simple_action_2, created), - ?assert(CAt2 < Now2), - [{_, DAt2}] = ets:lookup(simple_action_2, destroyed), - ?assert(DAt2 > Now2), - - %% enable the rule again and verify the action instances has been created - Now3 = erlang:timestamp(), - emqx_rule_engine:update_rule(#{ id => <<"simple_rule_2">>, - enabled => true}), - [{_, CAt3}] = ets:lookup(simple_action_2, created), - ?assert(CAt3 > Now3), - [{_, DAt3}] = ets:lookup(simple_action_2, destroyed), - ?assert(DAt3 < Now3), - ok = emqx_rule_engine:delete_rule(<<"simple_rule_2">>). - t_get_rules_for_topic(_Config) -> Len0 = length(emqx_rule_registry:get_rules_for_topic(<<"simple/topic">>)), ok = emqx_rule_registry:add_rules( @@ -719,93 +356,6 @@ t_get_rules_with_same_event(_Config) -> ok = emqx_rule_registry:remove_rules([<<"r1">>, <<"r2">>,<<"r3">>, <<"r4">>,<<"r5">>, <<"r6">>, <<"r7">>, <<"r8">>, <<"r9">>, <<"r10">>]), ok. -t_add_get_remove_action(_Config) -> - ActionName0 = 'action-debug-0', - Action0 = make_simple_action(ActionName0), - ok = emqx_rule_registry:add_action(Action0), - ?assertMatch({ok, #action{name = ActionName0}}, emqx_rule_registry:find_action(ActionName0)), - ok = emqx_rule_registry:remove_action(ActionName0), - ?assertMatch(not_found, emqx_rule_registry:find_action(ActionName0)), - - ok = emqx_rule_registry:add_action(Action0), - ?assertMatch({ok, #action{name = ActionName0}}, emqx_rule_registry:find_action(ActionName0)), - ok = emqx_rule_registry:remove_action(Action0), - ?assertMatch(not_found, emqx_rule_registry:find_action(ActionName0)), - ok. - -t_add_get_remove_actions(_Config) -> - InitActionLen = length(emqx_rule_registry:get_actions()), - ActionName1 = 'action-debug-1', - ActionName2 = 'action-debug-2', - Action1 = make_simple_action(ActionName1), - Action2 = make_simple_action(ActionName2), - ok = emqx_rule_registry:add_actions([Action1, Action2]), - ?assertMatch(2, length(emqx_rule_registry:get_actions()) - InitActionLen), - ok = emqx_rule_registry:remove_actions([ActionName1, ActionName2]), - ?assertMatch(InitActionLen, length(emqx_rule_registry:get_actions())), - - ok = emqx_rule_registry:add_actions([Action1, Action2]), - ?assertMatch(2, length(emqx_rule_registry:get_actions()) - InitActionLen), - ok = emqx_rule_registry:remove_actions([Action1, Action2]), - ?assertMatch(InitActionLen, length(emqx_rule_registry:get_actions())), - ok. - -t_remove_actions_of(_Config) -> - ok = emqx_rule_registry:add_actions([make_simple_action('action-debug-1'), - make_simple_action('action-debug-2')]), - Len1 = length(emqx_rule_registry:get_actions()), - ?assert(Len1 >= 2), - ok = emqx_rule_registry:remove_actions_of(?APP), - ?assert((Len1 - length(emqx_rule_registry:get_actions())) >= 2), - ok. - -t_add_get_remove_resource(_Config) -> - ResId = <<"resource-debug">>, - Res = make_simple_resource(ResId), - ok = emqx_rule_registry:add_resource(Res), - ?assertMatch({ok, #resource{id = ResId}}, emqx_rule_registry:find_resource(ResId)), - ok = emqx_rule_registry:remove_resource(ResId), - ?assertEqual(not_found, emqx_rule_registry:find_resource(ResId)), - ok = emqx_rule_registry:add_resource(Res), - ?assertMatch({ok, #resource{id = ResId}}, emqx_rule_registry:find_resource(ResId)), - ok = emqx_rule_registry:remove_resource(Res), - ?assertEqual(not_found, emqx_rule_registry:find_resource(ResId)), - ok. -t_get_resources(_Config) -> - Len0 = length(emqx_rule_registry:get_resources()), - Res1 = make_simple_resource(<<"resource-debug-1">>), - Res2 = make_simple_resource(<<"resource-debug-2">>), - ok = emqx_rule_registry:add_resource(Res1), - ok = emqx_rule_registry:add_resource(Res2), - ?assertEqual(Len0+2, length(emqx_rule_registry:get_resources())), - ok. - -t_resource_types(_Config) -> - register_resource_types(), - get_resource_type(), - get_resource_types(), - unregister_resource_types_of(). - -register_resource_types() -> - ResType1 = make_simple_resource_type(<<"resource-type-debug-1">>), - ResType2 = make_simple_resource_type(<<"resource-type-debug-2">>), - emqx_rule_registry:register_resource_types([ResType1,ResType2]), - ok. -get_resource_type() -> - ?assertMatch({ok, #resource_type{name = <<"resource-type-debug-1">>}}, emqx_rule_registry:find_resource_type(<<"resource-type-debug-1">>)), - ok. -get_resource_types() -> - ResTypes = emqx_rule_registry:get_resource_types(), - ct:pal("resource types now: ~p", [ResTypes]), - ?assert(length(ResTypes) > 0), - ok. -unregister_resource_types_of() -> - NumOld = length(emqx_rule_registry:get_resource_types()), - ok = emqx_rule_registry:unregister_resource_types_of(?APP), - NumNow = length(emqx_rule_registry:get_resource_types()), - ?assert((NumOld - NumNow) >= 2), - ok. - %%------------------------------------------------------------------------------ %% Test cases for rule runtime %%------------------------------------------------------------------------------ @@ -876,37 +426,13 @@ message_acked(_Client) -> verify_event('message.acked'), ok. -t_mfa_action(_Config) -> - ok = emqx_rule_registry:add_action( - #action{name = 'mfa-action', app = ?APP, - module = ?MODULE, on_create = mfa_action, - types=[], params_spec = #{}, - title = #{en => <<"MFA callback action">>}, - description = #{en => <<"MFA callback action">>}}), - SQL = "SELECT * FROM \"t1\"", - {ok, #rule{id = Id}} = emqx_rule_engine:create_rule( - #{id => <<"rule:t_mfa_action">>, - rawsql => SQL, - actions => [#{id => <<"action:mfa-test">>, name => 'mfa-action', args => #{}}], - description => <<"Debug rule">>}), - {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), - {ok, _} = emqtt:connect(Client), - emqtt:publish(Client, <<"t1">>, <<"{\"id\": 1, \"name\": \"ha\"}">>, 0), - emqtt:stop(Client), - ct:sleep(500), - ?assertEqual(1, persistent_term:get(<<"action:mfa-test">>, 0)), - emqx_rule_registry:remove_rule(Id), - emqx_rule_registry:remove_action('mfa-action'), - ok. - t_match_atom_and_binary(_Config) -> - ok = emqx_rule_engine:load_providers(), - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT connected_at as ts, * " - "FROM \"$events/client_connected\" " - "WHERE username = 'emqx2' ", - <<"user:${ts}">>), + SQL = "SELECT connected_at as ts, *, republish('t2', 'user:' + ts, 0) " + "FROM \"$events/client_connected\" " + "WHERE username = 'emqx2' ", + {ok, TopicRule} = emqx_rule_engine:create_rule( + #{sql => SQL, id => ?TMP_RULEID, + outputs => []}), {ok, Client} = emqtt:start_link([{username, <<"emqx1">>}]), {ok, _} = emqtt:connect(Client), {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), @@ -931,32 +457,32 @@ t_sqlselect_0(_Config) -> "where payload.cmd.info = 'tt'", ?assertMatch({ok,#{payload := <<"{\"cmd\": {\"info\":\"tt\"}}">>}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql, + context => + #{payload => <<"{\"cmd\": {\"info\":\"tt\"}}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), Sql2 = "select payload.cmd as cmd " "from \"t/#\" " "where cmd.info = 'tt'", ?assertMatch({ok,#{<<"cmd">> := #{<<"info">> := <<"tt">>}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql2, + context => + #{payload => <<"{\"cmd\": {\"info\":\"tt\"}}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), Sql3 = "select payload.cmd as cmd, cmd.info as info " "from \"t/#\" " "where cmd.info = 'tt' and info = 'tt'", ?assertMatch({ok,#{<<"cmd">> := #{<<"info">> := <<"tt">>}, <<"info">> := <<"tt">>}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql3, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql3, + context => + #{payload => <<"{\"cmd\": {\"info\":\"tt\"}}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), %% cascaded as Sql4 = "select payload.cmd as cmd, cmd.info as meta.info " "from \"t/#\" " @@ -964,11 +490,11 @@ t_sqlselect_0(_Config) -> ?assertMatch({ok,#{<<"cmd">> := #{<<"info">> := <<"tt">>}, <<"meta">> := #{<<"info">> := <<"tt">>}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql4, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql4, + context => + #{payload => <<"{\"cmd\": {\"info\":\"tt\"}}">>, - <<"topic">> => <<"t/a">>}})). + topic => <<"t/a">>}})). t_sqlselect_00(_Config) -> %% Verify plus/subtract and unary_add_or_subtract @@ -976,42 +502,42 @@ t_sqlselect_00(_Config) -> "from \"t/#\" ", ?assertMatch({ok,#{<<"a">> := 0}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => + #{payload => <<"">>, + topic => <<"t/a">>}})), Sql1 = "select -1 + 1 as a " "from \"t/#\" ", ?assertMatch({ok,#{<<"a">> := 0}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql1, - <<"ctx">> => - #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql1, + context => + #{payload => <<"">>, + topic => <<"t/a">>}})), Sql2 = "select 1 + 1 as a " "from \"t/#\" ", ?assertMatch({ok,#{<<"a">> := 2}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => - #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql2, + context => + #{payload => <<"">>, + topic => <<"t/a">>}})), Sql3 = "select +1 as a " "from \"t/#\" ", ?assertMatch({ok,#{<<"a">> := 1}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql3, - <<"ctx">> => - #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql3, + context => + #{payload => <<"">>, + topic => <<"t/a">>}})). t_sqlselect_01(_Config) -> - ok = emqx_rule_engine:load_providers(), - TopicRule1 = create_simple_repub_rule( - <<"t2">>, - "SELECT json_decode(payload) as p, payload " - "FROM \"t3/#\", \"t1\" " - "WHERE p.x = 1"), + SQL = "SELECT json_decode(payload) as p, payload, republish('t2', payload, 0) " + "FROM \"t3/#\", \"t1\" " + "WHERE p.x = 1", + {ok, TopicRule1} = emqx_rule_engine:create_rule( + #{sql => SQL, id => ?TMP_RULEID, + outputs => []}), {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), {ok, _} = emqtt:connect(Client), {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), @@ -1043,12 +569,12 @@ t_sqlselect_01(_Config) -> emqx_rule_registry:remove_rule(TopicRule1). t_sqlselect_02(_Config) -> - ok = emqx_rule_engine:load_providers(), - TopicRule1 = create_simple_repub_rule( - <<"t2">>, - "SELECT * " - "FROM \"t3/#\", \"t1\" " - "WHERE payload.x = 1"), + SQL = "SELECT *, republish('t2', payload, 0) " + "FROM \"t3/#\", \"t1\" " + "WHERE payload.x = 1", + {ok, TopicRule1} = emqx_rule_engine:create_rule( + #{sql => SQL, id => ?TMP_RULEID, + outputs => []}), {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), {ok, _} = emqtt:connect(Client), {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), @@ -1080,12 +606,12 @@ t_sqlselect_02(_Config) -> emqx_rule_registry:remove_rule(TopicRule1). t_sqlselect_1(_Config) -> - ok = emqx_rule_engine:load_providers(), - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT json_decode(payload) as p, payload " - "FROM \"t1\" " - "WHERE p.x = 1 and p.y = 2"), + SQL = "SELECT json_decode(payload) as p, payload, republish('t2', payload, 0) " + "FROM \"t1\" " + "WHERE p.x = 1 and p.y = 2", + {ok, TopicRule} = emqx_rule_engine:create_rule( + #{sql => SQL, id => ?TMP_RULEID, + outputs => []}), {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), {ok, _} = emqtt:connect(Client), {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), @@ -1109,12 +635,12 @@ t_sqlselect_1(_Config) -> emqx_rule_registry:remove_rule(TopicRule). t_sqlselect_2(_Config) -> - ok = emqx_rule_engine:load_providers(), %% recursively republish to t2 - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT * " - "FROM \"t2\" "), + SQL = "SELECT *, republish('t2', payload, 0) " + "FROM \"t2\" ", + {ok, TopicRule} = emqx_rule_engine:create_rule( + #{sql => SQL, id => ?TMP_RULEID, + outputs => []}), {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), {ok, _} = emqtt:connect(Client), {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), @@ -1134,91 +660,14 @@ t_sqlselect_2(_Config) -> emqtt:stop(Client), emqx_rule_registry:remove_rule(TopicRule). -t_sqlselect_2_1(_Config) -> - ok = emqx_rule_engine:load_providers(), - %% recursively republish to t2, if the msg dropped - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT * " - "FROM \"$events/message_dropped\" "), - {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), - {ok, _} = emqtt:connect(Client), - emqtt:publish(Client, <<"t2">>, <<"{\"x\":1,\"y\":144}">>, 0), - Fun = fun() -> - receive {publish, #{topic := <<"t2">>, payload := _}} -> - received_t2 - after 500 -> - received_nothing - end - end, - received_nothing = Fun(), - - %% it should not keep republishing "t2" - {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), - received_nothing = Fun(), - - emqtt:stop(Client), - emqx_rule_registry:remove_rule(TopicRule). - -t_sqlselect_2_2(_Config) -> - ok = emqx_rule_engine:load_providers(), - %% recursively republish to t2, if the msg acked - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT * " - "FROM \"$events/message_acked\" "), - {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), - {ok, _} = emqtt:connect(Client), - {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 1), - emqtt:publish(Client, <<"t2">>, <<"{\"x\":1,\"y\":144}">>, 1), - Fun = fun() -> - receive {publish, #{topic := <<"t2">>, payload := _}} -> - received_t2 - after 500 -> - received_nothing - end - end, - received_t2 = Fun(), - received_t2 = Fun(), - received_nothing = Fun(), - - emqtt:stop(Client), - emqx_rule_registry:remove_rule(TopicRule). - -t_sqlselect_2_3(_Config) -> - ok = emqx_rule_engine:load_providers(), - %% recursively republish to t2, if the msg delivered - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT * " - "FROM \"$events/message_delivered\" "), - {ok, Client} = emqtt:start_link([{username, <<"emqx">>}]), - {ok, _} = emqtt:connect(Client), - {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), - emqtt:publish(Client, <<"t2">>, <<"{\"x\":1,\"y\":144}">>, 0), - Fun = fun() -> - receive {publish, #{topic := <<"t2">>, payload := _}} -> - received_t2 - after 500 -> - received_nothing - end - end, - received_t2 = Fun(), - received_t2 = Fun(), - received_nothing = Fun(), - - emqtt:stop(Client), - emqx_rule_registry:remove_rule(TopicRule). - t_sqlselect_3(_Config) -> - ok = emqx_rule_engine:load_providers(), %% republish the client.connected msg - TopicRule = create_simple_repub_rule( - <<"t2">>, - "SELECT * " + SQL = "SELECT *, republish('t2', 'clientid=' + clientid, 0) " "FROM \"$events/client_connected\" " "WHERE username = 'emqx1'", - <<"clientid=${clientid}">>), + {ok, TopicRule} = emqx_rule_engine:create_rule( + #{sql => SQL, id => ?TMP_RULEID, + outputs => []}), {ok, Client} = emqtt:start_link([{clientid, <<"emqx0">>}, {username, <<"emqx0">>}]), {ok, _} = emqtt:connect(Client), {ok, _, _} = emqtt:subscribe(Client, <<"t2">>, 0), @@ -1242,226 +691,29 @@ t_sqlselect_3(_Config) -> emqtt:stop(Client), emqx_rule_registry:remove_rule(TopicRule). -t_sqlselect_multi_actoins_1(Config) -> - %% We create 2 actions in the same rule: - %% The first will fail and we need to make sure the - %% second one can still execute as the on_action_failed - %% defaults to 'continue' - {ok, Rule} = emqx_rule_engine:create_rule( - #{rawsql => ?config(connsql, Config), - actions => [ - #{name => 'crash_action', args => #{}, fallbacks => []}, - #{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"clientid=${clientid}">> - }, - fallbacks => []} - ] - }), - - (?config(conn_event, Config))(), - receive {publish, #{topic := T, payload := Payload}} -> - ?assertEqual(<<"t2">>, T), - ?assertEqual(<<"clientid=c_emqx1">>, Payload) - after 1000 -> - ct:fail(wait_for_t2) - end, - - emqx_rule_registry:remove_rule(Rule). - -t_sqlselect_multi_actoins_1_1(Config) -> - %% Try again but set on_action_failed = 'continue' explicitly - {ok, Rule2} = emqx_rule_engine:create_rule( - #{rawsql => ?config(connsql, Config), - on_action_failed => 'continue', - actions => [ - #{name => 'crash_action', args => #{}, fallbacks => []}, - #{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"clientid=${clientid}">> - }, - fallbacks => []} - ] - }), - - (?config(conn_event, Config))(), - receive {publish, #{topic := T2, payload := Payload2}} -> - ?assertEqual(<<"t2">>, T2), - ?assertEqual(<<"clientid=c_emqx1">>, Payload2) - after 1000 -> - ct:fail(wait_for_t2) - end, - - emqx_rule_registry:remove_rule(Rule2). - -t_sqlselect_multi_actoins_2(Config) -> - %% We create 2 actions in the same rule: - %% The first will fail and we need to make sure the - %% second one cannot execute as we've set the on_action_failed = 'stop' - {ok, Rule} = emqx_rule_engine:create_rule( - #{rawsql => ?config(connsql, Config), - on_action_failed => stop, - actions => [ - #{name => 'crash_action', args => #{}, fallbacks => []}, - #{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"clientid=${clientid}">> - }, - fallbacks => []} - ] - }), - - (?config(conn_event, Config))(), - receive {publish, #{topic := <<"t2">>}} -> - ct:fail(unexpected_t2) - after 1000 -> - ok - end, - - emqx_rule_registry:remove_rule(Rule). - -t_sqlselect_multi_actoins_3(Config) -> - %% We create 2 actions in the same rule (on_action_failed = continue): - %% The first will fail and we need to make sure the - %% fallback actions can be executed, and the next actoins - %% will be run without influence - {ok, Rule} = emqx_rule_engine:create_rule( - #{rawsql => ?config(connsql, Config), - on_action_failed => continue, - actions => [ - #{name => 'crash_action', args => #{}, fallbacks =>[ - #{name => 'plus_by_one', args => #{}, fallbacks =>[]}, - #{name => 'plus_by_one', args => #{}, fallbacks =>[]} - ]}, - #{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"clientid=${clientid}">> - }, - fallbacks => []} - ] - }), - - (?config(conn_event, Config))(), - timer:sleep(100), - - %% verfiy the fallback actions has been run - ?assertEqual(2, ets:lookup_element(plus_by_one_action, num, 2)), - - %% verfiy the next actions can be run - receive {publish, #{topic := T, payload := Payload}} -> - ?assertEqual(<<"t2">>, T), - ?assertEqual(<<"clientid=c_emqx1">>, Payload) - after 1000 -> - ct:fail(wait_for_t2) - end, - - emqx_rule_registry:remove_rule(Rule). - -t_sqlselect_multi_actoins_3_1(Config) -> - %% We create 2 actions in the same rule (on_action_failed = continue): - %% The first will fail (with a 'badact' return) and we need to make sure the - %% fallback actions can be executed, and the next actoins - %% will be run without influence - {ok, Rule} = emqx_rule_engine:create_rule( - #{rawsql => ?config(connsql, Config), - on_action_failed => continue, - actions => [ - #{name => 'failure_action', args => #{}, fallbacks =>[ - #{name => 'plus_by_one', args => #{}, fallbacks =>[]}, - #{name => 'plus_by_one', args => #{}, fallbacks =>[]} - ]}, - #{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"clientid=${clientid}">> - }, - fallbacks => []} - ] - }), - - (?config(conn_event, Config))(), - timer:sleep(100), - - %% verfiy the fallback actions has been run - ?assertEqual(2, ets:lookup_element(plus_by_one_action, num, 2)), - - %% verfiy the next actions can be run - receive {publish, #{topic := T, payload := Payload}} -> - ?assertEqual(<<"t2">>, T), - ?assertEqual(<<"clientid=c_emqx1">>, Payload) - after 1000 -> - ct:fail(wait_for_t2) - end, - - emqx_rule_registry:remove_rule(Rule). - -t_sqlselect_multi_actoins_4(Config) -> - %% We create 2 actions in the same rule (on_action_failed = continue): - %% The first will fail and we need to make sure the - %% fallback actions can be executed, and the next actoins - %% will be run without influence - {ok, Rule} = emqx_rule_engine:create_rule( - #{rawsql => ?config(connsql, Config), - on_action_failed => continue, - actions => [ - #{name => 'crash_action', args => #{}, fallbacks => [ - #{name =>'plus_by_one', args => #{}, fallbacks =>[]}, - #{name =>'crash_action', args => #{}, fallbacks =>[]}, - #{name =>'plus_by_one', args => #{}, fallbacks =>[]} - ]}, - #{name => 'republish', - args => #{<<"target_topic">> => <<"t2">>, - <<"target_qos">> => -1, - <<"payload_tmpl">> => <<"clientid=${clientid}">> - }, - fallbacks => []} - ] - }), - - (?config(conn_event, Config))(), - timer:sleep(100), - - %% verfiy all the fallback actions were run, even if the second - %% fallback action crashed - ?assertEqual(2, ets:lookup_element(plus_by_one_action, num, 2)), - - %% verfiy the next actions can be run - receive {publish, #{topic := T, payload := Payload}} -> - ?assertEqual(<<"t2">>, T), - ?assertEqual(<<"clientid=c_emqx1">>, Payload) - after 1000 -> - ct:fail(wait_for_t2) - end, - - emqx_rule_registry:remove_rule(Rule). - t_sqlparse_event_1(_Config) -> Sql = "select topic as tp " "from \"$events/session_subscribed\" ", ?assertMatch({ok,#{<<"tp">> := <<"t/tt">>}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"topic">> => <<"t/tt">>}})). + #{sql => Sql, + context => #{topic => <<"t/tt">>}})). t_sqlparse_event_2(_Config) -> Sql = "select clientid " "from \"$events/client_connected\" ", ?assertMatch({ok,#{<<"clientid">> := <<"abc">>}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"clientid">> => <<"abc">>}})). + #{sql => Sql, + context => #{clientid => <<"abc">>}})). t_sqlparse_event_3(_Config) -> Sql = "select clientid, topic as tp " "from \"t/tt\", \"$events/client_connected\" ", ?assertMatch({ok,#{<<"clientid">> := <<"abc">>, <<"tp">> := <<"t/tt">>}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"clientid">> => <<"abc">>, <<"topic">> => <<"t/tt">>}})). + #{sql => Sql, + context => #{clientid => <<"abc">>, topic => <<"t/tt">>}})). t_sqlparse_foreach_1(_Config) -> %% Verify foreach with and without 'AS' @@ -1469,34 +721,35 @@ t_sqlparse_foreach_1(_Config) -> "from \"t/#\" ", ?assertMatch({ok,[#{<<"s">> := 1}, #{<<"s">> := 2}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"sensors\": [1, 2]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"sensors\": [1, 2]}">>, + topic => <<"t/a">>}})), Sql2 = "foreach payload.sensors " "from \"t/#\" ", ?assertMatch({ok,[#{item := 1}, #{item := 2}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => #{<<"payload">> => <<"{\"sensors\": [1, 2]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql2, + context => #{payload => <<"{\"sensors\": [1, 2]}">>, + topic => <<"t/a">>}})), Sql3 = "foreach payload.sensors " "from \"t/#\" ", ?assertMatch({ok,[#{item := #{<<"cmd">> := <<"1">>}, clientid := <<"c_a">>}, #{item := #{<<"cmd">> := <<"2">>, <<"name">> := <<"ct">>}, clientid := <<"c_a">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql3, - <<"ctx">> => #{ - <<"payload">> => <<"{\"sensors\": [{\"cmd\":\"1\"}, {\"cmd\":\"2\",\"name\":\"ct\"}]}">>, <<"clientid">> => <<"c_a">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql3, + context => #{ + payload => <<"{\"sensors\": [{\"cmd\":\"1\"}, {\"cmd\":\"2\",\"name\":\"ct\"}]}">>, + clientid => <<"c_a">>, + topic => <<"t/a">>}})), Sql4 = "foreach payload.sensors " "from \"t/#\" ", {ok,[#{metadata := #{rule_id := TRuleId}}, #{metadata := #{rule_id := TRuleId}}]} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql4, - <<"ctx">> => #{ - <<"payload">> => <<"{\"sensors\": [1, 2]}">>, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql4, + context => #{ + payload => <<"{\"sensors\": [1, 2]}">>, + topic => <<"t/a">>}}), ?assert(is_binary(TRuleId)). t_sqlparse_foreach_2(_Config) -> @@ -1506,31 +759,31 @@ t_sqlparse_foreach_2(_Config) -> "from \"t/#\" ", ?assertMatch({ok,[#{<<"msg_type">> := <<"1">>},#{<<"msg_type">> := <<"2">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": [{\"cmd\":\"1\"}, {\"cmd\":\"2\"}]}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), Sql2 = "foreach payload.sensors " "do item.cmd as msg_type " "from \"t/#\" ", ?assertMatch({ok,[#{<<"msg_type">> := <<"1">>},#{<<"msg_type">> := <<"2">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql2, + context => + #{payload => <<"{\"sensors\": [{\"cmd\":\"1\"}, {\"cmd\":\"2\"}]}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), Sql3 = "foreach payload.sensors " "do item as item " "from \"t/#\" ", ?assertMatch({ok,[#{<<"item">> := 1},#{<<"item">> := 2}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql3, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql3, + context => + #{payload => <<"{\"sensors\": [1, 2]}">>, - <<"topic">> => <<"t/a">>}})). + topic => <<"t/a">>}})). t_sqlparse_foreach_3(_Config) -> %% Verify foreach-incase with and without 'AS' @@ -1541,11 +794,11 @@ t_sqlparse_foreach_3(_Config) -> #{<<"s">> := #{<<"cmd">> := 3}} ]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": [{\"cmd\":1}, {\"cmd\":2}, {\"cmd\":3}]}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), Sql2 = "foreach payload.sensors " "incase item.cmd != 1 " "from \"t/#\" ", @@ -1553,11 +806,11 @@ t_sqlparse_foreach_3(_Config) -> #{item := #{<<"cmd">> := 3}} ]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql2, + context => + #{payload => <<"{\"sensors\": [{\"cmd\":1}, {\"cmd\":2}, {\"cmd\":3}]}">>, - <<"topic">> => <<"t/a">>}})). + topic => <<"t/a">>}})). t_sqlparse_foreach_4(_Config) -> %% Verify foreach-do-incase @@ -1567,24 +820,24 @@ t_sqlparse_foreach_4(_Config) -> "from \"t/#\" ", ?assertMatch({ok,[#{<<"msg_type">> := <<"1">>},#{<<"msg_type">> := <<"2">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": [{\"cmd\":\"1\"}, {\"cmd\":\"2\"}]}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), ?assertMatch({ok,[#{<<"msg_type">> := <<"1">>, <<"name">> := <<"n1">>}, #{<<"msg_type">> := <<"2">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": [{\"cmd\":\"1\", \"name\":\"n1\"}, {\"cmd\":\"2\"}, {\"name\":\"n3\"}]}">>, - <<"topic">> => <<"t/a">>}})), + topic => <<"t/a">>}})), ?assertMatch({ok,[]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => <<"{\"sensors\": [1, 2]}">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": [1, 2]}">>, + topic => <<"t/a">>}})). t_sqlparse_foreach_5(_Config) -> %% Verify foreach on a empty-list or non-list variable @@ -1592,23 +845,23 @@ t_sqlparse_foreach_5(_Config) -> "do s.cmd as msg_type, s.name as name " "from \"t/#\" ", ?assertMatch({ok,[]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => <<"{\"sensors\": 1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": 1}">>, + topic => <<"t/a">>}})), ?assertMatch({ok,[]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => <<"{\"sensors\": []}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => + #{payload => <<"{\"sensors\": []}">>, + topic => <<"t/a">>}})), Sql2 = "foreach payload.sensors " "from \"t/#\" ", ?assertMatch({ok,[]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => - #{<<"payload">> => <<"{\"sensors\": 1}">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql2, + context => + #{payload => <<"{\"sensors\": 1}">>, + topic => <<"t/a">>}})). t_sqlparse_foreach_6(_Config) -> %% Verify foreach on a empty-list or non-list variable @@ -1616,10 +869,10 @@ t_sqlparse_foreach_6(_Config) -> "do item.id as zid, timestamp as t " "from \"t/#\" ", {ok, Res} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => <<"[{\"id\": 5},{\"id\": 15}]">>, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql, + context => + #{payload => <<"[{\"id\": 5},{\"id\": 15}]">>, + topic => <<"t/a">>}}), [#{<<"t">> := Ts1, <<"zid">> := Zid1}, #{<<"t">> := Ts2, <<"zid">> := Zid2}] = Res, ?assertEqual(true, is_integer(Ts1)), @@ -1637,10 +890,10 @@ t_sqlparse_foreach_7(_Config) -> Payload = <<"{\"sensors\": {\"page\": 2, \"collection\": {\"info\":[{\"name\":\"cmd1\", \"cmd\":\"1\"}, {\"cmd\":\"2\"}]} } }">>, ?assertMatch({ok,[#{<<"name">> := <<"cmd1">>, <<"msg_type">> := <<"1">>}, #{<<"msg_type">> := <<"2">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => Payload, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => + #{payload => Payload, + topic => <<"t/a">>}})), Sql2 = "foreach json_decode(payload) as p, p.sensors as s, s.collection as c, c.info as info " "do info.cmd as msg_type, info.name as name " "incase is_not_null(info.cmd) " @@ -1648,10 +901,10 @@ t_sqlparse_foreach_7(_Config) -> "where s.page = '3' ", ?assertMatch({error, nomatch}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => - #{<<"payload">> => Payload, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql2, + context => + #{payload => Payload, + topic => <<"t/a">>}})). t_sqlparse_foreach_8(_Config) -> %% Verify foreach-do-incase and cascaded AS @@ -1663,10 +916,10 @@ t_sqlparse_foreach_8(_Config) -> Payload = <<"{\"sensors\": {\"page\": 2, \"collection\": {\"info\":[\"haha\", {\"name\":\"cmd1\", \"cmd\":\"1\"}]} } }">>, ?assertMatch({ok,[#{<<"name">> := <<"cmd1">>, <<"msg_type">> := <<"1">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => - #{<<"payload">> => Payload, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => + #{payload => Payload, + topic => <<"t/a">>}})), Sql3 = "foreach json_decode(payload) as p, p.sensors as s, s.collection as c, sublist(2,1,c.info) as info " "do info.cmd as msg_type, info.name as name " @@ -1674,10 +927,10 @@ t_sqlparse_foreach_8(_Config) -> "where s.page = '2' ", [?assertMatch({ok,[#{<<"name">> := <<"cmd1">>, <<"msg_type">> := <<"1">>}]}, emqx_rule_sqltester:test( - #{<<"rawsql">> => SqlN, - <<"ctx">> => - #{<<"payload">> => Payload, - <<"topic">> => <<"t/a">>}})) + #{sql => SqlN, + context => + #{payload => Payload, + topic => <<"t/a">>}})) || SqlN <- [Sql3]]. t_sqlparse_case_when_1(_Config) -> @@ -1689,25 +942,25 @@ t_sqlparse_case_when_1(_Config) -> " end as y " "from \"t/#\" ", ?assertMatch({ok, #{<<"y">> := 1}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 1}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 0}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 0}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 0}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 0}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": -1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": -1}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 7}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 7}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 7}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 7}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 8}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 8}">>, + topic => <<"t/a">>}})), ok. t_sqlparse_case_when_2(_Config) -> @@ -1719,25 +972,25 @@ t_sqlparse_case_when_2(_Config) -> " end as y " "from \"t/#\" ", ?assertMatch({ok, #{<<"y">> := 2}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 1}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 3}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 2}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 2}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 4}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 4}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 4}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 4}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 7}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 7}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 4}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 8}">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql, + context => #{payload => <<"{\"x\": 8}">>, + topic => <<"t/a">>}})). t_sqlparse_case_when_3(_Config) -> %% case-when clause @@ -1747,29 +1000,29 @@ t_sqlparse_case_when_3(_Config) -> " end as y " "from \"t/#\" ", ?assertMatch({ok, #{}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 1}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 5}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 5}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 0}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 0}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 0}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": -1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": -1}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 7}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 7}">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{<<"y">> := 7}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 8}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 8}">>, + topic => <<"t/a">>}})), ok. t_sqlparse_array_index_1(_Config) -> @@ -1779,38 +1032,38 @@ t_sqlparse_array_index_1(_Config) -> " p[1] as a " "from \"t/#\" ", ?assertMatch({ok, #{<<"a">> := #{<<"x">> := 1}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"[{\"x\": 1}]">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"[{\"x\": 1}]">>, + topic => <<"t/a">>}})), ?assertMatch({ok, #{}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": 1}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql, + context => #{payload => <<"{\"x\": 1}">>, + topic => <<"t/a">>}})), %% index get without 'as' Sql2 = "select " " payload.x[2] " "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := #{<<"x">> := [3]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => #{<<"payload">> => #{<<"x">> => [1,3,4]}, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql2, + context => #{payload => #{<<"x">> => [1,3,4]}, + topic => <<"t/a">>}})), %% index get without 'as' again Sql3 = "select " " payload.x[2].y " "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := #{<<"x">> := [#{<<"y">> := 3}]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql3, - <<"ctx">> => #{<<"payload">> => #{<<"x">> => [1,#{y => 3},4]}, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql3, + context => #{payload => #{<<"x">> => [1,#{y => 3},4]}, + topic => <<"t/a">>}})), %% index get with 'as' Sql4 = "select " " payload.x[2].y as b " "from \"t/#\" ", ?assertMatch({ok, #{<<"b">> := 3}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql4, - <<"ctx">> => #{<<"payload">> => #{<<"x">> => [1,#{y => 3},4]}, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql4, + context => #{payload => #{<<"x">> => [1,#{y => 3},4]}, + topic => <<"t/a">>}})). t_sqlparse_array_index_2(_Config) -> %% array get with negative index @@ -1818,9 +1071,9 @@ t_sqlparse_array_index_2(_Config) -> " payload.x[-2].y as b " "from \"t/#\" ", ?assertMatch({ok, #{<<"b">> := 3}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql1, - <<"ctx">> => #{<<"payload">> => #{<<"x">> => [1,#{y => 3},4]}, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql1, + context => #{payload => #{<<"x">> => [1,#{y => 3},4]}, + topic => <<"t/a">>}})), %% array append to head or tail of a list: Sql2 = "select " " payload.x as b, " @@ -1829,9 +1082,9 @@ t_sqlparse_array_index_2(_Config) -> " b as c[0] " "from \"t/#\" ", ?assertMatch({ok, #{<<"b">> := 0, <<"c">> := [0,1,2]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => #{<<"payload">> => #{<<"x">> => 0}, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql2, + context => #{payload => #{<<"x">> => 0}, + topic => <<"t/a">>}})), %% construct an empty list: Sql3 = "select " " [] as c, " @@ -1840,9 +1093,9 @@ t_sqlparse_array_index_2(_Config) -> " 0 as c[0] " "from \"t/#\" ", ?assertMatch({ok, #{<<"c">> := [0,1,2]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql3, - <<"ctx">> => #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql3, + context => #{payload => <<"">>, + topic => <<"t/a">>}})), %% construct a list: Sql4 = "select " " [payload.a, \"topic\", 'c'] as c, " @@ -1851,9 +1104,9 @@ t_sqlparse_array_index_2(_Config) -> " 0 as c[0] " "from \"t/#\" ", ?assertMatch({ok, #{<<"c">> := [0,11,<<"t/a">>,<<"c">>,1,2]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql4, - <<"ctx">> => #{<<"payload">> => <<"{\"a\":11}">>, - <<"topic">> => <<"t/a">> + #{sql => Sql4, + context => #{payload => <<"{\"a\":11}">>, + topic => <<"t/a">> }})). t_sqlparse_array_index_3(_Config) -> @@ -1864,25 +1117,25 @@ t_sqlparse_array_index_3(_Config) -> "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := #{<<"x">> := [1, #{<<"y">> := [1,2]}, 3]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql0, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql0, + context => #{payload => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, + topic => <<"t/a">>}})), %% same as above but don't select payload: Sql1 = "select " "payload.x[2].y as b " "from \"t/#\" ", ?assertMatch({ok, #{<<"b">> := [1,2]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql1, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql1, + context => #{payload => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, + topic => <<"t/a">>}})), %% same as above but add 'as' clause: Sql2 = "select " "payload.x[2].y as b.c " "from \"t/#\" ", ?assertMatch({ok, #{<<"b">> := #{<<"c">> := [1,2]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql2, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql2, + context => #{payload => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, + topic => <<"t/a">>}})). t_sqlparse_array_index_4(_Config) -> %% array with json string payload: @@ -1891,9 +1144,9 @@ t_sqlparse_array_index_4(_Config) -> "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := #{<<"x">> := [#{<<"y">> := 0}]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql0, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql0, + context => #{payload => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, + topic => <<"t/a">>}})), %% array with json string payload, and also select payload.x: Sql1 = "select " "payload.x, " @@ -1901,9 +1154,9 @@ t_sqlparse_array_index_4(_Config) -> "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := #{<<"x">> := [1, #{<<"y">> := 0}, 3]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql1, - <<"ctx">> => #{<<"payload">> => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql1, + context => #{payload => <<"{\"x\": [1,{\"y\": [1,2]},3]}">>, + topic => <<"t/a">>}})). t_sqlparse_array_index_5(_Config) -> Sql00 = "select " @@ -1911,9 +1164,9 @@ t_sqlparse_array_index_5(_Config) -> "from \"t/#\" ", {ok, Res00} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql00, - <<"ctx">> => #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql00, + context => #{payload => <<"">>, + topic => <<"t/a">>}}), ?assert(lists:any(fun({_K, V}) -> V =:= [1,2,3,4] end, maps:to_list(Res00))). @@ -1925,17 +1178,17 @@ t_sqlparse_select_matadata_1(_Config) -> "from \"t/#\" ", ?assertNotMatch({ok, #{<<"payload">> := <<"abc">>, metadata := _}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql0, - <<"ctx">> => #{<<"payload">> => <<"abc">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql0, + context => #{payload => <<"abc">>, + topic => <<"t/a">>}})), Sql1 = "select " "payload, metadata " "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := <<"abc">>, <<"metadata">> := _}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql1, - <<"ctx">> => #{<<"payload">> => <<"abc">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql1, + context => #{payload => <<"abc">>, + topic => <<"t/a">>}})). t_sqlparse_array_range_1(_Config) -> %% get a range of list @@ -1943,19 +1196,19 @@ t_sqlparse_array_range_1(_Config) -> " payload.a[1..4] as c " "from \"t/#\" ", ?assertMatch({ok, #{<<"c">> := [0,1,2,3]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql0, - <<"ctx">> => #{<<"payload">> => <<"{\"a\":[0,1,2,3,4,5]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql0, + context => #{payload => <<"{\"a\":[0,1,2,3,4,5]}">>, + topic => <<"t/a">>}})), %% get a range from non-list data Sql02 = "select " " payload.a[1..4] as c " "from \"t/#\" ", ?assertThrow({select_and_transform_error, {error,{range_get,non_list_data},_}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql02, - <<"ctx">> => - #{<<"payload">> => <<"{\"x\":[0,1,2,3,4,5]}">>, - <<"topic">> => <<"t/a">>}})), + #{sql => Sql02, + context => + #{payload => <<"{\"x\":[0,1,2,3,4,5]}">>, + topic => <<"t/a">>}})), %% construct a range: Sql1 = "select " " [1..4] as c, " @@ -1964,9 +1217,9 @@ t_sqlparse_array_range_1(_Config) -> " 0 as c[0] " "from \"t/#\" ", ?assertMatch({ok, #{<<"c">> := [0,1,2,3,4,5,6]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql1, - <<"ctx">> => #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql1, + context => #{payload => <<"">>, + topic => <<"t/a">>}})). t_sqlparse_array_range_2(_Config) -> %% construct a range without 'as' @@ -1975,9 +1228,9 @@ t_sqlparse_array_range_2(_Config) -> "from \"t/#\" ", {ok, Res00} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql00, - <<"ctx">> => #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql00, + context => #{payload => <<"">>, + topic => <<"t/a">>}}), ?assert(lists:any(fun({_K, V}) -> V =:= [1,2,3,4] end, maps:to_list(Res00))), @@ -1987,17 +1240,17 @@ t_sqlparse_array_range_2(_Config) -> "from \"t/#\" ", ?assertMatch({ok, #{<<"a">> := [2,3,4]}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql01, - <<"ctx">> => #{<<"a">> => [1,2,3,4,5], - <<"topic">> => <<"t/a">>}})), + #{sql => Sql01, + context => #{<<"a">> => [1,2,3,4,5], + topic => <<"t/a">>}})), %% get a range of list without 'as' Sql02 = "select " " payload.a[1..4] " "from \"t/#\" ", ?assertMatch({ok, #{<<"payload">> := #{<<"a">> := [0,1,2,3]}}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql02, - <<"ctx">> => #{<<"payload">> => <<"{\"a\":[0,1,2,3,4,5]}">>, - <<"topic">> => <<"t/a">>}})). + #{sql => Sql02, + context => #{payload => <<"{\"a\":[0,1,2,3,4,5]}">>, + topic => <<"t/a">>}})). t_sqlparse_true_false(_Config) -> %% construct a range without 'as' @@ -2007,9 +1260,9 @@ t_sqlparse_true_false(_Config) -> "from \"t/#\" ", {ok, Res00} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql00, - <<"ctx">> => #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql00, + context => #{payload => <<"">>, + topic => <<"t/a">>}}), ?assertMatch(#{<<"a">> := true, <<"b">> := false, <<"x">> := #{<<"y">> := false}, <<"c">> := [true] @@ -2023,9 +1276,9 @@ t_sqlparse_new_map(_Config) -> "from \"t/#\" ", {ok, Res00} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql00, - <<"ctx">> => #{<<"payload">> => <<"">>, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql00, + context => #{payload => <<"">>, + topic => <<"t/a">>}}), ?assertMatch(#{<<"a">> := #{}, <<"b">> := #{}, <<"x">> := #{<<"y">> := #{}}, <<"c">> := [#{}] @@ -2039,9 +1292,9 @@ t_sqlparse_payload_as(_Config) -> "FROM \"t/#\" ", Payload1 = <<"{ \"msgId\": 1002, \"params\": { \"convertTemp\": 20, \"engineSpeed\": 42, \"hydOilTem\": 30 } }">>, {ok, Res01} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql00, - <<"ctx">> => #{<<"payload">> => Payload1, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql00, + context => #{payload => Payload1, + topic => <<"t/a">>}}), ?assertMatch(#{ <<"payload">> := #{ <<"params">> := #{ @@ -2055,9 +1308,9 @@ t_sqlparse_payload_as(_Config) -> Payload2 = <<"{ \"msgId\": 1002, \"params\": { \"convertTemp\": 20, \"engineSpeed\": 42 } }">>, {ok, Res02} = emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql00, - <<"ctx">> => #{<<"payload">> => Payload2, - <<"topic">> => <<"t/a">>}}), + #{sql => Sql00, + context => #{payload => Payload2, + topic => <<"t/a">>}}), ?assertMatch(#{ <<"payload">> := #{ <<"params">> := #{ @@ -2074,139 +1327,47 @@ t_sqlparse_nested_get(_Config) -> "from \"t/#\" ", ?assertMatch({ok,#{<<"c">> := 0}}, emqx_rule_sqltester:test( - #{<<"rawsql">> => Sql, - <<"ctx">> => #{ - <<"topic">> => <<"t/1">>, - <<"payload">> => <<"{\"a\": {\"b\": 0}}">> + #{sql => Sql, + context => #{ + topic => <<"t/1">>, + payload => <<"{\"a\": {\"b\": 0}}">> }})). %%------------------------------------------------------------------------------ %% Internal helpers %%------------------------------------------------------------------------------ -make_simple_rule(RuleId) when is_binary(RuleId) -> - #rule{id = RuleId, - rawsql = <<"select * from \"simple/topic\"">>, - for = [<<"simple/topic">>], - fields = [<<"*">>], - is_foreach = false, - conditions = {}, - actions = [{'inspect', #{}}], - description = <<"simple rule">>}. - make_simple_rule_with_ts(RuleId, Ts) when is_binary(RuleId) -> - #rule{id = RuleId, - rawsql = <<"select * from \"simple/topic\"">>, - for = [<<"simple/topic">>], - fields = [<<"*">>], - is_foreach = false, - conditions = {}, - actions = [{'inspect', #{}}], - created_at = Ts, - description = <<"simple rule">>}. + SQL = <<"select * from \"simple/topic\"">>, + Topics = [<<"simple/topic">>], + make_simple_rule(RuleId, SQL, Topics, Ts). -make_simple_rule(RuleId, SQL, ForTopics) when is_binary(RuleId) -> - #rule{id = RuleId, - rawsql = SQL, - for = ForTopics, - fields = [<<"*">>], - is_foreach = false, - conditions = {}, - actions = [{'inspect', #{}}], - description = <<"simple rule">>}. +make_simple_rule(RuleId) when is_binary(RuleId) -> + SQL = <<"select * from \"simple/topic\"">>, + Topics = [<<"simple/topic">>], + make_simple_rule(RuleId, SQL, Topics). -create_simple_repub_rule(TargetTopic, SQL) -> - create_simple_repub_rule(TargetTopic, SQL, <<"${payload}">>). +make_simple_rule(RuleId, SQL, Topics) when is_binary(RuleId) -> + make_simple_rule(RuleId, SQL, Topics, erlang:system_time(millisecond)). -create_simple_repub_rule(TargetTopic, SQL, Template) -> - {ok, Rule} = emqx_rule_engine:create_rule( - #{rawsql => SQL, - actions => [#{name => 'republish', - args => #{<<"target_topic">> => TargetTopic, - <<"target_qos">> => -1, - <<"payload_tmpl">> => Template} - }], - description => <<"simple repub rule">>}), - Rule. +make_simple_rule(RuleId, SQL, Topics, Ts) when is_binary(RuleId) -> + #rule{ + id = RuleId, + info = #{ + sql => SQL, + from => Topics, + fields => [<<"*">>], + is_foreach => false, + conditions => {}, + ouputs => [console], + description => <<"simple rule">> + }, + created_at = Ts + }. -make_simple_action(ActionName) when is_atom(ActionName) -> - #action{name = ActionName, app = ?APP, - module = ?MODULE, on_create = simple_action_inspect, params_spec = #{}, - title = #{en => <<"Simple inspect action">>}, - description = #{en => <<"Simple inspect action">>}}. -make_simple_action(ActionName, Hook) when is_atom(ActionName) -> - #action{name = ActionName, app = ?APP, for = Hook, - module = ?MODULE, on_create = simple_action_inspect, params_spec = #{}, - title = #{en => <<"Simple inspect action">>}, - description = #{en => <<"Simple inspect action with hook">>}}. - -simple_action_inspect(Params) -> - fun(Data) -> - io:format("Action InputData: ~p, Action InitParams: ~p~n", [Data, Params]) - end. - -make_simple_resource(ResId) -> - #resource{id = ResId, - type = simple_resource_type, - config = #{}, - description = <<"Simple Resource">>}. - -make_simple_resource_type(ResTypeName) -> - #resource_type{name = ResTypeName, provider = ?APP, - params_spec = #{}, - on_create = {?MODULE, on_simple_resource_type_create}, - on_destroy = {?MODULE, on_simple_resource_type_destroy}, - on_status = {?MODULE, on_simple_resource_type_status}, - title = #{en => <<"Simple Resource Type">>}, - description = #{en => <<"Simple Resource Type">>}}. - -on_simple_resource_type_create(_Id, #{}) -> #{}. -on_simple_resource_type_destroy(_Id, #{}) -> ok. -on_simple_resource_type_status(_Id, #{}, #{}) -> #{is_alive => true}. - -hook_metrics_action(_Id, _Params) -> - fun(Data = #{event := EventName}, _Envs) -> - ct:pal("applying hook_metrics_action: ~p", [Data]), - ets:insert(events_record_tab, {EventName, Data}) - end. - -mfa_action(Id, _Params) -> - persistent_term:put(Id, 0), - {?MODULE, mfa_action_do, [Id]}. - -mfa_action_do(_Data, _Envs, K) -> - persistent_term:put(K, 1). - -failure_action(_Id, _Params) -> - fun(Data, _Envs) -> - ct:pal("applying crash action, Data: ~p", [Data]), - {badact, intentional_failure} - end. - -crash_action(_Id, _Params) -> - fun(Data, _Envs) -> - ct:pal("applying crash action, Data: ~p", [Data]), - error(crash) - end. - -simple_action_2_create(_Id, _Params) -> - ets:insert(simple_action_2, {created, erlang:timestamp()}), - fun(_Data, _Envs) -> ok end. - -simple_action_2_destroy(_Id, _Params) -> - ets:insert(simple_action_2, {destroyed, erlang:timestamp()}), - fun(_Data, _Envs) -> ok end. - -init_plus_by_one_action() -> - ets:new(plus_by_one_action, [named_table, set, public]), - ets:insert(plus_by_one_action, {num, 0}). - -plus_by_one_action(_Id, #{}) -> - fun(Data, _Envs) -> - ct:pal("applying plus_by_one_action, Data: ~p", [Data]), - Num = ets:lookup_element(plus_by_one_action, num, 2), - ets:insert(plus_by_one_action, {num, Num + 1}) - end. +output_record_triggered_events(Data = #{event := EventName}, _Envs) -> + ct:pal("applying output_record_triggered_events: ~p", [Data]), + ets:insert(events_record_tab, {EventName, Data}). verify_event(EventName) -> ct:sleep(50), @@ -2471,74 +1632,3 @@ deps_path(App, RelativePath) -> local_path(RelativePath) -> deps_path(emqx_rule_engine, RelativePath). -set_special_configs(emqx_rule_engine) -> - application:set_env(emqx_rule_engine, ignore_sys_message, true), - application:set_env(emqx_rule_engine, events, - [{'client.connected',on,1}, - {'client.disconnected',on,1}, - {'session.subscribed',on,1}, - {'session.unsubscribed',on,1}, - {'message.acked',on,1}, - {'message.dropped',on,1}, - {'message.delivered',on,1} - ]), - ok; -set_special_configs(_App) -> - ok. - -mock_print() -> - catch meck:unload(emqx_ctl), - meck:new(emqx_ctl, [non_strict, passthrough]), - meck:expect(emqx_ctl, print, fun(Arg) -> emqx_ctl:format(Arg) end), - meck:expect(emqx_ctl, print, fun(Msg, Arg) -> emqx_ctl:format(Msg, Arg) end), - meck:expect(emqx_ctl, usage, fun(Usages) -> emqx_ctl:format_usage(Usages) end), - meck:expect(emqx_ctl, usage, fun(Cmd, Descr) -> emqx_ctl:format_usage(Cmd, Descr) end). - -unmock_print() -> - meck:unload(emqx_ctl). - -t_load_providers(_) -> - error('TODO'). - -t_unload_providers(_) -> - error('TODO'). - -t_delete_rule(_) -> - error('TODO'). - -t_start_resource(_) -> - error('TODO'). - -t_test_resource(_) -> - error('TODO'). - -t_get_resource_status(_) -> - error('TODO'). - -t_get_resource_params(_) -> - error('TODO'). - -t_delete_resource(_) -> - error('TODO'). - -t_refresh_resources(_) -> - error('TODO'). - -t_refresh_rules(_) -> - error('TODO'). - -t_refresh_resource_status(_) -> - error('TODO'). - -t_init_resource(_) -> - error('TODO'). - -t_init_action(_) -> - error('TODO'). - -t_clear_resource(_) -> - error('TODO'). - -t_clear_action(_) -> - error('TODO'). - diff --git a/apps/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl deleted file mode 100644 index 2273d886d..000000000 --- a/apps/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl +++ /dev/null @@ -1,148 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_rule_registry_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_testcase(_TestCase, Config) -> - Config. - -end_per_testcase(_TestCase, Config) -> - Config. - -% t_mnesia(_) -> -% error('TODO'). - -% t_dump(_) -> -% error('TODO'). - -% t_start_link(_) -> -% error('TODO'). - -% t_get_rules_for_topic(_) -> -% error('TODO'). - -% t_add_rules(_) -> -% error('TODO'). - -% t_remove_rules(_) -> -% error('TODO'). - -% t_add_action(_) -> -% error('TODO'). - -% t_remove_action(_) -> -% error('TODO'). - -% t_remove_actions(_) -> -% error('TODO'). - -% t_init(_) -> -% error('TODO'). - -% t_handle_call(_) -> -% error('TODO'). - -% t_handle_cast(_) -> -% error('TODO'). - -% t_handle_info(_) -> -% error('TODO'). - -% t_terminate(_) -> -% error('TODO'). - -% t_code_change(_) -> -% error('TODO'). - -% t_get_resource_types(_) -> -% error('TODO'). - -% t_get_resources_by_type(_) -> -% error('TODO'). - -% t_get_actions_for(_) -> -% error('TODO'). - -% t_get_actions(_) -> -% error('TODO'). - -% t_get_action_instance_params(_) -> -% error('TODO'). - -% t_remove_action_instance_params(_) -> -% error('TODO'). - -% t_remove_resource_params(_) -> -% error('TODO'). - -% t_add_action_instance_params(_) -> -% error('TODO'). - -% t_add_resource_params(_) -> -% error('TODO'). - -% t_find_action(_) -> -% error('TODO'). - -% t_get_rules(_) -> -% error('TODO'). - -% t_get_resources(_) -> -% error('TODO'). - -% t_remove_resource(_) -> -% error('TODO'). - -% t_find_resource_params(_) -> -% error('TODO'). - -% t_add_resource(_) -> -% error('TODO'). - -% t_find_resource_type(_) -> -% error('TODO'). - -% t_remove_rule(_) -> -% error('TODO'). - -% t_add_rule(_) -> -% error('TODO'). - -% t_register_resource_types(_) -> -% error('TODO'). - -% t_add_actions(_) -> -% error('TODO'). - -% t_unregister_resource_types_of(_) -> -% error('TODO'). - -% t_remove_actions_of(_) -> -% error('TODO'). - -% t_get_rule(_) -> -% error('TODO'). - -% t_find_resource(_) -> -% error('TODO'). -