Ver código fonte

common tests

Feng 10 anos atrás
pai
commit
928780f322

+ 7 - 0
.gitignore

@@ -19,3 +19,10 @@ log/
 *.so
 examples
 docs/build/*
+.erlang.mk/
+cover/
+emqttd.d
+eunit.coverdata
+test/ct.cover.spec
+logs
+ct.coverdata

+ 4 - 1
Makefile

@@ -26,7 +26,10 @@ clean:
 	@$(REBAR) clean
 
 test:
-	@ERL_FLAGS="-args_file rel/files/vm.args -config rel/files/test.config" $(REBAR) skip_deps=true eunit
+	$(REBAR) skip_deps=true eunit
+
+ct:
+	ERL_FLAGS="-config rel/files/test.config" $(REBAR) -v skip_deps=true ct
 
 edoc:
 	@$(REBAR) doc

+ 14 - 5
rebar.config

@@ -11,17 +11,26 @@
             {i, "include"},
 			{src_dirs, ["src"]}]}.
 
-{eunit_opts, []}. %%verbose
-
-{xref_checks, [undefined_function_calls]}.
-{cover_enabled, true}.
-
 {validate_app_modules, true}.
 
 {erl_first_files, ["src/gen_server2.erl",
                    "src/emqttd_auth_mod.erl",
                    "src/emqttd_acl_mod.erl"]}.
 
+{eunit_opts, []}. %%verbose
+
+{ct_dir, "test"}.
+
+{ct_log_dir, "logs"}.
+
+{ct_extra_params, "-name ct_emqttd@127.0.0.1 -config rel/files/test.config"}.
+
+{ct_use_short_names, false}.
+
+{xref_checks, [undefined_function_calls]}.
+
+{cover_enabled, true}.
+
 %% plugins cannot find emqttd.hrl without ".." lib dirs:(
 %% but this setting will make deps apps collision
 %% comment in 0.13.0 release

+ 2 - 2
rel/files/test.config

@@ -5,7 +5,7 @@
     {start_pg2, true}
  ]},
  {sasl, [
-    {sasl_error_logger, {file, "log/emqttd_sasl.log"}}
+    {sasl_error_logger, {file, "emqttd_sasl.log"}}
  ]},
  {ssl, [
     %{versions, ['tlsv1.2', 'tlsv1.1']}
@@ -69,7 +69,7 @@
         %% ACL config
         {acl, [
             %% Internal ACL module
-            {internal,  [{file, "testdata/test_acl.config"}, {nomatch, allow}]}
+            %% {internal,  [{file, "testdata/test_acl.config"}, {nomatch, allow}]}
         ]}
     ]},
     %% MQTT Protocol Options

+ 214 - 0
test/emqttd_SUITE.erl

@@ -0,0 +1,214 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
+%%
+%% 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(emqttd_SUITE).
+
+-compile(export_all).
+
+-include("emqttd.hrl").
+
+all() ->
+    [{group, pubsub},
+     {group, router},
+     {group, session},
+     {group, retainer},
+     {group, broker},
+     {group, metrics},
+     {group, stats}].
+
+groups() ->
+    [{pubsub, [sequence],
+      [create_topic,
+       create_subscription,
+       subscribe_unsubscribe,
+       publish_message]},
+     {router, [sequence],
+      [add_delete_routes,
+       add_delete_route,
+       route_message]},
+     {session, [sequence],
+      [start_session]},
+     {retainer, [sequence],
+      [retain_message]},
+     {broker, [sequence],
+      [hook_unhook]},
+     {metrics, [sequence],
+      [inc_dec_metric]},
+     {stats, [sequence],
+      [set_get_stat]}].
+
+init_per_suite(Config) ->
+    application:start(lager),
+    application:ensure_all_started(emqttd),
+    Config.
+
+end_per_suite(_Config) ->
+    application:stop(emqttd),
+    application:stop(esockd),
+    application:stop(gproc),
+    emqttd_mnesia:ensure_stopped().
+
+%%--------------------------------------------------------------------
+%% PubSub Group
+%%--------------------------------------------------------------------
+
+create_topic(_) ->
+    Node = node(),
+    ok = emqttd_pubsub:create(topic, <<"topic/create">>),
+    ok = emqttd_pubsub:create(topic, <<"topic/create2">>),
+    [#mqtt_topic{topic = <<"topic/create">>, node  = Node}]
+        = emqttd_pubsub:lookup(topic, <<"topic/create">>).
+
+create_subscription(_) ->
+    ok = emqttd_pubsub:create(subscription, {<<"clientId">>, <<"topic/sub">>, qos2}),
+    [#mqtt_subscription{subid = <<"clientId">>, topic = <<"topic/sub">>, qos = 2}]
+        = emqttd_pubsub:lookup(subscription, <<"clientId">>),
+    ok = emqttd_pubsub:delete(subscription, <<"clientId">>),
+    [] = emqttd_pubsub:lookup(subscription, <<"clientId">>).
+
+subscribe_unsubscribe(_) ->
+    {ok, [1]} = emqttd_pubsub:subscribe({<<"topic/subunsub">>, 1}),
+    {ok, [1, 2]} = emqttd_pubsub:subscribe([{<<"topic/subunsub1">>, 1}, {<<"topic/subunsub2">>, 2}]),
+    ok = emqttd_pubsub:unsubscribe(<<"topic/subunsub">>),
+    ok = emqttd_pubsub:unsubscribe([<<"topic/subunsub1">>, <<"topic/subunsub2">>]),
+
+    {ok, [1]} = emqttd_pubsub:subscribe(<<"client_subunsub">>, {<<"topic/subunsub">>, 1}),
+    {ok, [1,2]} = emqttd_pubsub:subscribe(<<"client_subunsub">>, [{<<"topic/subunsub1">>, 1},
+                                                         {<<"topic/subunsub2">>, 2}]),
+    ok = emqttd_pubsub:unsubscribe(<<"client_subunsub">>, <<"topic/subunsub">>),
+    ok = emqttd_pubsub:unsubscribe(<<"client_subunsub">>, [<<"topic/subunsub1">>,
+                                                           <<"topic/subunsub2">>]).
+
+publish_message(_) ->
+    Msg = emqttd_message:make(ct, <<"test/pubsub">>, <<"hello">>),
+    {ok, [1]} = emqttd_pubsub:subscribe({<<"test/+">>, qos1}),
+    emqttd_pubsub:publish(Msg),
+    true = receive {dispatch, <<"test/+">>, Msg} -> true after 5 -> false end.
+
+%%--------------------------------------------------------------------
+%% Route Group
+%%--------------------------------------------------------------------
+
+add_delete_route(_) ->
+    Self = self(),
+    emqttd_router:add_route(<<"topic1">>, Self),
+    true = emqttd_router:has_route(<<"topic1">>),
+    emqttd_router:add_route(<<"topic2">>, Self),
+    true = emqttd_router:has_route(<<"topic2">>),
+    [Self] = emqttd_router:lookup_routes(<<"topic1">>),
+    [Self] = emqttd_router:lookup_routes(<<"topic2">>),
+    %% Del topic1
+    emqttd_router:delete_route(<<"topic1">>, Self),
+    erlang:yield(),
+    timer:sleep(10),
+    false = emqttd_router:has_route(<<"topic1">>),
+    %% Del topic2
+    emqttd_router:delete_route(<<"topic2">>, Self),
+    erlang:yield(),
+    timer:sleep(10),
+    false = emqttd_router:has_route(<<"topic2">>).
+
+add_delete_routes(_) ->
+    Self = self(),
+    emqttd_router:add_routes([], Self),
+    emqttd_router:add_routes([<<"t0">>], Self),
+    emqttd_router:add_routes([<<"t1">>,<<"t2">>,<<"t3">>], Self),
+    true = emqttd_router:has_route(<<"t1">>),
+    [Self] = emqttd_router:lookup_routes(<<"t1">>),
+    [Self] = emqttd_router:lookup_routes(<<"t2">>),
+    [Self] = emqttd_router:lookup_routes(<<"t3">>),
+
+    emqttd_router:delete_routes([<<"t3">>], Self),
+    emqttd_router:delete_routes([<<"t0">>, <<"t1">>], Self),
+    erlang:yield(),
+    timer:sleep(10),
+    false = emqttd_router:has_route(<<"t0">>),
+    false = emqttd_router:has_route(<<"t1">>),
+    true = emqttd_router:has_route(<<"t2">>),
+    false = emqttd_router:has_route(<<"t3">>).
+
+route_message(_) ->
+    Self = self(),
+    Pid = spawn_link(fun() -> timer:sleep(1000) end),
+    emqttd_router:add_routes([<<"$Q/1">>,<<"t/2">>,<<"t/3">>], Self),
+    emqttd_router:add_routes([<<"t/2">>], Pid),
+    Msg1 = #mqtt_message{topic = <<"$Q/1">>, payload = <<"q">>},
+    Msg2 = #mqtt_message{topic = <<"t/2">>, payload = <<"t2">>},
+    Msg3 = #mqtt_message{topic = <<"t/3">>, payload = <<"t3">>},
+    emqttd_router:route(<<"$Q/1">>, Msg1),
+    emqttd_router:route(<<"t/2">>, Msg2),
+    emqttd_router:route(<<"t/3">>, Msg3),
+    [Msg1, Msg2, Msg3] = recv_loop([]),
+    emqttd_router:add_route(<<"$Q/1">>, Self),
+    emqttd_router:route(<<"$Q/1">>, Msg1).
+
+recv_loop(Msgs) ->
+    receive
+        {dispatch, _Topic, Msg} ->
+            recv_loop([Msg|Msgs])
+        after
+            100 -> lists:reverse(Msgs)
+    end.
+
+%%--------------------------------------------------------------------
+%% Session Group
+%%--------------------------------------------------------------------
+
+start_session(_) ->
+    {ok, ClientPid} = emqttd_mock_client:start_link(<<"clientId">>),
+    {ok, SessPid} = emqttd_mock_client:start_session(ClientPid),
+    Message = emqttd_message:make(<<"clientId">>, 2, <<"topic">>, <<"hello">>),
+    Message1 = Message#mqtt_message{pktid = 1},
+    emqttd_session:publish(SessPid, Message1),
+    emqttd_session:pubrel(SessPid, 1),
+    emqttd_session:subscribe(SessPid, [{<<"topic/session">>, 2}]),
+    Message2 = emqttd_message:make(<<"clientId">>, 1, <<"topic/session">>, <<"test">>),
+    emqttd_session:publish(SessPid, Message2),
+    emqttd_session:unsubscribe(SessPid, [<<"topic/session">>]),
+    emqttd_mock_client:stop(ClientPid).
+
+%%--------------------------------------------------------------------
+%% Retainer Group
+%%--------------------------------------------------------------------
+
+retain_message(_) ->
+    Msg = #mqtt_message{retain = true, topic = <<"a/b/c">>,
+                        payload = <<"payload">>},
+    emqttd_retainer:retain(Msg),
+    emqttd_retainer:dispatch(<<"a/b/+">>, self()),
+    true = receive {dispatch, <<"a/b/+">>, Msg} -> true after 10 -> false end,
+    emqttd_retainer:retain(#mqtt_message{retain = true, topic = <<"a/b/c">>, payload = <<>>}),
+    [] = mnesia:dirty_read({retained, <<"a/b/c">>}).
+
+%%--------------------------------------------------------------------
+%% Broker Group
+%%--------------------------------------------------------------------
+hook_unhook(_) ->
+    ok.
+
+%%--------------------------------------------------------------------
+%% Metric Group
+%%--------------------------------------------------------------------
+inc_dec_metric(_) ->
+    emqttd_metrics:inc(gauge, 'messages/retained', 10),
+    emqttd_metrics:dec(gauge, 'messages/retained', 10).
+
+%%--------------------------------------------------------------------
+%% Stats Group
+%%--------------------------------------------------------------------
+set_get_stat(_) ->
+    emqttd_stats:setstat('retained/max', 99),
+    99 = emqttd_stats:getstat('retained/max').

+ 166 - 0
test/emqttd_access_SUITE.erl

@@ -0,0 +1,166 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
+%%
+%% 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(emqttd_access_SUITE).
+
+-compile(export_all).
+
+-include("emqttd.hrl").
+
+-define(AC, emqttd_access_control).
+
+-import(emqttd_access_rule, [compile/1, match/3]).
+
+all() ->
+    [{group, access_control},
+     {group, access_rule}].
+
+groups() ->
+    [{access_control, [sequence],
+      [reload_acl,
+       register_mod,
+       unregister_mod,
+       check_acl]},
+     {access_rule, [],
+      [compile_rule,
+       match_rule]}].
+
+init_per_group(_Group, Config) ->
+    Config.
+
+end_per_group(_Group, Config) ->
+    Config.
+
+init_per_testcase(TestCase, Config) when TestCase =:= reload_acl;
+                                         TestCase =:= register_mod;
+                                         TestCase =:= unregister_mod;
+                                         TestCase =:= check_acl ->
+    DataDir = proplists:get_value(data_dir, Config),
+    AclOpts = [
+        {auth, [{anonymous, []}]},
+        {acl,  [{internal, [{file, filename:join([DataDir, "test_acl.config"])},
+                            {nomatch, allow}]}]}
+    ],
+    {ok, _Pid} = ?AC:start_link(AclOpts),
+    Config;
+
+init_per_testcase(_TestCase, Config) ->
+    Config.
+
+end_per_testcase(TestCase, _Config) when TestCase =:= reload_acl;
+                                         TestCase =:= register_mod;
+                                         TestCase =:= unregister_mod;
+                                         TestCase =:= check_acl ->
+    ?AC:stop();
+
+end_per_testcase(_TestCase, _Config) ->
+    ok.
+
+%%--------------------------------------------------------------------
+%% emqttd_access_control
+%%--------------------------------------------------------------------
+
+reload_acl(_) ->
+    ct:print("~p~n", [whereis(?AC)]),
+    [ok] = ?AC:reload_acl().
+
+register_mod(_) ->
+    ok = ?AC:register_mod(acl, emqttd_acl_test_mod, []),
+    [{emqttd_acl_test_mod, _, 0},
+     {emqttd_acl_internal, _, 0}] = ?AC:lookup_mods(acl),
+    ok = ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
+    ok = ?AC:register_mod(auth, emqttd_auth_dashboard, [], 99),
+    [{emqttd_auth_dashboard, _, 99},
+     {emqttd_auth_anonymous_test_mod, _, 0},
+     {emqttd_auth_anonymous, _, 0}] = ?AC:lookup_mods(auth).
+
+unregister_mod(_) ->
+    ok = ?AC:register_mod(acl, emqttd_acl_test_mod, []),
+    [{emqttd_acl_test_mod, _, 0},
+     {emqttd_acl_internal, _, 0}] = ?AC:lookup_mods(acl),
+    ok = ?AC:unregister_mod(acl, emqttd_acl_test_mod),
+    timer:sleep(5),
+    [{emqttd_acl_internal, _, 0}] = ?AC:lookup_mods(acl),
+    ok = ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
+    [{emqttd_auth_anonymous_test_mod, _, 0},
+     {emqttd_auth_anonymous, _, 0}] = ?AC:lookup_mods(auth),
+
+    ok = ?AC:unregister_mod(auth, emqttd_auth_anonymous_test_mod),
+    timer:sleep(5),
+    [{emqttd_auth_anonymous, _, 0}] = ?AC:lookup_mods(auth).
+
+check_acl(_) ->
+    User1 = #mqtt_client{client_id = <<"client1">>, username = <<"testuser">>},
+    User2 = #mqtt_client{client_id = <<"client2">>, username = <<"xyz">>},
+    allow = ?AC:check_acl(User1, subscribe, <<"users/testuser/1">>),
+    allow = ?AC:check_acl(User1, subscribe, <<"clients/client1">>),
+    deny  = ?AC:check_acl(User1, subscribe, <<"clients/client1/x/y">>),
+    allow = ?AC:check_acl(User1, publish, <<"users/testuser/1">>),
+    allow = ?AC:check_acl(User1, subscribe, <<"a/b/c">>),
+    deny  = ?AC:check_acl(User2, subscribe, <<"a/b/c">>).
+
+%%--------------------------------------------------------------------
+%% emqttd_access_rule
+%%--------------------------------------------------------------------
+
+compile_rule(_) ->
+
+    {allow, {'and', [{ipaddr, {"127.0.0.1", _I, _I}},
+                     {user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
+        compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]}),
+    {allow, {'or', [{ipaddr, {"127.0.0.1", _I, _I}},
+                    {user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
+        compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]}),
+
+    {allow, {ipaddr, {"127.0.0.1", _I, _I}}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
+        compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}),
+    {allow, {user, <<"testuser">>}, subscribe, [ [<<"a">>, <<"b">>, <<"c">>], [<<"d">>, <<"e">>, <<"f">>, '#'] ]} =
+        compile({allow, {user, "testuser"}, subscribe, ["a/b/c", "d/e/f/#"]}),
+    {allow, {user, <<"admin">>}, pubsub, [ [<<"d">>, <<"e">>, <<"f">>, '#'] ]} =
+        compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]}),
+    {allow, {client, <<"testClient">>}, publish, [ [<<"testTopics">>, <<"testClient">>] ]} =
+        compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]}),
+    {allow, all, pubsub, [{pattern, [<<"clients">>, <<"$c">>]}]} =
+        compile({allow, all, pubsub, ["clients/$c"]}),
+    {allow, all, subscribe, [{pattern, [<<"users">>, <<"$u">>, '#']}]} =
+        compile({allow, all, subscribe, ["users/$u/#"]}),
+    {deny, all, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]} =
+        compile({deny, all, subscribe, ["$SYS/#", "#"]}),
+    {allow, all} = compile({allow, all}),
+    {deny, all} = compile({deny, all}).
+
+match_rule(_) ->
+    User = #mqtt_client{peername = {{127,0,0,1}, 2948}, client_id = <<"testClient">>, username = <<"TestUser">>},
+    User2 = #mqtt_client{peername = {{192,168,0,10}, 3028}, client_id = <<"testClient">>, username = <<"TestUser">>},
+    
+    {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(#mqtt_client{username = <<"user2">>}, <<"users/user2/abc/def">>,
+                             compile({allow, all, subscribe, ["users/$u/#"]})),
+    {matched, deny} = match(User, <<"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),
+    AndRule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}),
+    {matched, allow} = match(User, <<"Topic">>, AndRule),
+    OrRule = compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}),
+    {matched, allow} = match(User, <<"Topic">>, OrRule).
+

testdata/test_acl.config → test/emqttd_access_SUITE_data/test_acl.config


+ 0 - 93
test/emqttd_access_control_tests.erl

@@ -1,93 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_access_control_tests).
-
--ifdef(TEST).
-
--include("emqttd.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--define(AC, emqttd_access_control).
-
-acl_test_() ->
-    {foreach,
-     fun setup/0,
-     fun teardown/1,
-     [?_test(t_reload_acl()),
-      ?_test(t_register_mod()),
-      ?_test(t_unregister_mod()),
-      ?_test(t_check_acl())
-     ]}.
-
-setup() ->
-    AclOpts = [
-        {auth, [{anonymous, []}]},
-        {acl, [ %% ACL config
-            %% Internal ACL module
-            {internal,  [{file, "../testdata/test_acl.config"}, {nomatch, allow}]}
-        ]}
-    ],
-    ?AC:start_link(AclOpts).
-
-teardown({ok, _Pid}) ->
-    ?AC:stop().
-
-t_reload_acl() ->
-    ?assertEqual([ok], ?AC:reload_acl()).
-
-t_register_mod() ->
-    ?AC:register_mod(acl, emqttd_acl_test_mod, []),
-    ?assertMatch([{emqttd_acl_test_mod, _, 0},
-                  {emqttd_acl_internal, _, 0}],
-                 ?AC:lookup_mods(acl)),
-    ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
-    ?AC:register_mod(auth, emqttd_auth_dashboard, [], 99),
-    ?assertMatch([{emqttd_auth_dashboard, _, 99},
-                  {emqttd_auth_anonymous_test_mod, _, 0},
-                  {emqttd_auth_anonymous, _, 0}],
-                 ?AC:lookup_mods(auth)).
-
-t_unregister_mod() ->
-    ?AC:register_mod(acl, emqttd_acl_test_mod, []),
-    ?assertMatch([{emqttd_acl_test_mod, _, 0}, {emqttd_acl_internal, _, 0}],
-                 ?AC:lookup_mods(acl)),
-    ?AC:unregister_mod(acl, emqttd_acl_test_mod),
-    timer:sleep(5),
-    ?assertMatch([{emqttd_acl_internal, _, 0}], ?AC:lookup_mods(acl)),
-
-    ?AC:register_mod(auth, emqttd_auth_anonymous_test_mod,[]),
-    ?assertMatch([{emqttd_auth_anonymous_test_mod, _, 0},
-                  {emqttd_auth_anonymous, _, 0}],
-                 ?AC:lookup_mods(auth)),
-
-    ?AC:unregister_mod(auth, emqttd_auth_anonymous_test_mod),
-    timer:sleep(5),
-    ?assertMatch([{emqttd_auth_anonymous, _, 0}], ?AC:lookup_mods(auth)).
-
-t_check_acl() ->
-    User1 = #mqtt_client{client_id = <<"client1">>, username = <<"testuser">>},
-    User2 = #mqtt_client{client_id = <<"client2">>, username = <<"xyz">>},
-    ?assertEqual(allow, ?AC:check_acl(User1, subscribe, <<"users/testuser/1">>)),
-    ?assertEqual(allow, ?AC:check_acl(User1, subscribe, <<"clients/client1">>)),
-    ?assertEqual(deny, ?AC:check_acl(User1, subscribe, <<"clients/client1/x/y">>)),
-    ?assertEqual(allow, ?AC:check_acl(User1, publish, <<"users/testuser/1">>)),
-    ?assertEqual(allow, ?AC:check_acl(User1, subscribe, <<"a/b/c">>)),
-    ?assertEqual(deny, ?AC:check_acl(User2, subscribe, <<"a/b/c">>)).
-
--endif.
-

+ 0 - 82
test/emqttd_access_rule_tests.erl

@@ -1,82 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_access_rule_tests).
-
--ifdef(TEST).
-
--include("emqttd.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--import(emqttd_access_rule, [compile/1, match/3]).
-
-compile_test() ->
-
-    ?assertMatch({allow, {'and', [{ipaddr, {"127.0.0.1", _I, _I}},
-                                  {user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
-                 compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]})),
-    ?assertMatch({allow, {'or', [{ipaddr, {"127.0.0.1", _I, _I}},
-                                 {user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
-                 compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]})),
-
-    ?assertMatch({allow, {ipaddr, {"127.0.0.1", _I, _I}}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
-                 compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]})),
-    ?assertMatch({allow, {user, <<"testuser">>}, subscribe, [ [<<"a">>, <<"b">>, <<"c">>], [<<"d">>, <<"e">>, <<"f">>, '#'] ]},
-                 compile({allow, {user, "testuser"}, subscribe, ["a/b/c", "d/e/f/#"]})),
-    ?assertEqual({allow, {user, <<"admin">>}, pubsub, [ [<<"d">>, <<"e">>, <<"f">>, '#'] ]},
-                 compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]})),
-    ?assertEqual({allow, {client, <<"testClient">>}, publish, [ [<<"testTopics">>, <<"testClient">>] ]},
-                 compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]})),
-    ?assertEqual({allow, all, pubsub, [{pattern, [<<"clients">>, <<"$c">>]}]},
-                 compile({allow, all, pubsub, ["clients/$c"]})),
-    ?assertEqual({allow, all, subscribe, [{pattern, [<<"users">>, <<"$u">>, '#']}]},
-                 compile({allow, all, subscribe, ["users/$u/#"]})),
-    ?assertEqual({deny, all, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
-                 compile({deny, all, subscribe, ["$SYS/#", "#"]})),
-    ?assertEqual({allow, all}, compile({allow, all})),
-    ?assertEqual({deny, all},  compile({deny, all})).
-
-match_test() ->
-    User = #mqtt_client{peername = {{127,0,0,1}, 2948}, client_id = <<"testClient">>, username = <<"TestUser">>},
-    User2 = #mqtt_client{peername = {{192,168,0,10}, 3028}, client_id = <<"testClient">>, username = <<"TestUser">>},
-    
-    ?assertEqual({matched, allow}, match(User, <<"Test/Topic">>, {allow, all})),
-    ?assertEqual({matched, deny},  match(User, <<"Test/Topic">>, {deny, all})),
-    ?assertMatch({matched, allow}, match(User, <<"Test/Topic">>,
-                 compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}))),
-    ?assertMatch({matched, allow}, match(User2, <<"Test/Topic">>,
-                 compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]}))),
-    ?assertMatch({matched, allow}, match(User, <<"d/e/f/x">>, compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]}))),
-    ?assertEqual(nomatch, match(User, <<"d/e/f/x">>, compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]}))),
-    ?assertMatch({matched, allow}, match(User, <<"testTopics/testClient">>,
-                 compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]}))),
-    ?assertMatch({matched, allow}, match(User, <<"clients/testClient">>,
-                                                       compile({allow, all, pubsub, ["clients/$c"]}))),
-    ?assertMatch({matched, allow}, match(#mqtt_client{username = <<"user2">>}, <<"users/user2/abc/def">>,
-                                         compile({allow, all, subscribe, ["users/$u/#"]}))),
-    ?assertMatch({matched, deny}, match(User, <<"d/e/f">>,
-                                        compile({deny, all, subscribe, ["$SYS/#", "#"]}))),
-    Rule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}),
-    ?assertMatch(nomatch, match(User, <<"Topic">>, Rule)),
-    AndRule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}),
-    ?assertMatch({matched, allow}, match(User, <<"Topic">>, AndRule)),
-    OrRule = compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}),
-    ?assertMatch({matched, allow}, match(User, <<"Topic">>, OrRule)).
-
--endif.
-
-

+ 13 - 11
test/emqttd_guid_tests.erl

@@ -14,21 +14,23 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqttd_guid_tests).
+-module(emqttd_backend_SUITE).
 
--ifdef(TEST).
+-compile(export_all).
 
--include_lib("eunit/include/eunit.hrl").
+all() -> [{group, retainer}].
 
-gen_test() ->
-    Guid1 = emqttd_guid:gen(),
-    Guid2 = emqttd_guid:gen(),
-    ?assertMatch(<<_:128>>, Guid1),
-    ?assertEqual(true, Guid2 >= Guid1),
-    {Ts, _, 0} = Tup = emqttd_guid:new(),
-    ?assertEqual(Ts, emqttd_guid:timestamp(emqttd_guid:bin(Tup))).
+groups() -> [{retainer, [], [t_retain]}].
 
--endif.
+init_per_group(retainer, _Config) ->
+    ok = emqttd_mnesia:ensure_started(),
+    emqttd_retainer:mnesia(boot),
+    emqttd_retainer:mnesia(copy).
 
+end_per_group(retainer, _Config) ->
+    ok;
+end_per_group(_Group, _Config) ->
+    ok.
 
+t_retain(_) -> ok.
 

+ 146 - 0
test/emqttd_lib_SUITE.erl

@@ -0,0 +1,146 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
+%%
+%% 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(emqttd_lib_SUITE).
+
+-compile(export_all).
+
+-define(SOCKOPTS, [
+	binary,
+	{packet,    raw},
+	{reuseaddr, true},
+	{backlog,   512},
+	{nodelay,   true}
+]).
+
+-define(PQ, priority_queue).
+
+all() -> [{group, guid}, {group, opts},
+          {group, ?PQ}, {group, time},
+          {group, node}].
+
+groups() ->
+    [{guid, [], [guid_gen]},
+     {opts, [], [opts_merge]},
+     {?PQ,  [], [priority_queue_plen,
+                 priority_queue_out2]},
+     {time, [], [time_now_to_]},
+     {node, [], [node_is_aliving, node_parse_name]}].
+
+%%--------------------------------------------------------------------
+%% emqttd_guid
+%%--------------------------------------------------------------------
+
+guid_gen(_) ->
+    Guid1 = emqttd_guid:gen(),
+    Guid2 = emqttd_guid:gen(),
+    <<_:128>> = Guid1,
+    true = (Guid2 >= Guid1),
+    {Ts1, _, 0} = emqttd_guid:new(),
+    Ts2 = emqttd_guid:timestamp(emqttd_guid:gen()),
+    true = Ts2 > Ts1.
+
+%%--------------------------------------------------------------------
+%% emqttd_opts
+%%--------------------------------------------------------------------
+
+opts_merge(_) ->
+    Opts = emqttd_opts:merge(?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).
+
+%%--------------------------------------------------------------------
+%% emqttd_time
+%%--------------------------------------------------------------------
+
+time_now_to_(_) ->
+    emqttd_time:seed(),
+    emqttd_time:now_to_secs(),
+    emqttd_time:now_to_ms().
+
+%%--------------------------------------------------------------------
+%% emqttd_node
+%%--------------------------------------------------------------------
+
+node_is_aliving(_) ->
+    io:format("Node: ~p~n", [node()]),
+    true = emqttd_node:is_aliving(node()),
+    false = emqttd_node:is_aliving('x@127.0.0.1').
+
+node_parse_name(_) ->
+    'a@127.0.0.1' = emqttd_node:parse_name("a@127.0.0.1"),
+    'b@127.0.0.1' = emqttd_node:parse_name("b").
+

+ 0 - 70
test/emqttd_message_tests.erl

@@ -1,70 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_message_tests).
-
--ifdef(TEST).
-
--include("emqttd.hrl").
-
--include("emqttd_protocol.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--define(M, emqttd_message).
-
-make_test() ->
-    Msg = ?M:make(<<"clientid">>, <<"topic">>, <<"payload">>),
-    ?assertEqual(0, Msg#mqtt_message.qos),
-    ?assertEqual(undefined, Msg#mqtt_message.msgid),
-    Msg1 = ?M:make(<<"clientid">>, qos2, <<"topic">>, <<"payload">>),
-    ?assert(is_binary(Msg1#mqtt_message.msgid)),
-    ?assertEqual(2, Msg1#mqtt_message.qos).
-
-from_packet_test() ->
-    Msg = ?M:from_packet(?PUBLISH_PACKET(1, <<"topic">>, 10, <<"payload">>)),
-    ?assertEqual(1, Msg#mqtt_message.qos),
-    ?assertEqual(10, Msg#mqtt_message.pktid),
-    ?assertEqual(<<"topic">>, Msg#mqtt_message.topic),
-
-    WillMsg = ?M:from_packet(#mqtt_packet_connect{will_flag  = true,
-                                                  will_topic = <<"WillTopic">>,
-                                                  will_msg   = <<"WillMsg">>}),
-    ?assertEqual(<<"WillTopic">>, WillMsg#mqtt_message.topic),
-    ?assertEqual(<<"WillMsg">>, WillMsg#mqtt_message.payload),
-
-    Msg2 = ?M:from_packet(<<"username">>, <<"clientid">>,
-                          ?PUBLISH_PACKET(1, <<"topic">>, 20, <<"payload">>)),
-    ?assertEqual(<<"clientid">>, Msg2#mqtt_message.from),
-    ?assertEqual(<<"username">>, Msg2#mqtt_message.sender),
-    ?debugFmt("~s", [?M:format(Msg2)]).
-
-flag_test() ->
-    Pkt = ?PUBLISH_PACKET(1, <<"t">>, 2, <<"payload">>),
-    Msg2 = ?M:from_packet(<<"clientid">>, Pkt),
-    Msg3 = ?M:set_flag(retain, Msg2),
-    Msg4 = ?M:set_flag(dup, Msg3),
-    ?assert(Msg4#mqtt_message.dup),
-    ?assert(Msg4#mqtt_message.retain),
-    Msg5 = ?M:set_flag(Msg4),
-    Msg6 = ?M:unset_flag(dup, Msg5),
-    Msg7 = ?M:unset_flag(retain, Msg6),
-    ?assertNot(Msg7#mqtt_message.dup),
-    ?assertNot(Msg7#mqtt_message.retain),
-    ?M:unset_flag(Msg7),
-    ?M:to_packet(Msg7).
-
--endif.

+ 63 - 0
test/emqttd_mock_client.erl

@@ -0,0 +1,63 @@
+
+-module(emqttd_mock_client).
+
+-behaviour(gen_server).
+
+%% ------------------------------------------------------------------
+%% API Function Exports
+%% ------------------------------------------------------------------
+
+-export([start_link/1, start_session/1, stop/1]).
+
+%% ------------------------------------------------------------------
+%% gen_server Function Exports
+%% ------------------------------------------------------------------
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+         terminate/2, code_change/3]).
+
+-record(state, {clientid, session}).
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+start_link(ClientId) ->
+    gen_server:start_link(?MODULE, [ClientId], []).
+
+start_session(CPid) ->
+    gen_server:call(CPid, start_session).
+
+stop(CPid) ->
+    gen_server:call(CPid, stop).
+
+%% ------------------------------------------------------------------
+%% gen_server Function Definitions
+%% ------------------------------------------------------------------
+
+init([ClientId]) ->
+    {ok, #state{clientid = ClientId}}.
+
+handle_call(start_session, _From, State = #state{clientid = ClientId}) ->
+    {ok, SessPid, _} = emqttd_sm:start_session(true, ClientId),
+    {reply, {ok, SessPid}, State#state{session = SessPid}};
+
+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(_Info, State) ->
+    {noreply, State}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
+
+

+ 13 - 13
test/emqttd_node_tests.erl

@@ -14,22 +14,22 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqttd_node_tests).
+-module(emqttd_mod_SUITE).
 
--author("Feng Lee <feng@emqtt.io>").
+-compile(export_all).
 
--ifdef(TEST).
+-include("emqttd.hrl").
 
--include_lib("eunit/include/eunit.hrl").
+all() -> [mod_subscription_rep].
 
-is_aliving_test() ->
-    ?debugFmt("Node: ~p~n", [node()]),
-    ?assert(emqttd_node:is_aliving(node())),
-    ?assertNot(emqttd_node:is_aliving('x@127.0.0.1')).
+mod_subscription_rep(_) -> ok.
+%%    <<"topic/clientId">> = emqttd_mod_subscription:rep(
+%%            <<"$c">>, <<"clientId">>, <<"topic/$c">>),
+%%   <<"topic/username">> = emqttd_mod_subscription:rep(
+%%           <<"$u">>, <<"username">>, <<"topic/$u">>),
+%%   <<"topic/username/clientId">> = emqttd_mod_subscription:rep(
+%%           <<"$c">>, <<"clientId">>, emqttd_mod_subscription:rep(
+%%               <<"$u">>, <<"username">>, <<"topic/$u/$c">>)).
+ 
 
-parse_name_test() ->
-    ?assertEqual('a@127.0.0.1', emqttd_node:parse_name("a@127.0.0.1")),
-    ?assertEqual('b@127.0.0.1', emqttd_node:parse_name("b")).
-
--endif.
 

+ 0 - 36
test/emqttd_mod_subscription_tests.erl

@@ -1,36 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_mod_subscription_tests).
-
--ifdef(TEST).
-
--include("emqttd.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--define(M, emqttd_mod_subscription).
-
-rep_test() ->
-    ?assertEqual(<<"topic/clientId">>,
-                    ?M:rep(<<"$c">>, <<"clientId">>, <<"topic/$c">>)),
-    ?assertEqual(<<"topic/username">>,
-                    ?M:rep(<<"$u">>, <<"username">>, <<"topic/$u">>)),
-    ?assertEqual(<<"topic/username/clientId">>,
-                 ?M:rep(<<"$c">>, <<"clientId">>,
-                       ?M:rep(<<"$u">>, <<"username">>, <<"topic/$u/$c">>))).
-
--endif.

+ 54 - 54
test/emqttd_mqueue_tests.erl

@@ -14,87 +14,89 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqttd_mqueue_tests).
+-module(emqttd_mqueue_SUITE).
 
--ifdef(TEST).
+-compile(export_all).
 
 -include("emqttd.hrl").
 
--include_lib("eunit/include/eunit.hrl").
-
 -define(Q, emqttd_mqueue).
 
-in_test() ->
+all() -> [t_in, t_in_qos0, t_out, t_simple_mqueue, t_priority_mqueue,
+          t_priority_mqueue2, t_infinity_priority_mqueue,
+          t_infinity_simple_mqueue].
+
+t_in(_) ->
     Opts = [{max_length, 5},
             {queue_qos0, true}],
     Q = ?Q:new(<<"testQ">>, Opts, alarm_fun()),
-    ?assertEqual(true, ?Q:is_empty(Q)),
+    true = ?Q:is_empty(Q),
     Q1 = ?Q:in(#mqtt_message{}, Q),
-    ?assertEqual(1, ?Q:len(Q1)),
+    1 = ?Q:len(Q1),
     Q2 = ?Q:in(#mqtt_message{qos = 1}, Q1),
-    ?assertEqual(2, ?Q:len(Q2)),
+    2 = ?Q:len(Q2),
     Q3 = ?Q:in(#mqtt_message{qos = 2}, Q2),
     Q4 = ?Q:in(#mqtt_message{}, Q3),
     Q5 = ?Q:in(#mqtt_message{}, Q4),
-    ?assertEqual(5, ?Q:len(Q5)).
-    
-in_qos0_test() ->
+    5 = ?Q:len(Q5).
+
+t_in_qos0(_) ->
     Opts = [{max_length, 5},
             {queue_qos0, false}],
     Q = ?Q:new(<<"testQ">>, Opts, alarm_fun()),
     Q1 = ?Q:in(#mqtt_message{}, Q),
-    ?assertEqual(true, ?Q:is_empty(Q1)),
+    true = ?Q:is_empty(Q1),
     Q2 = ?Q:in(#mqtt_message{qos = 0}, Q1),
-    ?assertEqual(true, ?Q:is_empty(Q2)).
+    true = ?Q:is_empty(Q2).
 
-out_test() ->
+t_out(_) ->
     Opts = [{max_length, 5},
             {queue_qos0, true}],
     Q = ?Q:new(<<"testQ">>, Opts, alarm_fun()),
-    ?assertMatch({empty, Q}, ?Q:out(Q)),
+    {empty, Q} = ?Q:out(Q),
     Q1 = ?Q:in(#mqtt_message{}, Q),
     {Value, Q2} = ?Q:out(Q1),
-    ?assertEqual(0, ?Q:len(Q2)),
-    ?assertMatch({value, #mqtt_message{}}, Value).
+    0 = ?Q:len(Q2),
+    {value, #mqtt_message{}} = Value.
 
-simple_mqueue_test() ->
+t_simple_mqueue(_) ->
     Opts = [{type, simple},
             {max_length, 3},
             {low_watermark, 0.2},
             {high_watermark, 0.6},
             {queue_qos0, false}],
     Q = ?Q:new("simple_queue", Opts, alarm_fun()),
-    ?assertEqual(simple, ?Q:type(Q)),
-    ?assertEqual(3, ?Q:max_len(Q)),
-    ?assertEqual(<<"simple_queue">>, ?Q:name(Q)),
-    ?assert(?Q:is_empty(Q)),
+    simple = ?Q:type(Q),
+    3 = ?Q:max_len(Q),
+    <<"simple_queue">> = ?Q:name(Q),
+    true = ?Q:is_empty(Q),
     Q1 = ?Q:in(#mqtt_message{qos = 1, payload = <<"1">>}, Q),
     Q2 = ?Q:in(#mqtt_message{qos = 1, payload = <<"2">>}, Q1),
     Q3 = ?Q:in(#mqtt_message{qos = 1, payload = <<"3">>}, Q2),
     Q4 = ?Q:in(#mqtt_message{qos = 1, payload = <<"4">>}, Q3),
-    ?assertEqual(3, ?Q:len(Q4)),
+    3 = ?Q:len(Q4),
     {{value, Msg}, Q5} = ?Q:out(Q4),
-    ?assertMatch(<<"2">>, Msg#mqtt_message.payload),
-    ?assertEqual([{len, 2}, {max_len, 3}, {dropped, 1}], ?Q:stats(Q5)).
+    <<"2">> = Msg#mqtt_message.payload,
+    [{len, 2}, {max_len, 3}, {dropped, 1}] = ?Q:stats(Q5).
 
-infinity_simple_mqueue_test() ->
+t_infinity_simple_mqueue(_) ->
     Opts = [{type, simple},
             {max_length, infinity},
             {low_watermark, 0.2},
             {high_watermark, 0.6},
             {queue_qos0, false}],
     Q = ?Q:new("infinity_simple_queue", Opts, alarm_fun()),
-    ?assert(?Q:is_empty(Q)),
-    ?assertEqual(infinity, ?Q:max_len(Q)),
+    true = ?Q:is_empty(Q),
+    infinity = ?Q:max_len(Q),
     Qx = lists:foldl(fun(I, AccQ) ->
                     ?Q:in(#mqtt_message{qos = 1, payload = iolist_to_binary([I])}, AccQ)
             end, Q, lists:seq(1, 255)),
-    ?assertEqual(255, ?Q:len(Qx)),
-    ?assertEqual([{len, 255}, {max_len, infinity}, {dropped, 0}], ?Q:stats(Qx)),
-    {{value, V}, Qy} = ?Q:out(Qx),
-    ?assertEqual(<<1>>, V#mqtt_message.payload).
+    255 = ?Q:len(Qx),
+    [{len, 255}, {max_len, infinity}, {dropped, 0}] = ?Q:stats(Qx),
+    {{value, V}, _Qy} = ?Q:out(Qx),
+    <<1>> = V#mqtt_message.payload.
 
-priority_mqueue_test() ->
+t_priority_mqueue(_) ->
     Opts = [{type, priority},
             {priority, [{<<"t">>, 10}]},
             {max_length, 3},
@@ -102,56 +104,54 @@ priority_mqueue_test() ->
             {high_watermark, 0.6},
             {queue_qos0, false}],
     Q = ?Q:new("priority_queue", Opts, alarm_fun()),
-    ?assertEqual(priority, ?Q:type(Q)),
-    ?assertEqual(3, ?Q:max_len(Q)),
-    ?assertEqual(<<"priority_queue">>, ?Q:name(Q)),
+    priority = ?Q:type(Q),
+    3 = ?Q:max_len(Q),
+    <<"priority_queue">> = ?Q:name(Q),
 
-    ?assert(?Q:is_empty(Q)),
+    true = ?Q:is_empty(Q),
     Q1 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q),
     Q2 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t">>}, Q1),
     Q3 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t2">>}, Q2),
-    ?assertEqual(3, ?Q:len(Q3)),
+    3 = ?Q:len(Q3),
     Q4 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q3),
-    ?assertEqual(4, ?Q:len(Q4)),
+    4 = ?Q:len(Q4),
     Q5 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q4),
-    ?assertEqual(5, ?Q:len(Q5)),
+    5 = ?Q:len(Q5),
     Q6 = ?Q:in(#mqtt_message{qos = 1, topic = <<"t1">>}, Q5),
-    ?assertEqual(5, ?Q:len(Q6)),
-    {{value, Msg}, Q7} = ?Q:out(Q6),
-    ?assertMatch(<<"t">>, Msg#mqtt_message.topic).
+    5 = ?Q:len(Q6),
+    {{value, Msg}, _Q7} = ?Q:out(Q6),
+    <<"t">> = Msg#mqtt_message.topic.
 
-infinity_priority_mqueue_test() ->
+t_infinity_priority_mqueue(_) ->
     Opts = [{type, priority},
             {priority, [{<<"t1">>, 10}, {<<"t2">>, 8}]},
             {max_length, infinity},
             {queue_qos0, false}],
     Q = ?Q:new("infinity_priority_queue", Opts, alarm_fun()),
-    ?assertEqual(infinity, ?Q:max_len(Q)),
+    infinity = ?Q:max_len(Q),
     Qx = lists:foldl(fun(I, AccQ) ->
                     AccQ1 =
                     ?Q:in(#mqtt_message{topic = <<"t1">>, qos = 1, payload = iolist_to_binary([I])}, AccQ),
                     ?Q:in(#mqtt_message{topic = <<"t">>, qos = 1, payload = iolist_to_binary([I])}, AccQ1)
             end, Q, lists:seq(1, 255)),
-    ?assertEqual(510, ?Q:len(Qx)),
-    ?assertEqual([{len, 510}, {max_len, infinity}, {dropped, 0}], ?Q:stats(Qx)).
+    510 = ?Q:len(Qx),
+    [{len, 510}, {max_len, infinity}, {dropped, 0}] = ?Q:stats(Qx).
 
-priority_mqueue2_test() ->
+t_priority_mqueue2(_) ->
     Opts = [{type, priority},
             {max_length, 2},
             {low_watermark, 0.2},
             {high_watermark, 0.6},
             {queue_qos0, false}],
     Q = ?Q:new("priority_queue2_test", Opts, alarm_fun()),
-    ?assertEqual(2, ?Q:max_len(Q)),
+    2 = ?Q:max_len(Q),
     Q1 = ?Q:in(#mqtt_message{topic = <<"x">>, qos = 1, payload = <<1>>}, Q),
     Q2 = ?Q:in(#mqtt_message{topic = <<"x">>, qos = 1, payload = <<2>>}, Q1),
     Q3 = ?Q:in(#mqtt_message{topic = <<"y">>, qos = 1, payload = <<3>>}, Q2),
     Q4 = ?Q:in(#mqtt_message{topic = <<"y">>, qos = 1, payload = <<4>>}, Q3),
-    ?assertEqual(4, ?Q:len(Q4)),
-    {{value, Val}, Q5} = ?Q:out(Q4),
-    ?assertEqual(3, ?Q:len(Q5)).
+    4 = ?Q:len(Q4),
+    {{value, _Val}, Q5} = ?Q:out(Q4),
+    3 = ?Q:len(Q5).
  
 alarm_fun() -> fun(_, _) -> alarm_fun() end.
 
--endif.
-

+ 15 - 9
test/emqttd_keepalive_tests.erl

@@ -1,5 +1,5 @@
 %%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
+%% Copyright (c) 2016 Feng Lee <feng@emqtt.io>.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -14,25 +14,31 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqttd_keepalive_tests).
+-module(emqttd_net_SUITE).
 
--ifdef(TEST).
+%% CT
+-compile(export_all).
 
--include_lib("eunit/include/eunit.hrl").
+all() -> [{group, keepalive}].
 
-keepalive_test() ->
+groups() -> [{keepalive, [], [t_keepalive]}].
+
+%%--------------------------------------------------------------------
+%% Keepalive
+%%--------------------------------------------------------------------
+
+t_keepalive(_) ->
     KA = emqttd_keepalive:start(fun() -> {ok, 1} end, 1, {keepalive, timeout}),
-    ?assertEqual([resumed, timeout], lists:reverse(loop(KA, []))).
+    [resumed, timeout] = lists:reverse(keepalive_recv(KA, [])).
 
-loop(KA, Acc) ->
+keepalive_recv(KA, Acc) ->
     receive
         {keepalive, timeout} ->
             case emqttd_keepalive:check(KA) of
-                {ok, KA1} -> loop(KA1, [resumed | Acc]);
+                {ok, KA1} -> keepalive_recv(KA1, [resumed | Acc]);
                 {error, timeout} -> [timeout | Acc]
             end
         after 4000 ->
                 Acc
     end.
 
--endif.

+ 0 - 49
test/emqttd_opts_tests.erl

@@ -1,49 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_opts_tests).
-
--ifdef(TEST).
-
--include_lib("eunit/include/eunit.hrl").
-
--define(SOCKOPTS, [
-	binary,
-	{packet,    raw},
-	{reuseaddr, true},
-	{backlog,   512},
-	{nodelay,   true}
-]).
-
-merge_test() ->
-    Opts = emqttd_opts:merge(?SOCKOPTS, [raw,
-                                         binary,
-                                         {backlog, 1024},
-                                         {nodelay, false},
-                                         {max_clients, 1024},
-                                         {acceptors, 16}]),
-    ?assertEqual(1024, proplists:get_value(backlog, Opts)),
-    ?assertEqual(1024, proplists:get_value(max_clients, Opts)),
-    ?assertEqual(lists:sort(Opts), [binary, raw,
-                                    {acceptors, 16},
-                                    {backlog, 1024},
-                                    {max_clients, 1024},
-                                    {nodelay, false},
-                                    {packet, raw},
-                                    {reuseaddr, true}]).
-
-
--endif.

+ 0 - 56
test/emqttd_packet_tests.erl

@@ -1,56 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_packet_tests).
-
--ifdef(TEST).
-
--include("emqttd_protocol.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--define(P, emqttd_packet).
-
-protocol_name_test() ->
-    ?assertEqual(<<"MQIsdp">>, ?P:protocol_name(3)),
-    ?assertEqual(<<"MQTT">>,   ?P:protocol_name(4)).
-
-type_name_test() ->
-    ?assertEqual( 'CONNECT',     ?P:type_name(?CONNECT) ),
-    ?assertEqual( 'UNSUBSCRIBE', ?P:type_name(?UNSUBSCRIBE) ).
-
-connack_name_test() ->
-    ?assertEqual( 'CONNACK_ACCEPT',      ?P:connack_name(?CONNACK_ACCEPT) ),
-    ?assertEqual( 'CONNACK_PROTO_VER',   ?P:connack_name(?CONNACK_PROTO_VER) ),
-    ?assertEqual( 'CONNACK_INVALID_ID',  ?P:connack_name(?CONNACK_INVALID_ID) ),
-    ?assertEqual( 'CONNACK_SERVER',      ?P:connack_name(?CONNACK_SERVER) ),
-    ?assertEqual( 'CONNACK_CREDENTIALS', ?P:connack_name(?CONNACK_CREDENTIALS) ),
-    ?assertEqual( 'CONNACK_AUTH',        ?P:connack_name(?CONNACK_AUTH) ).
-
-format_test() ->
-    ?debugFmt("~s", [?P:format(?CONNECT_PACKET(#mqtt_packet_connect{}))]),
-    ?debugFmt("~s", [?P:format(?CONNACK_PACKET(?CONNACK_SERVER))]),
-    ?debugFmt("~s", [?P:format(?PUBLISH_PACKET(?QOS_1, 1))]),
-    ?debugFmt("~s", [?P:format(?PUBLISH_PACKET(?QOS_2, <<"topic">>, 10, <<"payload">>))]),
-    ?debugFmt("~s", [?P:format(?PUBACK_PACKET(?PUBACK, 98))]),
-    ?debugFmt("~s", [?P:format(?PUBREL_PACKET(99))]),
-    ?debugFmt("~s", [?P:format(?SUBSCRIBE_PACKET(15, [{<<"topic">>, ?QOS0}, {<<"topic1">>, ?QOS1}]))]),
-    ?debugFmt("~s", [?P:format(?SUBACK_PACKET(40, [?QOS0, ?QOS1]))]),
-    ?debugFmt("~s", [?P:format(?UNSUBSCRIBE_PACKET(89, [<<"t">>, <<"t2">>]))]),
-    ?debugFmt("~s", [?P:format(?UNSUBACK_PACKET(90))]).
-
--endif.
-

+ 0 - 147
test/emqttd_parser_tests.erl

@@ -1,147 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_parser_tests).
-
--ifdef(TEST).
-
--include("emqttd_protocol.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
-parse_connect_test() ->
-    Parser = emqttd_parser:new([]),
-    %% CONNECT(Qos=0, Retain=false, Dup=false, ClientId=mosqpub/10451-iMac.loca, ProtoName=MQIsdp, ProtoVsn=3, CleanSess=true, KeepAlive=60, Username=undefined, Password=undefined)
-    V31ConnBin = <<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>>,
-    ?assertMatch({ok, #mqtt_packet{
-                         header = #mqtt_packet_header{type = ?CONNECT,
-                                                      dup  = false,
-                                                      qos  = 0,
-                                                      retain = false},
-                         variable = #mqtt_packet_connect{proto_ver  = 3,
-                                                         proto_name = <<"MQIsdp">>,
-                                                         client_id  = <<"mosqpub/10451-iMac.loca">>,
-                                                         clean_sess = true,
-                                                         keep_alive = 60}}, <<>>}, Parser(V31ConnBin)),
-    %% CONNECT(Qos=0, Retain=false, Dup=false, ClientId=mosqpub/10451-iMac.loca, ProtoName=MQTT, ProtoVsn=4, CleanSess=true, KeepAlive=60, Username=undefined, Password=undefined)
-    V311ConnBin = <<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>>,
-    ?assertMatch({ok, #mqtt_packet{ 
-                         header = #mqtt_packet_header{type = ?CONNECT, 
-                                                      dup = false, 
-                                                      qos = 0, 
-                                                      retain = false}, 
-                         variable = #mqtt_packet_connect{proto_ver  = 4, 
-                                                         proto_name = <<"MQTT">>, 
-                                                         client_id  = <<"mosqpub/10451-iMac.loca">>,
-                                                         clean_sess = true, 
-                                                         keep_alive = 60 } }, <<>>}, Parser(V311ConnBin)),
-
-    %% CONNECT(Qos=0, Retain=false, Dup=false, ClientId="", ProtoName=MQTT, ProtoVsn=4, CleanSess=true, KeepAlive=60)
-    V311ConnWithoutClientId = <<16,12,0,4,77,81,84,84,4,2,0,60,0,0>>,
-    ?assertMatch({ok, #mqtt_packet{ 
-                         header = #mqtt_packet_header{type = ?CONNECT, 
-                                                      dup = false, 
-                                                      qos = 0, 
-                                                      retain = false}, 
-                         variable = #mqtt_packet_connect{proto_ver = 4, 
-                                                         proto_name = <<"MQTT">>, 
-                                                         client_id  = <<>>,
-                                                         clean_sess = true, 
-                                                         keep_alive = 60 } }, <<>>}, Parser(V311ConnWithoutClientId)),
-    %%CONNECT(Qos=0, Retain=false, Dup=false, ClientId=mosqpub/10452-iMac.loca, ProtoName=MQIsdp, ProtoVsn=3, CleanSess=true, KeepAlive=60, Username=test, Password=******, Will(Qos=1, Retain=false, Topic=/will, Msg=willmsg))
-    ConnBinWithWill = <<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,112,117,98,108,105,99>>,
-    ?assertMatch({ok, #mqtt_packet{ 
-                         header = #mqtt_packet_header{type = ?CONNECT,
-                                                      dup = false,
-                                                      qos = 0,
-                                                      retain = false},
-                         variable = #mqtt_packet_connect{proto_ver = 3,
-                                                         proto_name = <<"MQIsdp">>, 
-                                                         client_id  = <<"mosqpub/10452-iMac.loca">>,
-                                                         clean_sess = true, 
-                                                         keep_alive = 60,
-                                                         will_retain = false,
-                                                         will_qos = 1,
-                                                         will_flag = true,
-                                                         will_topic = <<"/will">>,
-                                                         will_msg = <<"willmsg">> ,
-                                                         username = <<"test">>,
-                                                         password = <<"public">>}},
-                  <<>> }, Parser(ConnBinWithWill)),
-    ok.
-
-parse_publish_test() ->
-    Parser = emqttd_parser:new([]),
-    %%PUBLISH(Qos=1, Retain=false, Dup=false, TopicName=a/b/c, PacketId=1, Payload=<<"hahah">>)
-    PubBin = <<50,14,0,5,97,47,98,47,99,0,1,104,97,104,97,104>>,
-    ?assertMatch({ok, #mqtt_packet{ 
-                         header = #mqtt_packet_header{type = ?PUBLISH, 
-                                                      dup = false, 
-                                                      qos = 1, 
-                                                      retain = false},  
-                         variable = #mqtt_packet_publish{topic_name = <<"a/b/c">>, 
-                                                         packet_id = 1},
-                         payload = <<"hahah">> }, <<>>}, Parser(PubBin)),
-    
-    %PUBLISH(Qos=0, Retain=false, Dup=false, TopicName=xxx/yyy, PacketId=undefined, Payload=<<"hello">>)
-    %DISCONNECT(Qos=0, Retain=false, Dup=false)
-    PubBin1 = <<48,14,0,7,120,120,120,47,121,121,121,104,101,108,108,111,224,0>>,
-    ?assertMatch({ok, #mqtt_packet { 
-                         header = #mqtt_packet_header{type = ?PUBLISH,
-                                                      dup = false,
-                                                      qos = 0,
-                                                      retain = false},
-                         variable = #mqtt_packet_publish{topic_name = <<"xxx/yyy">>, 
-                                                         packet_id = undefined},
-                         payload = <<"hello">> }, <<224,0>>}, Parser(PubBin1)),
-    ?assertMatch({ok, #mqtt_packet{ 
-                         header = #mqtt_packet_header{type = ?DISCONNECT,
-                                                      dup = false,
-                                                      qos = 0,
-                                                      retain = false}
-                        }, <<>>}, Parser(<<224, 0>>)).
-
-parse_puback_test() ->
-    Parser = emqttd_parser:new([]),
-    %%PUBACK(Qos=0, Retain=false, Dup=false, PacketId=1)
-    PubAckBin = <<64,2,0,1>>,
-    ?assertMatch({ok, #mqtt_packet { 
-                         header = #mqtt_packet_header{type = ?PUBACK, 
-                                                      dup = false, 
-                                                      qos = 0, 
-                                                      retain = false } 
-                }, <<>>}, Parser(PubAckBin)),
-    ok.
-
-parse_subscribe_test() ->
-    ok.
-
-parse_pingreq_test() ->
-    ok.
-
-parse_disconnect_test() ->
-    Parser = emqttd_parser:new([]),
-    %DISCONNECT(Qos=0, Retain=false, Dup=false)
-    Bin = <<224, 0>>,
-    ?assertMatch({ok, #mqtt_packet{ 
-                         header = #mqtt_packet_header{type = ?DISCONNECT,
-                                                      dup = false,
-                                                      qos = 0,
-                                                      retain = false}
-                }, <<>>}, Parser(Bin)).
-
--endif.
-

+ 308 - 0
test/emqttd_protocol_SUITE.erl

@@ -0,0 +1,308 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
+%%
+%% 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(emqttd_protocol_SUITE).
+
+-compile(export_all).
+
+-import(emqttd_serializer, [serialize/1]).
+
+-include("emqttd.hrl").
+
+-include("emqttd_protocol.hrl").
+
+all() ->
+    [{group, parser},
+     {group, serializer},
+     {group, packet},
+     {group, message}].
+
+groups() ->
+    [{parser, [],
+      [parse_connect,
+       parse_publish,
+       parse_puback,
+       parse_subscribe,
+       parse_pingreq,
+       parse_disconnect]},
+     {serializer, [],
+      [serialize_connect,
+       serialize_connack,
+       serialize_publish,
+       serialize_puback,
+       serialize_pubrel,
+       serialize_subscribe,
+       serialize_suback,
+       serialize_unsubscribe,
+       serialize_unsuback,
+       serialize_pingreq,
+       serialize_pingresp,
+       serialize_disconnect]},
+     {packet, [],
+      [packet_proto_name,
+       packet_type_name,
+       packet_connack_name,
+       packet_format]},
+     {message, [],
+      [message_make,
+       message_from_packet,
+       message_flag]}].
+
+%%--------------------------------------------------------------------
+%% Parse Cases
+%%--------------------------------------------------------------------
+
+parse_connect(_) ->
+    Parser = emqttd_parser:new([]),
+    %% CONNECT(Q0, R0, D0, ClientId=mosqpub/10451-iMac.loca, ProtoName=MQIsdp, ProtoVsn=3, CleanSess=true, KeepAlive=60, Username=undefined, Password=undefined)
+    V31ConnBin = <<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>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT,
+                                                   dup  = false,
+                                                   qos  = 0,
+                                                   retain = false},
+                      variable = #mqtt_packet_connect{proto_ver  = 3,
+                                                      proto_name = <<"MQIsdp">>,
+                                                      client_id  = <<"mosqpub/10451-iMac.loca">>,
+                                                      clean_sess = true,
+                                                      keep_alive = 60}}, <<>>} = Parser(V31ConnBin),
+    %% CONNECT(Q0, R0, D0, ClientId=mosqpub/10451-iMac.loca, ProtoName=MQTT, ProtoVsn=4, CleanSess=true, KeepAlive=60, Username=undefined, Password=undefined)
+    V311ConnBin = <<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>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT, 
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false},
+                      variable = #mqtt_packet_connect{proto_ver  = 4,
+                                                      proto_name = <<"MQTT">>,
+                                                      client_id  = <<"mosqpub/10451-iMac.loca">>,
+                                                      clean_sess = true,
+                                                      keep_alive = 60 } }, <<>>} = Parser(V311ConnBin),
+
+    %% CONNECT(Qos=0, Retain=false, Dup=false, ClientId="", ProtoName=MQTT, ProtoVsn=4, CleanSess=true, KeepAlive=60)
+    V311ConnWithoutClientId = <<16,12,0,4,77,81,84,84,4,2,0,60,0,0>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT,
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false},
+                      variable = #mqtt_packet_connect{proto_ver = 4,
+                                                      proto_name = <<"MQTT">>,
+                                                      client_id  = <<>>,
+                                                      clean_sess = true,
+                                                      keep_alive = 60 } }, <<>>} = Parser(V311ConnWithoutClientId),
+    %%CONNECT(Q0, R0, D0, ClientId=mosqpub/10452-iMac.loca, ProtoName=MQIsdp, ProtoVsn=3, CleanSess=true, KeepAlive=60,
+    %% Username=test, Password=******, Will(Qos=1, Retain=false, Topic=/will, Msg=willmsg))
+    ConnBinWithWill = <<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,112,117,98,108,105,99>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?CONNECT,
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false},
+                      variable = #mqtt_packet_connect{proto_ver = 3,
+                                                      proto_name = <<"MQIsdp">>,
+                                                      client_id  = <<"mosqpub/10452-iMac.loca">>,
+                                                      clean_sess = true,
+                                                      keep_alive = 60,
+                                                      will_retain = false,
+                                                      will_qos = 1,
+                                                      will_flag = true,
+                                                      will_topic = <<"/will">>,
+                                                      will_msg = <<"willmsg">>,
+                                                      username = <<"test">>,
+                                                      password = <<"public">>}}, <<>>} = Parser(ConnBinWithWill),
+    ok.
+
+parse_publish(_) ->
+    Parser = emqttd_parser:new([]),
+    %%PUBLISH(Qos=1, Retain=false, Dup=false, TopicName=a/b/c, PacketId=1, Payload=<<"hahah">>)
+    PubBin = <<50,14,0,5,97,47,98,47,99,0,1,104,97,104,97,104>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
+                                                   dup = false,
+                                                   qos = 1,
+                                                   retain = false},
+                      variable = #mqtt_packet_publish{topic_name = <<"a/b/c">>,
+                                                      packet_id = 1},
+                      payload = <<"hahah">> }, <<>>} = Parser(PubBin),
+    
+    %PUBLISH(Qos=0, Retain=false, Dup=false, TopicName=xxx/yyy, PacketId=undefined, Payload=<<"hello">>)
+    %DISCONNECT(Qos=0, Retain=false, Dup=false)
+    PubBin1 = <<48,14,0,7,120,120,120,47,121,121,121,104,101,108,108,111,224,0>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBLISH,
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false},
+                      variable = #mqtt_packet_publish{topic_name = <<"xxx/yyy">>,
+                                                      packet_id = undefined},
+                      payload = <<"hello">> }, <<224,0>>} = Parser(PubBin1),
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?DISCONNECT,
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false}}, <<>>} = Parser(<<224, 0>>).
+
+parse_puback(_) ->
+    Parser = emqttd_parser:new([]),
+    %%PUBACK(Qos=0, Retain=false, Dup=false, PacketId=1)
+    PubAckBin = <<64,2,0,1>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?PUBACK,
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false}}, <<>>} = Parser(PubAckBin).
+
+parse_subscribe(_) ->
+    ok.
+
+parse_pingreq(_) ->
+    ok.
+
+parse_disconnect(_) ->
+    Parser = emqttd_parser:new([]),
+    %DISCONNECT(Qos=0, Retain=false, Dup=false)
+    Bin = <<224, 0>>,
+    {ok, #mqtt_packet{header = #mqtt_packet_header{type = ?DISCONNECT,
+                                                   dup = false,
+                                                   qos = 0,
+                                                   retain = false}}, <<>>} = Parser(Bin).
+
+%%--------------------------------------------------------------------
+%% Serialize Cases
+%%--------------------------------------------------------------------
+
+serialize_connect(_) ->
+    serialize(?CONNECT_PACKET(#mqtt_packet_connect{})),
+    serialize(?CONNECT_PACKET(#mqtt_packet_connect{
+                client_id = <<"clientId">>,
+                will_qos = ?QOS1,
+                will_flag = true,
+                will_retain = true,
+                will_topic = <<"will">>,
+                will_msg = <<"haha">>,
+                clean_sess = true})).
+
+serialize_connack(_) ->
+    ConnAck = #mqtt_packet{header = #mqtt_packet_header{type = ?CONNACK}, 
+                           variable = #mqtt_packet_connack{ack_flags = 0, return_code = 0}},
+    <<32,2,0,0>> = serialize(ConnAck).
+
+serialize_publish(_) ->
+    serialize(?PUBLISH_PACKET(?QOS_0, <<"Topic">>, undefined, <<"Payload">>)),
+    serialize(?PUBLISH_PACKET(?QOS_1, <<"Topic">>, 938, <<"Payload">>)),
+    serialize(?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 99, long_payload())).
+
+serialize_puback(_) ->
+    serialize(?PUBACK_PACKET(?PUBACK, 10384)).
+
+serialize_pubrel(_) ->
+    serialize(?PUBREL_PACKET(10384)).
+
+serialize_subscribe(_) ->
+    TopicTable = [{<<"TopicQos0">>, ?QOS_0}, {<<"TopicQos1">>, ?QOS_1}, {<<"TopicQos2">>, ?QOS_2}],
+    serialize(?SUBSCRIBE_PACKET(10, TopicTable)).
+
+serialize_suback(_) ->
+    serialize(?SUBACK_PACKET(10, [?QOS_0, ?QOS_1, 128])).
+
+serialize_unsubscribe(_) ->
+    serialize(?UNSUBSCRIBE_PACKET(10, [<<"Topic1">>, <<"Topic2">>])).
+
+serialize_unsuback(_) ->
+    serialize(?UNSUBACK_PACKET(10)).
+
+serialize_pingreq(_) ->
+    serialize(?PACKET(?PINGREQ)).
+
+serialize_pingresp(_) ->
+    serialize(?PACKET(?PINGRESP)).
+
+serialize_disconnect(_) ->
+    serialize(?PACKET(?DISCONNECT)).
+
+long_payload() ->
+    iolist_to_binary(["payload." || _I <- lists:seq(1, 100)]).
+
+%%--------------------------------------------------------------------
+%% Packet Cases
+%%--------------------------------------------------------------------
+
+packet_proto_name(_) ->
+    <<"MQIsdp">> = emqttd_packet:protocol_name(3),
+    <<"MQTT">> = emqttd_packet:protocol_name(4).
+
+packet_type_name(_) ->
+    'CONNECT' = emqttd_packet:type_name(?CONNECT),
+    'UNSUBSCRIBE' = emqttd_packet:type_name(?UNSUBSCRIBE).
+
+packet_connack_name(_) ->
+    'CONNACK_ACCEPT'      = emqttd_packet:connack_name(?CONNACK_ACCEPT),
+    'CONNACK_PROTO_VER'   = emqttd_packet:connack_name(?CONNACK_PROTO_VER),
+    'CONNACK_INVALID_ID'  = emqttd_packet:connack_name(?CONNACK_INVALID_ID),
+    'CONNACK_SERVER'      = emqttd_packet:connack_name(?CONNACK_SERVER),
+    'CONNACK_CREDENTIALS' = emqttd_packet:connack_name(?CONNACK_CREDENTIALS),
+    'CONNACK_AUTH'        = emqttd_packet:connack_name(?CONNACK_AUTH).
+
+packet_format(_) ->
+    io:format("~s", [emqttd_packet:format(?CONNECT_PACKET(#mqtt_packet_connect{}))]),
+    io:format("~s", [emqttd_packet:format(?CONNACK_PACKET(?CONNACK_SERVER))]),
+    io:format("~s", [emqttd_packet:format(?PUBLISH_PACKET(?QOS_1, 1))]),
+    io:format("~s", [emqttd_packet:format(?PUBLISH_PACKET(?QOS_2, <<"topic">>, 10, <<"payload">>))]),
+    io:format("~s", [emqttd_packet:format(?PUBACK_PACKET(?PUBACK, 98))]),
+    io:format("~s", [emqttd_packet:format(?PUBREL_PACKET(99))]),
+    io:format("~s", [emqttd_packet:format(?SUBSCRIBE_PACKET(15, [{<<"topic">>, ?QOS0}, {<<"topic1">>, ?QOS1}]))]),
+    io:format("~s", [emqttd_packet:format(?SUBACK_PACKET(40, [?QOS0, ?QOS1]))]),
+    io:format("~s", [emqttd_packet:format(?UNSUBSCRIBE_PACKET(89, [<<"t">>, <<"t2">>]))]),
+    io:format("~s", [emqttd_packet:format(?UNSUBACK_PACKET(90))]).
+
+%%--------------------------------------------------------------------
+%% Message Cases
+%%--------------------------------------------------------------------
+
+message_make(_) ->
+    Msg = emqttd_message:make(<<"clientid">>, <<"topic">>, <<"payload">>),
+    0 = Msg#mqtt_message.qos,
+    undefined = Msg#mqtt_message.msgid,
+    Msg1 = emqttd_message:make(<<"clientid">>, qos2, <<"topic">>, <<"payload">>),
+    true = is_binary(Msg1#mqtt_message.msgid),
+    2 = Msg1#mqtt_message.qos.
+
+message_from_packet(_) ->
+    Msg = emqttd_message:from_packet(?PUBLISH_PACKET(1, <<"topic">>, 10, <<"payload">>)),
+    1 = Msg#mqtt_message.qos,
+    10 = Msg#mqtt_message.pktid,
+    <<"topic">> = Msg#mqtt_message.topic,
+
+    WillMsg = emqttd_message:from_packet(#mqtt_packet_connect{will_flag  = true,
+                                                              will_topic = <<"WillTopic">>,
+                                                              will_msg   = <<"WillMsg">>}),
+    <<"WillTopic">> = WillMsg#mqtt_message.topic,
+    <<"WillMsg">> = WillMsg#mqtt_message.payload,
+
+    Msg2 = emqttd_message:from_packet(<<"username">>, <<"clientid">>,
+                                      ?PUBLISH_PACKET(1, <<"topic">>, 20, <<"payload">>)),
+    <<"clientid">> = Msg2#mqtt_message.from,
+    <<"username">> = Msg2#mqtt_message.sender,
+    io:format("~s", [emqttd_message:format(Msg2)]).
+
+message_flag(_) ->
+    Pkt = ?PUBLISH_PACKET(1, <<"t">>, 2, <<"payload">>),
+    Msg2 = emqttd_message:from_packet(<<"clientid">>, Pkt),
+    Msg3 = emqttd_message:set_flag(retain, Msg2),
+    Msg4 = emqttd_message:set_flag(dup, Msg3),
+    true = Msg4#mqtt_message.dup,
+    true = Msg4#mqtt_message.retain,
+    Msg5 = emqttd_message:set_flag(Msg4),
+    Msg6 = emqttd_message:unset_flag(dup, Msg5),
+    Msg7 = emqttd_message:unset_flag(retain, Msg6),
+    false = Msg7#mqtt_message.dup,
+    false = Msg7#mqtt_message.retain,
+    emqttd_message:unset_flag(Msg7),
+    emqttd_message:to_packet(Msg7).
+

+ 0 - 29
test/emqttd_retainer_tests.erl

@@ -1,29 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_retainer_tests).
-
--ifdef(TEST).
-
--include("emqttd.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
-retain_test() ->
-    mnesia:start(),
-    emqttd_retainer:mnesia(boot).
-
--endif.

+ 0 - 126
test/emqttd_router_tests.erl

@@ -1,126 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_router_tests).
-
--ifdef(TEST).
-
--include("emqttd.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--define(R, emqttd_router).
-
-route_test_() ->
-    {timeout, 60,
-     [{setup,
-       fun setup/0,
-       fun teardown/1,
-       [?_test(t_add_del_route()),
-        ?_test(t_add_del_routes()),
-        ?_test(t_route())
-       ]}
-     ]}.
-
-setup() ->
-    application:start(gproc),
-    application:start(mnesia),
-    emqttd_pubsub:create_table(topic, ram_copies),
-    emqttd_trie:mnesia(boot),
-    emqttd_pubsub_sup:create_tab(route),
-    gproc_pool:new(router, hash, [{size, 2}]),
-    lists:foreach(fun(I) ->
-                gproc_pool:add_worker(router, {router, I}, I),
-                {ok, R} = ?R:start_link(router, I, fun(_) -> ok end, [{route_aging, 2}])
-        end, [1, 2]).
-
-ensure_tab(Tab, Opts) ->
-    case ets:info(Tab, name) of
-        undefined -> ets:new(Tab, Opts);
-        _ -> ok
-    end.
-
-teardown(_) ->
-    lists:foreach(fun(I) ->
-            ?R:stop(I), gproc_pool:remove_worker(router, {router, I})
-        end, [1, 2]),
-    gproc_pool:delete(router),
-    ets:delete(route),
-    application:stop(gproc).
-
-t_add_del_route() ->
-    Self = self(),
-    ?R:add_route(<<"topic1">>, Self),
-    ?assert(?R:has_route(<<"topic1">>)),
-    ?R:add_route(<<"topic2">>, Self),
-    ?assert(?R:has_route(<<"topic2">>)),
-    ?assertEqual([Self], ?R:lookup_routes(<<"topic1">>)),
-    ?assertEqual([Self], ?R:lookup_routes(<<"topic2">>)),
-    %% Del topic1
-    ?R:delete_route(<<"topic1">>, Self),
-    erlang:yield(),
-    timer:sleep(10),
-    ?assertNot(?R:has_route(<<"topic1">>)),
-    %% Del topic2
-    ?R:delete_route(<<"topic2">>, Self),
-    erlang:yield(),
-    timer:sleep(10),
-    ?assertNot(?R:has_route(<<"topic2">>)).
-
-t_add_del_routes() ->
-    Self = self(),
-    ?R:add_routes([], Self),
-    ?R:add_routes([<<"t0">>], Self),
-    ?R:add_routes([<<"t1">>,<<"t2">>,<<"t3">>], Self),
-    ?assert(?R:has_route(<<"t1">>)),
-    ?assertEqual([Self], ?R:lookup_routes(<<"t1">>)),
-    ?assertEqual([Self], ?R:lookup_routes(<<"t2">>)),
-    ?assertEqual([Self], ?R:lookup_routes(<<"t3">>)),
-
-    ?R:delete_routes([<<"t3">>], Self),
-    ?R:delete_routes([<<"t0">>, <<"t1">>], Self),
-    erlang:yield(),
-    timer:sleep(10),
-    ?assertNot(?R:has_route(<<"t0">>)),
-    ?assertNot(?R:has_route(<<"t1">>)),
-    ?assert(?R:has_route(<<"t2">>)),
-    ?assertNot(?R:has_route(<<"t3">>)).
-
-t_route() ->
-    Self = self(),
-    Pid = spawn_link(fun() -> timer:sleep(1000) end),
-    ?R:add_routes([<<"$Q/1">>,<<"t/2">>,<<"t/3">>], Self),
-    ?R:add_routes([<<"t/2">>], Pid),
-    Msg1 = #mqtt_message{topic = <<"$Q/1">>, payload = <<"q">>},
-    Msg2 = #mqtt_message{topic = <<"t/2">>, payload = <<"t2">>},
-    Msg3 = #mqtt_message{topic = <<"t/3">>, payload = <<"t3">>},
-    ?R:route(<<"$Q/1">>, Msg1),
-    ?R:route(<<"t/2">>, Msg2),
-    ?R:route(<<"t/3">>, Msg3),
-    ?assertEqual([Msg1, Msg2, Msg3], recv_loop([])),
-    ?R:add_route(<<"$Q/1">>, Pid),
-    ?R:route(<<"$Q/1">>, Msg1).
-
-recv_loop(Msgs) ->
-    receive
-        {dispatch, _Topic, Msg} ->
-            recv_loop([Msg|Msgs])
-        after
-            500 -> lists:reverse(Msgs)
-    end.
-
--endif.
-

+ 0 - 80
test/emqttd_serializer_tests.erl

@@ -1,80 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_serializer_tests).
-
--ifdef(TEST).
-
--include("emqttd_protocol.hrl").
-
--include_lib("eunit/include/eunit.hrl").
-
--import(emqttd_serializer, [serialize/1]).
-
-serialize_connect_test() ->
-    serialize(?CONNECT_PACKET(#mqtt_packet_connect{})),
-    serialize(?CONNECT_PACKET(#mqtt_packet_connect{
-                client_id = <<"clientId">>,
-                will_qos = ?QOS1,
-                will_flag = true,
-                will_retain = true,
-                will_topic = <<"will">>,
-                will_msg = <<"haha">>,
-                clean_sess = true})).
-
-serialize_connack_test() ->
-    ConnAck = #mqtt_packet{header = #mqtt_packet_header{type = ?CONNACK}, 
-                           variable = #mqtt_packet_connack{ack_flags = 0, return_code = 0}},
-    ?assertEqual(<<32,2,0,0>>, serialize(ConnAck)).
-
-serialize_publish_test() ->
-    serialize(?PUBLISH_PACKET(?QOS_0, <<"Topic">>, undefined, <<"Payload">>)),
-    serialize(?PUBLISH_PACKET(?QOS_1, <<"Topic">>, 938, <<"Payload">>)),
-    serialize(?PUBLISH_PACKET(?QOS_2, <<"Topic">>, 99, long_payload())).
-
-serialize_puback_test() ->
-    serialize(?PUBACK_PACKET(?PUBACK, 10384)).
-
-serialize_pubrel_test() ->
-    serialize(?PUBREL_PACKET(10384)).
-
-serialize_subscribe_test() ->
-    TopicTable = [{<<"TopicQos0">>, ?QOS_0}, {<<"TopicQos1">>, ?QOS_1}, {<<"TopicQos2">>, ?QOS_2}],
-    serialize(?SUBSCRIBE_PACKET(10, TopicTable)).
-
-serialize_suback_test() ->
-    serialize(?SUBACK_PACKET(10, [?QOS_0, ?QOS_1, 128])).
-
-serialize_unsubscribe_test() ->
-    serialize(?UNSUBSCRIBE_PACKET(10, [<<"Topic1">>, <<"Topic2">>])).
-
-serialize_unsuback_test() ->
-    serialize(?UNSUBACK_PACKET(10)).
-
-serialize_pingreq_test() ->
-    serialize(?PACKET(?PINGREQ)).
-
-serialize_pingresp_test() ->
-    serialize(?PACKET(?PINGRESP)).
-
-serialize_disconnect_test() ->
-    serialize(?PACKET(?DISCONNECT)).
-
-long_payload() ->
-    iolist_to_binary(["payload." || _I <- lists:seq(1, 100)]).
-
--endif.
-

+ 0 - 29
test/emqttd_time_tests.erl

@@ -1,29 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_time_tests).
-
--ifdef(TEST).
-
--include_lib("eunit/include/eunit.hrl").
-
-all_test() ->
-    emqttd_time:seed(),
-    emqttd_time:now_to_secs(),
-    emqttd_time:now_to_ms().
-
--endif.
-

+ 176 - 0
test/emqttd_topic_SUITE.erl

@@ -0,0 +1,176 @@
+%%--------------------------------------------------------------------
+%% Copyright (c) 2016 Feng Lee <feng@emqtt.io>.
+%%
+%% 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(emqttd_topic_SUITE).
+
+%% CT
+-compile(export_all).
+
+-import(emqttd_topic, [wildcard/1, match/2, validate/1, triples/1, join/1,
+                       words/1, systop/1, is_queue/1, feed_var/3]).
+
+-define(N, 10000).
+
+all() -> [t_wildcard, t_match, t_match2, t_validate, t_triples, t_join,
+          t_words, t_systop, t_is_queue, t_feed_var, t_sys_match, 't_#_match',
+          t_sigle_level_validate, t_sigle_level_match, t_match_perf,
+          t_triples_perf].
+
+t_wildcard(_) ->
+    true  = wildcard(<<"a/b/#">>),
+    true  = wildcard(<<"a/+/#">>),
+    false = wildcard(<<"">>),
+    false = wildcard(<<"a/b/c">>).
+
+t_match(_) ->
+    true  = match(<<"a/b/c">>, <<"a/b/+">>),
+    true  = match(<<"a/b/c">>, <<"a/#">>),
+    true  = match(<<"abcd/ef/g">>, <<"#">>),
+    true  = match(<<"abc/de/f">>, <<"abc/de/f">>),
+    true  = match(<<"abc">>, <<"+">>),
+    true  = match(<<"a/b/c">>, <<"a/b/c">>),
+    false = match(<<"a/b/c">>, <<"a/c/d">>),
+    false = match(<<"$shared/x/y">>, <<"+">>),
+    false = match(<<"$shared/x/y">>, <<"+/x/y">>),
+    false = match(<<"$shared/x/y">>, <<"#">>),
+    false = match(<<"$shared/x/y">>, <<"+/+/#">>),
+    false = match(<<"house/1/sensor/0">>, <<"house/+">>),
+    false = match(<<"house">>, <<"house/+">>).
+
+t_match2(_) ->
+    true  = match(<<"sport/tennis/player1">>, <<"sport/tennis/player1/#">>),
+    true  = match(<<"sport/tennis/player1/ranking">>, <<"sport/tennis/player1/#">>),
+    true  = match(<<"sport/tennis/player1/score/wimbledon">>, <<"sport/tennis/player1/#">>),
+    true  = match(<<"sport">>, <<"sport/#">>),
+    true  = match(<<"sport">>, <<"#">>),
+    true  = match(<<"/sport/football/score/1">>, <<"#">>),
+    true  = match(<<"Topic/C">>, <<"+/+">>),
+    true  = match(<<"TopicA/B">>, <<"+/+">>),
+    true  = match(<<"TopicA/C">>, <<"+/+">>),
+    true  = match(<<"abc">>, <<"+">>),
+    true  = match(<<"a/b/c">>, <<"a/b/c">>),
+    false = match(<<"a/b/c">>, <<"a/c/d">>),
+    false = match(<<"$shared/x/y">>, <<"+">>),
+    false = match(<<"$shared/x/y">>, <<"+/x/y">>),
+    false = match(<<"$shared/x/y">>, <<"#">>),
+    false = match(<<"$shared/x/y">>, <<"+/+/#">>),
+    false = match(<<"house/1/sensor/0">>, <<"house/+">>).
+
+t_sigle_level_match(_) ->
+    true  = match(<<"sport/tennis/player1">>, <<"sport/tennis/+">>),
+    false = match(<<"sport/tennis/player1/ranking">>, <<"sport/tennis/+">>),
+    false = match(<<"sport">>, <<"sport/+">>),
+    true  = match(<<"sport/">>, <<"sport/+">>),
+    true  = match(<<"/finance">>, <<"+/+">>),
+    true  = match(<<"/finance">>, <<"/+">>),
+    false = match(<<"/finance">>, <<"+">>).
+
+t_sys_match(_) ->
+    true  = match(<<"$SYS/broker/clients/testclient">>, <<"$SYS/#">>),
+    true  = match(<<"$SYS/broker">>, <<"$SYS/+">>),
+    false = match(<<"$SYS/broker">>, <<"+/+">>),
+    false = match(<<"$SYS/broker">>, <<"#">>).
+
+'t_#_match'(_) ->
+    true = match(<<"a/b/c">>, <<"#">>),
+    true = match(<<"a/b/c">>, <<"+/#">>),
+    false = match(<<"$SYS/brokers">>, <<"#">>).
+
+t_match_perf(_) ->
+    true = match(<<"a/b/ccc">>, <<"a/#">>),
+    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]).
+
+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/#">>}),
+    false = validate({name, <<>>}),
+    false = validate({name, long_topic()}),
+    false = validate({name, <<"abc/#">>}),
+    false = validate({filter, <<"abc/#/1">>}),
+    false = validate({filter, <<"abc/#xzy/+">>}),
+    false = validate({filter, <<"abc/xzy/+9827">>}),
+	false = validate({filter, <<"sport/tennis#">>}),
+    false = validate({filter, <<"sport/tennis/#/ranking">>}).
+
+t_sigle_level_validate(_) ->
+    true  = validate({filter, <<"+">>}),
+    true  = validate({filter, <<"+/tennis/#">>}),
+    true  = validate({filter, <<"sport/+/player1">>}),
+    false = validate({filter, <<"sport+">>}).
+
+t_triples(_) ->
+    Triples = [{root,<<"a">>,<<"a">>},
+               {<<"a">>,<<"b">>,<<"a/b">>},
+               {<<"a/b">>,<<"c">>,<<"a/b/c">>}],
+    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]).
+
+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]).
+
+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/+/#">>)).
+
+t_is_queue(_) ->
+    true  = is_queue(<<"$Q/queue">>),
+    true  = is_queue(<<"$q/queue">>),
+    false = is_queue(<<"xyz/queue">>).
+
+t_systop(_) ->
+    SysTop1 = iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/xyz"]),
+    SysTop1 = systop('xyz'),
+    SysTop2 = iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/abc"]),
+    SysTop2 = systop(<<"abc">>).
+
+t_feed_var(_) ->
+    <<"$Q/client/clientId">> = feed_var(<<"$c">>, <<"clientId">>, <<"$Q/client/$c">>),
+    <<"username/test/client/x">> = feed_var(<<"%u">>, <<"test">>, <<"username/%u/client/x">>),
+    <<"username/test/client/clientId">> = feed_var(<<"%c">>, <<"clientId">>, <<"username/test/client/%c">>).
+
+long_topic() ->
+    iolist_to_binary([[integer_to_list(I), "/"] || I <- lists:seq(0, 10000)]).
+

+ 0 - 158
test/emqttd_topic_tests.erl

@@ -1,158 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(emqttd_topic_tests).
-
--ifdef(TEST).
-
--include_lib("eunit/include/eunit.hrl").
-
--import(emqttd_topic, [validate/1, wildcard/1, match/2, triples/1, words/1,
-                       join/1, feed_var/3, is_queue/1, systop/1]).
-
--define(N, 10000).
-
-validate_test() ->
-	?assert( validate({filter, <<"sport/tennis/#">>}) ),
-	?assert( validate({filter, <<"a/b/c">>}) ),
-	?assert( validate({filter, <<"/a/b">>}) ),
-	?assert( validate({filter, <<"/+/x">>}) ),
-	?assert( validate({filter, <<"/a/b/c/#">>}) ),
-    ?assert( validate({filter, <<"x">>}) ),
-    ?assertNot( validate({name, <<>>}) ),
-	?assertNot( validate({filter, <<"a/#/c">>}) ),
-	?assertNot( validate({filter, <<"sport/tennis#">>}) ),
-	?assertNot( validate({filter, <<"sport/tennis/#/ranking">>}) ).
-
-sigle_level_validate_test() ->
-    ?assert( validate({filter, <<"+">>}) ),
-    ?assert( validate({filter, <<"+/tennis/#">>}) ),
-    ?assertNot( validate({filter, <<"sport+">>}) ),
-    ?assert( validate({filter, <<"sport/+/player1">>}) ).
-
-match_test() ->
-    ?assert( match(<<"sport/tennis/player1">>, <<"sport/tennis/player1/#">>) ),
-    ?assert( match(<<"sport/tennis/player1/ranking">>, <<"sport/tennis/player1/#">>) ),
-    ?assert( match(<<"sport/tennis/player1/score/wimbledon">>, <<"sport/tennis/player1/#">>) ),
-
-    ?assert( match(<<"sport">>, <<"sport/#">>) ),
-    ?assert( match(<<"sport">>, <<"#">>) ),
-    ?assert( match(<<"/sport/football/score/1">>, <<"#">>) ),
-    %% paho test
-    ?assert( match(<<"Topic/C">>, <<"+/+">>) ),
-    ?assert( match(<<"TopicA/B">>, <<"+/+">>) ),
-    ?assert( match(<<"TopicA/C">>, <<"+/+">>) ),
-
-    ?assert( match(<<"abc">>, <<"+">>) ),
-    ?assert( match(<<"a/b/c">>, <<"a/b/c">>) ),
-    ?assertNot( match(<<"a/b/c">>, <<"a/c/d">>) ),
-    ?assertNot( match(<<"$shared/x/y">>, <<"+">>) ),
-    ?assertNot( match(<<"$shared/x/y">>, <<"+/x/y">>) ),
-    ?assertNot( match(<<"$shared/x/y">>, <<"#">>) ),
-    ?assertNot( match(<<"$shared/x/y">>, <<"+/+/#">>) ),
-    ?assertNot( match(<<"house/1/sensor/0">>, <<"house/+">>) ).
-
-sigle_level_match_test() ->
-    ?assert( match(<<"sport/tennis/player1">>, <<"sport/tennis/+">>) ),
-    ?assertNot( match(<<"sport/tennis/player1/ranking">>, <<"sport/tennis/+">>) ),
-    ?assertNot( match(<<"sport">>, <<"sport/+">>) ),
-    ?assert( match(<<"sport/">>, <<"sport/+">>) ),
-    ?assert( match(<<"/finance">>, <<"+/+">>) ),
-    ?assert( match(<<"/finance">>, <<"/+">>) ),
-    ?assertNot( match(<<"/finance">>, <<"+">>) ).
-
-sys_match_test() ->
-    ?assert( match(<<"$SYS/broker/clients/testclient">>, <<"$SYS/#">>) ),
-    ?assert( match(<<"$SYS/broker">>, <<"$SYS/+">>) ),
-    ?assertNot( match(<<"$SYS/broker">>, <<"+/+">>) ),
-    ?assertNot( match(<<"$SYS/broker">>, <<"#">>) ).
-
-'#_match_test'() ->
-    ?assert( match(<<"a/b/c">>, <<"#">>) ),
-    ?assert( match(<<"a/b/c">>, <<"+/#">>) ),
-    ?assertNot( match(<<"$SYS/brokers">>, <<"#">>) ).
-
-match_perf_test() ->
-    ?assert( match(<<"a/b/ccc">>, <<"a/#">>) ),
-    Name = <<"/abkc/19383/192939/akakdkkdkak/xxxyyuya/akakak">>,
-    Filter = <<"/abkc/19383/+/akakdkkdkak/#">>,
-    ?assert( match(Name, Filter) ),
-    %?debugFmt("Match ~p with ~p", [Name, Filter]),
-    {Time, _} = timer:tc(fun() ->
-                [match(Name, Filter) || _I <- lists:seq(1, ?N)]
-        end),
-    ?debugFmt("Time for match: ~p(micro)", [Time/?N]),
-    ok.
-
-triples_test() ->
-    Triples = [{root, <<"a">>, <<"a">>}, {<<"a">>, <<"b">>, <<"a/b">>}],
-    ?assertMatch(Triples, triples(<<"a/b">>) ).
-
-triples_perf_test() ->
-    Topic = <<"/abkc/19383/192939/akakdkkdkak/xxxyyuya/akakak">>,
-    {Time, _} = timer:tc(fun() ->
-                [triples(Topic) || _I <- lists:seq(1, ?N)]
-        end),
-    ?debugFmt("Time for triples: ~p(micro)", [Time/?N]),
-    ok.
-
-type_test() ->
-	?assertEqual(false, wildcard(<<"/a/b/cdkd">>)),
-	?assertEqual(true, wildcard(<<"/a/+/d">>)),
-	?assertEqual(true, wildcard(<<"/a/b/#">>)).
-
-words_test() ->
-    ?assertEqual(['', <<"a">>, '+', '#'], words(<<"/a/+/#">>) ),
-    ?assertMatch(['', <<"abkc">>, <<"19383">>, '+', <<"akakdkkdkak">>, '#'],  words(<<"/abkc/19383/+/akakdkkdkak/#">>)),
-    {Time, _} = timer:tc(fun() ->
-                [words(<<"/abkc/19383/+/akakdkkdkak/#">>) || _I <- lists:seq(1, ?N)]
-        end),
-    ?debugFmt("Time for words: ~p(micro)", [Time/?N]),
-    {Time2, _} = timer:tc(fun() ->
-                [binary:split(<<"/abkc/19383/+/akakdkkdkak/#">>, <<"/">>, [global]) || _I <- lists:seq(1, ?N)]
-        end),
-    ?debugFmt("Time for binary:split: ~p(micro)", [Time2/?N]),
-    ok.
-
-is_queue_test() ->
-    ?assert( is_queue(<<"$Q/queue">>) ),
-    ?assert( is_queue(<<"$q/queue">>) ),
-    ?assertNot( is_queue(<<"xyz/queue">>) ).
-
-systop_test() ->
-    ?assertEqual( iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/xyz"]), systop('xyz') ),
-    ?assertEqual( iolist_to_binary(["$SYS/brokers/", atom_to_list(node()), "/abc"]), systop(<<"abc">>) ).
-
-feed_var_test() ->
-    ?assertEqual(<<"$Q/client/clientId">>, feed_var(<<"$c">>, <<"clientId">>, <<"$Q/client/$c">>)),
-    ?assertEqual(<<"username/test/client/x">>,
-                 feed_var(<<"%u">>, <<"test">>, <<"username/%u/client/x">>)),
-    ?assertEqual(<<"username/test/client/clientId">>,
-                 feed_var(<<"%c">>, <<"clientId">>, <<"username/test/client/%c">>)).
-
-join_test() ->
-    ?assertEqual(<<"/ab/cd/ef/">>, join(words(<<"/ab/cd/ef/">>))),
-    ?assertEqual(<<"ab/+/#">>, join(words(<<"ab/+/#">>))),
-    ?assertEqual( <<"x/y/z/+">>, join([<<"x">>, <<"y">>, <<"z">>, '+']) ),
-    ?assertEqual( <<>>, join([]) ),
-    ?assertEqual( <<"x">>, join([<<"x">>]) ),
-    ?assertEqual( <<"#">>, join(['#']) ),
-    ?assertEqual( <<"+//#">>, join(['+', '', '#']) ).
-
-long_topic() ->
-    iolist_to_binary([[integer_to_list(I), "/"] || I <- lists:seq(0, 10000)]).
-
--endif.

+ 39 - 47
test/emqttd_trie_tests.erl

@@ -1,5 +1,5 @@
 %%--------------------------------------------------------------------
-%% Copyright (c) 2016 Feng Lee <feng@emqtt.io>. All Rights Reserved.
+%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -14,45 +14,39 @@
 %% limitations under the License.
 %%--------------------------------------------------------------------
 
--module(emqttd_trie_tests).
+-module(emqttd_trie_SUITE).
 
--ifdef(TEST).
-
--include("emqttd.hrl").
+-compile(export_all).
 
 -include("emqttd_trie.hrl").
 
--include_lib("eunit/include/eunit.hrl").
-
 -define(TRIE, emqttd_trie).
 
-trie_test_() ->
-    {setup, fun setup/0, fun teardown/1,
-     [{foreach, fun() -> ok end, fun(_) -> clear() end,
-       [?_test(t_insert()),
-        ?_test(t_match()),
-        ?_test(t_match2()),
-        ?_test(t_match3()),
-        ?_test(t_delete()),
-        ?_test(t_delete2()),
-        ?_test(t_delete3())]
-      }]}.
-
-setup() ->
+all() ->
+    [t_insert, t_match, t_match2, t_match3, t_delete, t_delete2, t_delete3].
+
+init_per_suite(Config) ->
     emqttd_mnesia:ensure_started(),
     ?TRIE:mnesia(boot),
-    ?TRIE:mnesia(copy).
+    ?TRIE:mnesia(copy),
+    Config.
 
-teardown(_) ->
+end_per_suite(_Config) ->
     emqttd_mnesia:ensure_stopped(),
     emqttd_mnesia:delete_schema().
 
-t_insert() ->
+init_per_testcase(_TestCase, Config) ->
+    Config.
+
+end_per_testcase(_TestCase, _Config) ->
+    clear_tables().
+
+t_insert(_) ->
     TN = #trie_node{node_id = <<"sensor">>,
                     edge_count = 3,
                     topic = <<"sensor">>,
                     flags = undefined},
-    ?assertEqual({atomic, [TN]}, mnesia:transaction(
+    {atomic, [TN]} = mnesia:transaction(
             fun() ->
                 ?TRIE:insert(<<"sensor/1/metric/2">>),
                 ?TRIE:insert(<<"sensor/+/#">>),
@@ -60,43 +54,43 @@ t_insert() ->
                 ?TRIE:insert(<<"sensor">>),
                 ?TRIE:insert(<<"sensor">>),
                 ?TRIE:lookup(<<"sensor">>)
-            end)).
+            end).
 
-t_match() ->
+t_match(_) ->
     Machted = [<<"sensor/+/#">>, <<"sensor/#">>],
-    ?assertEqual({atomic, Machted}, mnesia:transaction(
+    {atomic, Machted} = mnesia:transaction(
             fun() ->
                 ?TRIE:insert(<<"sensor/1/metric/2">>),
                 ?TRIE:insert(<<"sensor/+/#">>),
                 ?TRIE:insert(<<"sensor/#">>),
                 ?TRIE:match(<<"sensor/1">>)
-            end)).
+            end).
 
-t_match2() ->
+t_match2(_) ->
     Matched = {[<<"+/+/#">>, <<"+/#">>, <<"#">>], []},
-    ?assertEqual({atomic, Matched}, mnesia:transaction(
+    {atomic, Matched} = mnesia:transaction(
             fun() ->
                 ?TRIE:insert(<<"#">>),
                 ?TRIE:insert(<<"+/#">>),
                 ?TRIE:insert(<<"+/+/#">>),
                 {?TRIE:match(<<"a/b/c">>),
                  ?TRIE:match(<<"$SYS/broker/zenmq">>)}
-            end)).
+            end).
 
-t_match3() ->
+t_match3(_) ->
     Topics = [<<"d/#">>, <<"a/b/c">>, <<"a/b/+">>, <<"a/#">>, <<"#">>, <<"$SYS/#">>],
     mnesia:transaction(fun() -> [emqttd_trie:insert(Topic) || Topic <- Topics] end),
     Matched = mnesia:async_dirty(fun emqttd_trie:match/1, [<<"a/b/c">>]),
-    ?assertEqual(4, length(Matched)),
+    4 = length(Matched),
     SysMatched = mnesia:async_dirty(fun emqttd_trie:match/1, [<<"$SYS/a/b/c">>]),
-    ?assertEqual([<<"$SYS/#">>], SysMatched).
+    [<<"$SYS/#">>] = SysMatched.
 
-t_delete() ->
+t_delete(_) ->
     TN = #trie_node{node_id = <<"sensor/1">>,
                     edge_count = 2,
                     topic = undefined,
                     flags = undefined},
-    ?assertEqual({atomic, [TN]}, mnesia:transaction(
+    {atomic, [TN]} = mnesia:transaction(
             fun() ->
                 ?TRIE:insert(<<"sensor/1/#">>),
                 ?TRIE:insert(<<"sensor/1/metric/2">>),
@@ -105,10 +99,10 @@ t_delete() ->
                 ?TRIE:delete(<<"sensor/1/metric">>),
                 ?TRIE:delete(<<"sensor/1/metric">>),
                 ?TRIE:lookup(<<"sensor/1">>)
-            end)).
+            end).
 
-t_delete2() ->
-    ?assertEqual({atomic, {[], []}}, mnesia:transaction(
+t_delete2(_) ->
+    {atomic, {[], []}} = mnesia:transaction(
             fun() ->
                 ?TRIE:insert(<<"sensor">>),
                 ?TRIE:insert(<<"sensor/1/metric/2">>),
@@ -118,10 +112,10 @@ t_delete2() ->
                 ?TRIE:delete(<<"sensor/1/metric/3">>),
                 {?TRIE:lookup(<<"sensor">>),
                  ?TRIE:lookup(<<"sensor/1">>)}
-            end)).
+            end).
 
-t_delete3() ->
-    ?assertEqual({atomic, {[], []}}, mnesia:transaction(
+t_delete3(_) ->
+    {atomic, {[], []}} = mnesia:transaction(
             fun() ->
                 ?TRIE:insert(<<"sensor/+">>),
                 ?TRIE:insert(<<"sensor/+/metric/2">>),
@@ -132,10 +126,8 @@ t_delete3() ->
                 ?TRIE:delete(<<"sensor/+">>),
                 ?TRIE:delete(<<"sensor/+/unknown">>),
                 {?TRIE:lookup(<<"sensor">>), ?TRIE:lookup(<<"sensor/+">>)}
-            end)).
+            end).
 
-clear() ->
-    mnesia:clear_table(trie),
-    mnesia:clear_table(trie_node).
+clear_tables() ->
+    lists:foreach(fun mnesia:clear_table/1, [trie, trie_node]).
 
--endif.

+ 0 - 72
test/priority_queue_tests.erl

@@ -1,72 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2012-2016 Feng Lee <feng@emqtt.io>.
-%%
-%% 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(priority_queue_tests).
-
--include("emqttd.hrl").
-
--ifdef(TEST).
-
--include_lib("eunit/include/eunit.hrl").
-
--define(PQ, priority_queue).
-
-plen_test() ->
-    Q = ?PQ:new(),
-    ?assertEqual(0, ?PQ:plen(0, Q)),
-    Q0 = ?PQ:in(z, Q),
-    ?assertEqual(1, ?PQ:plen(0, Q0)),
-    Q1 = ?PQ:in(x, 1, Q0),
-    ?assertEqual(1, ?PQ:plen(1, Q1)),
-    Q2 = ?PQ:in(y, 2, Q1),
-    ?assertEqual(1, ?PQ:plen(2, Q2)),
-    Q3 = ?PQ:in(z, 2, Q2),
-    ?assertEqual(2, ?PQ:plen(2, Q3)),
-    {_, Q4} = ?PQ:out(1, Q3),
-    ?assertEqual(0, ?PQ:plen(1, Q4)),
-    {_, Q5} = ?PQ:out(Q4),
-    ?assertEqual(1, ?PQ:plen(2, Q5)),
-    {_, Q6} = ?PQ:out(Q5),
-    ?assertEqual(0, ?PQ:plen(2, Q6)),
-    ?assertEqual(1, ?PQ:len(Q6)),
-    {_, Q7} = ?PQ:out(Q6),
-    ?assertEqual(0, ?PQ:len(Q7)).
-
-out2_test() ->
-    Els = [a, {b, 1}, {c, 1}, {d, 2}, {e, 2}, {f, 2}],
-    Q  = ?PQ:new(),
-    Q0 = lists:foldl(
-            fun({El, P}, Q) ->
-                    ?PQ:in(El, P, Q);
-                (El, Q) ->
-                    ?PQ:in(El, Q)
-            end, Q, Els),
-    {Val, Q1} = ?PQ:out(Q0),
-    ?assertEqual({value, d}, Val),
-    {Val1, Q2} = ?PQ:out(2, Q1),
-    ?assertEqual({value, e}, Val1),
-    {Val2, Q3} = ?PQ:out(1, Q2),
-    ?assertEqual({value, b}, Val2),
-    {Val3, Q4} = ?PQ:out(Q3),
-    ?assertEqual({value, f}, Val3),
-    {Val4, Q5} = ?PQ:out(Q4),
-    ?assertEqual({value, c}, Val4),
-    {Val5, Q6} = ?PQ:out(Q5),
-    ?assertEqual({value, a}, Val5),
-    {empty, _Q7} = ?PQ:out(Q6).
-
--endif.
-