diff --git a/rebar.config b/rebar.config index 798d812a9..ac1cc106f 100644 --- a/rebar.config +++ b/rebar.config @@ -31,8 +31,8 @@ [{deps, [{meck, "0.8.13"}, % hex {bbmustache, "1.7.0"}, % hex - {emqx_ct_helpers, "1.1.3"}, % hex - {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "v1.0.1"}}} + {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "v1.0.1"}}}, + {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {branch, "develop"}}} ]} ]} ]}. diff --git a/src/emqx_banned.erl b/src/emqx_banned.erl index c38552bd7..ba3743385 100644 --- a/src/emqx_banned.erl +++ b/src/emqx_banned.erl @@ -32,9 +32,10 @@ -export([start_link/0]). --export([ add/1 +-export([ check/1 + , add/1 , delete/1 - , check/1 + , info/1 ]). %% gen_server callbacks @@ -81,7 +82,11 @@ add(Banned) when is_record(Banned, banned) -> -spec(delete({client_id, emqx_types:client_id()} | {username, emqx_types:username()} | {peername, emqx_types:peername()}) -> ok). -delete(Key) -> mnesia:dirty_delete(?BANNED_TAB, Key). +delete(Key) -> + mnesia:dirty_delete(?BANNED_TAB, Key). + +info(InfoKey) -> + mnesia:table_info(?BANNED_TAB, InfoKey). %%-------------------------------------------------------------------- %% gen_server callbacks diff --git a/src/emqx_inflight.erl b/src/emqx_inflight.erl index 1bf70f4c8..a51abdc68 100644 --- a/src/emqx_inflight.erl +++ b/src/emqx_inflight.erl @@ -16,8 +16,11 @@ -module(emqx_inflight). +-compile(inline). + %% APIs --export([ new/1 +-export([ new/0 + , new/1 , contain/2 , lookup/2 , insert/3 @@ -45,9 +48,8 @@ -define(Inflight(MaxSize, Tree), {inflight, MaxSize, (Tree)}). -%%-------------------------------------------------------------------- -%% APIs -%%-------------------------------------------------------------------- +-spec(new() -> inflight()). +new() -> new(0). -spec(new(non_neg_integer()) -> inflight()). new(MaxSize) when MaxSize >= 0 -> diff --git a/src/emqx_json.erl b/src/emqx_json.erl index c9130646f..665e7ad57 100644 --- a/src/emqx_json.erl +++ b/src/emqx_json.erl @@ -16,6 +16,8 @@ -module(emqx_json). +-compile(inline). + -export([ encode/1 , encode/2 , safe_encode/1 @@ -32,7 +34,8 @@ encode(Term) -> jsx:encode(Term). --spec(encode(jsx:json_term(), jsx_to_json:config()) -> jsx:json_text()). +-spec(encode(jsx:json_term(), jsx_to_json:config()) + -> jsx:json_text()). encode(Term, Opts) -> jsx:encode(Term, Opts). @@ -55,7 +58,8 @@ safe_encode(Term, Opts) -> decode(Json) -> jsx:decode(Json). --spec(decode(jsx:json_text(), jsx_to_json:config()) -> jsx:json_term()). +-spec(decode(jsx:json_text(), jsx_to_json:config()) + -> jsx:json_term()). decode(Json, Opts) -> jsx:decode(Json, Opts). diff --git a/src/emqx_mountpoint.erl b/src/emqx_mountpoint.erl index 4b820fdc7..986bbd048 100644 --- a/src/emqx_mountpoint.erl +++ b/src/emqx_mountpoint.erl @@ -17,7 +17,7 @@ -module(emqx_mountpoint). -include("emqx.hrl"). --include("logger.hrl"). +-include("types.hrl"). -export([ mount/2 , unmount/2 @@ -29,41 +29,46 @@ -type(mountpoint() :: binary()). -%%-------------------------------------------------------------------- -%% APIs -%%-------------------------------------------------------------------- - +-spec(mount(maybe(mountpoint()), Any) -> Any + when Any :: emqx_types:topic() + | emqx_types:message() + | emqx_types:topic_filters()). mount(undefined, Any) -> Any; mount(MountPoint, Topic) when is_binary(Topic) -> - <>; + prefix(MountPoint, Topic); mount(MountPoint, Msg = #message{topic = Topic}) -> - Msg#message{topic = <>}; + Msg#message{topic = prefix(MountPoint, Topic)}; mount(MountPoint, TopicFilters) when is_list(TopicFilters) -> - [{<>, SubOpts} - || {Topic, SubOpts} <- TopicFilters]. + [{prefix(MountPoint, Topic), SubOpts} || {Topic, SubOpts} <- TopicFilters]. -unmount(undefined, Msg) -> - Msg; -%% TODO: Fixme later +%% @private +-compile({inline, [prefix/2]}). +prefix(MountPoint, Topic) -> + <>. + +-spec(unmount(maybe(mountpoint()), Any) -> Any + when Any :: emqx_types:topic() + | emqx_types:message()). +unmount(undefined, Any) -> + Any; unmount(MountPoint, Topic) when is_binary(Topic) -> - try split_binary(Topic, byte_size(MountPoint)) of - {MountPoint, Topic1} -> Topic1 - catch - error:badarg-> Topic + case string:prefix(Topic, MountPoint) of + nomatch -> Topic; + Topic1 -> Topic1 end; unmount(MountPoint, Msg = #message{topic = Topic}) -> - try split_binary(Topic, byte_size(MountPoint)) of - {MountPoint, Topic1} -> Msg#message{topic = Topic1} - catch - error:badarg-> - Msg + case string:prefix(Topic, MountPoint) of + nomatch -> Msg; + Topic1 -> Msg#message{topic = Topic1} end. +-spec(replvar(maybe(mountpoint()), map()) -> maybe(mountpoint())). replvar(undefined, _Vars) -> undefined; replvar(MountPoint, #{client_id := ClientId, username := Username}) -> - lists:foldl(fun feed_var/2, MountPoint, [{<<"%c">>, ClientId}, {<<"%u">>, Username}]). + lists:foldl(fun feed_var/2, MountPoint, + [{<<"%c">>, ClientId}, {<<"%u">>, Username}]). feed_var({<<"%c">>, ClientId}, MountPoint) -> emqx_topic:feed_var(<<"%c">>, ClientId, MountPoint); diff --git a/src/emqx_reason_codes.erl b/src/emqx_reason_codes.erl index 327b96018..784552a2d 100644 --- a/src/emqx_reason_codes.erl +++ b/src/emqx_reason_codes.erl @@ -163,5 +163,7 @@ connack_error(banned) -> ?RC_BANNED; connack_error(bad_authentication_method) -> ?RC_BAD_AUTHENTICATION_METHOD; connack_error(_) -> ?RC_NOT_AUTHORIZED. +%%TODO: This function should be removed. puback([]) -> ?RC_NO_MATCHING_SUBSCRIBERS; puback(L) when is_list(L) -> ?RC_SUCCESS. + diff --git a/src/emqx_router.erl b/src/emqx_router.erl index f1c96b190..d0e5bf188 100644 --- a/src/emqx_router.erl +++ b/src/emqx_router.erl @@ -66,16 +66,16 @@ -type(group() :: binary()). --type(destination() :: node() | {group(), node()}). +-type(dest() :: node() | {group(), node()}). --define(ROUTE, emqx_route). +-define(ROUTE_TAB, emqx_route). %%-------------------------------------------------------------------- %% Mnesia bootstrap %%-------------------------------------------------------------------- mnesia(boot) -> - ok = ekka_mnesia:create_table(?ROUTE, [ + ok = ekka_mnesia:create_table(?ROUTE_TAB, [ {type, bag}, {ram_copies, [node()]}, {record_name, route}, @@ -83,7 +83,7 @@ mnesia(boot) -> {storage_properties, [{ets, [{read_concurrency, true}, {write_concurrency, true}]}]}]); mnesia(copy) -> - ok = ekka_mnesia:copy_table(?ROUTE). + ok = ekka_mnesia:copy_table(?ROUTE_TAB). %%-------------------------------------------------------------------- %% Start a router @@ -102,7 +102,7 @@ start_link(Pool, Id) -> add_route(Topic) when is_binary(Topic) -> add_route(Topic, node()). --spec(add_route(emqx_topic:topic(), destination()) -> ok | {error, term()}). +-spec(add_route(emqx_topic:topic(), dest()) -> ok | {error, term()}). add_route(Topic, Dest) when is_binary(Topic) -> call(pick(Topic), {add_route, Topic, Dest}). @@ -110,7 +110,7 @@ add_route(Topic, Dest) when is_binary(Topic) -> do_add_route(Topic) when is_binary(Topic) -> do_add_route(Topic, node()). --spec(do_add_route(emqx_topic:topic(), destination()) -> ok | {error, term()}). +-spec(do_add_route(emqx_topic:topic(), dest()) -> ok | {error, term()}). do_add_route(Topic, Dest) when is_binary(Topic) -> Route = #route{topic = Topic, dest = Dest}, case lists:member(Route, lookup_routes(Topic)) of @@ -142,17 +142,17 @@ match_trie(Topic) -> -spec(lookup_routes(emqx_topic:topic()) -> [emqx_types:route()]). lookup_routes(Topic) -> - ets:lookup(?ROUTE, Topic). + ets:lookup(?ROUTE_TAB, Topic). -spec(has_routes(emqx_topic:topic()) -> boolean()). has_routes(Topic) when is_binary(Topic) -> - ets:member(?ROUTE, Topic). + ets:member(?ROUTE_TAB, Topic). -spec(delete_route(emqx_topic:topic()) -> ok | {error, term()}). delete_route(Topic) when is_binary(Topic) -> delete_route(Topic, node()). --spec(delete_route(emqx_topic:topic(), destination()) -> ok | {error, term()}). +-spec(delete_route(emqx_topic:topic(), dest()) -> ok | {error, term()}). delete_route(Topic, Dest) when is_binary(Topic) -> call(pick(Topic), {delete_route, Topic, Dest}). @@ -160,7 +160,7 @@ delete_route(Topic, Dest) when is_binary(Topic) -> do_delete_route(Topic) when is_binary(Topic) -> do_delete_route(Topic, node()). --spec(do_delete_route(emqx_topic:topic(), destination()) -> ok | {error, term()}). +-spec(do_delete_route(emqx_topic:topic(), dest()) -> ok | {error, term()}). do_delete_route(Topic, Dest) -> Route = #route{topic = Topic, dest = Dest}, case emqx_topic:wildcard(Topic) of @@ -170,7 +170,7 @@ do_delete_route(Topic, Dest) -> -spec(topics() -> list(emqx_topic:topic())). topics() -> - mnesia:dirty_all_keys(?ROUTE). + mnesia:dirty_all_keys(?ROUTE_TAB). %% @doc Print routes to a topic -spec(print_routes(emqx_topic:topic()) -> ok). @@ -224,25 +224,25 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- insert_direct_route(Route) -> - mnesia:async_dirty(fun mnesia:write/3, [?ROUTE, Route, sticky_write]). + mnesia:async_dirty(fun mnesia:write/3, [?ROUTE_TAB, Route, sticky_write]). insert_trie_route(Route = #route{topic = Topic}) -> - case mnesia:wread({?ROUTE, Topic}) of + case mnesia:wread({?ROUTE_TAB, Topic}) of [] -> emqx_trie:insert(Topic); _ -> ok end, - mnesia:write(?ROUTE, Route, sticky_write). + mnesia:write(?ROUTE_TAB, Route, sticky_write). delete_direct_route(Route) -> - mnesia:async_dirty(fun mnesia:delete_object/3, [?ROUTE, Route, sticky_write]). + mnesia:async_dirty(fun mnesia:delete_object/3, [?ROUTE_TAB, Route, sticky_write]). delete_trie_route(Route = #route{topic = Topic}) -> - case mnesia:wread({?ROUTE, Topic}) of + case mnesia:wread({?ROUTE_TAB, Topic}) of [Route] -> %% Remove route and trie - ok = mnesia:delete_object(?ROUTE, Route, sticky_write), + ok = mnesia:delete_object(?ROUTE_TAB, Route, sticky_write), emqx_trie:delete(Topic); [_|_] -> %% Remove route only - mnesia:delete_object(?ROUTE, Route, sticky_write); + mnesia:delete_object(?ROUTE_TAB, Route, sticky_write); [] -> ok end. diff --git a/src/emqx_tables.erl b/src/emqx_tables.erl index 106af13c2..fec1864e0 100644 --- a/src/emqx_tables.erl +++ b/src/emqx_tables.erl @@ -16,12 +16,21 @@ -module(emqx_tables). --export([new/2, delete/1]). +-export([ new/1 + , new/2 + ]). -export([ lookup_value/2 , lookup_value/3 ]). +-export([delete/1]). + +%% Create an ets table. +-spec(new(atom()) -> ok). +new(Tab) -> + new(Tab, []). + %% Create a named_table ets. -spec(new(atom(), list()) -> ok). new(Tab, Opts) -> @@ -32,26 +41,25 @@ new(Tab, Opts) -> Tab -> ok end. --spec(delete(atom()) -> ok). +%% KV lookup +-spec(lookup_value(ets:tab(), term()) -> any()). +lookup_value(Tab, Key) -> + lookup_value(Tab, Key, undefined). + +-spec(lookup_value(ets:tab(), term(), any()) -> any()). +lookup_value(Tab, Key, Def) -> + try ets:lookup_element(Tab, Key, 2) + catch + error:badarg -> Def + end. + +%% Delete the ets table. +-spec(delete(ets:tab()) -> ok). delete(Tab) -> case ets:info(Tab, name) of - undefined -> - ok; + undefined -> ok; Tab -> ets:delete(Tab), ok end. -%% KV lookup --spec(lookup_value(atom(), term()) -> any()). -lookup_value(Tab, Key) -> - lookup_value(Tab, Key, undefined). - --spec(lookup_value(atom(), term(), any()) -> any()). -lookup_value(Tab, Key, Def) -> - try - ets:lookup_element(Tab, Key, 2) - catch - error:badarg -> Def - end. - diff --git a/src/emqx_time.erl b/src/emqx_time.erl index e1c5e8527..16508cdda 100644 --- a/src/emqx_time.erl +++ b/src/emqx_time.erl @@ -21,9 +21,16 @@ , now_secs/1 , now_ms/0 , now_ms/1 - , ts_from_ms/1 ]). +-compile({inline, + [ seed/0 + , now_secs/0 + , now_secs/1 + , now_ms/0 + , now_ms/1 + ]}). + seed() -> rand:seed(exsplus, erlang:timestamp()). @@ -39,6 +46,3 @@ now_ms() -> now_ms({MegaSecs, Secs, MicroSecs}) -> (MegaSecs * 1000000 + Secs) * 1000 + round(MicroSecs/1000). -ts_from_ms(Ms) -> - {Ms div 1000000, Ms rem 1000000, 0}. - diff --git a/src/emqx_topic.erl b/src/emqx_topic.erl index dd187ddf6..680cb299e 100644 --- a/src/emqx_topic.erl +++ b/src/emqx_topic.erl @@ -16,8 +16,6 @@ -module(emqx_topic). --include("emqx_mqtt.hrl"). - %% APIs -export([ match/2 , validate/1 @@ -66,7 +64,7 @@ wildcard(['+'|_]) -> wildcard([_H|T]) -> wildcard(T). -%% @doc Match Topic name with filter +%% @doc Match Topic name with filter. -spec(match(Name, Filter) -> boolean() when Name :: topic() | words(), Filter :: topic() | words()). @@ -74,7 +72,7 @@ match(<<$$, _/binary>>, <<$+, _/binary>>) -> false; match(<<$$, _/binary>>, <<$#, _/binary>>) -> false; -match(Name, Filter) when is_binary(Name) and is_binary(Filter) -> +match(Name, Filter) when is_binary(Name), is_binary(Filter) -> match(words(Name), words(Filter)); match([], []) -> true; @@ -101,13 +99,15 @@ validate({Type, Topic}) when Type =:= name; Type =:= filter -> -spec(validate(name | filter, topic()) -> true). validate(_, <<>>) -> error(empty_topic); -validate(_, Topic) when is_binary(Topic) and (size(Topic) > ?MAX_TOPIC_LEN) -> +validate(_, Topic) when is_binary(Topic) andalso (size(Topic) > ?MAX_TOPIC_LEN) -> error(topic_too_long); validate(filter, Topic) when is_binary(Topic) -> validate2(words(Topic)); validate(name, Topic) when is_binary(Topic) -> Words = words(Topic), - validate2(Words) and (not wildcard(Words)). + validate2(Words) + andalso (not wildcard(Words)) + orelse error(topic_name_error). validate2([]) -> true; @@ -129,7 +129,7 @@ validate3(<>) when C == $#; C == $+; C == 0 -> validate3(<<_/utf8, Rest/binary>>) -> validate3(Rest). -%% @doc Topic to triples +%% @doc Topic to triples. -spec(triples(topic()) -> list(triple())). triples(Topic) when is_binary(Topic) -> triples(words(Topic), root, []). @@ -218,13 +218,14 @@ parse(TopicFilter) when is_binary(TopicFilter) -> parse({TopicFilter, Options}) when is_binary(TopicFilter) -> parse(TopicFilter, Options). +-spec(parse(topic(), map()) -> {topic(), map()}). parse(TopicFilter = <<"$queue/", _/binary>>, #{share := _Group}) -> error({invalid_topic_filter, TopicFilter}); -parse(TopicFilter = <>, #{share := _Group}) -> +parse(TopicFilter = <<"$share/", _/binary>>, #{share := _Group}) -> error({invalid_topic_filter, TopicFilter}); parse(<<"$queue/", TopicFilter/binary>>, Options) -> parse(TopicFilter, Options#{share => <<"$queue">>}); -parse(TopicFilter = <>, Options) -> +parse(TopicFilter = <<"$share/", Rest/binary>>, Options) -> case binary:split(Rest, <<"/">>) of [_Any] -> error({invalid_topic_filter, TopicFilter}); [ShareName, Filter] -> diff --git a/src/emqx_trie.erl b/src/emqx_trie.erl index d437fec9d..c0c037a7c 100644 --- a/src/emqx_trie.erl +++ b/src/emqx_trie.erl @@ -34,8 +34,8 @@ -export([empty/0]). %% Mnesia tables --define(TRIE, emqx_trie). --define(TRIE_NODE, emqx_trie_node). +-define(TRIE_TAB, emqx_trie). +-define(TRIE_NODE_TAB, emqx_trie_node). %%-------------------------------------------------------------------- %% Mnesia bootstrap @@ -48,13 +48,13 @@ mnesia(boot) -> StoreProps = [{ets, [{read_concurrency, true}, {write_concurrency, true}]}], %% Trie table - ok = ekka_mnesia:create_table(?TRIE, [ + ok = ekka_mnesia:create_table(?TRIE_TAB, [ {ram_copies, [node()]}, {record_name, trie}, {attributes, record_info(fields, trie)}, {storage_properties, StoreProps}]), %% Trie node table - ok = ekka_mnesia:create_table(?TRIE_NODE, [ + ok = ekka_mnesia:create_table(?TRIE_NODE_TAB, [ {ram_copies, [node()]}, {record_name, trie_node}, {attributes, record_info(fields, trie_node)}, @@ -62,9 +62,9 @@ mnesia(boot) -> mnesia(copy) -> %% Copy trie table - ok = ekka_mnesia:copy_table(?TRIE), + ok = ekka_mnesia:copy_table(?TRIE_TAB), %% Copy trie_node table - ok = ekka_mnesia:copy_table(?TRIE_NODE). + ok = ekka_mnesia:copy_table(?TRIE_NODE_TAB). %%-------------------------------------------------------------------- %% Trie APIs @@ -73,7 +73,7 @@ mnesia(copy) -> %% @doc Insert a topic filter into the trie. -spec(insert(emqx_topic:topic()) -> ok). insert(Topic) when is_binary(Topic) -> - case mnesia:wread({?TRIE_NODE, Topic}) of + case mnesia:wread({?TRIE_NODE_TAB, Topic}) of [#trie_node{topic = Topic}] -> ok; [TrieNode = #trie_node{topic = undefined}] -> @@ -94,14 +94,14 @@ match(Topic) when is_binary(Topic) -> %% @doc Lookup a trie node. -spec(lookup(NodeId :: binary()) -> [#trie_node{}]). lookup(NodeId) -> - mnesia:read(?TRIE_NODE, NodeId). + mnesia:read(?TRIE_NODE_TAB, NodeId). %% @doc Delete a topic filter from the trie. -spec(delete(emqx_topic:topic()) -> ok). delete(Topic) when is_binary(Topic) -> - case mnesia:wread({?TRIE_NODE, Topic}) of + case mnesia:wread({?TRIE_NODE_TAB, Topic}) of [#trie_node{edge_count = 0}] -> - ok = mnesia:delete({?TRIE_NODE, Topic}), + ok = mnesia:delete({?TRIE_NODE_TAB, Topic}), delete_path(lists:reverse(emqx_topic:triples(Topic))); [TrieNode] -> write_trie_node(TrieNode#trie_node{topic = undefined}); @@ -111,7 +111,7 @@ delete(Topic) when is_binary(Topic) -> %% @doc Is the trie empty? -spec(empty() -> boolean()). empty() -> - ets:info(?TRIE, size) == 0. + ets:info(?TRIE_TAB, size) == 0. %%-------------------------------------------------------------------- %% Internal functions @@ -121,9 +121,9 @@ empty() -> %% @doc Add a path to the trie. add_path({Node, Word, Child}) -> Edge = #trie_edge{node_id = Node, word = Word}, - case mnesia:wread({?TRIE_NODE, Node}) of + case mnesia:wread({?TRIE_NODE_TAB, Node}) of [TrieNode = #trie_node{edge_count = Count}] -> - case mnesia:wread({?TRIE, Edge}) of + case mnesia:wread({?TRIE_TAB, Edge}) of [] -> ok = write_trie_node(TrieNode#trie_node{edge_count = Count + 1}), write_trie(#trie{edge = Edge, node_id = Child}); @@ -143,11 +143,11 @@ match_node(NodeId, Words) -> match_node(NodeId, Words, []). match_node(NodeId, [], ResAcc) -> - mnesia:read(?TRIE_NODE, NodeId) ++ 'match_#'(NodeId, ResAcc); + mnesia:read(?TRIE_NODE_TAB, NodeId) ++ 'match_#'(NodeId, ResAcc); match_node(NodeId, [W|Words], ResAcc) -> lists:foldl(fun(WArg, Acc) -> - case mnesia:read(?TRIE, #trie_edge{node_id = NodeId, word = WArg}) of + case mnesia:read(?TRIE_TAB, #trie_edge{node_id = NodeId, word = WArg}) of [#trie{node_id = ChildId}] -> match_node(ChildId, Words, Acc); [] -> Acc end @@ -156,9 +156,9 @@ match_node(NodeId, [W|Words], ResAcc) -> %% @private %% @doc Match node with '#'. 'match_#'(NodeId, ResAcc) -> - case mnesia:read(?TRIE, #trie_edge{node_id = NodeId, word = '#'}) of + case mnesia:read(?TRIE_TAB, #trie_edge{node_id = NodeId, word = '#'}) of [#trie{node_id = ChildId}] -> - mnesia:read(?TRIE_NODE, ChildId) ++ ResAcc; + mnesia:read(?TRIE_NODE_TAB, ChildId) ++ ResAcc; [] -> ResAcc end. @@ -167,10 +167,10 @@ match_node(NodeId, [W|Words], ResAcc) -> delete_path([]) -> ok; delete_path([{NodeId, Word, _} | RestPath]) -> - ok = mnesia:delete({?TRIE, #trie_edge{node_id = NodeId, word = Word}}), - case mnesia:wread({?TRIE_NODE, NodeId}) of + ok = mnesia:delete({?TRIE_TAB, #trie_edge{node_id = NodeId, word = Word}}), + case mnesia:wread({?TRIE_NODE_TAB, NodeId}) of [#trie_node{edge_count = 1, topic = undefined}] -> - ok = mnesia:delete({?TRIE_NODE, NodeId}), + ok = mnesia:delete({?TRIE_NODE_TAB, NodeId}), delete_path(RestPath); [TrieNode = #trie_node{edge_count = 1, topic = _}] -> write_trie_node(TrieNode#trie_node{edge_count = 0}); @@ -182,9 +182,9 @@ delete_path([{NodeId, Word, _} | RestPath]) -> %% @private write_trie(Trie) -> - mnesia:write(?TRIE, Trie, write). + mnesia:write(?TRIE_TAB, Trie, write). %% @private write_trie_node(TrieNode) -> - mnesia:write(?TRIE_NODE, TrieNode, write). + mnesia:write(?TRIE_NODE_TAB, TrieNode, write). diff --git a/test/emqx_SUITE.erl b/test/emqx_SUITE.erl deleted file mode 100644 index a74e16552..000000000 --- a/test/emqx_SUITE.erl +++ /dev/null @@ -1,206 +0,0 @@ -%% Copyright (c) 2013-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_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --define(APP, emqx). - --include_lib("eunit/include/eunit.hrl"). - --include_lib("common_test/include/ct.hrl"). - --include("emqx_mqtt.hrl"). - --record(ssl_socket, {tcp, ssl}). - - --define(CLIENT, ?CONNECT_PACKET(#mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - username = <<"admin">>, - password = <<"public">>})). - --define(CLIENT2, ?CONNECT_PACKET(#mqtt_packet_connect{ - username = <<"admin">>, - clean_start = false, - password = <<"public">>})). - --define(CLIENT3, ?CONNECT_PACKET(#mqtt_packet_connect{ - username = <<"admin">>, - proto_ver = ?MQTT_PROTO_V5, - clean_start = false, - password = <<"public">>, - will_props = #{'Will-Delay-Interval' => 2}})). - --define(SUBCODE, [0]). - --define(PACKETID, 1). - --define(PUBQOS, 1). - --define(SUBPACKET, ?SUBSCRIBE_PACKET(?PACKETID, [{<<"sub/topic">>, ?DEFAULT_SUBOPTS}])). - --define(PUBPACKET, ?PUBLISH_PACKET(?PUBQOS, <<"sub/topic">>, ?PACKETID, <<"publish">>)). - --define(PAYLOAD, [{type,"dsmSimulationData"}, - {id, 9999}, - {status, "running"}, - {soc, 1536702170}, - {fracsec, 451000}, - {data, lists:seq(1, 20480)}]). - --define(BIG_PUBPACKET, ?PUBLISH_PACKET(?PUBQOS, <<"sub/topic">>, ?PACKETID, emqx_json:encode(?PAYLOAD))). - -all() -> - [{group, connect}, - {group, publish}]. - -groups() -> - [{connect, [non_parallel_tests], - [mqtt_connect, - mqtt_connect_with_tcp, - mqtt_connect_with_will_props, - mqtt_connect_with_ssl_oneway, - mqtt_connect_with_ssl_twoway, - mqtt_connect_with_ws]}, - {publish, [non_parallel_tests], - [packet_size]}]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -%%-------------------------------------------------------------------- -%% Protocol Test -%%-------------------------------------------------------------------- -mqtt_connect(_) -> - %% Issue #599 - %% Empty clientId and clean_session = false - ?assertEqual(<<32,2,0,2>>, connect_broker_(<<16,12,0,4,77,81,84,84,4,0,0,90,0,0>>, 4)), - %% Empty clientId and clean_session = true - ?assertEqual(<<32,2,0,0>>, connect_broker_(<<16,12,0,4,77,81,84,84,4,2,0,90,0,0>>, 4)). - -connect_broker_(Packet, RecvSize) -> - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - emqx_client_sock:send(Sock, Packet), - {ok, Data} = gen_tcp:recv(Sock, RecvSize, 3000), - emqx_client_sock:close(Sock), - Data. - -mqtt_connect_with_tcp(_) -> - %% Issue #599 - %% Empty clientId and clean_session = false - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - Packet = raw_send_serialize(?CLIENT2), - emqx_client_sock:send(Sock, Packet), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?CONNACK_INVALID_ID), <<>>, _} = raw_recv_pase(Data), - emqx_client_sock:close(Sock). - -mqtt_connect_with_will_props(_) -> - %% Issue #599 - %% Empty clientId and clean_session = false - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - Packet = raw_send_serialize(?CLIENT3), - emqx_client_sock:send(Sock, Packet), - emqx_client_sock:close(Sock). - -mqtt_connect_with_ssl_oneway(_) -> - emqx:shutdown(), - emqx_ct_helpers:change_emqx_opts(ssl_oneway), - emqx:start(), - ClientSsl = emqx_ct_helpers:client_ssl(), - {ok, #ssl_socket{tcp = _Sock1, ssl = SslSock} = Sock} - = emqx_client_sock:connect("127.0.0.1", 8883, [{ssl_opts, ClientSsl}], 3000), - Packet = raw_send_serialize(?CLIENT), - emqx_client_sock:setopts(Sock, [{active, once}]), - emqx_client_sock:send(Sock, Packet), - ?assert( - receive {ssl, _, ConAck}-> - {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), <<>>, _} = raw_recv_pase(ConAck), true - after 1000 -> - false - end), - ssl:close(SslSock). - -mqtt_connect_with_ssl_twoway(_Config) -> - emqx:shutdown(), - emqx_ct_helpers:change_emqx_opts(ssl_twoway), - emqx:start(), - ClientSsl = emqx_ct_helpers:client_ssl_twoway(), - {ok, #ssl_socket{tcp = _Sock1, ssl = SslSock} = Sock} - = emqx_client_sock:connect("127.0.0.1", 8883, [{ssl_opts, ClientSsl}], 3000), - Packet = raw_send_serialize(?CLIENT), - emqx_client_sock:setopts(Sock, [{active, once}]), - emqx_client_sock:send(Sock, Packet), - timer:sleep(500), - ?assert( - receive {ssl, _, Data}-> - {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), <<>>, _} = raw_recv_pase(Data), true - after 1000 -> - false - end), - ssl:close(SslSock), - emqx_client_sock:close(Sock). - -mqtt_connect_with_ws(_Config) -> - WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), - {ok, _} = rfc6455_client:open(WS), - - %% Connect Packet - Packet = raw_send_serialize(?CLIENT), - ok = rfc6455_client:send_binary(WS, Packet), - {binary, CONACK} = rfc6455_client:recv(WS), - {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), <<>>, _} = raw_recv_pase(CONACK), - - %% Sub Packet - SubPacket = raw_send_serialize(?SUBPACKET), - rfc6455_client:send_binary(WS, SubPacket), - {binary, SubAck} = rfc6455_client:recv(WS), - {ok, ?SUBACK_PACKET(?PACKETID, ?SUBCODE), <<>>, _} = raw_recv_pase(SubAck), - - %% Pub Packet QoS 1 - PubPacket = raw_send_serialize(?PUBPACKET), - rfc6455_client:send_binary(WS, PubPacket), - {binary, PubAck} = rfc6455_client:recv(WS), - {ok, ?PUBACK_PACKET(?PACKETID), <<>>, _} = raw_recv_pase(PubAck), - {close, _} = rfc6455_client:close(WS), - ok. - -%%issue 1811 -packet_size(_Config) -> - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - Packet = raw_send_serialize(?CLIENT), - emqx_client_sock:send(Sock, Packet), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), <<>>, _} = raw_recv_pase(Data), - - %% Pub Packet QoS 1 - PubPacket = raw_send_serialize(?BIG_PUBPACKET), - emqx_client_sock:send(Sock, PubPacket), - {ok, Data1} = gen_tcp:recv(Sock, 0), - {ok, ?PUBACK_PACKET(?PACKETID), <<>>, _} = raw_recv_pase(Data1), - emqx_client_sock:close(Sock). - -raw_send_serialize(Packet) -> - emqx_frame:serialize(Packet). - -raw_recv_pase(Bin) -> - emqx_frame:parse(Bin). - diff --git a/test/emqx_SUITE_data/acl.conf b/test/emqx_SUITE_data/acl.conf deleted file mode 100644 index 3cb3b8c52..000000000 --- a/test/emqx_SUITE_data/acl.conf +++ /dev/null @@ -1,29 +0,0 @@ -%%-------------------------------------------------------------------- -%% -%% [ACL](https://github.com/emqtt/emqttd/wiki/ACL) -%% -%% -type who() :: all | binary() | -%% {ipaddr, esockd_access:cidr()} | -%% {client, binary()} | -%% {user, binary()}. -%% -%% -type access() :: subscribe | publish | pubsub. -%% -%% -type topic() :: binary(). -%% -%% -type rule() :: {allow, all} | -%% {allow, who(), access(), list(topic())} | -%% {deny, all} | -%% {deny, who(), access(), list(topic())}. -%% -%%-------------------------------------------------------------------- - -{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. - -{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}. - -{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. - -{allow, all}. - - diff --git a/test/emqx_SUITE_data/loaded_plugins b/test/emqx_SUITE_data/loaded_plugins deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/emqx_access_SUITE.erl b/test/emqx_access_SUITE.erl index 4198d178f..c98973d22 100644 --- a/test/emqx_access_SUITE.erl +++ b/test/emqx_access_SUITE.erl @@ -21,41 +21,46 @@ -include("emqx.hrl"). --include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(AC, emqx_access_control). -define(CACHE, emqx_acl_cache). --import(emqx_access_rule, [compile/1, match/3]). +-import(emqx_access_rule, + [ compile/1 + , match/3 + ]). all() -> [{group, access_control}, {group, acl_cache}, {group, access_control_cache_mode}, - {group, access_rule}]. + {group, access_rule} + ]. groups() -> [{access_control, [sequence], - [reload_acl, - check_acl_1, - check_acl_2]}, - {access_control_cache_mode, [], - [acl_cache_basic, - acl_cache_expiry, - acl_cache_cleanup, - acl_cache_full]}, - {acl_cache, [], - [put_get_del_cache, - cache_update, - cache_expiry, - cache_replacement, - cache_cleanup, - cache_auto_emtpy, - cache_auto_cleanup]}, - {access_rule, [], - [compile_rule, - match_rule]}]. + [t_reload_acl, + t_check_acl_1, + t_check_acl_2]}, + {access_control_cache_mode, [sequence], + [t_acl_cache_basic, + t_acl_cache_expiry, + t_acl_cache_cleanup, + t_acl_cache_full]}, + {acl_cache, [sequence], + [t_put_get_del_cache, + t_cache_update, + t_cache_expiry, + t_cache_replacement, + t_cache_cleanup, + t_cache_auto_emtpy, + t_cache_auto_cleanup]}, + {access_rule, [parallel], + [t_compile_rule, + t_match_rule] + }]. init_per_suite(Config) -> emqx_ct_helpers:start_apps([]), @@ -102,62 +107,76 @@ end_per_group(_Group, Config) -> %% emqx_access_control %%-------------------------------------------------------------------- -reload_acl(_) -> +t_reload_acl(_) -> ok = ?AC:reload_acl(). -check_acl_1(_) -> - SelfUser = #{client_id => <<"client1">>, username => <<"testuser">>, zone => external}, - allow = ?AC:check_acl(SelfUser, subscribe, <<"users/testuser/1">>), - allow = ?AC:check_acl(SelfUser, subscribe, <<"clients/client1">>), - deny = ?AC:check_acl(SelfUser, subscribe, <<"clients/client1/x/y">>), - allow = ?AC:check_acl(SelfUser, publish, <<"users/testuser/1">>), - allow = ?AC:check_acl(SelfUser, subscribe, <<"a/b/c">>). -check_acl_2(_) -> - SelfUser = #{client_id => <<"client2">>, username => <<"xyz">>, zone => external}, - deny = ?AC:check_acl(SelfUser, subscribe, <<"a/b/c">>). +t_check_acl_1(_) -> + Client = #{zone => external, + client_id => <<"client1">>, + username => <<"testuser">> + }, + allow = ?AC:check_acl(Client, subscribe, <<"users/testuser/1">>), + allow = ?AC:check_acl(Client, subscribe, <<"clients/client1">>), + deny = ?AC:check_acl(Client, subscribe, <<"clients/client1/x/y">>), + allow = ?AC:check_acl(Client, publish, <<"users/testuser/1">>), + allow = ?AC:check_acl(Client, subscribe, <<"a/b/c">>). -acl_cache_basic(_) -> - SelfUser = #{client_id => <<"client1">>, username => <<"testuser">>, zone => external}, +t_check_acl_2(_) -> + Client = #{zone => external, + client_id => <<"client2">>, + username => <<"xyz">> + }, + deny = ?AC:check_acl(Client, subscribe, <<"a/b/c">>). + +t_acl_cache_basic(_) -> + Client = #{zone => external, + client_id => <<"client1">>, + username => <<"testuser">> + }, not_found = ?CACHE:get_acl_cache(subscribe, <<"users/testuser/1">>), not_found = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), - allow = ?AC:check_acl(SelfUser, subscribe, <<"users/testuser/1">>), - allow = ?AC:check_acl(SelfUser, subscribe, <<"clients/client1">>), + allow = ?AC:check_acl(Client, subscribe, <<"users/testuser/1">>), + allow = ?AC:check_acl(Client, subscribe, <<"clients/client1">>), allow = ?CACHE:get_acl_cache(subscribe, <<"users/testuser/1">>), - allow = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), - ok. + allow = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>). -acl_cache_expiry(_) -> +t_acl_cache_expiry(_) -> application:set_env(emqx, acl_cache_ttl, 100), - SelfUser = #{client_id => <<"client1">>, username => <<"testuser">>, zone => external}, - allow = ?AC:check_acl(SelfUser, subscribe, <<"clients/client1">>), + Client = #{zone => external, + client_id => <<"client1">>, + username => <<"testuser">> + }, + allow = ?AC:check_acl(Client, subscribe, <<"clients/client1">>), allow = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), ct:sleep(150), - not_found = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), - ok. + not_found = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>). -acl_cache_full(_) -> +t_acl_cache_full(_) -> application:set_env(emqx, acl_cache_max_size, 1), - - SelfUser = #{client_id => <<"client1">>, username => <<"testuser">>, zone => external}, - allow = ?AC:check_acl(SelfUser, subscribe, <<"users/testuser/1">>), - allow = ?AC:check_acl(SelfUser, subscribe, <<"clients/client1">>), + Client = #{zone => external, + client_id => <<"client1">>, + username => <<"testuser">> + }, + allow = ?AC:check_acl(Client, subscribe, <<"users/testuser/1">>), + allow = ?AC:check_acl(Client, subscribe, <<"clients/client1">>), %% the older ones (the <<"users/testuser/1">>) will be evicted first not_found = ?CACHE:get_acl_cache(subscribe, <<"users/testuser/1">>), - allow = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), - ok. + allow = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>). -acl_cache_cleanup(_) -> +t_acl_cache_cleanup(_) -> %% The acl cache will try to evict memory, if the size is full and the newest %% cache entry is expired application:set_env(emqx, acl_cache_ttl, 100), application:set_env(emqx, acl_cache_max_size, 2), - - SelfUser = #{client_id => <<"client1">>, username => <<"testuser">>, zone => external}, - allow = ?AC:check_acl(SelfUser, subscribe, <<"users/testuser/1">>), - allow = ?AC:check_acl(SelfUser, subscribe, <<"clients/client1">>), + Client = #{zone => external, + client_id => <<"client1">>, + username => <<"testuser">> + }, + allow = ?AC:check_acl(Client, subscribe, <<"users/testuser/1">>), + allow = ?AC:check_acl(Client, subscribe, <<"clients/client1">>), allow = ?CACHE:get_acl_cache(subscribe, <<"users/testuser/1">>), allow = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), @@ -166,14 +185,13 @@ acl_cache_cleanup(_) -> %% now the cache is full and the newest one - "clients/client1" %% should be expired, so we'll empty the cache before putting %% the next cache entry - deny = ?AC:check_acl(SelfUser, subscribe, <<"#">>), + deny = ?AC:check_acl(Client, subscribe, <<"#">>), not_found = ?CACHE:get_acl_cache(subscribe, <<"users/testuser/1">>), not_found = ?CACHE:get_acl_cache(subscribe, <<"clients/client1">>), - deny = ?CACHE:get_acl_cache(subscribe, <<"#">>), - ok. + deny = ?CACHE:get_acl_cache(subscribe, <<"#">>). -put_get_del_cache(_) -> +t_put_get_del_cache(_) -> application:set_env(emqx, acl_cache_ttl, 300000), application:set_env(emqx, acl_cache_max_size, 30), @@ -188,7 +206,7 @@ put_get_del_cache(_) -> 2 = ?CACHE:get_cache_size(), ?assertEqual(?CACHE:cache_k(subscribe, <<"b">>), ?CACHE:get_newest_key()). -cache_expiry(_) -> +t_cache_expiry(_) -> application:set_env(emqx, acl_cache_ttl, 100), application:set_env(emqx, acl_cache_max_size, 30), ok = ?CACHE:put_acl_cache(subscribe, <<"a">>, allow), @@ -203,7 +221,7 @@ cache_expiry(_) -> ct:sleep(150), not_found = ?CACHE:get_acl_cache(subscribe, <<"a">>). -cache_update(_) -> +t_cache_update(_) -> application:set_env(emqx, acl_cache_ttl, 300000), application:set_env(emqx, acl_cache_max_size, 30), [] = ?CACHE:dump_acl_cache(), @@ -222,7 +240,7 @@ cache_update(_) -> ?assertEqual(?CACHE:cache_k(publish, <<"b">>), ?CACHE:get_newest_key()), ?assertEqual(?CACHE:cache_k(subscribe, <<"a">>), ?CACHE:get_oldest_key()). -cache_replacement(_) -> +t_cache_replacement(_) -> application:set_env(emqx, acl_cache_ttl, 300000), application:set_env(emqx, acl_cache_max_size, 3), ok = ?CACHE:put_acl_cache(subscribe, <<"a">>, allow), @@ -248,7 +266,7 @@ cache_replacement(_) -> not_found = ?CACHE:get_acl_cache(publish, <<"b">>), allow = ?CACHE:get_acl_cache(publish, <<"c">>). -cache_cleanup(_) -> +t_cache_cleanup(_) -> application:set_env(emqx, acl_cache_ttl, 100), application:set_env(emqx, acl_cache_max_size, 30), ok = ?CACHE:put_acl_cache(subscribe, <<"a">>, allow), @@ -261,7 +279,7 @@ cache_cleanup(_) -> ?assertEqual(?CACHE:cache_k(publish, <<"c">>), ?CACHE:get_oldest_key()), 1 = ?CACHE:get_cache_size(). -cache_auto_emtpy(_) -> +t_cache_auto_emtpy(_) -> %% verify cache is emptied when cache full and even the newest %% one is expired. application:set_env(emqx, acl_cache_ttl, 100), @@ -275,7 +293,7 @@ cache_auto_emtpy(_) -> ok = ?CACHE:put_acl_cache(subscribe, <<"d">>, deny), 1 = ?CACHE:get_cache_size(). -cache_auto_cleanup(_) -> +t_cache_auto_cleanup(_) -> %% verify we'll cleanup expired entries when we got a exipired acl %% from cache. application:set_env(emqx, acl_cache_ttl, 100), @@ -299,7 +317,7 @@ cache_auto_cleanup(_) -> %% emqx_access_rule %%-------------------------------------------------------------------- -compile_rule(_) -> +t_compile_rule(_) -> {allow, {'and', [{ipaddr, {{127,0,0,1}, {127,0,0,1}, 32}}, {user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]}), @@ -324,23 +342,36 @@ compile_rule(_) -> {allow, all} = compile({allow, all}), {deny, all} = compile({deny, all}). -match_rule(_) -> - User = #{client_id => <<"testClient">>, username => <<"TestUser">>, peername => {{127,0,0,1}, 2948}, zone => external}, - User2 = #{client_id => <<"testClient">>, username => <<"TestUser">>, peername => {{192,168,0,10}, 3028}, zone => external}, - - {matched, allow} = match(User, <<"Test/Topic">>, {allow, all}), - {matched, deny} = match(User, <<"Test/Topic">>, {deny, all}), - {matched, allow} = match(User, <<"Test/Topic">>, compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]})), - {matched, allow} = match(User2, <<"Test/Topic">>, compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]})), - {matched, allow} = match(User, <<"d/e/f/x">>, compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]})), - nomatch = match(User, <<"d/e/f/x">>, compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]})), - {matched, allow} = match(User, <<"testTopics/testClient">>, compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]})), - {matched, allow} = match(User, <<"clients/testClient">>, compile({allow, all, pubsub, ["clients/%c"]})), - {matched, allow} = match(#{username => <<"user2">>}, <<"users/user2/abc/def">>, compile({allow, all, subscribe, ["users/%u/#"]})), - {matched, deny} = match(User, <<"d/e/f">>, compile({deny, all, subscribe, ["$SYS/#", "#"]})), +t_match_rule(_) -> + Client1 = #{zone => external, + client_id => <<"testClient">>, + username => <<"TestUser">>, + peername => {{127,0,0,1}, 2948} + }, + Client2 = #{zone => external, + client_id => <<"testClient">>, + username => <<"TestUser">>, + peername => {{192,168,0,10}, 3028} + }, + {matched, allow} = match(Client1, <<"Test/Topic">>, {allow, all}), + {matched, deny} = match(Client1, <<"Test/Topic">>, {deny, all}), + {matched, allow} = match(Client1, <<"Test/Topic">>, + compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]})), + {matched, allow} = match(Client2, <<"Test/Topic">>, + compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]})), + {matched, allow} = match(Client1, <<"d/e/f/x">>, + compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]})), + nomatch = match(Client1, <<"d/e/f/x">>, compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]})), + {matched, allow} = match(Client1, <<"testTopics/testClient">>, + compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]})), + {matched, allow} = match(Client1, <<"clients/testClient">>, compile({allow, all, pubsub, ["clients/%c"]})), + {matched, allow} = match(#{username => <<"user2">>}, <<"users/user2/abc/def">>, + compile({allow, all, subscribe, ["users/%u/#"]})), + {matched, deny} = match(Client1, <<"d/e/f">>, compile({deny, all, subscribe, ["$SYS/#", "#"]})), Rule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}), - nomatch = match(User, <<"Topic">>, Rule), + nomatch = match(Client1, <<"Topic">>, Rule), AndRule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}), - {matched, allow} = match(User, <<"Topic">>, AndRule), + {matched, allow} = match(Client1, <<"Topic">>, AndRule), OrRule = compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}), - {matched, allow} = match(User, <<"Topic">>, OrRule). + {matched, allow} = match(Client1, <<"Topic">>, OrRule). + diff --git a/test/emqx_acl_test_mod.erl b/test/emqx_acl_test_mod.erl index 867fe11aa..75386453f 100644 --- a/test/emqx_acl_test_mod.erl +++ b/test/emqx_acl_test_mod.erl @@ -17,7 +17,11 @@ -module(emqx_acl_test_mod). %% ACL callbacks --export([init/1, check_acl/2, reload_acl/1, description/0]). +-export([ init/1 + , check_acl/2 + , reload_acl/1 + , description/0 + ]). init(AclOpts) -> {ok, AclOpts}. diff --git a/test/emqx_alarm_handler_SUITE.erl b/test/emqx_alarm_handler_SUITE.erl deleted file mode 100644 index 08c3e10d5..000000000 --- a/test/emqx_alarm_handler_SUITE.erl +++ /dev/null @@ -1,110 +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_alarm_handler_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - --include_lib("common_test/include/ct.hrl"). - --include("emqx_mqtt.hrl"). --include("emqx.hrl"). - -all() -> [t_alarm_handler]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([], fun set_special_configs/1), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -set_special_configs(emqx) -> - application:set_env(emqx, acl_file, emqx_ct_helpers:deps_path(emqx, "test/emqx_access_SUITE_data/acl_deny_action.conf")); -set_special_configs(_App) -> - ok. - -with_connection(DoFun) -> - {ok, Sock} = emqx_client_sock:connect({127, 0, 0, 1}, 1883, - [binary, {packet, raw}, {active, false}], - 3000), - try - DoFun(Sock) - after - emqx_client_sock:close(Sock) - end. - -t_alarm_handler(_) -> - with_connection( - fun(Sock) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5}), - #{version => ?MQTT_PROTO_V5} - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5), - - Topic1 = emqx_topic:systop(<<"alarms/alert">>), - Topic2 = emqx_topic:systop(<<"alarms/clear">>), - SubOpts = #{rh => 1, qos => ?QOS_2, rap => 0, nl => 0, rc => 0}, - emqx_client_sock:send(Sock, - raw_send_serialize( - ?SUBSCRIBE_PACKET( - 1, - [{Topic1, SubOpts}, - {Topic2, SubOpts}]), - #{version => ?MQTT_PROTO_V5})), - - {ok, Data2} = gen_tcp:recv(Sock, 0), - {ok, ?SUBACK_PACKET(1, #{}, [2, 2]), <<>>, _} = raw_recv_parse(Data2, ?MQTT_PROTO_V5), - - alarm_handler:set_alarm({alarm_for_test, #alarm{id = alarm_for_test, - severity = error, - title="alarm title", - summary="alarm summary"}}), - - {ok, Data3} = gen_tcp:recv(Sock, 0), - - {ok, ?PUBLISH_PACKET(?QOS_0, Topic1, _, _), <<>>, _} = raw_recv_parse(Data3, ?MQTT_PROTO_V5), - - ?assertEqual(true, lists:keymember(alarm_for_test, 1, emqx_alarm_handler:get_alarms())), - - alarm_handler:clear_alarm(alarm_for_test), - - {ok, Data4} = gen_tcp:recv(Sock, 0), - - {ok, ?PUBLISH_PACKET(?QOS_0, Topic2, _, _), <<>>, _} = raw_recv_parse(Data4, ?MQTT_PROTO_V5), - - ?assertEqual(false, lists:keymember(alarm_for_test, 1, emqx_alarm_handler:get_alarms())) - - end). - -raw_send_serialize(Packet) -> - emqx_frame:serialize(Packet). - -raw_send_serialize(Packet, Opts) -> - emqx_frame:serialize(Packet, Opts). - -raw_recv_parse(Bin, ProtoVer) -> - emqx_frame:parse(Bin, {none, #{max_size => ?MAX_PACKET_SIZE, - version => ProtoVer}}). - diff --git a/test/emqx_auth_anonymous_test_mod.erl b/test/emqx_auth_anonymous_test_mod.erl deleted file mode 100644 index f4191c931..000000000 --- a/test/emqx_auth_anonymous_test_mod.erl +++ /dev/null @@ -1,29 +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_auth_anonymous_test_mod). - -%% ACL callbacks --export([init/1, check/3, description/0]). - -init(AclOpts) -> - {ok, AclOpts}. - -check(_Client, _Password, _Opts) -> - allow. - -description() -> - "Test emqx_auth_anonymous Mod". diff --git a/test/emqx_auth_dashboard.erl b/test/emqx_auth_dashboard.erl deleted file mode 100644 index 444006e96..000000000 --- a/test/emqx_auth_dashboard.erl +++ /dev/null @@ -1,30 +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_auth_dashboard). - -%% Auth callbacks --export([init/1, check/3, description/0]). - -init(Opts) -> - {ok, Opts}. - -check(_Client, _Password, _Opts) -> - allow. - -description() -> - "Test Auth Mod". - diff --git a/test/emqx_banned_SUITE.erl b/test/emqx_banned_SUITE.erl index 54cbb7566..1dc8e0dcb 100644 --- a/test/emqx_banned_SUITE.erl +++ b/test/emqx_banned_SUITE.erl @@ -20,35 +20,63 @@ -compile(nowarn_export_all). -include("emqx.hrl"). --include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). -all() -> [t_banned_all]. +all() -> emqx_ct:all(?MODULE). -t_banned_all(_) -> - emqx_ct_helpers:start_apps([]), - emqx_banned:start_link(), - TimeNow = erlang:system_time(second), +init_per_suite(Config) -> + application:load(emqx), + ok = ekka:start(), + Config. + +end_per_suite(_Config) -> + ekka:stop(), + ekka_mnesia:ensure_stopped(), + ekka_mnesia:delete_schema(). + +t_add_delete(_) -> Banned = #banned{who = {client_id, <<"TestClient">>}, reason = <<"test">>, by = <<"banned suite">>, desc = <<"test">>, - until = TimeNow + 1}, + until = erlang:system_time(second) + 1000 + }, ok = emqx_banned:add(Banned), - % here is not expire banned test because its check interval is greater than 5 mins, but its effect has been confirmed - ?assert(emqx_banned:check(#{client_id => <<"TestClient">>, - username => undefined, - peername => {undefined, undefined}})), - timer:sleep(2500), - ?assertNot(emqx_banned:check(#{client_id => <<"TestClient">>, - username => undefined, - peername => {undefined, undefined}})), - ok = emqx_banned:add(Banned), - ?assert(emqx_banned:check(#{client_id => <<"TestClient">>, - username => undefined, - peername => {undefined, undefined}})), - emqx_banned:delete({client_id, <<"TestClient">>}), - ?assertNot(emqx_banned:check(#{client_id => <<"TestClient">>, - username => undefined, - peername => {undefined, undefined}})), - emqx_ct_helpers:stop_apps([]). + ?assertEqual(1, emqx_banned:info(size)), + ok = emqx_banned:delete({client_id, <<"TestClient">>}), + ?assertEqual(0, emqx_banned:info(size)). + +t_check(_) -> + ok = emqx_banned:add(#banned{who = {client_id, <<"BannedClient">>}}), + ok = emqx_banned:add(#banned{who = {username, <<"BannedUser">>}}), + ok = emqx_banned:add(#banned{who = {ipaddr, {192,168,0,1}}}), + ?assertEqual(3, emqx_banned:info(size)), + Client1 = #{client_id => <<"BannedClient">>, + username => <<"user">>, + peername => {{127,0,0,1}, 5000} + }, + Client2 = #{client_id => <<"client">>, + username => <<"BannedUser">>, + peername => {{127,0,0,1}, 5000} + }, + Client3 = #{client_id => <<"client">>, + username => <<"user">>, + peername => {{192,168,0,1}, 5000} + }, + Client4 = #{client_id => <<"client">>, + username => <<"user">>, + peername => {{127,0,0,1}, 5000} + }, + ?assert(emqx_banned:check(Client1)), + ?assert(emqx_banned:check(Client2)), + ?assert(emqx_banned:check(Client3)), + ?assertNot(emqx_banned:check(Client4)), + ok = emqx_banned:delete({client_id, <<"BannedClient">>}), + ok = emqx_banned:delete({username, <<"BannedUser">>}), + ok = emqx_banned:delete({ipaddr, {192,168,0,1}}), + ?assertNot(emqx_banned:check(Client1)), + ?assertNot(emqx_banned:check(Client2)), + ?assertNot(emqx_banned:check(Client3)), + ?assertNot(emqx_banned:check(Client4)), + ?assertEqual(0, emqx_banned:info(size)). + diff --git a/test/emqx_batch_SUITE.erl b/test/emqx_batch_SUITE.erl index 0df74c36d..e45e89c83 100644 --- a/test/emqx_batch_SUITE.erl +++ b/test/emqx_batch_SUITE.erl @@ -21,11 +21,13 @@ -include_lib("eunit/include/eunit.hrl"). -all() -> - [batch_full_commit, batch_linger_commit]. +all() -> emqx_ct:all(?MODULE). -batch_full_commit(_) -> - B0 = emqx_batch:init(#{batch_size => 3, linger_ms => 2000, commit_fun => fun(_) -> ok end}), +t_batch_full_commit(_) -> + B0 = emqx_batch:init(#{batch_size => 3, + linger_ms => 2000, + commit_fun => fun(_) -> ok end + }), B3 = lists:foldl(fun(E, B) -> emqx_batch:push(E, B) end, B0, [a, b, c]), ?assertEqual(3, emqx_batch:size(B3)), ?assertEqual([a, b, c], emqx_batch:items(B3)), @@ -34,9 +36,12 @@ batch_full_commit(_) -> ?assertEqual(0, emqx_batch:size(B4)), ?assertEqual([], emqx_batch:items(B4)). -batch_linger_commit(_) -> +t_batch_linger_commit(_) -> CommitFun = fun(Q) -> ?assertEqual(3, length(Q)) end, - B0 = emqx_batch:init(#{batch_size => 3, linger_ms => 500, commit_fun => CommitFun}), + B0 = emqx_batch:init(#{batch_size => 3, + linger_ms => 500, + commit_fun => CommitFun + }), B3 = lists:foldl(fun(E, B) -> emqx_batch:push(E, B) end, B0, [a, b, c]), ?assertEqual(3, emqx_batch:size(B3)), ?assertEqual([a, b, c], emqx_batch:items(B3)), diff --git a/test/emqx_broker_SUITE.erl b/test/emqx_broker_SUITE.erl index e04a99a72..c6937c00c 100644 --- a/test/emqx_broker_SUITE.erl +++ b/test/emqx_broker_SUITE.erl @@ -29,19 +29,24 @@ all() -> [{group, pubsub}, - {group, session}, {group, metrics}, {group, stats}]. groups() -> - [{pubsub, [sequence], [subscribe_unsubscribe, - publish, pubsub, - t_shared_subscribe, - dispatch_with_no_sub, - 'pubsub#', 'pubsub+']}, - {session, [sequence], [start_session]}, - {metrics, [sequence], [inc_dec_metric]}, - {stats, [sequence], [set_get_stat]}]. + [{pubsub, [sequence], + [t_sub_unsub, + t_publish, + t_pubsub, + t_shared_subscribe, + t_dispatch_with_no_sub, + 't_pubsub#', + 't_pubsub+' + ]}, + {metrics, [sequence], + [inc_dec_metric]}, + {stats, [sequence], + [set_get_stat] + }]. init_per_suite(Config) -> emqx_ct_helpers:start_apps([]), @@ -54,47 +59,48 @@ end_per_suite(_Config) -> %% PubSub Test %%-------------------------------------------------------------------- -subscribe_unsubscribe(_) -> - ok = emqx:subscribe(<<"topic">>, <<"clientId">>), - ok = emqx:subscribe(<<"topic/1">>, <<"clientId">>, #{ qos => 1 }), - ok = emqx:subscribe(<<"topic/2">>, <<"clientId">>, #{ qos => 2 }), - true = emqx:subscribed(<<"clientId">>, <<"topic">>), - Topics = emqx:topics(), +t_sub_unsub(_) -> + ok = emqx_broker:subscribe(<<"topic">>, <<"clientId">>), + ok = emqx_broker:subscribe(<<"topic/1">>, <<"clientId">>, #{qos => 1}), + ok = emqx_broker:subscribe(<<"topic/2">>, <<"clientId">>, #{qos => 2}), + true = emqx_broker:subscribed(<<"clientId">>, <<"topic">>), + Topics = emqx_broker:topics(), lists:foreach(fun(Topic) -> ?assert(lists:member(Topic, Topics)) end, Topics), - ok = emqx:unsubscribe(<<"topic">>), - ok = emqx:unsubscribe(<<"topic/1">>), - ok = emqx:unsubscribe(<<"topic/2">>). + ok = emqx_broker:unsubscribe(<<"topic">>), + ok = emqx_broker:unsubscribe(<<"topic/1">>), + ok = emqx_broker:unsubscribe(<<"topic/2">>). -publish(_) -> +t_publish(_) -> Msg = emqx_message:make(ct, <<"test/pubsub">>, <<"hello">>), - ok = emqx:subscribe(<<"test/+">>), + ok = emqx_broker:subscribe(<<"test/+">>), timer:sleep(10), - emqx:publish(Msg), - ?assert(receive {dispatch, <<"test/+">>, #message{payload = <<"hello">>}} -> true after 100 -> false end). + emqx_broker:publish(Msg), + ?assert(receive {deliver, <<"test/+">>, #message{payload = <<"hello">>}} -> true after 100 -> false end). -dispatch_with_no_sub(_) -> +t_dispatch_with_no_sub(_) -> Msg = emqx_message:make(ct, <<"no_subscribers">>, <<"hello">>), Delivery = #delivery{sender = self(), message = Msg, results = []}, ?assertEqual(Delivery, emqx_broker:route([{<<"no_subscribers">>, node()}], Delivery)). -pubsub(_) -> +t_pubsub(_) -> true = emqx:is_running(node()), Self = self(), Subscriber = <<"clientId">>, - ok = emqx:subscribe(<<"a/b/c">>, Subscriber, #{ qos => 1 }), + ok = emqx_broker:subscribe(<<"a/b/c">>, Subscriber, #{ qos => 1 }), #{qos := 1} = ets:lookup_element(emqx_suboption, {Self, <<"a/b/c">>}, 2), #{qos := 1} = emqx_broker:get_subopts(Subscriber, <<"a/b/c">>), true = emqx_broker:set_subopts(<<"a/b/c">>, #{qos => 0}), #{qos := 0} = emqx_broker:get_subopts(Subscriber, <<"a/b/c">>), - ok = emqx:subscribe(<<"a/b/c">>, Subscriber, #{ qos => 2 }), + ok = emqx_broker:subscribe(<<"a/b/c">>, Subscriber, #{ qos => 2 }), %% ct:log("Emq Sub: ~p.~n", [ets:lookup(emqx_suboption, {<<"a/b/c">>, Subscriber})]), timer:sleep(10), [Self] = emqx_broker:subscribers(<<"a/b/c">>), - emqx:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), + emqx_broker:publish( + emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), ?assert( - receive {dispatch, <<"a/b/c">>, _ } -> + receive {deliver, <<"a/b/c">>, _ } -> true; P -> ct:log("Receive Message: ~p~n",[P]) @@ -102,62 +108,43 @@ pubsub(_) -> false end), spawn(fun() -> - emqx:subscribe(<<"a/b/c">>), - emqx:subscribe(<<"c/d/e">>), + emqx_broker:subscribe(<<"a/b/c">>), + emqx_broker:subscribe(<<"c/d/e">>), timer:sleep(10), - emqx:unsubscribe(<<"a/b/c">>) + emqx_broker:unsubscribe(<<"a/b/c">>) end), timer:sleep(20), - emqx:unsubscribe(<<"a/b/c">>). + emqx_broker:unsubscribe(<<"a/b/c">>). t_shared_subscribe(_) -> - emqx:subscribe("$share/group2/topic2"), - emqx:subscribe("$queue/topic3"), + emqx_broker:subscribe(<<"$share/group2/topic2">>), + emqx_broker:subscribe(<<"$queue/topic3">>), timer:sleep(10), - ct:log("share subscriptions: ~p~n", [emqx:subscriptions(self())]), - ?assertEqual(2, length(emqx:subscriptions(self()))), - emqx:unsubscribe("$share/group2/topic2"), - emqx:unsubscribe("$queue/topic3"), - ?assertEqual(0, length(emqx:subscriptions(self()))). + ct:pal("Share subscriptions: ~p", + [emqx_broker:subscriptions(self())]), + ?assertEqual(2, length(emqx_broker:subscriptions(self()))), + emqx_broker:unsubscribe(<<"$share/group2/topic2">>), + emqx_broker:unsubscribe(<<"$queue/topic3">>), + ?assertEqual(0, length(emqx_broker:subscriptions(self()))). -'pubsub#'(_) -> - emqx:subscribe(<<"a/#">>), +'t_pubsub#'(_) -> + emqx_broker:subscribe(<<"a/#">>), timer:sleep(10), - emqx:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), - ?assert(receive {dispatch, <<"a/#">>, _} -> true after 100 -> false end), - emqx:unsubscribe(<<"a/#">>). + emqx_broker:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), + ?assert(receive {deliver, <<"a/#">>, _} -> true after 100 -> false end), + emqx_broker:unsubscribe(<<"a/#">>). -'pubsub+'(_) -> - emqx:subscribe(<<"a/+/+">>), - timer:sleep(10), - emqx:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), - ?assert(receive {dispatch, <<"a/+/+">>, _} -> true after 100 -> false end), - emqx:unsubscribe(<<"a/+/+">>). - -%%-------------------------------------------------------------------- -%% Session Group -%%-------------------------------------------------------------------- -start_session(_) -> - ClientId = <<"clientId">>, - {ok, ClientPid} = emqx_mock_client:start_link(ClientId), - {ok, SessPid} = emqx_mock_client:open_session(ClientPid, ClientId, internal), - Message1 = emqx_message:make(<<"clientId">>, 2, <<"topic">>, <<"hello">>), - emqx_session:publish(SessPid, 1, Message1), - emqx_session:pubrel(SessPid, 2, reasoncode), - emqx_session:subscribe(SessPid, [{<<"topic/session">>, #{qos => 2}}]), - Message2 = emqx_message:make(<<"clientId">>, 1, <<"topic/session">>, <<"test">>), - emqx_session:publish(SessPid, 3, Message2), - emqx_session:unsubscribe(SessPid, [{<<"topic/session">>, []}]), - %% emqx_mock_client:stop(ClientPid). - emqx_mock_client:close_session(ClientPid). - -%%-------------------------------------------------------------------- -%% Broker Group -%%-------------------------------------------------------------------- +'t_pubsub+'(_) -> + emqx_broker:subscribe(<<"a/+/+">>), + timer:sleep(10), %% TODO: why sleep? + emqx_broker:publish(emqx_message:make(ct, <<"a/b/c">>, <<"hello">>)), + ?assert(receive {deliver, <<"a/+/+">>, _} -> true after 100 -> false end), + emqx_broker:unsubscribe(<<"a/+/+">>). %%-------------------------------------------------------------------- %% Metric Group %%-------------------------------------------------------------------- + inc_dec_metric(_) -> emqx_metrics:inc('messages.retained', 10), emqx_metrics:dec('messages.retained', 10). @@ -168,4 +155,5 @@ inc_dec_metric(_) -> set_get_stat(_) -> emqx_stats:setstat('retained.max', 99), - 99 = emqx_stats:getstat('retained.max'). + ?assertEqual(99, emqx_stats:getstat('retained.max')). + diff --git a/test/emqx_channel_SUITE.erl b/test/emqx_channel_SUITE.erl deleted file mode 100644 index 7d8b216f2..000000000 --- a/test/emqx_channel_SUITE.erl +++ /dev/null @@ -1,74 +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_channel_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). - --include_lib("eunit/include/eunit.hrl"). - --include_lib("common_test/include/ct.hrl"). - -all() -> - [t_connect_api]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_connect_api(_Config) -> - {ok, T1} = emqx_client:start_link([{host, "localhost"}, - {client_id, <<"client1">>}, - {username, <<"testuser1">>}, - {password, <<"pass1">>}]), - {ok, _} = emqx_client:connect(T1), - CPid = emqx_cm:lookup_conn_pid(<<"client1">>), - ConnStats = emqx_channel:stats(CPid), - ok = t_stats(ConnStats), - ConnAttrs = emqx_channel:attrs(CPid), - ok = t_attrs(ConnAttrs), - ConnInfo = emqx_channel:info(CPid), - ok = t_info(ConnInfo), - SessionPid = emqx_channel:session(CPid), - true = is_pid(SessionPid), - emqx_client:disconnect(T1). - -t_info(ConnInfo) -> - ?assertEqual(tcp, maps:get(socktype, ConnInfo)), - ?assertEqual(running, maps:get(conn_state, ConnInfo)), - ?assertEqual(<<"client1">>, maps:get(client_id, ConnInfo)), - ?assertEqual(<<"testuser1">>, maps:get(username, ConnInfo)), - ?assertEqual(<<"MQTT">>, maps:get(proto_name, ConnInfo)). - -t_attrs(AttrsData) -> - ?assertEqual(<<"client1">>, maps:get(client_id, AttrsData)), - ?assertEqual(emqx_channel, maps:get(conn_mod, AttrsData)), - ?assertEqual(<<"testuser1">>, maps:get(username, AttrsData)). - -t_stats(StatsData) -> - ?assertEqual(true, proplists:get_value(recv_oct, StatsData) >= 0), - ?assertEqual(true, proplists:get_value(mailbox_len, StatsData) >= 0), - ?assertEqual(true, proplists:get_value(heap_size, StatsData) >= 0), - ?assertEqual(true, proplists:get_value(reductions, StatsData) >=0), - ?assertEqual(true, proplists:get_value(recv_pkt, StatsData) =:=1), - ?assertEqual(true, proplists:get_value(recv_msg, StatsData) >=0), - ?assertEqual(true, proplists:get_value(send_pkt, StatsData) =:=1). diff --git a/test/emqx_client_SUITE.erl b/test/emqx_client_SUITE.erl deleted file mode 100644 index e639c689a..000000000 --- a/test/emqx_client_SUITE.erl +++ /dev/null @@ -1,209 +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_client_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --import(lists, [nth/2]). - --include("emqx_mqtt.hrl"). - --include_lib("eunit/include/eunit.hrl"). - --include_lib("common_test/include/ct.hrl"). - --define(TOPICS, [<<"TopicA">>, <<"TopicA/B">>, <<"Topic/C">>, <<"TopicA/C">>, - <<"/TopicA">>]). - --define(WILD_TOPICS, [<<"TopicA/+">>, <<"+/C">>, <<"#">>, <<"/#">>, <<"/+">>, - <<"+/+">>, <<"TopicA/#">>]). - -all() -> - [{group, mqttv4}]. - -groups() -> - [{mqttv4, [non_parallel_tests], - [basic_test, - will_message_test, - offline_message_queueing_test, - overlapping_subscriptions_test, - %% keepalive_test, - redelivery_on_reconnect_test, - %% subscribe_failure_test, - dollar_topics_test]}]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -receive_messages(Count) -> - receive_messages(Count, []). - -receive_messages(0, Msgs) -> - Msgs; -receive_messages(Count, Msgs) -> - receive - {publish, Msg} -> - receive_messages(Count-1, [Msg|Msgs]); - _Other -> - receive_messages(Count, Msgs) - after 100 -> - Msgs - end. - -basic_test(_Config) -> - Topic = nth(1, ?TOPICS), - ct:print("Basic test starting"), - {ok, C} = emqx_client:start_link(), - {ok, _} = emqx_client:connect(C), - {ok, _, [1]} = emqx_client:subscribe(C, Topic, qos1), - {ok, _, [2]} = emqx_client:subscribe(C, Topic, qos2), - {ok, _} = emqx_client:publish(C, Topic, <<"qos 2">>, 2), - {ok, _} = emqx_client:publish(C, Topic, <<"qos 2">>, 2), - {ok, _} = emqx_client:publish(C, Topic, <<"qos 2">>, 2), - ?assertEqual(3, length(receive_messages(3))), - ok = emqx_client:disconnect(C). - -will_message_test(_Config) -> - {ok, C1} = emqx_client:start_link([{clean_start, true}, - {will_topic, nth(3, ?TOPICS)}, - {will_payload, <<"client disconnected">>}, - {keepalive, 2}]), - {ok, _} = emqx_client:connect(C1), - - {ok, C2} = emqx_client:start_link(), - {ok, _} = emqx_client:connect(C2), - - {ok, _, [2]} = emqx_client:subscribe(C2, nth(3, ?TOPICS), 2), - timer:sleep(10), - ok = emqx_client:stop(C1), - timer:sleep(5), - ?assertEqual(1, length(receive_messages(1))), - ok = emqx_client:disconnect(C2), - ct:print("Will message test succeeded"). - -offline_message_queueing_test(_) -> - {ok, C1} = emqx_client:start_link([{clean_start, false}, - {client_id, <<"c1">>}]), - {ok, _} = emqx_client:connect(C1), - - {ok, _, [2]} = emqx_client:subscribe(C1, nth(6, ?WILD_TOPICS), 2), - ok = emqx_client:disconnect(C1), - {ok, C2} = emqx_client:start_link([{clean_start, true}, - {client_id, <<"c2">>}]), - {ok, _} = emqx_client:connect(C2), - - ok = emqx_client:publish(C2, nth(2, ?TOPICS), <<"qos 0">>, 0), - {ok, _} = emqx_client:publish(C2, nth(3, ?TOPICS), <<"qos 1">>, 1), - {ok, _} = emqx_client:publish(C2, nth(4, ?TOPICS), <<"qos 2">>, 2), - timer:sleep(10), - emqx_client:disconnect(C2), - {ok, C3} = emqx_client:start_link([{clean_start, false}, - {client_id, <<"c1">>}]), - {ok, _} = emqx_client:connect(C3), - - timer:sleep(10), - emqx_client:disconnect(C3), - ?assertEqual(3, length(receive_messages(3))). - -overlapping_subscriptions_test(_) -> - {ok, C} = emqx_client:start_link([]), - {ok, _} = emqx_client:connect(C), - - {ok, _, [2, 1]} = emqx_client:subscribe(C, [{nth(7, ?WILD_TOPICS), 2}, - {nth(1, ?WILD_TOPICS), 1}]), - timer:sleep(10), - {ok, _} = emqx_client:publish(C, nth(4, ?TOPICS), <<"overlapping topic filters">>, 2), - timer:sleep(10), - - Num = length(receive_messages(2)), - ?assert(lists:member(Num, [1, 2])), - if - Num == 1 -> - ct:print("This server is publishing one message for all - matching overlapping subscriptions, not one for each."); - Num == 2 -> - ct:print("This server is publishing one message per each - matching overlapping subscription."); - true -> ok - end, - emqx_client:disconnect(C). - -%% keepalive_test(_) -> -%% ct:print("Keepalive test starting"), -%% {ok, C1, _} = emqx_client:start_link([{clean_start, true}, -%% {keepalive, 5}, -%% {will_flag, true}, -%% {will_topic, nth(5, ?TOPICS)}, -%% %% {will_qos, 2}, -%% {will_payload, <<"keepalive expiry">>}]), -%% ok = emqx_client:pause(C1), -%% {ok, C2, _} = emqx_client:start_link([{clean_start, true}, -%% {keepalive, 0}]), -%% {ok, _, [2]} = emqx_client:subscribe(C2, nth(5, ?TOPICS), 2), -%% ok = emqx_client:disconnect(C2), -%% ?assertEqual(1, length(receive_messages(1))), -%% ct:print("Keepalive test succeeded"). - -redelivery_on_reconnect_test(_) -> - ct:print("Redelivery on reconnect test starting"), - {ok, C1} = emqx_client:start_link([{clean_start, false}, - {client_id, <<"c">>}]), - {ok, _} = emqx_client:connect(C1), - - {ok, _, [2]} = emqx_client:subscribe(C1, nth(7, ?WILD_TOPICS), 2), - timer:sleep(10), - ok = emqx_client:pause(C1), - {ok, _} = emqx_client:publish(C1, nth(2, ?TOPICS), <<>>, - [{qos, 1}, {retain, false}]), - {ok, _} = emqx_client:publish(C1, nth(4, ?TOPICS), <<>>, - [{qos, 2}, {retain, false}]), - timer:sleep(10), - ok = emqx_client:disconnect(C1), - ?assertEqual(0, length(receive_messages(2))), - {ok, C2} = emqx_client:start_link([{clean_start, false}, - {client_id, <<"c">>}]), - {ok, _} = emqx_client:connect(C2), - - timer:sleep(10), - ok = emqx_client:disconnect(C2), - ?assertEqual(2, length(receive_messages(2))). - -%% subscribe_failure_test(_) -> -%% ct:print("Subscribe failure test starting"), -%% {ok, C, _} = emqx_client:start_link([]), -%% {ok, _, [2]} = emqx_client:subscribe(C, <<"$SYS/#">>, 2), -%% timer:sleep(10), -%% ct:print("Subscribe failure test succeeded"). - -dollar_topics_test(_) -> - ct:print("$ topics test starting"), - {ok, C} = emqx_client:start_link([{clean_start, true}, - {keepalive, 0}]), - {ok, _} = emqx_client:connect(C), - - {ok, _, [1]} = emqx_client:subscribe(C, nth(6, ?WILD_TOPICS), 1), - {ok, _} = emqx_client:publish(C, << <<"$">>/binary, (nth(2, ?TOPICS))/binary>>, - <<"test">>, [{qos, 1}, {retain, false}]), - timer:sleep(10), - ?assertEqual(0, length(receive_messages(1))), - ok = emqx_client:disconnect(C), - ct:print("$ topics test succeeded"). diff --git a/test/emqx_cm_SUITE.erl b/test/emqx_cm_SUITE.erl deleted file mode 100644 index 761d890fc..000000000 --- a/test/emqx_cm_SUITE.erl +++ /dev/null @@ -1,71 +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_cm_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx.hrl"). --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - -all() -> [{group, cm}]. - -groups() -> - [{cm, [non_parallel_tests], - [t_get_set_conn_attrs, - t_get_set_conn_stats, - t_lookup_conn_pid]}]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -init_per_testcase(_TestCase, Config) -> - register_connection(), - Config. - -end_per_testcase(_TestCase, _Config) -> - unregister_connection(), - ok. - -t_get_set_conn_attrs(_) -> - ?assert(emqx_cm:set_conn_attrs(<<"conn1">>, [{port, 8080}, {ip, "192.168.0.1"}])), - ?assert(emqx_cm:set_conn_attrs(<<"conn2">>, self(), [{port, 8080}, {ip, "192.168.0.2"}])), - ?assertEqual([{port, 8080}, {ip, "192.168.0.1"}], emqx_cm:get_conn_attrs(<<"conn1">>)), - ?assertEqual([{port, 8080}, {ip, "192.168.0.2"}], emqx_cm:get_conn_attrs(<<"conn2">>, self())). - -t_get_set_conn_stats(_) -> - ?assert(emqx_cm:set_conn_stats(<<"conn1">>, [{count, 1}, {max, 2}])), - ?assert(emqx_cm:set_conn_stats(<<"conn2">>, self(), [{count, 1}, {max, 2}])), - ?assertEqual([{count, 1}, {max, 2}], emqx_cm:get_conn_stats(<<"conn1">>)), - ?assertEqual([{count, 1}, {max, 2}], emqx_cm:get_conn_stats(<<"conn2">>, self())). - -t_lookup_conn_pid(_) -> - ?assertEqual(ok, emqx_cm:register_connection(<<"conn1">>, self())), - ?assertEqual(self(), emqx_cm:lookup_conn_pid(<<"conn1">>)). - -register_connection() -> - ?assertEqual(ok, emqx_cm:register_connection(<<"conn1">>)), - ?assertEqual(ok, emqx_cm:register_connection(<<"conn2">>, self())). - -unregister_connection() -> - ?assertEqual(ok, emqx_cm:unregister_connection(<<"conn1">>)), - ?assertEqual(ok, emqx_cm:unregister_connection(<<"conn2">>, self())). diff --git a/test/emqx_flapping_SUITE.erl b/test/emqx_flapping_SUITE.erl deleted file mode 100644 index 0bb0ca395..000000000 --- a/test/emqx_flapping_SUITE.erl +++ /dev/null @@ -1,62 +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_flapping_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx.hrl"). - --include_lib("common_test/include/ct.hrl"). --include_lib("eunit/include/eunit.hrl"). - -all() -> - [t_flapping]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - prepare_for_test(), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_flapping(_Config) -> - process_flag(trap_exit, true), - flapping_connect(5), - {ok, C} = emqx_client:start_link([{client_id, <<"Client">>}]), - {error, _} = emqx_client:connect(C), - receive - {'EXIT', Client, _Reason} -> - ct:log("receive exit signal, Client: ~p", [Client]) - after 1000 -> - ct:log("timeout") - end. - - -flapping_connect(Times) -> - [flapping_connect() || _ <- lists:seq(1, Times)]. - -flapping_connect() -> - {ok, C} = emqx_client:start_link([{client_id, <<"Client">>}]), - {ok, _} = emqx_client:connect(C), - ok = emqx_client:disconnect(C). - -prepare_for_test() -> - emqx_zone:set_env(external, enable_flapping_detect, true), - emqx_zone:set_env(external, flapping_threshold, {10, 60}), - emqx_zone:set_env(external, flapping_expiry_interval, 3600). diff --git a/test/emqx_frame_SUITE.erl b/test/emqx_frame_SUITE.erl index 8de05e734..cde76bfb3 100644 --- a/test/emqx_frame_SUITE.erl +++ b/test/emqx_frame_SUITE.erl @@ -37,60 +37,60 @@ all() -> groups() -> [{connect, [parallel], - [serialize_parse_connect, - serialize_parse_v3_connect, - serialize_parse_v4_connect, - serialize_parse_v5_connect, - serialize_parse_connect_without_clientid, - serialize_parse_connect_with_will, - serialize_parse_bridge_connect + [t_serialize_parse_connect, + t_serialize_parse_v3_connect, + t_serialize_parse_v4_connect, + t_serialize_parse_v5_connect, + t_serialize_parse_connect_without_clientid, + t_serialize_parse_connect_with_will, + t_serialize_parse_bridge_connect ]}, {connack, [parallel], - [serialize_parse_connack, - serialize_parse_connack_v5 + [t_serialize_parse_connack, + t_serialize_parse_connack_v5 ]}, {publish, [parallel], - [serialize_parse_qos0_publish, - serialize_parse_qos1_publish, - serialize_parse_qos2_publish, - serialize_parse_publish_v5 + [t_serialize_parse_qos0_publish, + t_serialize_parse_qos1_publish, + t_serialize_parse_qos2_publish, + t_serialize_parse_publish_v5 ]}, {puback, [parallel], - [serialize_parse_puback, - serialize_parse_puback_v5, - serialize_parse_pubrec, - serialize_parse_pubrec_v5, - serialize_parse_pubrel, - serialize_parse_pubrel_v5, - serialize_parse_pubcomp, - serialize_parse_pubcomp_v5 + [t_serialize_parse_puback, + t_serialize_parse_puback_v5, + t_serialize_parse_pubrec, + t_serialize_parse_pubrec_v5, + t_serialize_parse_pubrel, + t_serialize_parse_pubrel_v5, + t_serialize_parse_pubcomp, + t_serialize_parse_pubcomp_v5 ]}, {subscribe, [parallel], - [serialize_parse_subscribe, - serialize_parse_subscribe_v5 + [t_serialize_parse_subscribe, + t_serialize_parse_subscribe_v5 ]}, {suback, [parallel], - [serialize_parse_suback, - serialize_parse_suback_v5 + [t_serialize_parse_suback, + t_serialize_parse_suback_v5 ]}, {unsubscribe, [parallel], - [serialize_parse_unsubscribe, - serialize_parse_unsubscribe_v5 + [t_serialize_parse_unsubscribe, + t_serialize_parse_unsubscribe_v5 ]}, {unsuback, [parallel], - [serialize_parse_unsuback, - serialize_parse_unsuback_v5 + [t_serialize_parse_unsuback, + t_serialize_parse_unsuback_v5 ]}, {ping, [parallel], - [serialize_parse_pingreq, - serialize_parse_pingresp + [t_serialize_parse_pingreq, + t_serialize_parse_pingresp ]}, {disconnect, [parallel], - [serialize_parse_disconnect, - serialize_parse_disconnect_v5 + [t_serialize_parse_disconnect, + t_serialize_parse_disconnect_v5 ]}, {auth, [parallel], - [serialize_parse_auth_v5] + [t_serialize_parse_auth_v5] }]. init_per_suite(Config) -> @@ -105,7 +105,7 @@ init_per_group(_Group, Config) -> end_per_group(_Group, _Config) -> ok. -serialize_parse_connect(_) -> +t_serialize_parse_connect(_) -> Packet1 = ?CONNECT_PACKET(#mqtt_packet_connect{}), ?assertEqual(Packet1, parse_serialize(Packet1)), Packet2 = ?CONNECT_PACKET(#mqtt_packet_connect{ @@ -119,7 +119,7 @@ serialize_parse_connect(_) -> }), ?assertEqual(Packet2, parse_serialize(Packet2)). -serialize_parse_v3_connect(_) -> +t_serialize_parse_v3_connect(_) -> Bin = <<16,37,0,6,77,81,73,115,100,112,3,2,0,60,0,23,109,111,115, 113,112,117, 98,47,49,48,52,53,49,45,105,77,97,99,46,108, 111,99,97>>, @@ -132,7 +132,7 @@ serialize_parse_v3_connect(_) -> }), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_v4_connect(_) -> +t_serialize_parse_v4_connect(_) -> Bin = <<16,35,0,4,77,81,84,84,4,2,0,60,0,23,109,111,115,113,112,117, 98,47,49,48,52,53,49,45,105,77,97,99,46,108,111,99,97>>, Packet = ?CONNECT_PACKET(#mqtt_packet_connect{proto_ver = 4, @@ -143,7 +143,7 @@ serialize_parse_v4_connect(_) -> ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_v5_connect(_) -> +t_serialize_parse_v5_connect(_) -> Props = #{'Session-Expiry-Interval' => 60, 'Receive-Maximum' => 100, 'Maximum-QoS' => ?QOS_2, @@ -183,7 +183,7 @@ serialize_parse_v5_connect(_) -> }), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_connect_without_clientid(_) -> +t_serialize_parse_connect_without_clientid(_) -> Bin = <<16,12,0,4,77,81,84,84,4,2,0,60,0,0>>, Packet = ?CONNECT_PACKET( #mqtt_packet_connect{proto_ver = 4, @@ -195,7 +195,7 @@ serialize_parse_connect_without_clientid(_) -> ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_connect_with_will(_) -> +t_serialize_parse_connect_with_will(_) -> Bin = <<16,67,0,6,77,81,73,115,100,112,3,206,0,60,0,23,109,111,115,113,112, 117,98,47,49,48,52,53,50,45,105,77,97,99,46,108,111,99,97,0,5,47,119, 105,108,108,0,7,119,105,108,108,109,115,103,0,4,116,101,115,116,0,6, @@ -217,7 +217,7 @@ serialize_parse_connect_with_will(_) -> ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_bridge_connect(_) -> +t_serialize_parse_bridge_connect(_) -> Bin = <<16,86,0,6,77,81,73,115,100,112,131,44,0,60,0,19,67,95,48,48,58,48,67, 58,50,57,58,50,66,58,55,55,58,53,50,0,48,36,83,89,83,47,98,114,111,107, 101,114,47,99,111,110,110,101,99,116,105,111,110,47,67,95,48,48,58,48, @@ -239,12 +239,12 @@ serialize_parse_bridge_connect(_) -> ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_connack(_) -> +t_serialize_parse_connack(_) -> Packet = ?CONNACK_PACKET(?RC_SUCCESS), ?assertEqual(<<32,2,0,0>>, serialize_to_binary(Packet)), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_connack_v5(_) -> +t_serialize_parse_connack_v5(_) -> Props = #{'Session-Expiry-Interval' => 60, 'Receive-Maximum' => 100, 'Maximum-QoS' => ?QOS_2, @@ -265,7 +265,7 @@ serialize_parse_connack_v5(_) -> Packet = ?CONNACK_PACKET(?RC_SUCCESS, 0, Props), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_qos0_publish(_) -> +t_serialize_parse_qos0_publish(_) -> Bin = <<48,14,0,7,120,120,120,47,121,121,121,104,101,108,108,111>>, Packet = #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH, dup = false, @@ -277,7 +277,7 @@ serialize_parse_qos0_publish(_) -> ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_qos1_publish(_) -> +t_serialize_parse_qos1_publish(_) -> Bin = <<50,13,0,5,97,47,98,47,99,0,1,104,97,104,97>>, Packet = #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH, dup = false, @@ -289,11 +289,11 @@ serialize_parse_qos1_publish(_) -> ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_qos2_publish(_) -> +t_serialize_parse_qos2_publish(_) -> Packet = ?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 1, payload()), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_publish_v5(_) -> +t_serialize_parse_publish_v5(_) -> Props = #{'Payload-Format-Indicator' => 1, 'Message-Expiry-Interval' => 60, 'Topic-Alias' => 16#AB, @@ -304,45 +304,45 @@ serialize_parse_publish_v5(_) -> Packet = ?PUBLISH_PACKET(?QOS_1, <<"$share/group/topic">>, 1, Props, <<"payload">>), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_puback(_) -> +t_serialize_parse_puback(_) -> Packet = ?PUBACK_PACKET(1), ?assertEqual(<<64,2,0,1>>, serialize_to_binary(Packet)), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_puback_v5(_) -> +t_serialize_parse_puback_v5(_) -> Packet = ?PUBACK_PACKET(16, ?RC_SUCCESS, #{'Reason-String' => <<"success">>}), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_pubrec(_) -> +t_serialize_parse_pubrec(_) -> Packet = ?PUBREC_PACKET(1), ?assertEqual(<<5:4,0:4,2,0,1>>, serialize_to_binary(Packet)), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_pubrec_v5(_) -> +t_serialize_parse_pubrec_v5(_) -> Packet = ?PUBREC_PACKET(16, ?RC_SUCCESS, #{'Reason-String' => <<"success">>}), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_pubrel(_) -> +t_serialize_parse_pubrel(_) -> Packet = ?PUBREL_PACKET(1), Bin = serialize_to_binary(Packet), ?assertEqual(<<6:4,2:4,2,0,1>>, Bin), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_pubrel_v5(_) -> +t_serialize_parse_pubrel_v5(_) -> Packet = ?PUBREL_PACKET(16, ?RC_SUCCESS, #{'Reason-String' => <<"success">>}), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_pubcomp(_) -> +t_serialize_parse_pubcomp(_) -> Packet = ?PUBCOMP_PACKET(1), Bin = serialize_to_binary(Packet), ?assertEqual(<<7:4,0:4,2,0,1>>, Bin), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_pubcomp_v5(_) -> +t_serialize_parse_pubcomp_v5(_) -> Packet = ?PUBCOMP_PACKET(16, ?RC_SUCCESS, #{'Reason-String' => <<"success">>}), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_subscribe(_) -> +t_serialize_parse_subscribe(_) -> %% SUBSCRIBE(Q1, R0, D0, PacketId=2, TopicTable=[{<<"TopicA">>,2}]) Bin = <<130,11,0,2,0,6,84,111,112,105,99,65,2>>, TopicOpts = #{nl => 0 , rap => 0, rc => 0, rh => 0, qos => 2}, @@ -352,61 +352,61 @@ serialize_parse_subscribe(_) -> %%ct:log("Bin: ~p, Packet: ~p ~n", [Packet, parse(Bin)]), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_subscribe_v5(_) -> +t_serialize_parse_subscribe_v5(_) -> TopicFilters = [{<<"TopicQos0">>, #{rh => 1, qos => ?QOS_2, rap => 0, nl => 0, rc => 0}}, {<<"TopicQos1">>, #{rh => 1, qos => ?QOS_2, rap => 0, nl => 0, rc => 0}}], Packet = ?SUBSCRIBE_PACKET(3, #{'Subscription-Identifier' => 16#FFFFFFF}, TopicFilters), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_suback(_) -> +t_serialize_parse_suback(_) -> Packet = ?SUBACK_PACKET(10, [?QOS_0, ?QOS_1, 128]), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_suback_v5(_) -> +t_serialize_parse_suback_v5(_) -> Packet = ?SUBACK_PACKET(1, #{'Reason-String' => <<"success">>, 'User-Property' => [{<<"key">>, <<"value">>}]}, [?QOS_0, ?QOS_1, 128]), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_unsubscribe(_) -> +t_serialize_parse_unsubscribe(_) -> %% UNSUBSCRIBE(Q1, R0, D0, PacketId=2, TopicTable=[<<"TopicA">>]) Packet = ?UNSUBSCRIBE_PACKET(2, [<<"TopicA">>]), Bin = <<162,10,0,2,0,6,84,111,112,105,99,65>>, ?assertEqual(Bin, serialize_to_binary(Packet)), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(Bin)). -serialize_parse_unsubscribe_v5(_) -> +t_serialize_parse_unsubscribe_v5(_) -> Props = #{'User-Property' => [{<<"key">>, <<"val">>}]}, Packet = ?UNSUBSCRIBE_PACKET(10, Props, [<<"Topic1">>, <<"Topic2">>]), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_unsuback(_) -> +t_serialize_parse_unsuback(_) -> Packet = ?UNSUBACK_PACKET(10), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_unsuback_v5(_) -> +t_serialize_parse_unsuback_v5(_) -> Packet = ?UNSUBACK_PACKET(10, #{'Reason-String' => <<"Not authorized">>, 'User-Property' => [{<<"key">>, <<"val">>}]}, [16#87, 16#87, 16#87]), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_pingreq(_) -> +t_serialize_parse_pingreq(_) -> PingReq = ?PACKET(?PINGREQ), ?assertEqual(PingReq, parse_serialize(PingReq)). -serialize_parse_pingresp(_) -> +t_serialize_parse_pingresp(_) -> PingResp = ?PACKET(?PINGRESP), ?assertEqual(PingResp, parse_serialize(PingResp)). -parse_disconnect(_) -> +t_parse_disconnect(_) -> Packet = ?DISCONNECT_PACKET(?RC_SUCCESS), ?assertMatch({ok, Packet, <<>>, _}, emqx_frame:parse(<<224, 0>>)). -serialize_parse_disconnect(_) -> +t_serialize_parse_disconnect(_) -> Packet = ?DISCONNECT_PACKET(?RC_SUCCESS), ?assertEqual(Packet, parse_serialize(Packet)). -serialize_parse_disconnect_v5(_) -> +t_serialize_parse_disconnect_v5(_) -> Packet = ?DISCONNECT_PACKET(?RC_SUCCESS, #{'Session-Expiry-Interval' => 60, 'Reason-String' => <<"server_moved">>, @@ -414,7 +414,7 @@ serialize_parse_disconnect_v5(_) -> }), ?assertEqual(Packet, parse_serialize(Packet, #{version => ?MQTT_PROTO_V5})). -serialize_parse_auth_v5(_) -> +t_serialize_parse_auth_v5(_) -> Packet = ?AUTH_PACKET(?RC_SUCCESS, #{'Authentication-Method' => <<"oauth2">>, 'Authentication-Data' => <<"3zekkd">>, @@ -427,7 +427,8 @@ parse_serialize(Packet) -> parse_serialize(Packet, #{}). parse_serialize(Packet, Opts) when is_map(Opts) -> - Bin = iolist_to_binary(emqx_frame:serialize(Packet, Opts)), + Ver = maps:get(version, Opts, ?MQTT_PROTO_V4), + Bin = iolist_to_binary(emqx_frame:serialize(Packet, Ver)), ParseState = emqx_frame:initial_parse_state(Opts), {ok, NPacket, <<>>, _} = emqx_frame:parse(Bin, ParseState), NPacket. diff --git a/test/emqx_gc_SUITE.erl b/test/emqx_gc_SUITE.erl index 666f4994e..5e6c13317 100644 --- a/test/emqx_gc_SUITE.erl +++ b/test/emqx_gc_SUITE.erl @@ -21,8 +21,7 @@ -include_lib("eunit/include/eunit.hrl"). -all() -> - [t_init, t_run, t_info, t_reset]. +all() -> emqx_ct:all(?MODULE). t_init(_) -> ?assertEqual(undefined, emqx_gc:init(false)), diff --git a/test/emqx_guid_SUITE.erl b/test/emqx_guid_SUITE.erl index 4499ec243..004661b72 100644 --- a/test/emqx_guid_SUITE.erl +++ b/test/emqx_guid_SUITE.erl @@ -16,21 +16,21 @@ -module(emqx_guid_SUITE). --include_lib("eunit/include/eunit.hrl"). - -compile(export_all). -compile(nowarn_export_all). -all() -> [t_guid_gen, t_guid_hexstr, t_guid_base62]. +-include_lib("eunit/include/eunit.hrl"). + +all() -> emqx_ct:all(?MODULE). t_guid_gen(_) -> Guid1 = emqx_guid:gen(), Guid2 = emqx_guid:gen(), <<_:128>> = Guid1, - true = (Guid2 >= Guid1), + ?assert((Guid2 >= Guid1)), {Ts1, _, 0} = emqx_guid:new(), Ts2 = emqx_guid:timestamp(emqx_guid:gen()), - true = Ts2 > Ts1. + ?assert(Ts2 > Ts1). t_guid_hexstr(_) -> Guid = emqx_guid:gen(), diff --git a/test/emqx_hooks_SUITE.erl b/test/emqx_hooks_SUITE.erl index 2904678d9..102a66161 100644 --- a/test/emqx_hooks_SUITE.erl +++ b/test/emqx_hooks_SUITE.erl @@ -20,12 +20,10 @@ -compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). -all() -> - [add_delete_hook, run_hook]. +all() -> emqx_ct:all(?MODULE). -add_delete_hook(_) -> +t_add_del_hook(_) -> {ok, _} = emqx_hooks:start_link(), ok = emqx:hook(test_hook, fun ?MODULE:hook_fun1/1, []), ok = emqx:hook(test_hook, fun ?MODULE:hook_fun2/1, []), @@ -56,7 +54,7 @@ add_delete_hook(_) -> ?assertEqual([], emqx_hooks:lookup(emqx_hook)), ok = emqx_hooks:stop(). -run_hook(_) -> +t_run_hooks(_) -> {ok, _} = emqx_hooks:start_link(), ok = emqx:hook(foldl_hook, fun ?MODULE:hook_fun3/4, [init]), ok = emqx:hook(foldl_hook, {?MODULE, hook_fun3, [init]}), @@ -86,6 +84,10 @@ run_hook(_) -> ok = emqx_hooks:stop(). +%%-------------------------------------------------------------------- +%% Hook fun +%%-------------------------------------------------------------------- + hook_fun1(arg) -> ok; hook_fun1(_) -> error. @@ -104,7 +106,7 @@ hook_fun7(arg, initArg) -> ok. hook_fun8(arg, initArg) -> ok. hook_fun9(arg, Acc) -> {stop, [r9 | Acc]}. -hook_fun10(arg, Acc) -> {stop, [r10 | Acc]}. +hook_fun10(arg, Acc) -> {stop, [r10 | Acc]}. hook_filter1(arg) -> true; hook_filter1(_) -> false. @@ -112,6 +114,7 @@ hook_filter1(_) -> false. hook_filter2(arg, _Acc, init_arg) -> true; hook_filter2(_, _Acc, _IntArg) -> false. -hook_filter2_1(arg, _Acc, init_arg) -> true; +hook_filter2_1(arg, _Acc, init_arg) -> true; hook_filter2_1(arg1, _Acc, init_arg) -> true; -hook_filter2_1(_, _Acc, _IntArg) -> false. +hook_filter2_1(_, _Acc, _IntArg) -> false. + diff --git a/test/emqx_inflight_SUITE.erl b/test/emqx_inflight_SUITE.erl index 533194f1e..7a015a443 100644 --- a/test/emqx_inflight_SUITE.erl +++ b/test/emqx_inflight_SUITE.erl @@ -19,26 +19,73 @@ -compile(export_all). -compile(nowarn_export_all). -all() -> [t_inflight_all]. +-include_lib("eunit/include/eunit.hrl"). +-include_lib("emqx_ct_helpers/include/emqx_ct.hrl"). -t_inflight_all(_) -> - Empty = emqx_inflight:new(2), - true = emqx_inflight:is_empty(Empty), - 2 = emqx_inflight:max_size(Empty), - false = emqx_inflight:contain(a, Empty), - none = emqx_inflight:lookup(a, Empty), - try emqx_inflight:update(a, 1, Empty) catch - error:Reason -> io:format("Reason: ~w~n", [Reason]) - end, - 0 = emqx_inflight:size(Empty), - Inflight1 = emqx_inflight:insert(a, 1, Empty), - Inflight2 = emqx_inflight:insert(b, 2, Inflight1), - 2 = emqx_inflight:size(Inflight2), - true = emqx_inflight:is_full(Inflight2), - {value, 1} = emqx_inflight:lookup(a, Inflight1), - {value, 2} = emqx_inflight:lookup(a, emqx_inflight:update(a, 2, Inflight1)), - false = emqx_inflight:contain(a, emqx_inflight:delete(a, Inflight1)), - [1, 2] = emqx_inflight:values(Inflight2), - [{a, 1}, {b ,2}] = emqx_inflight:to_list(Inflight2), - [a, b] = emqx_inflight:window(Inflight2). +all() -> emqx_ct:all(?MODULE). + +t_contain(_) -> + Inflight = emqx_inflight:insert(k, v, emqx_inflight:new()), + ?assert(emqx_inflight:contain(k, Inflight)), + ?assertNot(emqx_inflight:contain(badkey, Inflight)). + +t_lookup(_) -> + Inflight = emqx_inflight:insert(k, v, emqx_inflight:new()), + ?assertEqual({value, v}, emqx_inflight:lookup(k, Inflight)), + ?assertEqual(none, emqx_inflight:lookup(badkey, Inflight)). + +t_insert(_) -> + Inflight = emqx_inflight:insert( + b, 2, emqx_inflight:insert( + a, 1, emqx_inflight:new())), + ?assertEqual(2, emqx_inflight:size(Inflight)), + ?assertEqual({value, 1}, emqx_inflight:lookup(a, Inflight)), + ?assertEqual({value, 2}, emqx_inflight:lookup(b, Inflight)), + ?catch_error({key_exists, a}, emqx_inflight:insert(a, 1, Inflight)). + +t_update(_) -> + Inflight = emqx_inflight:insert(k, v, emqx_inflight:new()), + ?assertEqual(Inflight, emqx_inflight:update(k, v, Inflight)), + ?catch_error(function_clause, emqx_inflight:update(badkey, v, Inflight)). + +t_resize(_) -> + Inflight = emqx_inflight:insert(k, v, emqx_inflight:new(2)), + ?assertEqual(1, emqx_inflight:size(Inflight)), + ?assertEqual(2, emqx_inflight:max_size(Inflight)), + Inflight1 = emqx_inflight:resize(4, Inflight), + ?assertEqual(4, emqx_inflight:max_size(Inflight1)), + ?assertEqual(1, emqx_inflight:size(Inflight)). + +t_delete(_) -> + Inflight = emqx_inflight:insert(k, v, emqx_inflight:new(2)), + Inflight1 = emqx_inflight:delete(k, Inflight), + ?assert(emqx_inflight:is_empty(Inflight1)), + ?assertNot(emqx_inflight:contain(k, Inflight1)). + +t_values(_) -> + Inflight = emqx_inflight:insert( + b, 2, emqx_inflight:insert( + a, 1, emqx_inflight:new())), + ?assertEqual([1,2], emqx_inflight:values(Inflight)), + ?assertEqual([{a,1},{b,2}], emqx_inflight:to_list(Inflight)). + +t_is_full(_) -> + Inflight = emqx_inflight:insert(k, v, emqx_inflight:new()), + ?assertNot(emqx_inflight:is_full(Inflight)), + Inflight1 = emqx_inflight:insert( + b, 2, emqx_inflight:insert( + a, 1, emqx_inflight:new(2))), + ?assert(emqx_inflight:is_full(Inflight1)). + +t_is_empty(_) -> + Inflight = emqx_inflight:insert(a, 1, emqx_inflight:new(2)), + ?assertNot(emqx_inflight:is_empty(Inflight)), + Inflight1 = emqx_inflight:delete(a, Inflight), + ?assert(emqx_inflight:is_empty(Inflight1)). + +t_window(_) -> + Inflight = emqx_inflight:insert( + b, 2, emqx_inflight:insert( + a, 1, emqx_inflight:new(2))), + [a, b] = emqx_inflight:window(Inflight). diff --git a/test/emqx_json_SUITE.erl b/test/emqx_json_SUITE.erl index 2786a3506..122296a93 100644 --- a/test/emqx_json_SUITE.erl +++ b/test/emqx_json_SUITE.erl @@ -19,21 +19,26 @@ -compile(export_all). -compile(nowarn_export_all). -all() -> [t_decode_encode, t_safe_decode_encode]. +-include_lib("eunit/include/eunit.hrl"). + +-define(DEC_OPTS, [{labels, atom}, return_maps]). + +all() -> emqx_ct:all(?MODULE). t_decode_encode(_) -> JsonText = <<"{\"library\": \"jsx\", \"awesome\": true}">>, JsonTerm = emqx_json:decode(JsonText), JsonMaps = #{library => <<"jsx">>, awesome => true}, - JsonMaps = emqx_json:decode(JsonText, [{labels, atom}, return_maps]), - JsonText = emqx_json:encode(JsonTerm, [{space, 1}]). + ?assertEqual(JsonText, emqx_json:encode(JsonTerm, [{space, 1}])), + ?assertEqual(JsonMaps, emqx_json:decode(JsonText, ?DEC_OPTS)). t_safe_decode_encode(_) -> JsonText = <<"{\"library\": \"jsx\", \"awesome\": true}">>, {ok, JsonTerm} = emqx_json:safe_decode(JsonText), JsonMaps = #{library => <<"jsx">>, awesome => true}, - {ok, JsonMaps} = emqx_json:safe_decode(JsonText, [{labels, atom}, return_maps]), - {ok, JsonText} = emqx_json:safe_encode(JsonTerm, [{space, 1}]), + ?assertEqual({ok, JsonText}, emqx_json:safe_encode(JsonTerm, [{space, 1}])), + ?assertEqual({ok, JsonMaps}, emqx_json:safe_decode(JsonText, ?DEC_OPTS)), BadJsonText = <<"{\"library\", \"awesome\": true}">>, - {error, _} = emqx_json:safe_decode(BadJsonText), - {error, _} = emqx_json:safe_encode({a, {b ,1}}). + ?assertEqual({error, badarg}, emqx_json:safe_decode(BadJsonText)), + {error, badarg} = emqx_json:safe_encode({a, {b ,1}}). + diff --git a/test/emqx_keepalive_SUITE.erl b/test/emqx_keepalive_SUITE.erl index c16a7363b..abfd8ee2b 100644 --- a/test/emqx_keepalive_SUITE.erl +++ b/test/emqx_keepalive_SUITE.erl @@ -19,13 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). -all() -> [{group, keepalive}]. - -groups() -> [{keepalive, [], [t_keepalive]}]. - -%%-------------------------------------------------------------------- -%% Keepalive -%%-------------------------------------------------------------------- +all() -> emqx_ct:all(?MODULE). t_keepalive(_) -> {ok, KA} = emqx_keepalive:start(fun() -> {ok, 1} end, 1, {keepalive, timeout}), @@ -38,7 +32,6 @@ keepalive_recv(KA, Acc) -> {ok, KA1} -> keepalive_recv(KA1, [resumed | Acc]); {error, timeout} -> [timeout | Acc] end - after 4000 -> - Acc + after 4000 -> Acc end. diff --git a/test/emqx_lib_SUITE.erl b/test/emqx_lib_SUITE.erl deleted file mode 100644 index d89f029c3..000000000 --- a/test/emqx_lib_SUITE.erl +++ /dev/null @@ -1,175 +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_lib_SUITE). - --include_lib("eunit/include/eunit.hrl"). - --compile(export_all). --compile(nowarn_export_all). - --define(SOCKOPTS, [ - binary, - {packet, raw}, - {reuseaddr, true}, - {backlog, 512}, - {nodelay, true} -]). - --define(PQ, emqx_pqueue). - --define(BASE62, emqx_base62). - -all() -> [{group, guid}, {group, opts}, - {group, ?PQ}, {group, time}, - {group, node}, {group, base62}]. - -groups() -> - [{guid, [], [guid_gen, guid_hexstr, guid_base62]}, - {opts, [], [opts_merge]}, - {?PQ, [], [priority_queue_plen, - priority_queue_out2]}, - {time, [], [time_now_to_]}, - {node, [], [node_is_aliving, node_parse_name]}, - {base62, [], [base62_encode]}]. - -%%-------------------------------------------------------------------- -%% emqx_guid -%%-------------------------------------------------------------------- - -guid_gen(_) -> - Guid1 = emqx_guid:gen(), - Guid2 = emqx_guid:gen(), - <<_:128>> = Guid1, - true = (Guid2 >= Guid1), - {Ts1, _, 0} = emqx_guid:new(), - Ts2 = emqx_guid:timestamp(emqx_guid:gen()), - true = Ts2 > Ts1. - -guid_hexstr(_) -> - Guid = emqx_guid:gen(), - ?assertEqual(Guid, emqx_guid:from_hexstr(emqx_guid:to_hexstr(Guid))). - -guid_base62(_) -> - Guid = emqx_guid:gen(), - ?assertEqual(Guid, emqx_guid:from_base62(emqx_guid:to_base62(Guid))). - -%%-------------------------------------------------------------------- -%% emqx_opts -%%-------------------------------------------------------------------- - -opts_merge(_) -> - Opts = emqx_misc:merge_opts(?SOCKOPTS, [raw, - binary, - {backlog, 1024}, - {nodelay, false}, - {max_clients, 1024}, - {acceptors, 16}]), - 1024 = proplists:get_value(backlog, Opts), - 1024 = proplists:get_value(max_clients, Opts), - [binary, raw, - {acceptors, 16}, - {backlog, 1024}, - {max_clients, 1024}, - {nodelay, false}, - {packet, raw}, - {reuseaddr, true}] = lists:sort(Opts). - -%%-------------------------------------------------------------------- -%% priority_queue -%%-------------------------------------------------------------------- - -priority_queue_plen(_) -> - Q = ?PQ:new(), - 0 = ?PQ:plen(0, Q), - Q0 = ?PQ:in(z, Q), - 1 = ?PQ:plen(0, Q0), - Q1 = ?PQ:in(x, 1, Q0), - 1 = ?PQ:plen(1, Q1), - Q2 = ?PQ:in(y, 2, Q1), - 1 = ?PQ:plen(2, Q2), - Q3 = ?PQ:in(z, 2, Q2), - 2 = ?PQ:plen(2, Q3), - {_, Q4} = ?PQ:out(1, Q3), - 0 = ?PQ:plen(1, Q4), - {_, Q5} = ?PQ:out(Q4), - 1 = ?PQ:plen(2, Q5), - {_, Q6} = ?PQ:out(Q5), - 0 = ?PQ:plen(2, Q6), - 1 = ?PQ:len(Q6), - {_, Q7} = ?PQ:out(Q6), - 0 = ?PQ:len(Q7). - -priority_queue_out2(_) -> - Els = [a, {b, 1}, {c, 1}, {d, 2}, {e, 2}, {f, 2}], - Q = ?PQ:new(), - Q0 = lists:foldl( - fun({El, P}, Acc) -> - ?PQ:in(El, P, Acc); - (El, Acc) -> - ?PQ:in(El, Acc) - end, Q, Els), - {Val, Q1} = ?PQ:out(Q0), - {value, d} = Val, - {Val1, Q2} = ?PQ:out(2, Q1), - {value, e} = Val1, - {Val2, Q3} = ?PQ:out(1, Q2), - {value, b} = Val2, - {Val3, Q4} = ?PQ:out(Q3), - {value, f} = Val3, - {Val4, Q5} = ?PQ:out(Q4), - {value, c} = Val4, - {Val5, Q6} = ?PQ:out(Q5), - {value, a} = Val5, - {empty, _Q7} = ?PQ:out(Q6). - -%%-------------------------------------------------------------------- -%% emqx_time -%%-------------------------------------------------------------------- - -time_now_to_(_) -> - emqx_time:seed(), - emqx_time:now_secs(), - emqx_time:now_ms(). - -%%-------------------------------------------------------------------- -%% emqx_node -%%-------------------------------------------------------------------- - -node_is_aliving(_) -> - io:format("Node: ~p~n", [node()]), - true = ekka_node:is_aliving(node()), - false = ekka_node:is_aliving('x@127.0.0.1'). - -node_parse_name(_) -> - 'a@127.0.0.1' = ekka_node:parse_name("a@127.0.0.1"), - 'b@127.0.0.1' = ekka_node:parse_name("b"). - -%%-------------------------------------------------------------------- -%% base62 encode decode -%%-------------------------------------------------------------------- - -base62_encode(_) -> - <<"10">> = ?BASE62:decode(?BASE62:encode(<<"10">>)), - <<"100">> = ?BASE62:decode(?BASE62:encode(<<"100">>)), - <<"9999">> = ?BASE62:decode(?BASE62:encode(<<"9999">>)), - <<"65535">> = ?BASE62:decode(?BASE62:encode(<<"65535">>)), - <> = emqx_guid:gen(), - <> = emqx_guid:gen(), - X = ?BASE62:decode(?BASE62:encode(X), integer), - Y = ?BASE62:decode(?BASE62:encode(Y), integer), - <<"helloworld">> = ?BASE62:decode(?BASE62:encode("helloworld")), - "helloworld" = ?BASE62:decode(?BASE62:encode("helloworld", string), string). diff --git a/test/emqx_listeners_SUITE.erl b/test/emqx_listeners_SUITE.erl index 363a10db0..1cba68b74 100644 --- a/test/emqx_listeners_SUITE.erl +++ b/test/emqx_listeners_SUITE.erl @@ -19,16 +19,10 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("eunit/include/eunit.hrl"). - --include_lib("common_test/include/ct.hrl"). - -include("emqx.hrl"). -include("emqx_mqtt.hrl"). -all() -> - [start_stop_listeners, - restart_listeners]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> NewConfig = generate_config(), @@ -41,11 +35,11 @@ end_per_suite(_Config) -> application:stop(esockd), application:stop(cowboy). -start_stop_listeners(_) -> +t_start_stop_listeners(_) -> ok = emqx_listeners:start(), ok = emqx_listeners:stop(). -restart_listeners(_) -> +t_restart_listeners(_) -> ok = emqx_listeners:start(), ok = emqx_listeners:stop(), ok = emqx_listeners:restart(), @@ -95,3 +89,4 @@ get_base_dir(Module) -> get_base_dir() -> get_base_dir(?MODULE). + diff --git a/test/emqx_message_SUITE.erl b/test/emqx_message_SUITE.erl index 40d4c49bd..9c699b65d 100644 --- a/test/emqx_message_SUITE.erl +++ b/test/emqx_message_SUITE.erl @@ -16,7 +16,9 @@ -module(emqx_message_SUITE). --include("emqx.hrl"). +-compile(export_all). +-compile(nowarn_export_all). + -include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -32,17 +34,22 @@ , suite/0 ]). +all() -> emqx_ct:all(?MODULE). + +suite() -> + [{ct_hooks, [cth_surefire]}, {timetrap, {seconds, 30}}]. + t_make(_) -> Msg = emqx_message:make(<<"topic">>, <<"payload">>), - ?assertEqual(0, emqx_message:qos(Msg)), + ?assertEqual(?QOS_0, emqx_message:qos(Msg)), ?assertEqual(undefined, emqx_message:from(Msg)), ?assertEqual(<<"payload">>, emqx_message:payload(Msg)), Msg1 = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>), - ?assertEqual(0, emqx_message:qos(Msg1)), + ?assertEqual(?QOS_0, emqx_message:qos(Msg1)), ?assertEqual(<<"topic">>, emqx_message:topic(Msg1)), Msg2 = emqx_message:make(<<"clientid">>, ?QOS_2, <<"topic">>, <<"payload">>), ?assert(is_binary(emqx_message:id(Msg2))), - ?assertEqual(2, emqx_message:qos(Msg2)), + ?assertEqual(?QOS_2, emqx_message:qos(Msg2)), ?assertEqual(<<"clientid">>, emqx_message:from(Msg2)), ?assertEqual(<<"topic">>, emqx_message:topic(Msg2)), ?assertEqual(<<"payload">>, emqx_message:payload(Msg2)). @@ -86,21 +93,14 @@ t_expired(_) -> t_to_map(_) -> Msg = emqx_message:make(<<"clientid">>, ?QOS_1, <<"topic">>, <<"payload">>), - List = [{id, Msg#message.id}, + List = [{id, emqx_message:id(Msg)}, {qos, ?QOS_1}, {from, <<"clientid">>}, {flags, #{dup => false}}, {headers, #{}}, {topic, <<"topic">>}, {payload, <<"payload">>}, - {timestamp, Msg#message.timestamp}], + {timestamp, emqx_message:timestamp(Msg)}], ?assertEqual(List, emqx_message:to_list(Msg)), ?assertEqual(maps:from_list(List), emqx_message:to_map(Msg)). -all() -> - IsTestCase = fun("t_" ++ _) -> true; (_) -> false end, - [F || {F, _A} <- module_info(exports), IsTestCase(atom_to_list(F))]. - -suite() -> - [{ct_hooks, [cth_surefire]}, {timetrap, {seconds, 30}}]. - diff --git a/test/emqx_metrics_SUITE.erl b/test/emqx_metrics_SUITE.erl index 93f8923fa..cc7db5ad2 100644 --- a/test/emqx_metrics_SUITE.erl +++ b/test/emqx_metrics_SUITE.erl @@ -22,55 +22,64 @@ -include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). -all() -> [t_inc_dec, t_inc_recv, t_inc_sent, t_trans]. +all() -> emqx_ct:all(?MODULE). t_inc_dec(_) -> - {ok, _} = emqx_metrics:start_link(), - ?assertEqual(0, emqx_metrics:val('bytes.received')), - ?assertEqual(0, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:inc('bytes.received'), - ok = emqx_metrics:inc('bytes.received', 2), - ok = emqx_metrics:inc('bytes.received', 2), - ?assertEqual(5, emqx_metrics:val('bytes.received')), - ok = emqx_metrics:inc('messages.retained', 2), - ok = emqx_metrics:inc('messages.retained', 2), - ?assertEqual(4, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:dec('messages.retained'), - ok = emqx_metrics:dec('messages.retained', 1), - ?assertEqual(2, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:set('messages.retained', 3), - ?assertEqual(3, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:stop(). + with_metrics_server( + fun() -> + ?assertEqual(0, emqx_metrics:val('bytes.received')), + ?assertEqual(0, emqx_metrics:val('messages.retained')), + ok = emqx_metrics:inc('bytes.received'), + ok = emqx_metrics:inc('bytes.received', 2), + ok = emqx_metrics:inc('bytes.received', 2), + ?assertEqual(5, emqx_metrics:val('bytes.received')), + ok = emqx_metrics:inc('messages.retained', 2), + ok = emqx_metrics:inc('messages.retained', 2), + ?assertEqual(4, emqx_metrics:val('messages.retained')), + ok = emqx_metrics:dec('messages.retained'), + ok = emqx_metrics:dec('messages.retained', 1), + ?assertEqual(2, emqx_metrics:val('messages.retained')), + ok = emqx_metrics:set('messages.retained', 3), + ?assertEqual(3, emqx_metrics:val('messages.retained')) + end). t_inc_recv(_) -> - {ok, _} = emqx_metrics:start_link(), - ok = emqx_metrics:inc_recv(?PACKET(?CONNECT)), - ?assertEqual(1, emqx_metrics:val('packets.received')), - ?assertEqual(1, emqx_metrics:val('packets.connect.received')), - ok = emqx_metrics:stop(). + with_metrics_server( + fun() -> + ok = emqx_metrics:inc_recv(?PACKET(?CONNECT)), + ?assertEqual(1, emqx_metrics:val('packets.received')), + ?assertEqual(1, emqx_metrics:val('packets.connect.received')) + end). t_inc_sent(_) -> - {ok, _} = emqx_metrics:start_link(), - ok = emqx_metrics:inc_sent(?CONNACK_PACKET(0)), - ?assertEqual(1, emqx_metrics:val('packets.sent')), - ?assertEqual(1, emqx_metrics:val('packets.connack.sent')), - ok = emqx_metrics:stop(). + with_metrics_server( + fun() -> + ok = emqx_metrics:inc_sent(?CONNACK_PACKET(0)), + ?assertEqual(1, emqx_metrics:val('packets.sent')), + ?assertEqual(1, emqx_metrics:val('packets.connack.sent')) + end). t_trans(_) -> + with_metrics_server( + fun() -> + ok = emqx_metrics:trans(inc, 'bytes.received'), + ok = emqx_metrics:trans(inc, 'bytes.received', 2), + ?assertEqual(0, emqx_metrics:val('bytes.received')), + ok = emqx_metrics:trans(inc, 'messages.retained', 2), + ok = emqx_metrics:trans(inc, 'messages.retained', 2), + ?assertEqual(0, emqx_metrics:val('messages.retained')), + ok = emqx_metrics:commit(), + ?assertEqual(3, emqx_metrics:val('bytes.received')), + ?assertEqual(4, emqx_metrics:val('messages.retained')), + ok = emqx_metrics:trans(dec, 'messages.retained'), + ok = emqx_metrics:trans(dec, 'messages.retained', 1), + ?assertEqual(4, emqx_metrics:val('messages.retained')), + ok = emqx_metrics:commit(), + ?assertEqual(2, emqx_metrics:val('messages.retained')) + end). + +with_metrics_server(Fun) -> {ok, _} = emqx_metrics:start_link(), - ok = emqx_metrics:trans(inc, 'bytes.received'), - ok = emqx_metrics:trans(inc, 'bytes.received', 2), - ?assertEqual(0, emqx_metrics:val('bytes.received')), - ok = emqx_metrics:trans(inc, 'messages.retained', 2), - ok = emqx_metrics:trans(inc, 'messages.retained', 2), - ?assertEqual(0, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:commit(), - ?assertEqual(3, emqx_metrics:val('bytes.received')), - ?assertEqual(4, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:trans(dec, 'messages.retained'), - ok = emqx_metrics:trans(dec, 'messages.retained', 1), - ?assertEqual(4, emqx_metrics:val('messages.retained')), - ok = emqx_metrics:commit(), - ?assertEqual(2, emqx_metrics:val('messages.retained')), + _ = Fun(), ok = emqx_metrics:stop(). diff --git a/test/emqx_misc_tests.erl b/test/emqx_misc_SUITE.erl similarity index 76% rename from test/emqx_misc_tests.erl rename to test/emqx_misc_SUITE.erl index cc6d99550..c9a3929b6 100644 --- a/test/emqx_misc_tests.erl +++ b/test/emqx_misc_SUITE.erl @@ -14,7 +14,11 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqx_misc_tests). +-module(emqx_misc_SUITE). + +-compile(export_all). +-compile(nowarn_export_all). + -include_lib("eunit/include/eunit.hrl"). -define(SOCKOPTS, [binary, @@ -23,8 +27,9 @@ {backlog, 512}, {nodelay, true}]). +all() -> emqx_ct:all(?MODULE). -t_merge_opts_test() -> +t_merge_opts() -> Opts = emqx_misc:merge_opts(?SOCKOPTS, [raw, binary, {backlog, 1024}, @@ -41,33 +46,47 @@ t_merge_opts_test() -> {packet, raw}, {reuseaddr, true}] = lists:sort(Opts). -timer_cancel_flush_test() -> +t_timer_cancel_flush() -> Timer = emqx_misc:start_timer(0, foo), ok = emqx_misc:cancel_timer(Timer), - receive {timeout, Timer, foo} -> error(unexpected) + receive + {timeout, Timer, foo} -> + error(unexpected) after 0 -> ok end. -shutdown_disabled_test() -> +t_shutdown_disabled() -> ok = drain(), self() ! foo, - ?assertEqual(continue, conn_proc_mng_policy(0)), + ?assertEqual(continue, emqx_misc:conn_proc_mng_policy(0)), receive foo -> ok end, - ?assertEqual(hibernate, conn_proc_mng_policy(0)). + ?assertEqual(hibernate, emqx_misc:conn_proc_mng_policy(0)). -message_queue_too_long_test() -> +t_message_queue_too_long() -> ok = drain(), self() ! foo, self() ! bar, ?assertEqual({shutdown, message_queue_too_long}, - conn_proc_mng_policy(1)), + emqx_misc:conn_proc_mng_policy(1)), receive foo -> ok end, - ?assertEqual(continue, conn_proc_mng_policy(1)), + ?assertEqual(continue, emqx_misc:conn_proc_mng_policy(1)), receive bar -> ok end. -conn_proc_mng_policy(L) -> +t_conn_proc_mng_policy(L) -> emqx_misc:conn_proc_mng_policy(#{message_queue_len => L}). +t_proc_name(_) -> + 'TODO'. + +t_proc_stats(_) -> + 'TODO'. + +t_drain_deliver(_) -> + 'TODO'. + +t_drain_down(_) -> + 'TODO'. + %% drain self() msg queue for deterministic test behavior drain() -> _ = drain([]), % maybe log diff --git a/test/emqx_mock_client.erl b/test/emqx_mock_client.erl deleted file mode 100644 index dd2ae60b2..000000000 --- a/test/emqx_mock_client.erl +++ /dev/null @@ -1,101 +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_mock_client). - --behaviour(gen_server). - --export([start_link/1, open_session/3, open_session/4, - close_session/1, stop/1, get_last_message/1]). - --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). - --record(state, {clean_start, client_id, client_pid, last_msg, session_pid}). - -start_link(ClientId) -> - gen_server:start_link(?MODULE, [ClientId], []). - -open_session(ClientPid, ClientId, Zone) -> - open_session(ClientPid, ClientId, Zone, _Attrs = #{}). - -open_session(ClientPid, ClientId, Zone, Attrs0) -> - Attrs1 = default_session_attributes(Zone, ClientId, ClientPid), - Attrs = maps:merge(Attrs1, Attrs0), - gen_server:call(ClientPid, {start_session, ClientPid, ClientId, Attrs}). - -%% close session and terminate the client itself -close_session(ClientPid) -> - gen_server:call(ClientPid, stop_session, infinity). - -stop(CPid) -> - gen_server:call(CPid, stop, infinity). - -get_last_message(Pid) -> - gen_server:call(Pid, get_last_message, infinity). - -init([ClientId]) -> - erlang:process_flag(trap_exit, true), - {ok, #state{clean_start = true, - client_id = ClientId, - last_msg = undefined - } - }. - -handle_call({start_session, ClientPid, ClientId, Attrs}, _From, State) -> - {ok, SessPid} = emqx_sm:open_session(Attrs), - {reply, {ok, SessPid}, - State#state{clean_start = true, - client_id = ClientId, - client_pid = ClientPid, - session_pid = SessPid - }}; -handle_call(stop_session, _From, #state{session_pid = Pid} = State) -> - is_pid(Pid) andalso is_process_alive(Pid) andalso emqx_sm:close_session(Pid), - {stop, normal, ok, State#state{session_pid = undefined}}; -handle_call(get_last_message, _From, #state{last_msg = Msg} = State) -> - {reply, Msg, State}; -handle_call(stop, _From, State) -> - {stop, normal, ok, State}; -handle_call(_Request, _From, State) -> - {reply, ok, State}. - -handle_cast(_Msg, State) -> - {noreply, State}. - -handle_info({deliver, Msg}, State) -> - {noreply, State#state{last_msg = Msg}}; -handle_info(_Info, State) -> - {noreply, State}. - -terminate(_Reason, _State) -> - ok. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -default_session_attributes(Zone, ClientId, ClientPid) -> - #{zone => Zone, - client_id => ClientId, - conn_pid => ClientPid, - clean_start => true, - username => undefined, - expiry_interval => 0, - max_inflight => 0, - topic_alias_maximum => 0, - will_msg => undefined - }. - diff --git a/test/emqx_mod_SUITE.erl b/test/emqx_mod_SUITE.erl deleted file mode 100644 index 0a0a7fbea..000000000 --- a/test/emqx_mod_SUITE.erl +++ /dev/null @@ -1,27 +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_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx.hrl"). - -all() -> [mod_subscription_rep]. - -mod_subscription_rep(_) -> ok. - diff --git a/test/emqx_mod_rewrite_tests.erl b/test/emqx_mod_rewrite_tests.erl deleted file mode 100644 index 2778abf89..000000000 --- a/test/emqx_mod_rewrite_tests.erl +++ /dev/null @@ -1,65 +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_tests). - --include_lib("emqx.hrl"). --include_lib("eunit/include/eunit.hrl"). - - -rules() -> - Rawrules1 = "x/# ^x/y/(.+)$ z/y/$1", - Rawrules2 = "y/+/z/# ^y/(.+)/z/(.+)$ y/z/$2", - Rawrules = [Rawrules1, Rawrules2], - Rules = lists:map(fun(Rule) -> - [Topic, Re, Dest] = string:tokens(Rule, " "), - {rewrite, - list_to_binary(Topic), - list_to_binary(Re), - list_to_binary(Dest)} - end, Rawrules), - lists:map(fun({rewrite, Topic, Re, Dest}) -> - {ok, MP} = re:compile(Re), - {rewrite, Topic, MP, Dest} - end, Rules). - -rewrite_subscribe_test() -> - Rules = rules(), - io:format("Rules: ~p",[Rules]), - ?assertEqual({ok, [{<<"test">>, opts}]}, - emqx_mod_rewrite:rewrite_subscribe(credentials, [{<<"test">>, opts}], Rules)), - ?assertEqual({ok, [{<<"z/y/test">>, opts}]}, - emqx_mod_rewrite:rewrite_subscribe(credentials, [{<<"x/y/test">>, opts}], Rules)), - ?assertEqual({ok, [{<<"y/z/test_topic">>, opts}]}, - emqx_mod_rewrite:rewrite_subscribe(credentials, [{<<"y/test/z/test_topic">>, opts}], Rules)). - -rewrite_unsubscribe_test() -> - Rules = rules(), - ?assertEqual({ok, [{<<"test">>, opts}]}, - emqx_mod_rewrite:rewrite_subscribe(credentials, [{<<"test">>, opts}], Rules)), - ?assertEqual({ok, [{<<"z/y/test">>, opts}]}, - emqx_mod_rewrite:rewrite_subscribe(credentials, [{<<"x/y/test">>, opts}], Rules)), - ?assertEqual({ok, [{<<"y/z/test_topic">>, opts}]}, - emqx_mod_rewrite:rewrite_subscribe(credentials, [{<<"y/test/z/test_topic">>, opts}], Rules)). - -rewrite_publish_test() -> - Rules = rules(), - ?assertMatch({ok, #message{topic = <<"test">>}}, - emqx_mod_rewrite:rewrite_publish(#message{topic = <<"test">>}, Rules)), - ?assertMatch({ok, #message{topic = <<"z/y/test">>}}, - emqx_mod_rewrite:rewrite_publish(#message{topic = <<"x/y/test">>}, Rules)), - ?assertMatch({ok, #message{topic = <<"y/z/test_topic">>}}, - emqx_mod_rewrite:rewrite_publish(#message{topic = <<"y/test/z/test_topic">>}, Rules)). diff --git a/test/emqx_mod_sup_SUITE.erl b/test/emqx_mod_sup_SUITE.erl deleted file mode 100644 index 1e8c3d2c5..000000000 --- a/test/emqx_mod_sup_SUITE.erl +++ /dev/null @@ -1,45 +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_sup_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx.hrl"). - -all() -> [t_child_all]. - -start_link() -> - Pid = spawn_link(?MODULE, echo, [0]), - {ok, Pid}. - -echo(State) -> - receive - {From, Req} -> - ct:pal("======from:~p, req:~p", [From, Req]), - From ! Req, - echo(State) - end. - -t_child_all(_) -> - {ok, Pid} = emqx_mod_sup:start_link(), - {ok, Child} = emqx_mod_sup:start_child(?MODULE, worker), - timer:sleep(10), - Child ! {self(), hi}, - receive hi -> ok after 100 -> ct:fail({timeout, wait_echo}) end, - ok = emqx_mod_sup:stop_child(?MODULE), - exit(Pid, normal). diff --git a/test/emqx_mountpoint_SUITE.erl b/test/emqx_mountpoint_SUITE.erl index 73e9d387f..bb1f40db4 100644 --- a/test/emqx_mountpoint_SUITE.erl +++ b/test/emqx_mountpoint_SUITE.erl @@ -19,20 +19,49 @@ -compile(export_all). -compile(nowarn_export_all). --include("emqx.hrl"). --include("emqx_mqtt.hrl"). +-import(emqx_mountpoint, + [ mount/2 + , unmount/2 + , replvar/2 + ]). +-include("emqx.hrl"). -include_lib("eunit/include/eunit.hrl"). -all() -> [t_mount_unmount, t_replvar]. +all() -> emqx_ct:all(?MODULE). -t_mount_unmount(_) -> +t_mount(_) -> Msg = emqx_message:make(<<"clientid">>, <<"topic">>, <<"payload">>), - Msg2 = emqx_mountpoint:mount(<<"mount">>, Msg), - ?assertEqual(<<"mounttopic">>, Msg2#message.topic), - TopicFilter = [{<<"mounttopic">>, #{qos => ?QOS_2}}], - TopicFilter = emqx_mountpoint:mount(<<"mount">>, [{<<"topic">>, #{qos => ?QOS_2}}]), - Msg = emqx_mountpoint:unmount(<<"mount">>, Msg2). + TopicFilters = [{<<"topic">>, #{qos => 2}}], + ?assertEqual(<<"topic">>, mount(undefined, <<"topic">>)), + ?assertEqual(Msg, mount(undefined, Msg)), + ?assertEqual(TopicFilters, mount(undefined, TopicFilters)), + ?assertEqual(<<"device/1/topic">>, + mount(<<"device/1/">>, <<"topic">>)), + ?assertEqual(Msg#message{topic = <<"device/1/topic">>}, + mount(<<"device/1/">>, Msg)), + ?assertEqual([{<<"device/1/topic">>, #{qos => 2}}], + mount(<<"device/1/">>, TopicFilters)). + +t_unmount(_) -> + Msg = emqx_message:make(<<"clientid">>, <<"device/1/topic">>, <<"payload">>), + ?assertEqual(<<"topic">>, unmount(undefined, <<"topic">>)), + ?assertEqual(Msg, unmount(undefined, Msg)), + ?assertEqual(<<"topic">>, unmount(<<"device/1/">>, <<"device/1/topic">>)), + ?assertEqual(Msg#message{topic = <<"topic">>}, unmount(<<"device/1/">>, Msg)), + ?assertEqual(<<"device/1/topic">>, unmount(<<"device/2/">>, <<"device/1/topic">>)), + ?assertEqual(Msg#message{topic = <<"device/1/topic">>}, unmount(<<"device/2/">>, Msg)). t_replvar(_) -> - <<"mount/test/clientid">> = emqx_mountpoint:replvar(<<"mount/%u/%c">>, #{client_id => <<"clientid">>, username => <<"test">>}). + ?assertEqual(undefined, replvar(undefined, #{})), + ?assertEqual(<<"mount/user/clientid/">>, + replvar(<<"mount/%u/%c/">>, + #{client_id => <<"clientid">>, + username => <<"user">> + })), + ?assertEqual(<<"mount/%u/clientid/">>, + replvar(<<"mount/%u/%c/">>, + #{client_id => <<"clientid">>, + username => undefined + })). + diff --git a/test/emqx_mqtt_caps_SUITE.erl b/test/emqx_mqtt_caps_SUITE.erl deleted file mode 100644 index d47f41417..000000000 --- a/test/emqx_mqtt_caps_SUITE.erl +++ /dev/null @@ -1,133 +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_mqtt_caps_SUITE). - --include_lib("eunit/include/eunit.hrl"). - --include("emqx.hrl"). --include("emqx_mqtt.hrl"). - -%% CT --compile(export_all). --compile(nowarn_export_all). - -all() -> [t_get_set_caps, t_check_pub, t_check_sub]. - -t_get_set_caps(_) -> - {ok, _} = emqx_zone:start_link(), - Caps = #{ - max_packet_size => ?MAX_PACKET_SIZE, - max_clientid_len => ?MAX_CLIENTID_LEN, - max_topic_alias => 0, - max_topic_levels => 0, - max_qos_allowed => ?QOS_2, - mqtt_retain_available => true, - mqtt_shared_subscription => true, - mqtt_wildcard_subscription => true - }, - Caps2 = Caps#{max_packet_size => 1048576}, - case emqx_mqtt_caps:get_caps(zone) of - Caps -> ok; - Caps2 -> ok - end, - PubCaps = #{ - max_qos_allowed => ?QOS_2, - mqtt_retain_available => true, - max_topic_alias => 0 - }, - PubCaps = emqx_mqtt_caps:get_caps(zone, publish), - NewPubCaps = PubCaps#{max_qos_allowed => ?QOS_1}, - emqx_zone:set_env(zone, '$mqtt_pub_caps', NewPubCaps), - timer:sleep(100), - NewPubCaps = emqx_mqtt_caps:get_caps(zone, publish), - SubCaps = #{ - max_topic_levels => 0, - max_qos_allowed => ?QOS_2, - mqtt_shared_subscription => true, - mqtt_wildcard_subscription => true - }, - SubCaps = emqx_mqtt_caps:get_caps(zone, subscribe), - emqx_zone:stop(). - -t_check_pub(_) -> - {ok, _} = emqx_zone:start_link(), - PubCaps = #{ - max_qos_allowed => ?QOS_1, - mqtt_retain_available => false, - max_topic_alias => 4 - }, - emqx_zone:set_env(zone, '$mqtt_pub_caps', PubCaps), - timer:sleep(100), - ct:log("~p", [emqx_mqtt_caps:get_caps(zone, publish)]), - BadPubProps1 = #{ - qos => ?QOS_2, - retain => false - }, - {error, ?RC_QOS_NOT_SUPPORTED} = emqx_mqtt_caps:check_pub(zone, BadPubProps1), - BadPubProps2 = #{ - qos => ?QOS_1, - retain => true - }, - {error, ?RC_RETAIN_NOT_SUPPORTED} = emqx_mqtt_caps:check_pub(zone, BadPubProps2), - BadPubProps3 = #{ - qos => ?QOS_1, - retain => false, - topic_alias => 5 - }, - {error, ?RC_TOPIC_ALIAS_INVALID} = emqx_mqtt_caps:check_pub(zone, BadPubProps3), - PubProps = #{ - qos => ?QOS_1, - retain => false - }, - ok = emqx_mqtt_caps:check_pub(zone, PubProps), - emqx_zone:stop(). - -t_check_sub(_) -> - {ok, _} = emqx_zone:start_link(), - - Opts = #{qos => ?QOS_2, share => true, rc => 0}, - Caps = #{ - max_topic_levels => 0, - max_qos_allowed => ?QOS_2, - mqtt_shared_subscription => true, - mqtt_wildcard_subscription => true - }, - - ok = do_check_sub([{<<"client/stat">>, Opts}], [{<<"client/stat">>, Opts}]), - ok = do_check_sub(Caps#{max_qos_allowed => ?QOS_1}, [{<<"client/stat">>, Opts}], [{<<"client/stat">>, Opts#{qos => ?QOS_1}}]), - ok = do_check_sub(Caps#{max_topic_levels => 1}, - [{<<"client/stat">>, Opts}], - [{<<"client/stat">>, Opts#{rc => ?RC_TOPIC_FILTER_INVALID}}]), - ok = do_check_sub(Caps#{mqtt_shared_subscription => false}, - [{<<"client/stat">>, Opts}], - [{<<"client/stat">>, Opts#{rc => ?RC_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED}}]), - - ok = do_check_sub(Caps#{mqtt_wildcard_subscription => false}, - [{<<"vlient/+/dsofi">>, Opts}], - [{<<"vlient/+/dsofi">>, Opts#{rc => ?RC_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED}}]), - emqx_zone:stop(). - - - -do_check_sub(TopicFilters, Topics) -> - {ok, Topics} = emqx_mqtt_caps:check_sub(zone, TopicFilters), - ok. -do_check_sub(Caps, TopicFilters, Topics) -> - emqx_zone:set_env(zone, '$mqtt_sub_caps', Caps), - timer:sleep(100), - {_, Topics} = emqx_mqtt_caps:check_sub(zone, TopicFilters), - ok. diff --git a/test/emqx_mqtt_packet_SUITE.erl b/test/emqx_mqtt_packet_SUITE.erl deleted file mode 100644 index 3f249e7b0..000000000 --- a/test/emqx_mqtt_packet_SUITE.erl +++ /dev/null @@ -1,117 +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_mqtt_packet_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --import(emqx_frame, [serialize/1]). - --include("emqx_mqtt.hrl"). - --include_lib("eunit/include/eunit.hrl"). - --define(INVALID_RESERVED, 1). - --define(CONNECT_INVALID_PACKET(Var), - #mqtt_packet{header = #mqtt_packet_header{type = ?INVALID_RESERVED}, - variable = Var}). - --define(CASE1_PROTOCOL_NAME, ?CONNECT_PACKET(#mqtt_packet_connect{ - proto_name = <<"MQTC">>, - client_id = <<"mqtt_protocol_name">>, - username = <<"admin">>, - password = <<"public">>})). - --define(CASE2_PROTOCAL_VER, ?CONNECT_PACKET(#mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - proto_ver = 6, - username = <<"admin">>, - password = <<"public">>})). - --define(CASE3_PROTOCAL_INVALID_RESERVED, ?CONNECT_INVALID_PACKET(#mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - proto_ver = 5, - username = <<"admin">>, - password = <<"public">>})). - --define(PROTOCOL5, ?CONNECT_PACKET(#mqtt_packet_connect{ - proto_ver = 5, - keepalive = 60, - properties = #{'Message-Expiry-Interval' => 3600}, - client_id = <<"mqtt_client">>, - will_topic = <<"will_tipic">>, - will_payload = <<"will message">>, - username = <<"admin">>, - password = <<"public">>})). - - - -all() -> [{group, connect}]. - -groups() -> [{connect, [sequence], - [case1_protocol_name, - case2_protocol_ver%, - %TOTO case3_invalid_reserved - ]}]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -init_per_group(_Group, Config) -> - Config. - -end_per_group(_Group, _Config) -> - ok. - -case1_protocol_name(_) -> - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - MqttPacket = serialize(?CASE1_PROTOCOL_NAME), - emqx_client_sock:send(Sock, MqttPacket), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?CONNACK_PROTO_VER), <<>>, _} = raw_recv_pase(Data), - Disconnect = gen_tcp:recv(Sock, 0), - ?assertEqual({error, closed}, Disconnect). - -case2_protocol_ver(_) -> - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - Packet = serialize(?CASE2_PROTOCAL_VER), - emqx_client_sock:send(Sock, Packet), - {ok, Data} = gen_tcp:recv(Sock, 0), - %% case1 Unacceptable protocol version - {ok, ?CONNACK_PACKET(?CONNACK_PROTO_VER), <<>>, _} = raw_recv_pase(Data), - Disconnect = gen_tcp:recv(Sock, 0), - ?assertEqual({error, closed}, Disconnect). - -case3_invalid_reserved(_) -> - {ok, Sock} = emqx_client_sock:connect({127,0,0,1}, 1883, [binary, {packet, raw}, {active, false}], 3000), - Packet = serialize(?CASE3_PROTOCAL_INVALID_RESERVED), - emqx_client_sock:send(Sock, Packet), - {ok, Data} = gen_tcp:recv(Sock, 0), - %% case1 Unacceptable protocol version - ct:log("Data:~p~n", [raw_recv_pase(Data)]), - {ok, ?CONNACK_PACKET(?CONNACK_PROTO_VER), _} = raw_recv_pase(Data), - Disconnect = gen_tcp:recv(Sock, 0), - ?assertEqual({error, closed}, Disconnect). - -raw_recv_pase(P) -> - emqx_frame:parse(P, {none, #{max_packet_size => ?MAX_PACKET_SIZE, - version => ?MQTT_PROTO_V4} }). diff --git a/test/emqx_mqtt_props_SUITE.erl b/test/emqx_mqtt_props_SUITE.erl index 23869691d..b1a1b04b4 100644 --- a/test/emqx_mqtt_props_SUITE.erl +++ b/test/emqx_mqtt_props_SUITE.erl @@ -21,9 +21,21 @@ -include("emqx_mqtt.hrl"). -all() -> [t_mqtt_properties_all]. +all() -> emqx_ct:all(?MODULE). -t_mqtt_properties_all(_) -> +t_id(_) -> + 'TODO'. + +t_name(_) -> + 'TODO'. + +t_filter(_) -> + 'TODO'. + +t_validate(_) -> + 'TODO'. + +deprecated_mqtt_properties_all(_) -> Props = emqx_mqtt_props:filter(?CONNECT, #{'Session-Expiry-Interval' => 1, 'Maximum-Packet-Size' => 255}), ok = emqx_mqtt_props:validate(Props), #{} = emqx_mqtt_props:filter(?CONNECT, #{'Maximum-QoS' => ?QOS_2}). diff --git a/test/emqx_mqueue_SUITE.erl b/test/emqx_mqueue_SUITE.erl index f94ca5a5f..cd15b1b8e 100644 --- a/test/emqx_mqueue_SUITE.erl +++ b/test/emqx_mqueue_SUITE.erl @@ -26,8 +26,7 @@ -define(Q, emqx_mqueue). -all() -> [t_in, t_in_qos0, t_out, t_simple_mqueue, t_infinity_simple_mqueue, - t_priority_mqueue, t_infinity_priority_mqueue]. +all() -> emqx_ct:all(?MODULE). t_in(_) -> Opts = #{max_len => 5, store_qos0 => true}, @@ -130,15 +129,18 @@ t_infinity_priority_mqueue(_) -> ?assertEqual(510, ?Q:len(Qx)), ?assertEqual([{len, 510}, {max_len, 0}, {dropped, 0}], ?Q:stats(Qx)). -t_priority_mqueue2(_) -> - Opts = #{max_length => 2, store_qos0 => false}, - Q = ?Q:init("priority_queue2_test", Opts), +%%TODO: fixme later +t_length_priority_mqueue(_) -> + Opts = #{max_len => 2, + store_qos0 => false + }, + Q = ?Q:init(Opts), 2 = ?Q:max_len(Q), {_, Q1} = ?Q:in(#message{topic = <<"x">>, qos = 1, payload = <<1>>}, Q), {_, Q2} = ?Q:in(#message{topic = <<"x">>, qos = 1, payload = <<2>>}, Q1), {_, Q3} = ?Q:in(#message{topic = <<"y">>, qos = 1, payload = <<3>>}, Q2), {_, Q4} = ?Q:in(#message{topic = <<"y">>, qos = 1, payload = <<4>>}, Q3), - 4 = ?Q:len(Q4), + ?assertEqual(2, ?Q:len(Q4)), {{value, _Val}, Q5} = ?Q:out(Q4), - 3 = ?Q:len(Q5). + ?assertEqual(1, ?Q:len(Q5)). diff --git a/test/emqx_os_mon_SUITE.erl b/test/emqx_os_mon_SUITE.erl index e14d9e734..7d816000f 100644 --- a/test/emqx_os_mon_SUITE.erl +++ b/test/emqx_os_mon_SUITE.erl @@ -21,9 +21,7 @@ -include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - -all() -> [t_api]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> application:ensure_all_started(os_mon), @@ -56,3 +54,4 @@ t_api(_) -> % timer:sleep(3000), % ?assertEqual(false, lists:keymember(cpu_high_watermark, 1, alarm_handler:get_alarms())), ok. + diff --git a/test/emqx_packet_SUITE.erl b/test/emqx_packet_SUITE.erl index 01a9f0ffa..b334093b8 100644 --- a/test/emqx_packet_SUITE.erl +++ b/test/emqx_packet_SUITE.erl @@ -20,35 +20,28 @@ -compile(nowarn_export_all). -include("emqx.hrl"). - -include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). -all() -> - [ - packet_proto_name, - packet_type_name, - packet_validate, - packet_message, - packet_format, - packet_will_msg - ]. +all() -> emqx_ct:all(?MODULE). -packet_proto_name(_) -> +t_proto_name(_) -> ?assertEqual(<<"MQIsdp">>, emqx_packet:protocol_name(3)), ?assertEqual(<<"MQTT">>, emqx_packet:protocol_name(4)), ?assertEqual(<<"MQTT">>, emqx_packet:protocol_name(5)). -packet_type_name(_) -> - ?assertEqual('CONNECT', emqx_packet:type_name(?CONNECT)), +t_type_name(_) -> + ?assertEqual('CONNECT', emqx_packet:type_name(?CONNECT)), ?assertEqual('UNSUBSCRIBE', emqx_packet:type_name(?UNSUBSCRIBE)). -packet_validate(_) -> - ?assert(emqx_packet:validate(?SUBSCRIBE_PACKET(15, #{'Subscription-Identifier' => 1}, [{<<"topic">>, #{qos => ?QOS_0}}]))), +t_validate(_) -> + ?assert(emqx_packet:validate(?SUBSCRIBE_PACKET(15, #{'Subscription-Identifier' => 1}, + [{<<"topic">>, #{qos => ?QOS_0}}]))), ?assert(emqx_packet:validate(?UNSUBSCRIBE_PACKET(89, [<<"topic">>]))), ?assert(emqx_packet:validate(?CONNECT_PACKET(#mqtt_packet_connect{}))), - ?assert(emqx_packet:validate(?PUBLISH_PACKET(1, <<"topic">>, 1, #{'Response-Topic' => <<"responsetopic">>, 'Topic-Alias' => 1}, <<"payload">>))), + Props = #{'Response-Topic' => <<"responsetopic">>, 'Topic-Alias' => 1}, + ?assert(emqx_packet:validate(?PUBLISH_PACKET(?QOS_1, <<"topic">>, 1, Props, <<"payload">>))), ?assert(emqx_packet:validate(?CONNECT_PACKET(#mqtt_packet_connect{properties = #{'Receive-Maximum' => 1}}))), ?assertError(subscription_identifier_invalid, emqx_packet:validate( @@ -89,7 +82,7 @@ packet_validate(_) -> properties = #{'Receive-Maximum' => 0}}))). -packet_message(_) -> +t_from_to_message(_) -> Pkt = #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH, qos = ?QOS_0, retain = false, @@ -111,7 +104,7 @@ packet_message(_) -> Msg5 = Msg4#message{timestamp = Msg3#message.timestamp, id = Msg3#message.id}, Msg5 = Msg3. -packet_format(_) -> +t_packet_format(_) -> io:format("~s", [emqx_packet:format(?CONNECT_PACKET(#mqtt_packet_connect{}))]), io:format("~s", [emqx_packet:format(?CONNACK_PACKET(?CONNACK_SERVER))]), io:format("~s", [emqx_packet:format(?PUBLISH_PACKET(?QOS_1, 1))]), @@ -123,15 +116,17 @@ packet_format(_) -> io:format("~s", [emqx_packet:format(?UNSUBSCRIBE_PACKET(89, [<<"t">>, <<"t2">>]))]), io:format("~s", [emqx_packet:format(?UNSUBACK_PACKET(90))]). -packet_will_msg(_) -> - Pkt = #mqtt_packet_connect{ will_flag = true, - client_id = <<"clientid">>, - username = "test", - will_retain = true, - will_qos = ?QOS_2, - will_topic = <<"topic">>, - will_props = #{}, - will_payload = <<"payload">>}, +t_will_msg(_) -> + Pkt = #mqtt_packet_connect{will_flag = true, + client_id = <<"clientid">>, + username = "test", + will_retain = true, + will_qos = ?QOS_2, + will_topic = <<"topic">>, + will_props = #{}, + will_payload = <<"payload">> + }, Msg = emqx_packet:will_msg(Pkt), ?assertEqual(<<"clientid">>, Msg#message.from), ?assertEqual(<<"topic">>, Msg#message.topic). + diff --git a/test/emqx_pd_SUITE.erl b/test/emqx_pd_SUITE.erl index 741e6bd04..7c08d7f18 100644 --- a/test/emqx_pd_SUITE.erl +++ b/test/emqx_pd_SUITE.erl @@ -21,9 +21,9 @@ -include_lib("eunit/include/eunit.hrl"). -all() -> [update_counter]. +all() -> emqx_ct:all(?MODULE). -update_counter(_) -> +t_update_counter(_) -> ?assertEqual(undefined, emqx_pd:update_counter(bytes, 1)), ?assertEqual(1, emqx_pd:update_counter(bytes, 1)), ?assertEqual(2, emqx_pd:update_counter(bytes, 1)), diff --git a/test/emqx_pmon_SUITE.erl b/test/emqx_pmon_SUITE.erl index a46605180..f0c7ef64d 100644 --- a/test/emqx_pmon_SUITE.erl +++ b/test/emqx_pmon_SUITE.erl @@ -21,8 +21,7 @@ -include_lib("eunit/include/eunit.hrl"). -all() -> - [t_monitor, t_find, t_erase]. +all() -> emqx_ct:all(?MODULE). t_monitor(_) -> PMon = emqx_pmon:new(), diff --git a/test/emqx_pool_SUITE.erl b/test/emqx_pool_SUITE.erl index 5eeb86e97..8ec9d6941 100644 --- a/test/emqx_pool_SUITE.erl +++ b/test/emqx_pool_SUITE.erl @@ -19,20 +19,23 @@ -compile(export_all). -compile(nowarn_export_all). --include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). all() -> - [ - {group, submit_case}, - {group, async_submit_case}, + [{group, submit}, + {group, async_submit}, t_unexpected ]. groups() -> - [ - {submit_case, [sequence], [submit_mfa, submit_fa]}, - {async_submit_case, [sequence], [async_submit_mfa, async_submit_crash]} + [{submit, [sequence], + [t_submit_mfa, + t_submit_fa + ]}, + {async_submit, [sequence], + [t_async_submit_mfa, + t_async_submit_crash + ]} ]. init_per_suite(Config) -> @@ -48,22 +51,28 @@ init_per_testcase(_, Config) -> end_per_testcase(_, Config) -> Sup = proplists:get_value(pool_sup, Config), + %% ??? exit(Sup, normal). -submit_mfa(_Config) -> +t_submit_mfa(_Config) -> Result = emqx_pool:submit({?MODULE, test_mfa, []}), ?assertEqual(15, Result). -submit_fa(_Config) -> - Fun = fun(X) -> case X rem 2 of 0 -> {true, X div 2}; _ -> false end end, +t_submit_fa(_Config) -> + Fun = fun(X) -> + case X rem 2 of + 0 -> {true, X div 2}; + _ -> false + end + end, Result = emqx_pool:submit(Fun, [2]), ?assertEqual({true, 1}, Result). -async_submit_mfa(_Config) -> +t_async_submit_mfa(_Config) -> emqx_pool:async_submit({?MODULE, test_mfa, []}), emqx_pool:async_submit(fun ?MODULE:test_mfa/0, []). -async_submit_crash(_) -> +t_async_submit_crash(_) -> emqx_pool:async_submit(fun() -> error(unexpected_error) end). t_unexpected(_) -> diff --git a/test/emqx_pqueue_SUITE.erl b/test/emqx_pqueue_SUITE.erl index 5f30d9ebc..3960f7e26 100644 --- a/test/emqx_pqueue_SUITE.erl +++ b/test/emqx_pqueue_SUITE.erl @@ -16,15 +16,15 @@ -module(emqx_pqueue_SUITE). --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - -compile(export_all). -compile(nowarn_export_all). --define(PQ, emqx_pqueue). +-include_lib("eunit/include/eunit.hrl"). -all() -> [t_priority_queue_plen, t_priority_queue_out2, t_priority_queues]. +-define(PQ, emqx_pqueue). +-define(SUITE, ?MODULE). + +all() -> emqx_ct:all(?SUITE). t_priority_queue_plen(_) -> Q = ?PQ:new(), @@ -87,7 +87,7 @@ t_priority_queues(_) -> [{1, c}, {1, d}, {0, a}, {0, b}] = ?PQ:to_list(PQueue4), PQueue4 = ?PQ:from_list([{1, c}, {1, d}, {0, a}, {0, b}]), - + empty = ?PQ:highest(?PQ:new()), 0 = ?PQ:highest(PQueue1), 1 = ?PQ:highest(PQueue4), @@ -122,4 +122,3 @@ t_priority_queues(_) -> {pqueue,[{-1,{queue,[f],[d,f,d],4}}, {0,{queue,[b],[a,b,a],4}}]} = ?PQ:join(PQueue8, PQueue8). - diff --git a/test/emqx_protocol_SUITE.erl b/test/emqx_protocol_SUITE.erl deleted file mode 100644 index d0de0ccc1..000000000 --- a/test/emqx_protocol_SUITE.erl +++ /dev/null @@ -1,613 +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_protocol_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - --include_lib("common_test/include/ct.hrl"). - --include("emqx_mqtt.hrl"). - --define(TOPICS, [<<"TopicA">>, <<"TopicA/B">>, <<"Topic/C">>, <<"TopicA/C">>, - <<"/TopicA">>]). - --define(CLIENT, ?CONNECT_PACKET(#mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - username = <<"emqx">>, - password = <<"public">>})). - -all() -> - [{group, mqtt_common}, - {group, mqttv4}, - {group, mqttv5}, - {group, acl}, - {group, frame_partial}]. - -groups() -> - [{mqtt_common, [sequence], - [will_topic_check, - will_acl_check]}, - {mqttv4, [sequence], - [connect_v4, - subscribe_v4]}, - {mqttv5, [sequence], - [connect_v5, - subscribe_v5]}, - {acl, [sequence], - [acl_deny_action_ct]}, - {frame_partial, [sequence], - [handle_followed_packet]}]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([], fun set_special_configs/1), - MqttCaps = maps:from_list(emqx_mqtt_caps:default_caps()), - emqx_zone:set_env(external, '$mqtt_caps', MqttCaps#{max_topic_alias => 20}), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -batch_connect(NumberOfConnections) -> - batch_connect([], NumberOfConnections). - -batch_connect(Socks, 0) -> - Socks; -batch_connect(Socks, NumberOfConnections) -> - {ok, Sock} = emqx_client_sock:connect({127, 0, 0, 1}, 1883, - [binary, {packet, raw}, {active, false}], - 3000), - batch_connect([Sock | Socks], NumberOfConnections - 1). - -with_connection(DoFun, NumberOfConnections) -> - Socks = batch_connect(NumberOfConnections), - try - DoFun(Socks) - after - lists:foreach(fun(Sock) -> - emqx_client_sock:close(Sock) - end, Socks) - end. - -with_connection(DoFun) -> - with_connection(DoFun, 1). - -handle_followed_packet(_Config) -> - ConnPkt = <<16,12,0,4,77,81,84,84,4,2,0,60,0,0>>, - PartialPkt1 = <<50,182,1,0,4,116,101,115,116,0,1,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48>>, - PartialPkt2 = <<48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48>>, - - %% This is a PUBLISH message (Qos=1) - PubPkt = <>, - ComplexPkt = <>, - - AssertConnAck = fun(R) -> ?assertEqual({ok, <<32,2,0,0>>}, R) end, - AssertPubAck = fun(R) -> ?assertEqual({ok, <<64,2,0,1>>}, R) end, - - {ok, Sock} = gen_tcp:connect("127.0.0.1", 1883, [{active, false}, binary]), - - %% CONNECT - ok = gen_tcp:send(Sock, ConnPkt), - AssertConnAck(gen_tcp:recv(Sock, 4, 500)), - - %% Once Publish - ok = gen_tcp:send(Sock, PubPkt), - AssertPubAck(gen_tcp:recv(Sock, 4, 500)), - - %% Complex Packet - ok = gen_tcp:send(Sock, ComplexPkt), - AssertPubAck(gen_tcp:recv(Sock, 4, 500)), - AssertPubAck(gen_tcp:recv(Sock, 4, 500)), - AssertPubAck(gen_tcp:recv(Sock, 4, 500)), - - ok = gen_tcp:send(Sock, PartialPkt2), - AssertPubAck(gen_tcp:recv(Sock, 4, 500)), - gen_tcp:close(Sock). - -connect_v4(_) -> - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, raw_send_serialize(?PACKET(?PUBLISH))), - {error, closed} =gen_tcp:recv(Sock, 0) - end), - with_connection(fun([Sock]) -> - ConnectPacket = raw_send_serialize(?CONNECT_PACKET - (#mqtt_packet_connect{ - client_id = <<"mqttv4_client">>, - username = <<"admin">>, - password = <<"public">>, - proto_ver = ?MQTT_PROTO_V4 - })), - emqx_client_sock:send(Sock, ConnectPacket), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V4), - - emqx_client_sock:send(Sock, ConnectPacket), - {error, closed} = gen_tcp:recv(Sock, 0) - end), - ok. - - -connect_v5(_) -> - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET(#mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - properties = - #{'Request-Response-Information' => -1}}))), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?DISCONNECT_PACKET(?RC_PROTOCOL_ERROR), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5) - end), - - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - properties = - #{'Request-Problem-Information' => 2}}))), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?DISCONNECT_PACKET(?RC_PROTOCOL_ERROR), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5) - end), - - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - properties = - #{'Request-Response-Information' => 1}}) - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0, Props), <<>>, _} = - raw_recv_parse(Data, ?MQTT_PROTO_V5), - ?assertNot(maps:is_key('Response-Information', Props)) - end), - - % topic alias = 0 - with_connection(fun([Sock]) -> - - %% ct:log("emqx_protocol: ~p~n", [emqx_zone:get_zone(external, max_topic_alias)]), - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - client_id = "hello", - proto_ver = ?MQTT_PROTO_V5, - properties = - #{'Topic-Alias-Maximum' => 10}}), - #{version => ?MQTT_PROTO_V5} - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0, - #{'Topic-Alias-Maximum' := 20}), <<>>, _} = - raw_recv_parse(Data, ?MQTT_PROTO_V5), - emqx_client_sock:send(Sock, - raw_send_serialize( - ?PUBLISH_PACKET(?QOS_1, <<"TopicA">>, 1, #{'Topic-Alias' => 0}, <<"hello">>), - #{version => ?MQTT_PROTO_V5} - )), - - {ok, Data2} = gen_tcp:recv(Sock, 0), - {ok, ?DISCONNECT_PACKET(?RC_TOPIC_ALIAS_INVALID), <<>>, _} = raw_recv_parse(Data2, ?MQTT_PROTO_V5) - end), - - % topic alias maximum - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - properties = - #{'Topic-Alias-Maximum' => 10}}), - #{version => ?MQTT_PROTO_V5} - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0, - #{'Topic-Alias-Maximum' := 20}), <<>>, _} = - raw_recv_parse(Data, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock, raw_send_serialize(?SUBSCRIBE_PACKET(1, [{<<"TopicA">>, #{rh => 1, - qos => ?QOS_2, - rap => 0, - nl => 0, - rc => 0}}]), #{version => ?MQTT_PROTO_V5})), - - {ok, Data2} = gen_tcp:recv(Sock, 0), - {ok, ?SUBACK_PACKET(1, #{}, [2]), <<>>, _} = raw_recv_parse(Data2, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock, - raw_send_serialize( - ?PUBLISH_PACKET(?QOS_1, <<"TopicA">>, 1, #{'Topic-Alias' => 15}, <<"hello">>), - #{version => ?MQTT_PROTO_V5} - )), - - {ok, Data3} = gen_tcp:recv(Sock, 6), - - {ok, ?PUBACK_PACKET(1, 0), <<>>, _} = raw_recv_parse(Data3, ?MQTT_PROTO_V5), - - {ok, Data4} = gen_tcp:recv(Sock, 0), - - {ok, ?PUBLISH_PACKET(?QOS_1, <<"TopicA">>, _, <<"hello">>), <<>>, _} = raw_recv_parse(Data4, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock, - raw_send_serialize( - ?PUBLISH_PACKET(?QOS_1, <<"TopicA">>, 2, #{'Topic-Alias' => 21}, <<"hello">>), - #{version => ?MQTT_PROTO_V5} - )), - - {ok, Data5} = gen_tcp:recv(Sock, 0), - {ok, ?DISCONNECT_PACKET(?RC_TOPIC_ALIAS_INVALID), <<>>, _} = raw_recv_parse(Data5, ?MQTT_PROTO_V5) - end), - - % test clean start - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - clean_start = true, - client_id = <<"myclient">>, - properties = - #{'Session-Expiry-Interval' => 10}}) - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5), - emqx_client_sock:send(Sock, raw_send_serialize( - ?DISCONNECT_PACKET(?RC_SUCCESS) - )) - end), - - timer:sleep(1000), - - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - clean_start = false, - client_id = <<"myclient">>, - properties = - #{'Session-Expiry-Interval' => 10}}) - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 1), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5) - end), - - % test will message publish and cancel - with_connection(fun([Sock]) -> - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - clean_start = true, - client_id = <<"myclient">>, - will_flag = true, - will_qos = ?QOS_1, - will_retain = false, - will_props = #{'Will-Delay-Interval' => 5}, - will_topic = <<"TopicA">>, - will_payload = <<"will message">>, - properties = #{'Session-Expiry-Interval' => 0} - } - ) - ) - ), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5), - - {ok, Sock2} = emqx_client_sock:connect({127, 0, 0, 1}, 1883, - [binary, {packet, raw}, - {active, false}], 3000), - - do_connect(Sock2, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock2, raw_send_serialize(?SUBSCRIBE_PACKET(1, [{<<"TopicA">>, #{rh => 1, - qos => ?QOS_2, - rap => 0, - nl => 0, - rc => 0}}]), #{version => ?MQTT_PROTO_V5})), - - {ok, SubData} = gen_tcp:recv(Sock2, 0), - {ok, ?SUBACK_PACKET(1, #{}, [2]), <<>>, _} = raw_recv_parse(SubData, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock, raw_send_serialize( - ?DISCONNECT_PACKET(?RC_SUCCESS))), - - {error, timeout} = gen_tcp:recv(Sock2, 0, 2000), - - % session resumed - {ok, Sock3} = emqx_client_sock:connect({127, 0, 0, 1}, 1883, - [binary, {packet, raw}, - {active, false}], 3000), - - emqx_client_sock:send(Sock3, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - clean_start = false, - client_id = <<"myclient">>, - will_flag = true, - will_qos = ?QOS_1, - will_retain = false, - will_props = #{'Will-Delay-Interval' => 5}, - will_topic = <<"TopicA">>, - will_payload = <<"will message 2">>, - properties = #{'Session-Expiry-Interval' => 3} - } - ), - #{version => ?MQTT_PROTO_V5} - ) - ), - {ok, Data3} = gen_tcp:recv(Sock3, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0), <<>>, _} = raw_recv_parse(Data3, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock3, raw_send_serialize( - ?DISCONNECT_PACKET(?RC_DISCONNECT_WITH_WILL_MESSAGE), - #{version => ?MQTT_PROTO_V5} - ) - ), - - {ok, WillData} = gen_tcp:recv(Sock2, 0, 5000), - {ok, ?PUBLISH_PACKET(?QOS_1, <<"TopicA">>, _, <<"will message 2">>), <<>>, _} - = raw_recv_parse(WillData, ?MQTT_PROTO_V5) - end), - - % duplicate client id - with_connection(fun([Sock, Sock1]) -> - emqx_zone:set_env(external, use_username_as_clientid, true), - emqx_client_sock:send(Sock, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - clean_start = true, - client_id = <<"myclient">>, - properties = - #{'Session-Expiry-Interval' => 10}}) - )), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock1, - raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - proto_ver = ?MQTT_PROTO_V5, - clean_start = false, - client_id = <<"myclient">>, - username = <<"admin">>, - password = <<"public">>, - properties = - #{'Session-Expiry-Interval' => 10}}) - )), - {ok, Data1} = gen_tcp:recv(Sock1, 0), - {ok, ?CONNACK_PACKET(?RC_SUCCESS, 0), <<>>, _} = raw_recv_parse(Data1, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock, raw_send_serialize(?SUBSCRIBE_PACKET(1, [{<<"TopicA">>, #{rh => 1, - qos => ?QOS_2, - rap => 0, - nl => 0, - rc => 0}}]), - #{version => ?MQTT_PROTO_V5})), - - {ok, SubData} = gen_tcp:recv(Sock, 0), - {ok, ?SUBACK_PACKET(1, #{}, [2]), <<>>, _} = raw_recv_parse(SubData, ?MQTT_PROTO_V5), - - emqx_client_sock:send(Sock1, raw_send_serialize(?SUBSCRIBE_PACKET(1, [{<<"TopicA">>, #{rh => 1, - qos => ?QOS_2, - rap => 0, - nl => 0, - rc => 0}}]), - #{version => ?MQTT_PROTO_V5})), - - {ok, SubData1} = gen_tcp:recv(Sock1, 0), - {ok, ?SUBACK_PACKET(1, #{}, [2]), <<>>, _} = raw_recv_parse(SubData1, ?MQTT_PROTO_V5) - end, 2), - - ok. - -do_connect(Sock, ProtoVer) -> - emqx_client_sock:send(Sock, raw_send_serialize( - ?CONNECT_PACKET( - #mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - proto_ver = ProtoVer - }))), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?CONNACK_PACKET(?CONNACK_ACCEPT), <<>>, _} = raw_recv_parse(Data, ProtoVer). - -subscribe_v4(_) -> - with_connection(fun([Sock]) -> - do_connect(Sock, ?MQTT_PROTO_V4), - SubPacket = raw_send_serialize( - ?SUBSCRIBE_PACKET(15, - [{<<"topic">>, #{rh => 1, - qos => ?QOS_2, - rap => 0, - nl => 0, - rc => 0}}])), - emqx_client_sock:send(Sock, SubPacket), - {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, ?SUBACK_PACKET(15, _), <<>>, _} = raw_recv_parse(Data, ?MQTT_PROTO_V4) - end), - ok. - -subscribe_v5(_) -> - with_connection(fun([Sock]) -> - do_connect(Sock, ?MQTT_PROTO_V5), - SubPacket = raw_send_serialize(?SUBSCRIBE_PACKET(15, #{'Subscription-Identifier' => -1},[]), - #{version => ?MQTT_PROTO_V5}), - emqx_client_sock:send(Sock, SubPacket), - {ok, DisConnData} = gen_tcp:recv(Sock, 0), - {ok, ?DISCONNECT_PACKET(?RC_TOPIC_FILTER_INVALID), <<>>, _} = - raw_recv_parse(DisConnData, ?MQTT_PROTO_V5) - end), - with_connection(fun([Sock]) -> - do_connect(Sock, ?MQTT_PROTO_V5), - SubPacket = raw_send_serialize( - ?SUBSCRIBE_PACKET(0, #{}, [{<<"TopicQos0">>, - #{rh => 1, qos => ?QOS_2, - rap => 0, nl => 0, - rc => 0}}]), - #{version => ?MQTT_PROTO_V5}), - emqx_client_sock:send(Sock, SubPacket), - {ok, DisConnData} = gen_tcp:recv(Sock, 0), - ?assertMatch( - {ok, ?DISCONNECT_PACKET(?RC_MALFORMED_PACKET), <<>>, _}, - raw_recv_parse(DisConnData, ?MQTT_PROTO_V5)) - end), - with_connection(fun([Sock]) -> - do_connect(Sock, ?MQTT_PROTO_V5), - SubPacket = raw_send_serialize( - ?SUBSCRIBE_PACKET(1, #{'Subscription-Identifier' => 0}, - [{<<"TopicQos0">>, - #{rh => 1, qos => ?QOS_2, - rap => 0, nl => 0, - rc => 0}}]), - #{version => ?MQTT_PROTO_V5}), - emqx_client_sock:send(Sock, SubPacket), - {ok, DisConnData} = gen_tcp:recv(Sock, 0), - ?assertMatch( - {ok, ?DISCONNECT_PACKET(?RC_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED), <<>>, _}, - raw_recv_parse(DisConnData, ?MQTT_PROTO_V5)) - end), - with_connection(fun([Sock]) -> - do_connect(Sock, ?MQTT_PROTO_V5), - SubPacket = raw_send_serialize( - ?SUBSCRIBE_PACKET(1, #{'Subscription-Identifier' => 1}, - [{<<"TopicQos0">>, - #{rh => 1, qos => ?QOS_2, - rap => 0, nl => 0, - rc => 0}}]), - #{version => ?MQTT_PROTO_V5}), - emqx_client_sock:send(Sock, SubPacket), - {ok, SubData} = gen_tcp:recv(Sock, 0), - {ok, ?SUBACK_PACKET(1, #{}, [2]), <<>>, _} - = raw_recv_parse(SubData, ?MQTT_PROTO_V5) - end), - ok. - -publish_v4(_) -> - ok. - -publish_v5(_) -> - ok. - -raw_send_serialize(Packet) -> - emqx_frame:serialize(Packet). - -raw_send_serialize(Packet, Opts) -> - emqx_frame:serialize(Packet, Opts). - -raw_recv_parse(Bin, ProtoVer) -> - emqx_frame:parse(Bin, emqx_frame:initial_parse_state(#{version => ProtoVer})). - -acl_deny_action_ct(_) -> - emqx_zone:set_env(external, acl_deny_action, disconnect), - process_flag(trap_exit, true), - [acl_deny_do_disconnect(subscribe, QoS, <<"acl_deny_action">>) || QoS <- lists:seq(0, 2)], - [acl_deny_do_disconnect(publish, QoS, <<"acl_deny_action">>) || QoS <- lists:seq(0, 2)], - emqx_zone:set_env(external, acl_deny_action, ignore), - ok. - -will_topic_check(_) -> - {ok, Client} = emqx_client:start_link([{username, <<"emqx">>}, - {will_flag, true}, - {will_topic, <<"aaa">>}, - {will_payload, <<"I have died">>}, - {will_qos, 0}]), - {ok, _} = emqx_client:connect(Client), - - {ok, T} = emqx_client:start_link([{client_id, <<"client">>}]), - emqx_client:connect(T), - emqx_client:subscribe(T, <<"aaa">>), - ct:sleep(200), - - emqx_client:stop(Client), - ct:sleep(100), - false = is_process_alive(Client), - emqx_ct_helpers:wait_mqtt_payload(<<"I have died">>), - emqx_client:stop(T). - -will_acl_check(_) -> - %% The connection will be rejected if publishing of the will message is not allowed by - %% ACL rules - process_flag(trap_exit, true), - {ok, Client} = emqx_client:start_link([{username, <<"pub_deny">>}, - {will_flag, true}, - {will_topic, <<"pub_deny">>}, - {will_payload, <<"I have died">>}, - {will_qos, 0}]), - ?assertMatch({error,{_,_}}, emqx_client:connect(Client)). - -acl_deny_do_disconnect(publish, QoS, Topic) -> - process_flag(trap_exit, true), - {ok, Client} = emqx_client:start_link([{username, <<"emqx">>}]), - {ok, _} = emqx_client:connect(Client), - emqx_client:publish(Client, Topic, <<"test">>, QoS), - receive - {disconnected, shutdown, tcp_closed} -> - ct:pal(info, "[OK] after publish, client got disconnected: tcp_closed", []); - {'EXIT', Client, {shutdown,tcp_closed}} -> - ct:pal(info, "[OK] after publish, received exit: {shutdown,tcp_closed}"), - false = is_process_alive(Client); - {'EXIT', Client, Reason} -> - ct:pal(info, "[OK] after publish, client got disconnected: ~p", [Reason]) - after 1000 -> ct:fail({timeout, wait_tcp_closed}) - end; - -acl_deny_do_disconnect(subscribe, QoS, Topic) -> - process_flag(trap_exit, true), - {ok, Client} = emqx_client:start_link([{username, <<"emqx">>}]), - {ok, _} = emqx_client:connect(Client), - {ok, _, [128]} = emqx_client:subscribe(Client, Topic, QoS), - receive - {disconnected, shutdown, tcp_closed} -> - ct:pal(info, "[OK] after subscribe, client got disconnected: tcp_closed", []); - {'EXIT', Client, {shutdown,tcp_closed}} -> - ct:pal(info, "[OK] after subscribe, received exit: {shutdown,tcp_closed}"), - false = is_process_alive(Client); - {'EXIT', Client, Reason} -> - ct:pal(info, "[OK] after subscribe, client got disconnected: ~p", [Reason]) - after 1000 -> ct:fail({timeout, wait_tcp_closed}) - end. - -set_special_configs(emqx) -> - application:set_env(emqx, enable_acl_cache, false), - application:set_env(emqx, plugins_loaded_file, - emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_plugins")), - application:set_env(emqx, acl_deny_action, disconnect), - application:set_env(emqx, acl_file, - emqx_ct_helpers:deps_path(emqx, "test/emqx_access_SUITE_data/acl_deny_action.conf")); -set_special_configs(_App) -> - ok. diff --git a/test/emqx_protocol_tests.erl b/test/emqx_protocol_tests.erl deleted file mode 100644 index acadfe79d..000000000 --- a/test/emqx_protocol_tests.erl +++ /dev/null @@ -1,30 +0,0 @@ -%% Copyright (c) 2013-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_protocol_tests). - --include_lib("eunit/include/eunit.hrl"). - -set_property_test() -> - ?assertEqual(#{test => test_property}, emqx_protocol:set_property(test, test_property, undefined)), - TestMap = #{test => test_property}, - ?assertEqual(#{test => test_property, test1 => test_property2}, - emqx_protocol:set_property(test1, test_property2, TestMap)), - ok. - -init_username_test() -> - ?assertEqual(<<"Peercert">>, - emqx_protocol:init_username(<<"Peercert">>, [{peer_cert_as_username, crt}])), - ?assertEqual(undefined, - emqx_protocol:init_username(undefined, [{peer_cert_as_username, undefined}])). diff --git a/test/emqx_reason_codes_tests.erl b/test/emqx_reason_codes_SUITE.erl similarity index 97% rename from test/emqx_reason_codes_tests.erl rename to test/emqx_reason_codes_SUITE.erl index 9a3707fe2..48c3f938e 100644 --- a/test/emqx_reason_codes_tests.erl +++ b/test/emqx_reason_codes_SUITE.erl @@ -14,12 +14,13 @@ %% limitations under the License. %%-------------------------------------------------------------------- +-module(emqx_reason_codes_SUITE). --module(emqx_reason_codes_tests). - --include_lib("eunit/include/eunit.hrl"). +-compile(export_all). +-compile(nowarn_export_all). -include("emqx_mqtt.hrl"). +-include_lib("eunit/include/eunit.hrl"). -import(lists, [seq/2, zip/2, foreach/2]). @@ -89,25 +90,27 @@ ?CONNACK_AUTH, ?CONNACK_SERVER, ?CONNACK_SERVER, ?CONNACK_SERVER, ?CONNACK_SERVER]). -mqttv4_name_test() -> +all() -> emqx_ct:all(?MODULE). + +t_mqttv4_name() -> (((codes_test(?MQTT_PROTO_V4)) (seq(0,6))) (?MQTTV4_CODE_NAMES)) (fun emqx_reason_codes:name/2). -mqttv5_name_test() -> +t_mqttv5_name() -> (((codes_test(?MQTT_PROTO_V5)) (?MQTTV5_CODES)) (?MQTTV5_CODE_NAMES)) (fun emqx_reason_codes:name/2). -text_test() -> +t_text() -> (((codes_test(?MQTT_PROTO_V5)) (?MQTTV5_CODES)) (?MQTTV5_TXT)) (fun emqx_reason_codes:text/1). -compat_test() -> +t_compat() -> (((codes_test(connack)) (?COMPAT_CODES_V5)) (?COMPAT_CODES_V4)) @@ -135,3 +138,4 @@ codes_test(AsistVar) -> end end end. + diff --git a/test/emqx_router_SUITE.erl b/test/emqx_router_SUITE.erl index e195e94f3..711f1b1f9 100644 --- a/test/emqx_router_SUITE.erl +++ b/test/emqx_router_SUITE.erl @@ -16,26 +16,15 @@ -module(emqx_router_SUITE). --include("emqx.hrl"). --include_lib("eunit/include/eunit.hrl"). - -compile(export_all). -compile(nowarn_export_all). +-include("emqx.hrl"). +-include_lib("eunit/include/eunit.hrl"). + -define(R, emqx_router). -all() -> - [{group, route}]. - -groups() -> - [{route, [sequence], - [t_mnesia, - t_add_delete, - t_do_add_delete, - t_match_routes, - t_print_routes, - t_has_routes, - t_unexpected]}]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> emqx_ct_helpers:start_apps([]), @@ -107,4 +96,6 @@ t_unexpected(_) -> Router ! bad_info. clear_tables() -> - lists:foreach(fun mnesia:clear_table/1, [emqx_route, emqx_trie, emqx_trie_node]). + lists:foreach(fun mnesia:clear_table/1, + [emqx_route, emqx_trie, emqx_trie_node]). + diff --git a/test/emqx_rpc_SUITE.erl b/test/emqx_rpc_SUITE.erl deleted file mode 100644 index 7c8a6f1fa..000000000 --- a/test/emqx_rpc_SUITE.erl +++ /dev/null @@ -1,38 +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_rpc_SUITE). - --include("emqx.hrl"). --include_lib("eunit/include/eunit.hrl"). - --compile(export_all). --compile(nowarn_export_all). --define(MASTER, 'emqxct@127.0.0.1'). - -all() -> [t_rpc]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_rpc(_) -> - 60000 = emqx_rpc:call(?MASTER, timer, seconds, [60]), - {badrpc, _} = emqx_rpc:call(?MASTER, os, test, []), - {_, []} = emqx_rpc:multicall([?MASTER, ?MASTER], os, timestamp, []). diff --git a/test/emqx_sequence_SUITE.erl b/test/emqx_sequence_SUITE.erl index cb09c8a66..a5c49f2f6 100644 --- a/test/emqx_sequence_SUITE.erl +++ b/test/emqx_sequence_SUITE.erl @@ -21,20 +21,29 @@ -include_lib("eunit/include/eunit.hrl"). --import(emqx_sequence, [nextval/2, reclaim/2]). +-import(emqx_sequence, + [ nextval/2 + , currval/2 + , reclaim/2 + ]). -all() -> - [sequence_generate]. +all() -> emqx_ct:all(?MODULE). -sequence_generate(_) -> +t_generate(_) -> ok = emqx_sequence:create(seqtab), + ?assertEqual(0, currval(seqtab, key)), ?assertEqual(1, nextval(seqtab, key)), + ?assertEqual(1, currval(seqtab, key)), ?assertEqual(2, nextval(seqtab, key)), + ?assertEqual(2, currval(seqtab, key)), ?assertEqual(3, nextval(seqtab, key)), ?assertEqual(2, reclaim(seqtab, key)), ?assertEqual(1, reclaim(seqtab, key)), ?assertEqual(0, reclaim(seqtab, key)), - ?assertEqual(false, ets:member(seqtab, key)), ?assertEqual(1, nextval(seqtab, key)), - ?assert(emqx_sequence:delete(seqtab)). + ?assertEqual(0, reclaim(seqtab, key)), + ?assertEqual(0, reclaim(seqtab, key)), + ?assertEqual(false, ets:member(seqtab, key)), + ?assert(emqx_sequence:delete(seqtab)), + ?assertNot(emqx_sequence:delete(seqtab)). diff --git a/test/emqx_session_SUITE.erl b/test/emqx_session_SUITE.erl index d5e04f212..8736d69b7 100644 --- a/test/emqx_session_SUITE.erl +++ b/test/emqx_session_SUITE.erl @@ -21,9 +21,7 @@ -include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - -all() -> [ignore_loop, t_session_all]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> emqx_ct_helpers:start_apps([]), @@ -32,6 +30,42 @@ init_per_suite(Config) -> end_per_suite(_Config) -> emqx_ct_helpers:stop_apps([]). +t_info(_) -> + 'TODO'. + +t_attrs(_) -> + 'TODO'. + +t_stats(_) -> + 'TODO'. + +t_subscribe(_) -> + 'TODO'. + +t_unsubscribe(_) -> + 'TODO'. + +t_publish(_) -> + 'TODO'. + +t_puback(_) -> + 'TODO'. + +t_pubrec(_) -> + 'TODO'. + +t_pubrel(_) -> + 'TODO'. + +t_pubcomp(_) -> + 'TODO'. + +t_deliver(_) -> + 'TODO'. + +t_timeout(_) -> + 'TODO'. + ignore_loop(_Config) -> emqx_zone:set_env(external, ignore_loop_deliver, true), {ok, Client} = emqx_client:start_link(), @@ -45,7 +79,7 @@ ignore_loop(_Config) -> ok = emqx_client:disconnect(Client), emqx_zone:set_env(external, ignore_loop_deliver, false). -t_session_all(_) -> +session_all(_) -> emqx_zone:set_env(internal, idle_timeout, 1000), ClientId = <<"ClientId">>, {ok, ConnPid} = emqx_mock_client:start_link(ClientId), @@ -68,3 +102,4 @@ t_session_all(_) -> timer:sleep(200), [] = emqx:subscriptions(SPid), emqx_mock_client:close_session(ConnPid). + diff --git a/test/emqx_shared_sub_SUITE.erl b/test/emqx_shared_sub_SUITE.erl deleted file mode 100644 index 5a1788b48..000000000 --- a/test/emqx_shared_sub_SUITE.erl +++ /dev/null @@ -1,260 +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_shared_sub_SUITE). - --export([all/0, init_per_suite/1, end_per_suite/1]). --export([t_random_basic/1, - t_random/1, - t_round_robin/1, - t_sticky/1, - t_hash/1, - t_not_so_sticky/1, - t_no_connection_nack/1 - ]). - --include("emqx.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - --define(wait(For, Timeout), emqx_ct_helpers:wait_for(?FUNCTION_NAME, ?LINE, fun() -> For end, Timeout)). - -all() -> [t_random_basic, - t_random, - t_round_robin, - t_sticky, - t_hash, - t_not_so_sticky, - t_no_connection_nack]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_random_basic(_) -> - ok = ensure_config(random), - ClientId = <<"ClientId">>, - {ok, ConnPid} = emqx_mock_client:start_link(ClientId), - {ok, SPid} = emqx_mock_client:open_session(ConnPid, ClientId, internal), - Message1 = emqx_message:make(<<"ClientId">>, 2, <<"foo">>, <<"hello">>), - emqx_session:subscribe(SPid, [{<<"foo">>, #{qos => 2, share => <<"group1">>}}]), - %% wait for the subscription to show up - ?wait(subscribed(<<"group1">>, <<"foo">>, SPid), 1000), - PacketId = 1, - emqx_session:publish(SPid, PacketId, Message1), - ?wait(case emqx_mock_client:get_last_message(ConnPid) of - [{publish, 1, _}] -> true; - Other -> Other - end, 1000), - emqx_session:pubrec(SPid, PacketId, reasoncode), - emqx_session:pubcomp(SPid, PacketId, reasoncode), - emqx_mock_client:close_session(ConnPid), - ok. - -%% Start two subscribers share subscribe to "$share/g1/foo/bar" -%% Set 'sticky' dispatch strategy, send 1st message to find -%% out which member it picked, then close its connection -%% send the second message, the message should be 'nack'ed -%% by the sticky session and delivered to the 2nd session. -%% After the connection for the 2nd session is also closed, -%% i.e. when all clients are offline, the following message(s) -%% should be delivered randomly. -t_no_connection_nack(_) -> - ok = ensure_config(sticky), - Publisher = <<"publisher">>, - Subscriber1 = <<"Subscriber1">>, - Subscriber2 = <<"Subscriber2">>, - QoS = 1, - Group = <<"g1">>, - Topic = <<"foo/bar">>, - {ok, PubConnPid} = emqx_mock_client:start_link(Publisher), - {ok, SubConnPid1} = emqx_mock_client:start_link(Subscriber1), - {ok, SubConnPid2} = emqx_mock_client:start_link(Subscriber2), - %% allow session to persist after connection shutdown - Attrs = #{expiry_interval => timer:seconds(30)}, - {ok, P_Pid} = emqx_mock_client:open_session(PubConnPid, Publisher, internal, Attrs), - {ok, SPid1} = emqx_mock_client:open_session(SubConnPid1, Subscriber1, internal, Attrs), - {ok, SPid2} = emqx_mock_client:open_session(SubConnPid2, Subscriber2, internal, Attrs), - emqx_session:subscribe(SPid1, [{Topic, #{qos => QoS, share => Group}}]), - emqx_session:subscribe(SPid2, [{Topic, #{qos => QoS, share => Group}}]), - %% wait for the subscriptions to show up - ?wait(subscribed(Group, Topic, SPid1), 1000), - ?wait(subscribed(Group, Topic, SPid2), 1000), - MkPayload = fun(PacketId) -> iolist_to_binary(["hello-", integer_to_list(PacketId)]) end, - SendF = fun(PacketId) -> emqx_session:publish(P_Pid, PacketId, emqx_message:make(Publisher, QoS, Topic, MkPayload(PacketId))) end, - SendF(1), - Ref = make_ref(), - CasePid = self(), - Received = - fun(PacketId, ConnPid) -> - Payload = MkPayload(PacketId), - case emqx_mock_client:get_last_message(ConnPid) of - [{publish, _, #message{payload = Payload}}] -> - CasePid ! {Ref, PacketId, ConnPid}, - true; - _Other -> - false - end - end, - ?wait(Received(1, SubConnPid1) orelse Received(1, SubConnPid2), 1000), - %% This is the connection which was picked by broker to dispatch (sticky) for 1st message - ConnPid = receive {Ref, 1, Pid} -> Pid after 1000 -> error(timeout) end, - %% Now kill the connection, expect all following messages to be delivered to the other subscriber. - emqx_mock_client:stop(ConnPid), - %% sleep then make synced calls to session processes to ensure that - %% the connection pid's 'EXIT' message is propagated to the session process - %% also to be sure sessions are still alive - timer:sleep(2), - _ = emqx_session:info(SPid1), - _ = emqx_session:info(SPid2), - %% Now we know what is the other still alive connection - [TheOtherConnPid] = [SubConnPid1, SubConnPid2] -- [ConnPid], - %% Send some more messages - PacketIdList = lists:seq(2, 10), - lists:foreach(fun(Id) -> - SendF(Id), - ?wait(Received(Id, TheOtherConnPid), 1000) - end, PacketIdList), - %% Now close the 2nd (last connection) - emqx_mock_client:stop(TheOtherConnPid), - timer:sleep(2), - %% both sessions should have conn_pid = undefined - ?assertEqual({conn_pid, undefined}, lists:keyfind(conn_pid, 1, emqx_session:info(SPid1))), - ?assertEqual({conn_pid, undefined}, lists:keyfind(conn_pid, 1, emqx_session:info(SPid2))), - %% send more messages, but all should be queued in session state - lists:foreach(fun(Id) -> SendF(Id) end, PacketIdList), - {_, L1} = lists:keyfind(mqueue_len, 1, emqx_session:info(SPid1)), - {_, L2} = lists:keyfind(mqueue_len, 1, emqx_session:info(SPid2)), - ?assertEqual(length(PacketIdList), L1 + L2), - %% clean up - emqx_mock_client:close_session(PubConnPid), - emqx_sm:close_session(SPid1), - emqx_sm:close_session(SPid2), - ok. - -t_random(_) -> - test_two_messages(random). - -t_round_robin(_) -> - test_two_messages(round_robin). - -t_sticky(_) -> - test_two_messages(sticky). - -t_hash(_) -> - test_two_messages(hash, false). - -%% if the original subscriber dies, change to another one alive -t_not_so_sticky(_) -> - ok = ensure_config(sticky), - ClientId1 = <<"ClientId1">>, - ClientId2 = <<"ClientId2">>, - {ok, ConnPid1} = emqx_mock_client:start_link(ClientId1), - {ok, ConnPid2} = emqx_mock_client:start_link(ClientId2), - {ok, SPid1} = emqx_mock_client:open_session(ConnPid1, ClientId1, internal), - {ok, SPid2} = emqx_mock_client:open_session(ConnPid2, ClientId2, internal), - Message1 = emqx_message:make(ClientId1, 0, <<"foo/bar">>, <<"hello1">>), - Message2 = emqx_message:make(ClientId1, 0, <<"foo/bar">>, <<"hello2">>), - emqx_session:subscribe(SPid1, [{<<"foo/bar">>, #{qos => 0, share => <<"group1">>}}]), - %% wait for the subscription to show up - ?wait(subscribed(<<"group1">>, <<"foo/bar">>, SPid1), 1000), - emqx_session:publish(SPid1, 1, Message1), - ?wait(case emqx_mock_client:get_last_message(ConnPid1) of - [{publish, _, #message{payload = <<"hello1">>}}] -> true; - Other -> Other - end, 1000), - emqx_mock_client:close_session(ConnPid1), - ?wait(not subscribed(<<"group1">>, <<"foo/bar">>, SPid1), 1000), - emqx_session:subscribe(SPid2, [{<<"foo/#">>, #{qos => 0, share => <<"group1">>}}]), - ?wait(subscribed(<<"group1">>, <<"foo/#">>, SPid2), 1000), - emqx_session:publish(SPid2, 2, Message2), - ?wait(case emqx_mock_client:get_last_message(ConnPid2) of - [{publish, _, #message{payload = <<"hello2">>}}] -> true; - Other -> Other - end, 1000), - emqx_mock_client:close_session(ConnPid2), - ?wait(not subscribed(<<"group1">>, <<"foo/#">>, SPid2), 1000), - ok. - -test_two_messages(Strategy) -> - test_two_messages(Strategy, _WithAck = true). - -test_two_messages(Strategy, WithAck) -> - ok = ensure_config(Strategy, WithAck), - Topic = <<"foo/bar">>, - ClientId1 = <<"ClientId1">>, - ClientId2 = <<"ClientId2">>, - {ok, ConnPid1} = emqx_mock_client:start_link(ClientId1), - {ok, ConnPid2} = emqx_mock_client:start_link(ClientId2), - {ok, SPid1} = emqx_mock_client:open_session(ConnPid1, ClientId1, internal), - {ok, SPid2} = emqx_mock_client:open_session(ConnPid2, ClientId2, internal), - Message1 = emqx_message:make(ClientId1, 0, Topic, <<"hello1">>), - Message2 = emqx_message:make(ClientId1, 0, Topic, <<"hello2">>), - emqx_session:subscribe(SPid1, [{Topic, #{qos => 0, share => <<"group1">>}}]), - emqx_session:subscribe(SPid2, [{Topic, #{qos => 0, share => <<"group1">>}}]), - %% wait for the subscription to show up - ?wait(subscribed(<<"group1">>, Topic, SPid1) andalso - subscribed(<<"group1">>, Topic, SPid2), 1000), - emqx_broker:publish(Message1), - Me = self(), - WaitF = fun(ExpectedPayload) -> - case last_message(ExpectedPayload, [ConnPid1, ConnPid2]) of - {true, Pid} -> - Me ! {subscriber, Pid}, - true; - Other -> - Other - end - end, - ?wait(WaitF(<<"hello1">>), 2000), - UsedSubPid1 = receive {subscriber, P1} -> P1 end, - emqx_broker:publish(Message2), - ?wait(WaitF(<<"hello2">>), 2000), - UsedSubPid2 = receive {subscriber, P2} -> P2 end, - case Strategy of - sticky -> ?assert(UsedSubPid1 =:= UsedSubPid2); - round_robin -> ?assert(UsedSubPid1 =/= UsedSubPid2); - hash -> ?assert(UsedSubPid1 =:= UsedSubPid2); - _ -> ok - end, - emqx_mock_client:close_session(ConnPid1), - emqx_mock_client:close_session(ConnPid2), - ok. - -last_message(_ExpectedPayload, []) -> <<"not yet?">>; -last_message(ExpectedPayload, [Pid | Pids]) -> - case emqx_mock_client:get_last_message(Pid) of - [{publish, _, #message{payload = ExpectedPayload}}] -> {true, Pid}; - _Other -> last_message(ExpectedPayload, Pids) - end. - -%%------------------------------------------------------------------------------ -%% help functions -%%------------------------------------------------------------------------------ - -ensure_config(Strategy) -> - ensure_config(Strategy, _AckEnabled = true). - -ensure_config(Strategy, AckEnabled) -> - application:set_env(emqx, shared_subscription_strategy, Strategy), - application:set_env(emqx, shared_dispatch_ack_enabled, AckEnabled), - ok. - -subscribed(Group, Topic, Pid) -> - lists:member(Pid, emqx_shared_sub:subscribers(Group, Topic)). diff --git a/test/emqx_sm_SUITE.erl b/test/emqx_sm_SUITE.erl deleted file mode 100644 index 325bc6950..000000000 --- a/test/emqx_sm_SUITE.erl +++ /dev/null @@ -1,115 +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_sm_SUITE). - --include("emqx.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - --compile(export_all). --compile(nowarn_export_all). - --define(ATTRS, #{clean_start => true, - client_id => <<"client">>, - zone => internal, - username => <<"emqx">>, - expiry_interval => 0, - max_inflight => 0, - topic_alias_maximum => 0, - will_msg => undefined}). - -all() -> [{group, registry}, {group, ets}]. - -groups() -> - Cases = - [ t_resume_session, - t_discard_session, - t_register_unregister_session, - t_get_set_session_attrs, - t_get_set_session_stats, - t_lookup_session_pids], - [ {registry, [non_parallel_tests], Cases}, - {ets, [non_parallel_tests], Cases}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(registry, Config) -> - emqx_ct_helpers:start_apps([], fun enable_session_registry/1), - Config; -init_per_group(ets, Config) -> - emqx_ct_helpers:start_apps([], fun disable_session_registry/1), - Config. - -end_per_group(_, _Config) -> - emqx_ct_helpers:stop_apps([]). - -init_per_testcase(_All, Config) -> - {ok, SPid} = emqx_sm:open_session(?ATTRS#{conn_pid => self()}), - [{session_pid, SPid}|Config]. - -end_per_testcase(_All, Config) -> - emqx_sm:close_session(?config(session_pid, Config)), - receive - {shutdown, normal} -> ok - after 500 -> ct:fail({timeout, wait_session_shutdown}) - end. - -enable_session_registry(_) -> - application:set_env(emqx, enable_session_registry, true), - ok. - -disable_session_registry(_) -> - application:set_env(emqx, enable_session_registry, false), - ok. - -t_resume_session(Config) -> - ?assertEqual({ok, ?config(session_pid, Config)}, emqx_sm:resume_session(<<"client">>, ?ATTRS#{conn_pid => self()})). - -t_discard_session(_) -> - ?assertEqual(ok, emqx_sm:discard_session(<<"client1">>)). - -t_register_unregister_session(_) -> - Pid = self(), - ?assertEqual(ok, emqx_sm:register_session(<<"client">>)), - ?assertEqual(ok, emqx_sm:register_session(<<"client">>, Pid)), - ?assertEqual(ok, emqx_sm:unregister_session(<<"client">>)), - ?assertEqual(ok, emqx_sm:unregister_session(<<"client">>), Pid). - -t_get_set_session_attrs(Config) -> - SPid = ?config(session_pid, Config), - ClientPid0 = spawn(fun() -> receive _ -> ok end end), - ?assertEqual(true, emqx_sm:set_session_attrs(<<"client">>, [?ATTRS#{conn_pid => ClientPid0}])), - ?assertEqual(true, emqx_sm:set_session_attrs(<<"client">>, SPid, [?ATTRS#{conn_pid => ClientPid0}])), - [SAttr0] = emqx_sm:get_session_attrs(<<"client">>, SPid), - ?assertEqual(ClientPid0, maps:get(conn_pid, SAttr0)), - ?assertEqual(true, emqx_sm:set_session_attrs(<<"client">>, SPid, [?ATTRS#{conn_pid => self()}])), - [SAttr1] = emqx_sm:get_session_attrs(<<"client">>, SPid), - ?assertEqual(self(), maps:get(conn_pid, SAttr1)). - -t_get_set_session_stats(Config) -> - SPid = ?config(session_pid, Config), - ?assertEqual(true, emqx_sm:set_session_stats(<<"client">>, [{inflight, 10}])), - ?assertEqual(true, emqx_sm:set_session_stats(<<"client">>, SPid, [{inflight, 10}])), - ?assertEqual([{inflight, 10}], emqx_sm:get_session_stats(<<"client">>, SPid)). - -t_lookup_session_pids(Config) -> - SPid = ?config(session_pid, Config), - ?assertEqual([SPid], emqx_sm:lookup_session_pids(<<"client">>)). diff --git a/test/emqx_stats_tests.erl b/test/emqx_stats_SUITE.erl similarity index 80% rename from test/emqx_stats_tests.erl rename to test/emqx_stats_SUITE.erl index 89430306c..642674491 100644 --- a/test/emqx_stats_tests.erl +++ b/test/emqx_stats_SUITE.erl @@ -14,36 +14,41 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqx_stats_tests). +-module(emqx_stats_SUITE). + +-compile(export_all). +-compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). -get_state_test() -> +all() -> emqx_ct:all(?MODULE). + +t_get_state() -> with_proc(fun() -> SetConnsCount = emqx_stats:statsfun('connections.count'), SetConnsCount(1), - 1 = emqx_stats:getstat('connections.count'), + ?assertEqual(1, emqx_stats:getstat('connections.count')), emqx_stats:setstat('connections.count', 2), - 2 = emqx_stats:getstat('connections.count'), + ?assertEqual(2, emqx_stats:getstat('connections.count')), emqx_stats:setstat('connections.count', 'connections.max', 3), timer:sleep(100), - 3 = emqx_stats:getstat('connections.count'), - 3 = emqx_stats:getstat('connections.max'), + ?assertEqual(3, emqx_stats:getstat('connections.count')), + ?assertEqual(3, emqx_stats:getstat('connections.max')), emqx_stats:setstat('connections.count', 'connections.max', 2), timer:sleep(100), - 2 = emqx_stats:getstat('connections.count'), - 3 = emqx_stats:getstat('connections.max'), + ?assertEqual(2, emqx_stats:getstat('connections.count')), + ?assertEqual(3, emqx_stats:getstat('connections.max')), SetConns = emqx_stats:statsfun('connections.count', 'connections.max'), SetConns(4), timer:sleep(100), - 4 = emqx_stats:getstat('connections.count'), - 4 = emqx_stats:getstat('connections.max'), + ?assertEqual(4, emqx_stats:getstat('connections.count')), + ?assertEqual(4, emqx_stats:getstat('connections.max')), Conns = emqx_stats:getstats(), - 4 = proplists:get_value('connections.count', Conns), - 4 = proplists:get_value('connections.max', Conns) + ?assertEqual(4, proplists:get_value('connections.count', Conns)), + ?assertEqual(4, proplists:get_value('connections.max', Conns)) end). -update_interval_test() -> +t_update_interval() -> TickMs = 200, with_proc(fun() -> SleepMs = TickMs * 2 + TickMs div 2, %% sleep for 2.5 ticks diff --git a/test/emqx_sys_mon_SUITE.erl b/test/emqx_sys_mon_SUITE.erl index 105735e75..ef54ea630 100644 --- a/test/emqx_sys_mon_SUITE.erl +++ b/test/emqx_sys_mon_SUITE.erl @@ -19,21 +19,27 @@ -compile(export_all). -compile(nowarn_export_all). +-include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). +-define(SYSMON, emqx_sys_mon). --include("emqx_mqtt.hrl"). - --define(SYSMONPID, emqx_sys_mon). --define(INPUTINFO, [{self(), long_gc, concat_str("long_gc warning: pid = ~p, info: ~p", self(), "hello"), "hello"}, - {self(), long_schedule, concat_str("long_schedule warning: pid = ~p, info: ~p", self(), "hello"), "hello"}, - {self(), busy_port, concat_str("busy_port warning: suspid = ~p, port = ~p", self(), list_to_port("#Port<0.4>")), list_to_port("#Port<0.4>")}, - {self(), busy_dist_port, concat_str("busy_dist_port warning: suspid = ~p, port = ~p", self(), list_to_port("#Port<0.4>")),list_to_port("#Port<0.4>")}, - {list_to_port("#Port<0.4>"), long_schedule, concat_str("long_schedule warning: port = ~p, info: ~p", list_to_port("#Port<0.4>"), "hello"), "hello"} +-define(INPUTINFO, [{self(), long_gc, + concat_str("long_gc warning: pid = ~p, info: ~p", self(), "hello"), "hello"}, + {self(), long_schedule, + concat_str("long_schedule warning: pid = ~p, info: ~p", self(), "hello"), "hello"}, + {self(), busy_port, + concat_str("busy_port warning: suspid = ~p, port = ~p", + self(), list_to_port("#Port<0.4>")), list_to_port("#Port<0.4>")}, + {self(), busy_dist_port, + concat_str("busy_dist_port warning: suspid = ~p, port = ~p", + self(), list_to_port("#Port<0.4>")),list_to_port("#Port<0.4>")}, + {list_to_port("#Port<0.4>"), long_schedule, + concat_str("long_schedule warning: port = ~p, info: ~p", + list_to_port("#Port<0.4>"), "hello"), "hello"} ]). -all() -> [t_sys_mon]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> emqx_ct_helpers:start_apps([]), @@ -43,16 +49,17 @@ end_per_suite(_Config) -> emqx_ct_helpers:stop_apps([]). t_sys_mon(_Config) -> - lists:foreach(fun({PidOrPort, SysMonName,ValidateInfo, InfoOrPort}) -> - validate_sys_mon_info(PidOrPort, SysMonName,ValidateInfo, InfoOrPort) - end, ?INPUTINFO). + lists:foreach( + fun({PidOrPort, SysMonName,ValidateInfo, InfoOrPort}) -> + validate_sys_mon_info(PidOrPort, SysMonName,ValidateInfo, InfoOrPort) + end, ?INPUTINFO). validate_sys_mon_info(PidOrPort, SysMonName,ValidateInfo, InfoOrPort) -> {ok, C} = emqx_client:start_link([{host, "localhost"}]), {ok, _} = emqx_client:connect(C), emqx_client:subscribe(C, emqx_topic:systop(lists:concat(['sysmon/', SysMonName])), qos1), timer:sleep(100), - ?SYSMONPID ! {monitor, PidOrPort, SysMonName, InfoOrPort}, + ?SYSMON ! {monitor, PidOrPort, SysMonName, InfoOrPort}, receive {publish, #{payload := Info}} -> ?assertEqual(ValidateInfo, binary_to_list(Info)), diff --git a/test/emqx_tables_SUITE.erl b/test/emqx_tables_SUITE.erl index 60eb94860..106001f62 100644 --- a/test/emqx_tables_SUITE.erl +++ b/test/emqx_tables_SUITE.erl @@ -19,12 +19,27 @@ -compile(export_all). -compile(nowarn_export_all). -all() -> [t_new]. +-include_lib("eunit/include/eunit.hrl"). + +-define(TAB, ?MODULE). + +all() -> emqx_ct:all(?MODULE). t_new(_) -> - ok = emqx_tables:new(test_table, [{read_concurrency, true}]), - ets:insert(test_table, {key, 100}), - ok = emqx_tables:new(test_table, [{read_concurrency, true}]), - 100 = ets:lookup_element(test_table, key, 2), - ok = emqx_tables:delete(test_table), - ok = emqx_tables:delete(test_table). + ok = emqx_tables:new(?TAB), + ok = emqx_tables:new(?TAB, [{read_concurrency, true}]), + ?assertEqual(?TAB, ets:info(?TAB, name)). + +t_lookup_value(_) -> + ok = emqx_tables:new(?TAB, []), + true = ets:insert(?TAB, {key, val}), + ?assertEqual(val, emqx_tables:lookup_value(?TAB, key)), + ?assertEqual(undefined, emqx_tables:lookup_value(?TAB, badkey)). + +t_delete(_) -> + ok = emqx_tables:new(?TAB, []), + ?assertEqual(?TAB, ets:info(?TAB, name)), + ok = emqx_tables:delete(?TAB), + ok = emqx_tables:delete(?TAB), + ?assertEqual(undefined, ets:info(?TAB, name)). + diff --git a/test/emqx_time_SUITE.erl b/test/emqx_time_SUITE.erl index 6900185c2..e190c7f78 100644 --- a/test/emqx_time_SUITE.erl +++ b/test/emqx_time_SUITE.erl @@ -16,14 +16,19 @@ -module(emqx_time_SUITE). --include_lib("eunit/include/eunit.hrl"). - -compile(export_all). -compile(nowarn_export_all). -all() -> [t_time_now_to]. +-include_lib("eunit/include/eunit.hrl"). + +all() -> emqx_ct:all(?MODULE). + +t_seed(_) -> + ?assert(is_tuple(emqx_time:seed())). + +t_now_secs(_) -> + ?assert(emqx_time:now_secs() =< emqx_time:now_secs(os:timestamp())). + +t_now_ms(_) -> + ?assert(emqx_time:now_ms() =< emqx_time:now_ms(os:timestamp())). -t_time_now_to(_) -> - emqx_time:seed(), - emqx_time:now_secs(), - emqx_time:now_ms(). diff --git a/test/emqx_topic_SUITE.erl b/test/emqx_topic_SUITE.erl index 202f8beb8..b0776aa69 100644 --- a/test/emqx_topic_SUITE.erl +++ b/test/emqx_topic_SUITE.erl @@ -16,44 +16,29 @@ -module(emqx_topic_SUITE). --include_lib("eunit/include/eunit.hrl"). - -%% CT -compile(export_all). -compile(nowarn_export_all). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("emqx_ct_helpers/include/emqx_ct.hrl"). + -import(emqx_topic, [ wildcard/1 , match/2 , validate/1 , triples/1 + , prepend/2 , join/1 , words/1 , systop/1 , feed_var/3 , parse/1 + , parse/2 ]). --define(N, 10000). +-define(N, 100000). -all() -> - [t_wildcard, - t_match, t_match2, t_match3, - t_validate, - t_triples, - t_join, - t_levels, - t_tokens, - t_words, - t_systop, - t_feed_var, - t_sys_match, - 't_#_match', - t_sigle_level_validate, - t_sigle_level_match, - t_match_perf, - t_triples_perf, - t_parse]. +all() -> emqx_ct:all(?MODULE). t_wildcard(_) -> true = wildcard(<<"a/b/#">>), @@ -61,7 +46,7 @@ t_wildcard(_) -> false = wildcard(<<"">>), false = wildcard(<<"a/b/c">>). -t_match(_) -> +t_match1(_) -> true = match(<<"a/b/c">>, <<"a/b/+">>), true = match(<<"a/b/c">>, <<"a/#">>), true = match(<<"abcd/ef/g">>, <<"#">>), @@ -132,74 +117,74 @@ t_match_perf(_) -> Name = <<"/abkc/19383/192939/akakdkkdkak/xxxyyuya/akakak">>, Filter = <<"/abkc/19383/+/akakdkkdkak/#">>, true = match(Name, Filter), - {Time, _} = timer:tc(fun() -> - [match(Name, Filter) || _I <- lists:seq(1, ?N)] - end), - io:format("Time for match: ~p(micro)", [Time/?N]). + ok = bench('match/2', fun emqx_topic:match/2, [Name, Filter]). t_validate(_) -> - true = validate({name, <<"abc/de/f">>}), - true = validate({filter, <<"abc/+/f">>}), - true = validate({filter, <<"abc/#">>}), - true = validate({filter, <<"x">>}), - true = validate({name, <<"x//y">>}), - true = validate({filter, <<"sport/tennis/#">>}), - catch validate({name, <<>>}), - catch validate({name, long_topic()}), - catch validate({name, <<"abc/#">>}), - catch validate({filter, <<"abc/#/1">>}), - catch validate({filter, <<"abc/#xzy/+">>}), - catch validate({filter, <<"abc/xzy/+9827">>}), - catch validate({filter, <<"sport/tennis#">>}), - catch validate({filter, <<"sport/tennis/#/ranking">>}), - ok. + true = validate(<<"a/+/#">>), + true = validate(<<"a/b/c/d">>), + true = validate({name, <<"abc/de/f">>}), + true = validate({filter, <<"abc/+/f">>}), + true = validate({filter, <<"abc/#">>}), + true = validate({filter, <<"x">>}), + true = validate({name, <<"x//y">>}), + true = validate({filter, <<"sport/tennis/#">>}), + ok = ?catch_error(empty_topic, validate({name, <<>>})), + ok = ?catch_error(topic_name_error, validate({name, <<"abc/#">>})), + ok = ?catch_error(topic_too_long, validate({name, long_topic()})), + ok = ?catch_error('topic_invalid_#', validate({filter, <<"abc/#/1">>})), + ok = ?catch_error(topic_invalid_char, validate({filter, <<"abc/#xzy/+">>})), + ok = ?catch_error(topic_invalid_char, validate({filter, <<"abc/xzy/+9827">>})), + ok = ?catch_error(topic_invalid_char, validate({filter, <<"sport/tennis#">>})), + ok = ?catch_error('topic_invalid_#', validate({filter, <<"sport/tennis/#/ranking">>})). t_sigle_level_validate(_) -> - true = validate({filter, <<"+">>}), - true = validate({filter, <<"+/tennis/#">>}), - true = validate({filter, <<"sport/+/player1">>}), - catch validate({filter, <<"sport+">>}), - ok. + true = validate({filter, <<"+">>}), + true = validate({filter, <<"+/tennis/#">>}), + true = validate({filter, <<"sport/+/player1">>}), + ok = ?catch_error(topic_invalid_char, validate({filter, <<"sport+">>})). t_triples(_) -> Triples = [{root,<<"a">>,<<"a">>}, {<<"a">>,<<"b">>,<<"a/b">>}, {<<"a/b">>,<<"c">>,<<"a/b/c">>}], - Triples = triples(<<"a/b/c">>). + ?assertEqual(Triples, triples(<<"a/b/c">>)). t_triples_perf(_) -> Topic = <<"/abkc/19383/192939/akakdkkdkak/xxxyyuya/akakak">>, - {Time, _} = timer:tc(fun() -> - [triples(Topic) || _I <- lists:seq(1, ?N)] - end), - io:format("Time for triples: ~p(micro)", [Time/?N]). + ok = bench('triples/1', fun emqx_topic:triples/1, [Topic]). + +t_prepend(_) -> + ?assertEqual(<<"a/b/c">>, prepend(root, <<"a/b/c">>)), + ?assertEqual(<<"ab">>, prepend(undefined, <<"ab">>)), + ?assertEqual(<<"a/b">>, prepend(<<>>, <<"a/b">>)), + ?assertEqual(<<"x/a/b">>, prepend("x/", <<"a/b">>)), + ?assertEqual(<<"x/y/a/b">>, prepend(<<"x/y">>, <<"a/b">>)), + ?assertEqual(<<"+/a/b">>, prepend('+', <<"a/b">>)). t_levels(_) -> + ?assertEqual(3, emqx_topic:levels(<<"a/+/#">>)), ?assertEqual(4, emqx_topic:levels(<<"a/b/c/d">>)). t_tokens(_) -> - ?assertEqual([<<"a">>, <<"b">>, <<"+">>, <<"#">>], emqx_topic:tokens(<<"a/b/+/#">>)). + ?assertEqual([<<"a">>, <<"b">>, <<"+">>, <<"#">>], + emqx_topic:tokens(<<"a/b/+/#">>)). t_words(_) -> - ['', <<"a">>, '+', '#'] = words(<<"/a/+/#">>), - ['', <<"abkc">>, <<"19383">>, '+', <<"akakdkkdkak">>, '#'] = words(<<"/abkc/19383/+/akakdkkdkak/#">>), - {Time, _} = timer:tc(fun() -> - [words(<<"/abkc/19383/+/akakdkkdkak/#">>) || _I <- lists:seq(1, ?N)] - end), - io:format("Time for words: ~p(micro)", [Time/?N]), - {Time2, _} = timer:tc(fun() -> - [binary:split(<<"/abkc/19383/+/akakdkkdkak/#">>, <<"/">>, [global]) || _I <- lists:seq(1, ?N)] - end), - io:format("Time for binary:split: ~p(micro)", [Time2/?N]). + Topic = <<"/abkc/19383/+/akakdkkdkak/#">>, + ?assertEqual(['', <<"a">>, '+', '#'], words(<<"/a/+/#">>)), + ?assertEqual(['', <<"abkc">>, <<"19383">>, '+', <<"akakdkkdkak">>, '#'], words(Topic)), + ok = bench('words/1', fun emqx_topic:words/1, [Topic]), + BSplit = fun(Bin) -> binary:split(Bin, <<"/">>, [global]) end, + ok = bench('binary:split/3', BSplit, [Topic]). t_join(_) -> - <<>> = join([]), - <<"x">> = join([<<"x">>]), - <<"#">> = join(['#']), - <<"+//#">> = join(['+', '', '#']), - <<"x/y/z/+">> = join([<<"x">>, <<"y">>, <<"z">>, '+']), - <<"/ab/cd/ef/">> = join(words(<<"/ab/cd/ef/">>)), - <<"ab/+/#">> = join(words(<<"ab/+/#">>)). + ?assertEqual(<<>>, join([])), + ?assertEqual(<<"x">>, join([<<"x">>])), + ?assertEqual(<<"#">>, join(['#'])), + ?assertEqual(<<"+//#">>, join(['+', '', '#'])), + ?assertEqual(<<"x/y/z/+">>, join([<<"x">>, <<"y">>, <<"z">>, '+'])), + ?assertEqual(<<"/ab/cd/ef/">>, join(words(<<"/ab/cd/ef/">>))), + ?assertEqual(<<"ab/+/#">>, join(words(<<"ab/+/#">>))). t_systop(_) -> SysTop1 = iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/xyz"]), @@ -219,12 +204,29 @@ long_topic() -> iolist_to_binary([[integer_to_list(I), "/"] || I <- lists:seq(0, 10000)]). t_parse(_) -> + ok = ?catch_error({invalid_topic_filter, <<"$queue/t">>}, + parse(<<"$queue/t">>, #{share => <<"g">>})), + ok = ?catch_error({invalid_topic_filter, <<"$share/g/t">>}, + parse(<<"$share/g/t">>, #{share => <<"g">>})), + ok = ?catch_error({invalid_topic_filter, <<"$share/t">>}, + parse(<<"$share/t">>)), + ok = ?catch_error({invalid_topic_filter, <<"$share/+/t">>}, + parse(<<"$share/+/t">>)), ?assertEqual({<<"a/b/+/#">>, #{}}, parse(<<"a/b/+/#">>)), ?assertEqual({<<"a/b/+/#">>, #{qos => 1}}, parse({<<"a/b/+/#">>, #{qos => 1}})), - ?assertEqual({<<"topic">>, #{ share => <<"$queue">> }}, parse(<<"$queue/topic">>)), - ?assertEqual({<<"topic">>, #{ share => <<"group">>}}, parse(<<"$share/group/topic">>)), + ?assertEqual({<<"topic">>, #{share => <<"$queue">>}}, parse(<<"$queue/topic">>)), + ?assertEqual({<<"topic">>, #{share => <<"group">>}}, parse(<<"$share/group/topic">>)), + %% The '$local' and '$fastlane' topics have been deprecated. ?assertEqual({<<"$local/topic">>, #{}}, parse(<<"$local/topic">>)), ?assertEqual({<<"$local/$queue/topic">>, #{}}, parse(<<"$local/$queue/topic">>)), ?assertEqual({<<"$local/$share/group/a/b/c">>, #{}}, parse(<<"$local/$share/group/a/b/c">>)), ?assertEqual({<<"$fastlane/topic">>, #{}}, parse(<<"$fastlane/topic">>)). +bench(Case, Fun, Args) -> + {Time, ok} = timer:tc(fun lists:foreach/2, + [fun(_) -> apply(Fun, Args) end, + lists:seq(1, ?N) + ]), + ct:pal("Time consumed by ~s: ~.3f(us)~nCall ~s per second: ~w", + [Case, Time/?N, Case, (?N * 1000000) div Time]). + diff --git a/test/emqx_tracer_SUITE.erl b/test/emqx_tracer_SUITE.erl index 2d855a723..f02fa3209 100644 --- a/test/emqx_tracer_SUITE.erl +++ b/test/emqx_tracer_SUITE.erl @@ -20,10 +20,9 @@ -compile(nowarn_export_all). -include_lib("eunit/include/eunit.hrl"). - -include_lib("common_test/include/ct.hrl"). -all() -> [start_traces]. +all() -> [t_start_traces]. init_per_suite(Config) -> emqx_ct_helpers:start_apps([]), @@ -32,7 +31,7 @@ init_per_suite(Config) -> end_per_suite(_Config) -> emqx_ct_helpers:stop_apps([]). -start_traces(_Config) -> +t_start_traces(_Config) -> {ok, T} = emqx_client:start_link([{host, "localhost"}, {client_id, <<"client">>}, {username, <<"testuser">>}, diff --git a/test/emqx_trie_SUITE.erl b/test/emqx_trie_SUITE.erl index 2cb7d76de..1414c9027 100644 --- a/test/emqx_trie_SUITE.erl +++ b/test/emqx_trie_SUITE.erl @@ -25,8 +25,7 @@ -define(TRIE, emqx_trie). -define(TRIE_TABS, [emqx_trie, emqx_trie_node]). -all() -> - [t_mnesia, t_insert, t_match, t_match2, t_match3, t_empty, t_delete, t_delete2, t_delete3]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> application:load(emqx), @@ -51,7 +50,8 @@ t_insert(_) -> TN = #trie_node{node_id = <<"sensor">>, edge_count = 3, topic = <<"sensor">>, - flags = undefined}, + flags = undefined + }, Fun = fun() -> ?TRIE:insert(<<"sensor/1/metric/2">>), ?TRIE:insert(<<"sensor/+/#">>), diff --git a/test/emqx_vm_SUITE.erl b/test/emqx_vm_SUITE.erl index fc8f682a1..c4532ed26 100644 --- a/test/emqx_vm_SUITE.erl +++ b/test/emqx_vm_SUITE.erl @@ -19,7 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). --include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). -define(SYSTEM_INFO, [allocated_areas, allocator, @@ -94,82 +94,79 @@ min_heap_size]). %fullsweep_after]). +all() -> emqx_ct:all(?MODULE). +t_load(_Config) -> + ?assertMatch([{load1, _}, + {load5, _}, + {load15, _} + ], emqx_vm:loads()). -all() -> - [load, systeminfo, mem_info, process_list, process_info, process_gc, - get_ets_list, get_ets_info, get_ets_object, get_port_types, get_port_info, - scheduler_usage, get_memory, microsecs, schedulers, get_process_group_leader_info, - get_process_limit]. - -load(_Config) -> - Loads = emqx_vm:loads(), - [{load1, _}, {load5, _}, {load15, _}] = Loads. - -systeminfo(_Config) -> +t_systeminfo(_Config) -> Keys = [Key || {Key, _} <- emqx_vm:get_system_info()], ?SYSTEM_INFO = Keys. -mem_info(_Config) -> +t_mem_info(_Config) -> application:ensure_all_started(os_mon), MemInfo = emqx_vm:mem_info(), [{total_memory, _}, {used_memory, _}]= MemInfo, application:stop(os_mon). -process_list(_Config) -> +t_process_list(_Config) -> Pid = self(), ProcessInfo = emqx_vm:get_process_list(), true = lists:member({pid, Pid}, lists:concat(ProcessInfo)). -process_info(_Config) -> +t_process_info(_Config) -> ProcessInfos = emqx_vm:get_process_info(), ProcessInfo = lists:last(ProcessInfos), Keys = [K || {K, _V}<- ProcessInfo], ?PROCESS_INFO = Keys. -process_gc(_Config) -> +t_process_gc(_Config) -> ProcessGcs = emqx_vm:get_process_gc(), ProcessGc = lists:last(ProcessGcs), Keys = [K || {K, _V}<- ProcessGc], ?PROCESS_GC = Keys. - -get_ets_list(_Config) -> + +t_get_ets_list(_Config) -> ets:new(test, [named_table]), Ets = emqx_vm:get_ets_list(), true = lists:member(test, Ets). -get_ets_info(_Config) -> +t_get_ets_info(_Config) -> ets:new(test, [named_table]), [] = emqx_vm:get_ets_info(test1), EtsInfo = emqx_vm:get_ets_info(test), test = proplists:get_value(name, EtsInfo). -get_ets_object(_Config) -> +t_get_ets_object(_Config) -> ets:new(test, [named_table]), ets:insert(test, {k, v}), [{k, v}] = emqx_vm:get_ets_object(test). -get_port_types(_Config) -> +t_get_port_types(_Config) -> emqx_vm:get_port_types(). -get_port_info(_Config) -> +t_get_port_info(_Config) -> emqx_vm:get_port_info(). -scheduler_usage(_Config) -> +t_scheduler_usage(_Config) -> emqx_vm:scheduler_usage(5000). -get_memory(_Config) -> +t_get_memory(_Config) -> emqx_vm:get_memory(). - -microsecs(_Config) -> + +t_microsecs(_Config) -> emqx_vm:microsecs(). -schedulers(_Config) -> +t_schedulers(_Config) -> emqx_vm:schedulers(). -get_process_group_leader_info(_Config) -> +t_get_process_group_leader_info(_Config) -> emqx_vm:get_process_group_leader_info(self()). -get_process_limit(_Config) -> +t_get_process_limit(_Config) -> emqx_vm:get_process_limit(). + diff --git a/test/emqx_vm_mon_SUITE.erl b/test/emqx_vm_mon_SUITE.erl index f1234f1a2..438974ade 100644 --- a/test/emqx_vm_mon_SUITE.erl +++ b/test/emqx_vm_mon_SUITE.erl @@ -21,8 +21,6 @@ -include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - -define(WAIT(PATTERN, TIMEOUT), receive PATTERN -> @@ -32,7 +30,7 @@ error(timeout) end). -all() -> [t_api]. +all() -> emqx_ct:all(?MODULE). init_per_suite(Config) -> application:ensure_all_started(sasl), @@ -75,3 +73,4 @@ t_api(_) -> after meck:unload(alarm_handler) end. + diff --git a/test/emqx_ws_channel_SUITE.erl b/test/emqx_ws_channel_SUITE.erl deleted file mode 100644 index a02af8879..000000000 --- a/test/emqx_ws_channel_SUITE.erl +++ /dev/null @@ -1,144 +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_ws_channel_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("common_test/include/ct.hrl"). - --define(CLIENT, ?CONNECT_PACKET(#mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - username = <<"admin">>, - password = <<"public">>})). - --define(WILL_TOPIC, <<"test/websocket/will">>). - --define(WILL_CLIENT, ?CONNECT_PACKET(#mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - username = <<"admin">>, - password = <<"public">>, - will_flag = true, - will_qos = ?QOS_1, - will_topic = ?WILL_TOPIC, - will_payload = <<"payload">> - })). - -all() -> - [ t_ws_connect_api - , t_ws_auth_failure - , t_ws_other_type_frame - , t_ws_will - ]. - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_ws_will(_Config) -> - {ok, ClientPid} = emqx_client:start_link(), - {ok, _} = emqx_client:connect(ClientPid), - {ok, _, [1]} = emqx_client:subscribe(ClientPid, ?WILL_TOPIC, qos1), - WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), - {ok, _} = rfc6455_client:open(WS), - Packet = raw_send_serialize(?WILL_CLIENT), - ok = rfc6455_client:send_binary(WS, Packet), - {binary, Bin} = rfc6455_client:recv(WS), - Connack = ?CONNACK_PACKET(?CONNACK_ACCEPT), - {ok, Connack, <<>>, _} = raw_recv_pase(Bin), - exit(WS, abnomal), - ?assertEqual(1, length(emqx_client_SUITE:receive_messages(1))), - ok = emqx_client:disconnect(ClientPid), - ok. - -t_ws_auth_failure(_Config) -> - application:set_env(emqx, allow_anonymous, false), - WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), - {ok, _} = rfc6455_client:open(WS), - Connect = ?CONNECT_PACKET( - #mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - username = <<"admin">>, - password = <<"public">> - }), - ok = rfc6455_client:send_binary(WS, raw_send_serialize(Connect)), - {binary, Bin} = rfc6455_client:recv(WS), - Connack = ?CONNACK_PACKET(?CONNACK_ACCEPT), - {ok, Connack, <<>>, _} = raw_recv_pase(Bin), - Pid = emqx_cm:lookup_conn_pid(<<"mqtt_client">>), - ConnInfo = emqx_ws_channel:info(Pid), - ok = t_info(ConnInfo), - ConnAttrs = emqx_ws_channel:attrs(Pid), - ok = t_attrs(ConnAttrs), - ConnStats = emqx_ws_channel:stats(Pid), - ok = t_stats(ConnStats), - SessionPid = emqx_ws_channel:session(Pid), - true = is_pid(SessionPid), - ok = emqx_ws_channel:kick(Pid), - {close, _} = rfc6455_client:close(WS), - ok. - -t_ws_other_type_frame(_Config) -> - WS = rfc6455_client:new("ws://127.0.0.1:8083" ++ "/mqtt", self()), - {ok, _} = rfc6455_client:open(WS), - Connect = ?CONNECT_PACKET( - #mqtt_packet_connect{ - client_id = <<"mqtt_client">>, - username = <<"admin">>, - password = <<"public">> - }), - ok = rfc6455_client:send_binary(WS, raw_send_serialize(Connect)), - {binary, Bin} = rfc6455_client:recv(WS), - Connack = ?CONNACK_PACKET(?CONNACK_ACCEPT), - {ok, Connack, <<>>, _} = raw_recv_pase(Bin), - rfc6455_client:send(WS, <<"testdata">>), - timer:sleep(1000), - ?assertEqual(undefined, erlang:process_info(WS)), - ok. - -raw_send_serialize(Packet) -> - emqx_frame:serialize(Packet). - -raw_recv_pase(Packet) -> - emqx_frame:parse(Packet). - -t_info(InfoData) -> - ?assertEqual(websocket, maps:get(socktype, InfoData)), - ?assertEqual(running, maps:get(conn_state, InfoData)), - ?assertEqual(<<"mqtt_client">>, maps:get(client_id, InfoData)), - ?assertEqual(<<"admin">>, maps:get(username, InfoData)), - ?assertEqual(<<"MQTT">>, maps:get(proto_name, InfoData)). - -t_attrs(AttrsData) -> - ?assertEqual(<<"mqtt_client">>, maps:get(client_id, AttrsData)), - ?assertEqual(emqx_ws_channel, maps:get(conn_mod, AttrsData)), - ?assertEqual(<<"admin">>, maps:get(username, AttrsData)). - -t_stats(StatsData) -> - ?assertEqual(true, proplists:get_value(recv_oct, StatsData) >= 0), - ?assertEqual(true, proplists:get_value(mailbox_len, StatsData) >= 0), - ?assertEqual(true, proplists:get_value(heap_size, StatsData) >= 0), - ?assertEqual(true, proplists:get_value(reductions, StatsData) >=0), - ?assertEqual(true, proplists:get_value(recv_pkt, StatsData) =:=1), - ?assertEqual(true, proplists:get_value(recv_msg, StatsData) >=0), - ?assertEqual(true, proplists:get_value(send_pkt, StatsData) =:=1). - diff --git a/test/emqx_zone_SUITE.erl b/test/emqx_zone_SUITE.erl index ee73ecc7a..c9502d0a7 100644 --- a/test/emqx_zone_SUITE.erl +++ b/test/emqx_zone_SUITE.erl @@ -19,20 +19,31 @@ -compile(export_all). -compile(nowarn_export_all). --include("emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). -all() -> [t_set_get_env]. +-define(OPTS, [{enable_acl, true}, + {enable_banned, false} + ]). + +all() -> emqx_ct:all(?MODULE). t_set_get_env(_) -> - application:set_env(emqx, zones, [{china, [{language, chinese}]}]), + _ = application:load(emqx), + application:set_env(emqx, zones, [{external, ?OPTS}]), {ok, _} = emqx_zone:start_link(), - chinese = emqx_zone:get_env(china, language), - cn470 = emqx_zone:get_env(china, ism_band, cn470), - undefined = emqx_zone:get_env(undefined, delay), - 500 = emqx_zone:get_env(undefined, delay, 500), - application:set_env(emqx, zones, [{zone1, [{key, val}]}]), - ?assertEqual(undefined, emqx_zone:get_env(zone1, key)), - emqx_zone:force_reload(), - ?assertEqual(val, emqx_zone:get_env(zone1, key)), + ?assert(emqx_zone:get_env(external, enable_acl)), + ?assertNot(emqx_zone:get_env(external, enable_banned)), + ?assertEqual(defval, emqx_zone:get_env(extenal, key, defval)), + ?assertEqual(undefined, emqx_zone:get_env(external, key)), + ?assertEqual(undefined, emqx_zone:get_env(internal, key)), + ?assertEqual(def, emqx_zone:get_env(internal, key, def)), emqx_zone:stop(). + +t_force_reload(_) -> + {ok, _} = emqx_zone:start_link(), + application:set_env(emqx, zones, [{zone, [{key, val}]}]), + ?assertEqual(undefined, emqx_zone:get_env(zone, key)), + ok = emqx_zone:force_reload(), + ?assertEqual(val, emqx_zone:get_env(zone, key)), + emqx_zone:stop(). + diff --git a/test/rfc6455_client.erl b/test/rfc6455_client.erl deleted file mode 100644 index 18b094a76..000000000 --- a/test/rfc6455_client.erl +++ /dev/null @@ -1,251 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (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.mozilla.org/MPL/ -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -%% License for the specific language governing rights and limitations -%% under the License. -%% -%% The Original Code is RabbitMQ Management Console. -%% -%% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2012-2016 Pivotal Software, Inc. All rights reserved. -%% - --module(rfc6455_client). - --export([new/2, open/1, recv/1, send/2, send_binary/2, close/1, close/2]). - --record(state, {host, port, addr, path, ppid, socket, data, phase}). - -%% -------------------------------------------------------------------------- - -new(WsUrl, PPid) -> - crypto:start(), - "ws://" ++ Rest = WsUrl, - [Addr, Path] = split("/", Rest, 1), - [Host, MaybePort] = split(":", Addr, 1, empty), - Port = case MaybePort of - empty -> 80; - V -> {I, ""} = string:to_integer(V), I - end, - State = #state{host = Host, - port = Port, - addr = Addr, - path = "/" ++ Path, - ppid = PPid}, - spawn(fun() -> - start_conn(State) - end). - -open(WS) -> - receive - {rfc6455, open, WS, Opts} -> - {ok, Opts}; - {rfc6455, close, WS, R} -> - {close, R} - end. - -recv(WS) -> - receive - {rfc6455, recv, WS, Payload} -> - {ok, Payload}; - {rfc6455, recv_binary, WS, Payload} -> - {binary, Payload}; - {rfc6455, close, WS, R} -> - {close, R} - end. - -send(WS, IoData) -> - WS ! {send, IoData}, - ok. - -send_binary(WS, IoData) -> - WS ! {send_binary, IoData}, - ok. - -close(WS) -> - close(WS, {1000, ""}). - -close(WS, WsReason) -> - WS ! {close, WsReason}, - receive - {rfc6455, close, WS, R} -> - {close, R} - end. - - -%% -------------------------------------------------------------------------- - -start_conn(State) -> - {ok, Socket} = gen_tcp:connect(State#state.host, State#state.port, - [binary, - {packet, 0}]), - Key = base64:encode_to_string(crypto:strong_rand_bytes(16)), - gen_tcp:send(Socket, - "GET " ++ State#state.path ++ " HTTP/1.1\r\n" ++ - "Host: " ++ State#state.addr ++ "\r\n" ++ - "Upgrade: websocket\r\n" ++ - "Connection: Upgrade\r\n" ++ - "Sec-WebSocket-Key: " ++ Key ++ "\r\n" ++ - "Origin: null\r\n" ++ - "Sec-WebSocket-Protocol: mqtt\r\n" ++ - "Sec-WebSocket-Version: 13\r\n\r\n"), - - loop(State#state{socket = Socket, - data = <<>>, - phase = opening}). - -do_recv(State = #state{phase = opening, ppid = PPid, data = Data}) -> - case split("\r\n\r\n", binary_to_list(Data), 1, empty) of - [_Http, empty] -> State; - [Http, Data1] -> - %% TODO: don't ignore http response data, verify key - PPid ! {rfc6455, open, self(), [{http_response, Http}]}, - State#state{phase = open, - data = Data1} - end; -do_recv(State = #state{phase = Phase, data = Data, socket = Socket, ppid = PPid}) - when Phase =:= open orelse Phase =:= closing -> - R = case Data of - <> - when L < 126 -> - {F, O, Payload, Rest}; - - <> -> - {F, O, Payload, Rest}; - - <> -> - {F, O, Payload, Rest}; - - <<_:1, _:3, _:4, 1:1, _/binary>> -> - %% According o rfc6455 5.1 the server must not mask any frames. - die(Socket, PPid, {1006, "Protocol error"}, normal); - _ -> - moredata - end, - case R of - moredata -> - State; - _ -> do_recv2(State, R) - end. - -do_recv2(State = #state{phase = Phase, socket = Socket, ppid = PPid}, R) -> - case R of - {1, 1, Payload, Rest} -> - PPid ! {rfc6455, recv, self(), Payload}, - State#state{data = Rest}; - {1, 2, Payload, Rest} -> - PPid ! {rfc6455, recv_binary, self(), Payload}, - State#state{data = Rest}; - {1, 8, Payload, _Rest} -> - WsReason = case Payload of - <> -> {WC, WR}; - <<>> -> {1005, "No status received"} - end, - case Phase of - open -> %% echo - do_close(State, WsReason), - gen_tcp:close(Socket); - closing -> - ok - end, - die(Socket, PPid, WsReason, normal); - {_, _, _, _Rest2} -> - io:format("Unknown frame type~n"), - die(Socket, PPid, {1006, "Unknown frame type"}, normal) - end. - -encode_frame(F, O, Payload) -> - Mask = crypto:strong_rand_bytes(4), - MaskedPayload = apply_mask(Mask, iolist_to_binary(Payload)), - - L = byte_size(MaskedPayload), - IoData = case L of - _ when L < 126 -> - [<>, Mask, MaskedPayload]; - _ when L < 65536 -> - [<>, Mask, MaskedPayload]; - _ -> - [<>, Mask, MaskedPayload] - end, - iolist_to_binary(IoData). - -do_send(State = #state{socket = Socket}, Payload) -> - gen_tcp:send(Socket, encode_frame(1, 1, Payload)), - State. - -do_send_binary(State = #state{socket = Socket}, Payload) -> - gen_tcp:send(Socket, encode_frame(1, 2, Payload)), - State. - -do_close(State = #state{socket = Socket}, {Code, Reason}) -> - Payload = iolist_to_binary([<>, Reason]), - gen_tcp:send(Socket, encode_frame(1, 8, Payload)), - State#state{phase = closing}. - -loop(State = #state{socket = Socket, ppid = PPid, data = Data, - phase = Phase}) -> - receive - {tcp, Socket, Bin} -> - State1 = State#state{data = iolist_to_binary([Data, Bin])}, - loop(do_recv(State1)); - {send, Payload} when Phase == open -> - loop(do_send(State, Payload)); - {send_binary, Payload} when Phase == open -> - loop(do_send_binary(State, Payload)); - {tcp_closed, Socket} -> - die(Socket, PPid, {1006, "Connection closed abnormally"}, normal); - {close, WsReason} when Phase == open -> - loop(do_close(State, WsReason)) - end. - - -die(Socket, PPid, WsReason, Reason) -> - gen_tcp:shutdown(Socket, read_write), - PPid ! {rfc6455, close, self(), WsReason}, - exit(Reason). - - -%% -------------------------------------------------------------------------- - -split(SubStr, Str, Limit) -> - split(SubStr, Str, Limit, ""). - -split(SubStr, Str, Limit, Default) -> - Acc = split(SubStr, Str, Limit, [], Default), - lists:reverse(Acc). -split(_SubStr, Str, 0, Acc, _Default) -> [Str | Acc]; -split(SubStr, Str, Limit, Acc, Default) -> - {L, R} = case string:str(Str, SubStr) of - 0 -> {Str, Default}; - I -> {string:substr(Str, 1, I-1), - string:substr(Str, I+length(SubStr))} - end, - split(SubStr, R, Limit-1, [L | Acc], Default). - - -apply_mask(Mask, Data) when is_number(Mask) -> - apply_mask(<>, Data); - -apply_mask(<<0:32>>, Data) -> - Data; -apply_mask(Mask, Data) -> - iolist_to_binary(lists:reverse(apply_mask2(Mask, Data, []))). - -apply_mask2(M = <>, <>, Acc) -> - T = Data bxor Mask, - apply_mask2(M, Rest, [<> | Acc]); -apply_mask2(<>, <>, Acc) -> - T = Data bxor Mask, - [<> | Acc]; -apply_mask2(<>, <>, Acc) -> - T = Data bxor Mask, - [<> | Acc]; -apply_mask2(<>, <>, Acc) -> - T = Data bxor Mask, - [<> | Acc]; -apply_mask2(_, <<>>, Acc) -> - Acc. diff --git a/test/ws_client.erl b/test/ws_client.erl deleted file mode 100644 index 39f01467a..000000000 --- a/test/ws_client.erl +++ /dev/null @@ -1,75 +0,0 @@ --module(ws_client). - --export([ - start_link/0, - start_link/1, - send_binary/2, - send_ping/2, - recv/2, - recv/1, - stop/1 - ]). - --export([ - init/2, - websocket_handle/3, - websocket_info/3, - websocket_terminate/3 - ]). - --record(state, { - buffer = [] :: list(), - waiting = undefined :: undefined | pid() - }). - -start_link() -> - start_link("ws://localhost:8083/mqtt"). - -start_link(Url) -> - websocket_client:start_link(Url, ?MODULE, [], [{extra_headers, [{"Sec-Websocket-Protocol", "mqtt"}]}]). - -stop(Pid) -> - Pid ! stop. - -send_binary(Pid, Msg) -> - websocket_client:cast(Pid, {binary, Msg}). - -send_ping(Pid, Msg) -> - websocket_client:cast(Pid, {ping, Msg}). - -recv(Pid) -> - recv(Pid, 5000). - -recv(Pid, Timeout) -> - Pid ! {recv, self()}, - receive - M -> M - after - Timeout -> error - end. - -init(_, _WSReq) -> - {ok, #state{}}. - -websocket_handle(Frame, _, State = #state{waiting = undefined, buffer = Buffer}) -> - logger:info("Client received frame~p", [Frame]), - {ok, State#state{buffer = [Frame|Buffer]}}; -websocket_handle(Frame, _, State = #state{waiting = From}) -> - logger:info("Client received frame~p", [Frame]), - From ! Frame, - {ok, State#state{waiting = undefined}}. - -websocket_info({send_text, Text}, WSReq, State) -> - websocket_client:send({text, Text}, WSReq), - {ok, State}; -websocket_info({recv, From}, _, State = #state{buffer = []}) -> - {ok, State#state{waiting = From}}; -websocket_info({recv, From}, _, State = #state{buffer = [Top|Rest]}) -> - From ! Top, - {ok, State#state{buffer = Rest}}; -websocket_info(stop, _, State) -> - {close, <<>>, State}. - -websocket_terminate(Close, _, State) -> - io:format("Websocket closed with frame ~p and state ~p", [Close, State]), - ok.