From 3705f4f9293194dc40e1f5b7ffacc2af01875bf3 Mon Sep 17 00:00:00 2001 From: Feng Lee Date: Thu, 19 Sep 2019 11:04:29 +0800 Subject: [PATCH] Rewrite the test cases for extended modules --- src/emqx_mod_rewrite.erl | 33 +++--- test/emqx_mod_rewrite_SUITE.erl | 50 --------- test/emqx_mod_subscription_SUITE.erl | 52 ---------- test/emqx_modules_SUITE.erl | 148 +++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 118 deletions(-) delete mode 100644 test/emqx_mod_rewrite_SUITE.erl delete mode 100644 test/emqx_mod_subscription_SUITE.erl create mode 100644 test/emqx_modules_SUITE.erl diff --git a/src/emqx_mod_rewrite.erl b/src/emqx_mod_rewrite.erl index 7630831a9..0d32e9aee 100644 --- a/src/emqx_mod_rewrite.erl +++ b/src/emqx_mod_rewrite.erl @@ -22,8 +22,9 @@ -include_lib("emqx_mqtt.hrl"). -ifdef(TEST). --compile(export_all). --compile(nowarn_export_all). +-export([ compile/1 + , match_and_rewrite/2 + ]). -endif. %% APIs @@ -48,13 +49,13 @@ load(RawRules) -> emqx_hooks:add('message.publish', {?MODULE, rewrite_publish, [Rules]}). rewrite_subscribe(_ClientInfo, _Properties, TopicFilters, Rules) -> - {ok, [{match_rule(Topic, Rules), Opts} || {Topic, Opts} <- TopicFilters]}. + {ok, [{match_and_rewrite(Topic, Rules), Opts} || {Topic, Opts} <- TopicFilters]}. rewrite_unsubscribe(_ClientInfo, _Properties, TopicFilters, Rules) -> - {ok, [{match_rule(Topic, Rules), Opts} || {Topic, Opts} <- TopicFilters]}. + {ok, [{match_and_rewrite(Topic, Rules), Opts} || {Topic, Opts} <- TopicFilters]}. rewrite_publish(Message = #message{topic = Topic}, Rules) -> - {ok, Message#message{topic = match_rule(Topic, Rules)}}. + {ok, Message#message{topic = match_and_rewrite(Topic, Rules)}}. unload(_) -> emqx_hooks:del('client.subscribe', {?MODULE, rewrite_subscribe}), @@ -65,16 +66,22 @@ unload(_) -> %% Internal functions %%-------------------------------------------------------------------- -match_rule(Topic, []) -> +compile(Rules) -> + lists:map(fun({rewrite, Topic, Re, Dest}) -> + {ok, MP} = re:compile(Re), + {rewrite, Topic, MP, Dest} + end, Rules). + +match_and_rewrite(Topic, []) -> Topic; -match_rule(Topic, [{rewrite, Filter, MP, Dest} | Rules]) -> +match_and_rewrite(Topic, [{rewrite, Filter, MP, Dest} | Rules]) -> case emqx_topic:match(Topic, Filter) of - true -> match_regx(Topic, MP, Dest); - false -> match_rule(Topic, Rules) + true -> rewrite(Topic, MP, Dest); + false -> match_and_rewrite(Topic, Rules) end. -match_regx(Topic, MP, Dest) -> +rewrite(Topic, MP, Dest) -> case re:run(Topic, MP, [{capture, all_but_first, list}]) of {match, Captured} -> Vars = lists:zip(["\\$" ++ integer_to_list(I) @@ -86,9 +93,3 @@ match_regx(Topic, MP, Dest) -> nomatch -> Topic end. -compile(Rules) -> - lists:map(fun({rewrite, Topic, Re, Dest}) -> - {ok, MP} = re:compile(Re), - {rewrite, Topic, MP, Dest} - end, Rules). - diff --git a/test/emqx_mod_rewrite_SUITE.erl b/test/emqx_mod_rewrite_SUITE.erl deleted file mode 100644 index 158d93235..000000000 --- a/test/emqx_mod_rewrite_SUITE.erl +++ /dev/null @@ -1,50 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2019 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_mod_rewrite_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - --define(rules, [{rewrite,<<"x/#">>,<<"^x/y/(.+)$">>,<<"z/y/$1">>}, - {rewrite,<<"y/+/z/#">>,<<"^y/(.+)/z/(.+)$">>,<<"y/z/$2">>}]). - -all() -> emqx_ct:all(?MODULE). - -t_rewrite_rule(_Config) -> - {ok, _} = emqx_hooks:start_link(), - ok = emqx_mod_rewrite:load(?rules), - RawTopicFilters = [{<<"x/y/2">>, opts}, - {<<"x/1/2">>, opts}, - {<<"y/a/z/b">>, opts}, - {<<"y/def">>, opts}], - SubTopicFilters = emqx_hooks:run_fold('client.subscribe', [client, properties], RawTopicFilters), - UnSubTopicFilters = emqx_hooks:run_fold('client.unsubscribe', [client, properties], RawTopicFilters), - Messages = [emqx_hooks:run_fold('message.publish', [], emqx_message:make(Topic, <<"payload">>)) - || {Topic, _Opts} <- RawTopicFilters], - ExpectedTopicFilters = [{<<"z/y/2">>, opts}, - {<<"x/1/2">>, opts}, - {<<"y/z/b">>, opts}, - {<<"y/def">>, opts}], - ?assertEqual(ExpectedTopicFilters, SubTopicFilters), - ?assertEqual(ExpectedTopicFilters, UnSubTopicFilters), - [?assertEqual(ExpectedTopic, emqx_message:topic(Message)) - || {{ExpectedTopic, _opts}, Message} <- lists:zip(ExpectedTopicFilters, Messages)], - ok = emqx_mod_rewrite:unload(?rules), - ok = emqx_hooks:stop(). diff --git a/test/emqx_mod_subscription_SUITE.erl b/test/emqx_mod_subscription_SUITE.erl deleted file mode 100644 index 0c9c9c678..000000000 --- a/test/emqx_mod_subscription_SUITE.erl +++ /dev/null @@ -1,52 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2019 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_mod_subscription_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include("emqx.hrl"). - --include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules(all), - emqx_ct_helpers:start_apps([emqx]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([emqx]). - -t_mod_subscription(_) -> - emqx_mod_subscription:load([{<<"connected/%c/%u">>, ?QOS_0}]), - {ok, C} = emqtt:start_link([{host, "localhost"}, {client_id, "myclient"}, {username, "admin"}]), - {ok, _} = emqtt:connect(C), - % ct:sleep(100), - emqtt:publish(C, <<"connected/myclient/admin">>, <<"Hello world">>, ?QOS_0), - receive - {publish, #{topic := Topic, payload := Payload}} -> - ?assertEqual(<<"connected/myclient/admin">>, Topic), - ?assertEqual(<<"Hello world">>, Payload) - after 100 -> - ct:fail("no_message") - end, - ok = emqtt:disconnect(C), - emqx_mod_subscription:unload([]). diff --git a/test/emqx_modules_SUITE.erl b/test/emqx_modules_SUITE.erl new file mode 100644 index 000000000..3ebbb6c06 --- /dev/null +++ b/test/emqx_modules_SUITE.erl @@ -0,0 +1,148 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2019 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_modules_SUITE). + +%% API +-compile(export_all). +-compile(nowarn_export_all). + +-include("emqx.hrl"). +-include("emqx_mqtt.hrl"). + +%%-include_lib("proper/include/proper.hrl"). +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +%%-define(PROPTEST(M,F), true = proper:quickcheck(M:F())). + +-define(RULES, [{rewrite,<<"x/#">>,<<"^x/y/(.+)$">>,<<"z/y/$1">>}, + {rewrite,<<"y/+/z/#">>,<<"^y/(.+)/z/(.+)$">>,<<"y/z/$2">>} + ]). + +all() -> emqx_ct:all(?MODULE). + +suite() -> + [{ct_hooks,[cth_surefire]}, {timetrap, {seconds, 30}}]. + +init_per_suite(Config) -> + emqx_ct_helpers:boot_modules(all), + emqx_ct_helpers:start_apps([emqx]), + %% Ensure all the modules unloaded. + ok = emqx_modules:unload(), + Config. + +end_per_suite(_Config) -> + emqx_ct_helpers:stop_apps([emqx]). + +%%-------------------------------------------------------------------- +%% Test cases +%%-------------------------------------------------------------------- + +%% Test case for emqx_mod_presence +t_mod_presence(_) -> + ok = emqx_mod_presence:load([{qos, ?QOS_1}]), + {ok, C1} = emqtt:start_link([{client_id, <<"monsys">>}]), + {ok, _} = emqtt:connect(C1), + {ok, _Props, [?QOS_1]} = emqtt:subscribe(C1, <<"$SYS/brokers/+/clients/#">>, qos1), + %% Connected Presence + {ok, C2} = emqtt:start_link([{client_id, <<"clientid">>}, + {username, <<"username">>}]), + {ok, _} = emqtt:connect(C2), + ok = recv_and_check_presence(<<"clientid">>, <<"connected">>), + %% Disconnected Presence + ok = emqtt:disconnect(C2), + ok = recv_and_check_presence(<<"clientid">>, <<"disconnected">>), + ok = emqtt:disconnect(C1), + ok = emqx_mod_presence:unload([{qos, ?QOS_1}]). + +recv_and_check_presence(ClientId, Presence) -> + {ok, #{qos := ?QOS_1, topic := Topic, payload := Payload}} = receive_publish(100), + ?assertMatch([<<"$SYS">>, <<"brokers">>, _Node, <<"clients">>, ClientId, Presence], + binary:split(Topic, <<"/">>, [global])), + case Presence of + <<"connected">> -> + ?assertMatch(#{clientid := <<"clientid">>, + username := <<"username">>, + ipaddress := <<"127.0.0.1">>, + proto_name := <<"MQTT">>, + proto_ver := ?MQTT_PROTO_V4, + connack := ?RC_SUCCESS, + clean_start := true}, emqx_json:decode(Payload, [{labels, atom}, return_maps])); + <<"disconnected">> -> + ?assertMatch(#{clientid := <<"clientid">>, + username := <<"username">>, + reason := <<"normal">>}, emqx_json:decode(Payload, [{labels, atom}, return_maps])) + end. + +%% Test case for emqx_mod_subscription +t_mod_subscription(_) -> + emqx_mod_subscription:load([{<<"connected/%c/%u">>, ?QOS_0}]), + {ok, C} = emqtt:start_link([{host, "localhost"}, + {client_id, "myclient"}, + {username, "admin"}]), + {ok, _} = emqtt:connect(C), + emqtt:publish(C, <<"connected/myclient/admin">>, <<"Hello world">>, ?QOS_0), + {ok, #{topic := Topic, payload := Payload}} = receive_publish(100), + ?assertEqual(<<"connected/myclient/admin">>, Topic), + ?assertEqual(<<"Hello world">>, Payload), + ok = emqtt:disconnect(C), + emqx_mod_subscription:unload([]). + +%% Test case for emqx_mod_write +t_mod_rewrite(_Config) -> + ok = emqx_mod_rewrite:load(?RULES), + {ok, C} = emqtt:start_link([{client_id, <<"rewrite_client">>}]), + {ok, _} = emqtt:connect(C), + OrigTopics = [<<"x/y/2">>, <<"x/1/2">>, <<"y/a/z/b">>, <<"y/def">>], + DestTopics = [<<"z/y/2">>, <<"x/1/2">>, <<"y/z/b">>, <<"y/def">>], + %% Subscribe + {ok, _Props, _} = emqtt:subscribe(C, [{Topic, ?QOS_1} || Topic <- OrigTopics]), + timer:sleep(100), + Subscriptions = emqx_broker:subscriptions(<<"rewrite_client">>), + ?assertEqual(DestTopics, [Topic || {Topic, _SubOpts} <- Subscriptions]), + %% Publish + RecvTopics = [begin + ok = emqtt:publish(C, Topic, <<"payload">>), + {ok, #{topic := RecvTopic}} = receive_publish(100), + RecvTopic + end || Topic <- OrigTopics], + ?assertEqual(DestTopics, RecvTopics), + %% Unsubscribe + {ok, _, _} = emqtt:unsubscribe(C, OrigTopics), + timer:sleep(100), + ?assertEqual([], emqx_broker:subscriptions(<<"rewrite_client">>)), + ok = emqtt:disconnect(C), + ok = emqx_mod_rewrite:unload(?RULES). + +t_rewrite_rule(_Config) -> + Rules = emqx_mod_rewrite:compile(?RULES), + ?assertEqual(<<"z/y/2">>, emqx_mod_rewrite:match_and_rewrite(<<"x/y/2">>, Rules)), + ?assertEqual(<<"x/1/2">>, emqx_mod_rewrite:match_and_rewrite(<<"x/1/2">>, Rules)), + ?assertEqual(<<"y/z/b">>, emqx_mod_rewrite:match_and_rewrite(<<"y/a/z/b">>, Rules)), + ?assertEqual(<<"y/def">>, emqx_mod_rewrite:match_and_rewrite(<<"y/def">>, Rules)). + +%%-------------------------------------------------------------------- +%% Internal functions +%%-------------------------------------------------------------------- + +receive_publish(Timeout) -> + receive + {publish, Publish} -> {ok, Publish} + after + Timeout -> {error, timeout} + end. +