test: add some tests for persistent sessions
This commit is contained in:
parent
008eae5a8e
commit
5d4645b774
|
@ -333,37 +333,6 @@ t_connect_keepalive_timeout(Config) ->
|
||||||
error("keepalive timeout")
|
error("keepalive timeout")
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% [MQTT-3.1.2-23]
|
|
||||||
t_connect_session_expiry_interval(Config) ->
|
|
||||||
ConnFun = ?config(conn_fun, Config),
|
|
||||||
Topic = nth(1, ?TOPICS),
|
|
||||||
Payload = "test message",
|
|
||||||
|
|
||||||
{ok, Client1} = emqtt:start_link([ {clientid, <<"t_connect_session_expiry_interval">>},
|
|
||||||
{proto_ver, v5},
|
|
||||||
{properties, #{'Session-Expiry-Interval' => 7200}}
|
|
||||||
| Config
|
|
||||||
]),
|
|
||||||
{ok, _} = emqtt:ConnFun(Client1),
|
|
||||||
{ok, _, [2]} = emqtt:subscribe(Client1, Topic, qos2),
|
|
||||||
ok = emqtt:disconnect(Client1),
|
|
||||||
|
|
||||||
{ok, Client2} = emqtt:start_link([{proto_ver, v5} | Config]),
|
|
||||||
{ok, _} = emqtt:ConnFun(Client2),
|
|
||||||
{ok, 2} = emqtt:publish(Client2, Topic, Payload, 2),
|
|
||||||
ok = emqtt:disconnect(Client2),
|
|
||||||
|
|
||||||
{ok, Client3} = emqtt:start_link([ {clientid, <<"t_connect_session_expiry_interval">>},
|
|
||||||
{proto_ver, v5},
|
|
||||||
{clean_start, false} | Config
|
|
||||||
]),
|
|
||||||
{ok, _} = emqtt:ConnFun(Client3),
|
|
||||||
[Msg | _ ] = receive_messages(1),
|
|
||||||
?assertEqual({ok, iolist_to_binary(Topic)}, maps:find(topic, Msg)),
|
|
||||||
?assertEqual({ok, iolist_to_binary(Payload)}, maps:find(payload, Msg)),
|
|
||||||
?assertEqual({ok, 2}, maps:find(qos, Msg)),
|
|
||||||
ok = emqtt:disconnect(Client3).
|
|
||||||
|
|
||||||
%% [MQTT-3.1.3-9]
|
%% [MQTT-3.1.3-9]
|
||||||
%% !!!REFACTOR NEED:
|
%% !!!REFACTOR NEED:
|
||||||
%t_connect_will_delay_interval(Config) ->
|
%t_connect_will_delay_interval(Config) ->
|
||||||
|
|
|
@ -0,0 +1,307 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
%% you may not use this file except in compliance with the License.
|
||||||
|
%% You may obtain a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing, software
|
||||||
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
%% See the License for the specific language governing permissions and
|
||||||
|
%% limitations under the License.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_persistent_session_SUITE).
|
||||||
|
|
||||||
|
-include_lib("stdlib/include/assert.hrl").
|
||||||
|
|
||||||
|
-compile(export_all).
|
||||||
|
-compile(nowarn_export_all).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% SUITE boilerplate
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
all() ->
|
||||||
|
[ {group, tcp}
|
||||||
|
, {group, quic}
|
||||||
|
].
|
||||||
|
|
||||||
|
groups() ->
|
||||||
|
TCs = emqx_ct:all(?MODULE),
|
||||||
|
[ {tcp, [], TCs}
|
||||||
|
, {quic, [], TCs}
|
||||||
|
].
|
||||||
|
|
||||||
|
init_per_group(tcp, Config) ->
|
||||||
|
emqx_ct_helpers:start_apps([]),
|
||||||
|
[ {port, 1883}, {conn_fun, connect} | Config];
|
||||||
|
init_per_group(quic, Config) ->
|
||||||
|
emqx_ct_helpers:start_apps([]),
|
||||||
|
[ {port, 14567}, {conn_fun, quic_connect} | Config];
|
||||||
|
init_per_group(_, Config) ->
|
||||||
|
emqx_ct_helpers:stop_apps([]),
|
||||||
|
Config.
|
||||||
|
|
||||||
|
init_per_suite(Config) ->
|
||||||
|
%% Start Apps
|
||||||
|
emqx_ct_helpers:boot_modules(all),
|
||||||
|
emqx_ct_helpers:start_apps([emqx], fun set_special_confs/1),
|
||||||
|
Config.
|
||||||
|
|
||||||
|
set_special_confs(emqx) ->
|
||||||
|
application:set_env(emqx, plugins_loaded_file,
|
||||||
|
emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_plugins"));
|
||||||
|
set_special_confs(_) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
end_per_suite(_Config) ->
|
||||||
|
emqx_ct_helpers:stop_apps([]).
|
||||||
|
|
||||||
|
init_per_testcase(TestCase, Config) ->
|
||||||
|
case erlang:function_exported(?MODULE, TestCase, 2) of
|
||||||
|
true -> ?MODULE:TestCase(init, Config);
|
||||||
|
_ -> Config
|
||||||
|
end.
|
||||||
|
|
||||||
|
end_per_testcase(TestCase, Config) ->
|
||||||
|
case erlang:function_exported(?MODULE, TestCase, 2) of
|
||||||
|
true -> ?MODULE:TestCase('end', Config);
|
||||||
|
false -> ok
|
||||||
|
end,
|
||||||
|
Config.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Helpers
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
client_info(Key, Client) ->
|
||||||
|
maps:get(Key, maps:from_list(emqtt:info(Client)), undefined).
|
||||||
|
|
||||||
|
receive_messages(Count) ->
|
||||||
|
receive_messages(Count, []).
|
||||||
|
|
||||||
|
receive_messages(0, Msgs) ->
|
||||||
|
Msgs;
|
||||||
|
receive_messages(Count, Msgs) ->
|
||||||
|
receive
|
||||||
|
{publish, Msg} ->
|
||||||
|
receive_messages(Count-1, [Msg|Msgs]);
|
||||||
|
_Other ->
|
||||||
|
receive_messages(Count, Msgs)
|
||||||
|
after 1000 ->
|
||||||
|
Msgs
|
||||||
|
end.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Test Cases
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% [MQTT-3.1.2-23]
|
||||||
|
t_connect_session_expiry_interval(_) ->
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
Topic = <<"t_connect_session_expiry_interval/foo">>,
|
||||||
|
Payload = "test message",
|
||||||
|
|
||||||
|
{ok, Client1} = emqtt:start_link([ {clientid, <<"t_connect_session_expiry_interval">>},
|
||||||
|
{proto_ver, v5},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 7200}}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
{ok, _, [2]} = emqtt:subscribe(Client1, Topic, qos2),
|
||||||
|
ok = emqtt:disconnect(Client1),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([{proto_ver, v5}]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
{ok, 2} = emqtt:publish(Client2, Topic, Payload, 2),
|
||||||
|
ok = emqtt:disconnect(Client2),
|
||||||
|
|
||||||
|
{ok, Client3} = emqtt:start_link([ {clientid, <<"t_connect_session_expiry_interval">>},
|
||||||
|
{proto_ver, v5},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 7200}},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client3),
|
||||||
|
[Msg | _ ] = receive_messages(1),
|
||||||
|
?assertEqual({ok, iolist_to_binary(Topic)}, maps:find(topic, Msg)),
|
||||||
|
?assertEqual({ok, iolist_to_binary(Payload)}, maps:find(payload, Msg)),
|
||||||
|
?assertEqual({ok, 2}, maps:find(qos, Msg)),
|
||||||
|
ok = emqtt:disconnect(Client3).
|
||||||
|
|
||||||
|
t_without_client_id(_) ->
|
||||||
|
process_flag(trap_exit, true), %% Emqtt client dies
|
||||||
|
{ok, Client0} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 7200}},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{error, {client_identifier_not_valid, _}} = emqtt:connect(Client0),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
t_assigned_clientid_persistent_session(_) ->
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
{ok, Client1} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 7200}},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
|
||||||
|
AssignedClientId = client_info(clientid, Client1),
|
||||||
|
ok = emqtt:disconnect(Client1),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([ {clientid, AssignedClientId},
|
||||||
|
{proto_ver, v5},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
?assertEqual(1, client_info(session_present, Client2)),
|
||||||
|
ok = emqtt:disconnect(Client2).
|
||||||
|
|
||||||
|
t_cancel_on_disconnect(_) ->
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
ClientId = <<"t_cancel_on_disconnect">>,
|
||||||
|
{ok, Client1} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 16#FFFFFFFF}},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
ok = emqtt:disconnect(Client1, 0, #{'Session-Expiry-Interval' => 0}),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([ {clientid, ClientId},
|
||||||
|
{proto_ver, v5},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
?assertEqual(0, client_info(session_present, Client2)),
|
||||||
|
ok = emqtt:disconnect(Client2).
|
||||||
|
|
||||||
|
t_process_dies(_) ->
|
||||||
|
%% Emulate an error in the connect process,
|
||||||
|
%% or that the node of the process goes down.
|
||||||
|
%% A persistent session should survive anyway.
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
ClientId = <<"t_process_dies">>,
|
||||||
|
{ok, Client1} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 16#FFFFFFFF}},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
ok = emqtt:disconnect(Client1),
|
||||||
|
|
||||||
|
[ChannelPid] = emqx_cm:lookup_channels(ClientId),
|
||||||
|
?assert(is_pid(ChannelPid)),
|
||||||
|
exit(ChannelPid, kill),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
?assertEqual(1, client_info(session_present, Client2)),
|
||||||
|
emqtt:disconnect(Client2).
|
||||||
|
|
||||||
|
t_process_dies_session_expires(_) ->
|
||||||
|
%% Emulate an error in the connect process,
|
||||||
|
%% or that the node of the process goes down.
|
||||||
|
%% A persistent session should eventually expire.
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
ClientId = <<"t_process_dies_session_expires">>,
|
||||||
|
{ok, Client1} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 1}},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
ok = emqtt:disconnect(Client1),
|
||||||
|
|
||||||
|
[ChannelPid] = emqx_cm:lookup_channels(ClientId),
|
||||||
|
?assert(is_pid(ChannelPid)),
|
||||||
|
exit(ChannelPid, kill),
|
||||||
|
|
||||||
|
timer:sleep(1000),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
?assertEqual(0, client_info(session_present, Client2)),
|
||||||
|
emqtt:disconnect(Client2).
|
||||||
|
|
||||||
|
t_clean_start_drops_subscriptions(_) ->
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
Topic = <<"t_clean_start_drops_subscriptions/bar">>,
|
||||||
|
STopic = <<"t_clean_start_drops_subscriptions/+">>,
|
||||||
|
Payload = <<"hello">>,
|
||||||
|
ClientId = <<"t_clean_start_drops_subscriptions">>,
|
||||||
|
{ok, Client1} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 30}},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
{ok, _, [0]} = emqtt:subscribe(Client1, STopic, 0),
|
||||||
|
ok = emqtt:disconnect(Client1),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
?assertEqual(0, client_info(session_present, Client2)),
|
||||||
|
{ok, _, [0]} = emqtt:subscribe(Client2, STopic, 0),
|
||||||
|
|
||||||
|
{ok, Client3} = emqtt:start_link([{proto_ver, v5}]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client3),
|
||||||
|
{ok, 2} = emqtt:publish(Client3, Topic, Payload, 2),
|
||||||
|
ok = emqtt:disconnect(Client3),
|
||||||
|
|
||||||
|
[_Msg1] = receive_messages(1),
|
||||||
|
|
||||||
|
ok = emqtt:disconnect(Client2).
|
||||||
|
|
||||||
|
t_subscription_while_process_is_gone(_) ->
|
||||||
|
ConnFun = ?config(conn_fun, Config),
|
||||||
|
Topic = <<"t_clean_start_drops_subscriptions/bar">>,
|
||||||
|
STopic = <<"t_clean_start_drops_subscriptions/+">>,
|
||||||
|
Payload1 = <<"hello1">>,
|
||||||
|
Payload2 = <<"hello2">>,
|
||||||
|
ClientId = <<"t_clean_start_drops_subscriptions">>,
|
||||||
|
{ok, Client1} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 30}},
|
||||||
|
{clean_start, true}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client1),
|
||||||
|
{ok, _, [2]} = emqtt:subscribe(Client1, STopic, 2),
|
||||||
|
ok = emqtt:disconnect(Client1),
|
||||||
|
|
||||||
|
[ChannelPid] = emqx_cm:lookup_channels(ClientId),
|
||||||
|
?assert(is_pid(ChannelPid)),
|
||||||
|
exit(ChannelPid, kill),
|
||||||
|
|
||||||
|
{ok, Client2} = emqtt:start_link([]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client2),
|
||||||
|
{ok, 2} = emqtt:publish(Client2, Topic, Payload1, 2),
|
||||||
|
{ok, 3} = emqtt:publish(Client2, Topic, Payload2, 2),
|
||||||
|
|
||||||
|
{ok, Client3} = emqtt:start_link([ {proto_ver, v5},
|
||||||
|
{clientid, ClientId},
|
||||||
|
{properties, #{'Session-Expiry-Interval' => 30}},
|
||||||
|
{clean_start, false}
|
||||||
|
]),
|
||||||
|
{ok, _} = emqtt:ConnFun(Client3),
|
||||||
|
[Msg1] = receive_messages(1),
|
||||||
|
[Msg2] = receive_messages(1),
|
||||||
|
?assertEqual({ok, iolist_to_binary(Payload1)}, maps:find(payload, Msg1)),
|
||||||
|
?assertEqual({ok, 2}, maps:find(qos, Msg1)),
|
||||||
|
?assertEqual({ok, iolist_to_binary(Payload2)}, maps:find(payload, Msg2)),
|
||||||
|
?assertEqual({ok, 2}, maps:find(qos, Msg2)),
|
||||||
|
|
||||||
|
ok = emqtt:disconnect(Client2),
|
||||||
|
ok = emqtt:disconnect(Client3).
|
||||||
|
|
Loading…
Reference in New Issue