From ec243d894611d321c00402b8ebb1d80c68d9db2a Mon Sep 17 00:00:00 2001 From: firest Date: Fri, 1 Apr 2022 17:19:57 +0800 Subject: [PATCH 1/5] test(gateway): integration CoAP && LwM2M test with http authn --- .../src/coap/emqx_coap_message.erl | 2 +- apps/emqx_gateway/test/emqx_coap_SUITE.erl | 29 +- .../test/emqx_gateway_authn_http_SUITE.erl | 261 ++++++++++++++++++ apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl | 6 + 4 files changed, 288 insertions(+), 10 deletions(-) create mode 100644 apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl diff --git a/apps/emqx_gateway/src/coap/emqx_coap_message.erl b/apps/emqx_gateway/src/coap/emqx_coap_message.erl index d7a229532..41d42b165 100644 --- a/apps/emqx_gateway/src/coap/emqx_coap_message.erl +++ b/apps/emqx_gateway/src/coap/emqx_coap_message.erl @@ -43,7 +43,7 @@ set_payload_block/3, set_payload_block/4 ]). --include("src/coap/include/emqx_coap.hrl"). +-include_lib("emqx_gateway/src/coap/include/emqx_coap.hrl"). request(Type, Method) -> request(Type, Method, <<>>, []). diff --git a/apps/emqx_gateway/test/emqx_coap_SUITE.erl b/apps/emqx_gateway/test/emqx_coap_SUITE.erl index d3f4f8014..563fa9fa7 100644 --- a/apps/emqx_gateway/test/emqx_coap_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_coap_SUITE.erl @@ -64,6 +64,12 @@ end_per_suite(_) -> {ok, _} = emqx:remove_config([<<"gateway">>, <<"coap">>]), emqx_mgmt_api_test_util:end_suite([emqx_gateway]). +default_config() -> + ?CONF_DEFAULT. + +mqtt_prefix() -> + ?MQTT_PREFIX. + %%-------------------------------------------------------------------- %% Test Cases %%-------------------------------------------------------------------- @@ -100,19 +106,19 @@ t_connection(_) -> t_publish(_) -> Action = fun(Channel, Token) -> - Topic = <<"/abc">>, - Payload = <<"123">>, + Topic = <<"/abc">>, + Payload = <<"123">>, - TopicStr = binary_to_list(Topic), - URI = ?PS_PREFIX ++ TopicStr ++ "?clientid=client1&token=" ++ Token, + TopicStr = binary_to_list(Topic), + URI = ?PS_PREFIX ++ TopicStr ++ "?clientid=client1&token=" ++ Token, - %% Sub topic first - emqx:subscribe(Topic), + %% Sub topic first + emqx:subscribe(Topic), - Req = make_req(post, Payload), - {ok, changed, _} = do_request(Channel, URI, Req), + Req = make_req(post, Payload), + {ok, changed, _} = do_request(Channel, URI, Req), - receive + receive {deliver, Topic, Msg} -> ?assertEqual(Topic, Msg#message.topic), ?assertEqual(Payload, Msg#message.payload) @@ -425,3 +431,8 @@ receive_deliver(Wait) -> after Wait -> {error, timeout} end. + +get_field(type, #coap_message{type = Type}) -> + Type; +get_field(method, #coap_message{method = Method}) -> + Method. diff --git a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl new file mode 100644 index 000000000..f21e6a353 --- /dev/null +++ b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl @@ -0,0 +1,261 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020-2022 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_gateway_authn_http_SUITE). + +-compile(nowarn_export_all). +-compile(export_all). + +-include("emqx_authn.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). +-include_lib("emqx/include/emqx_placeholder.hrl"). + +-define(PATH, [?CONF_NS_ATOM]). + +-define(HTTP_PORT, 33333). +-define(HTTP_PATH, "/auth"). + +-define(CREDENTIALS, #{username => <<"admin">>, + password => <<"public">>, + listener => 'tcp:default', + protocol => mqtt + }). + +-define(checkMatch(Guard), + (fun (Expr) -> + case (Expr) of + Guard -> ok; + X__V -> + erlang:error({assertMatch, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, (??Guard)}, + {value, X__V}]}) + end + end)). +-define(FUNCTOR(Expr), fun() -> Expr end). +-define(FUNCTOR(Arg, Expr), fun(Arg) -> Expr end). + +-define(PROTOCOLS, [coap, lwm2m] ). +-define(CONFS, [emqx_coap_SUITE, emqx_lwm2m_SUITE]). +-define(CASES, [fun case_coap/0, fun case_lwm2m/0, fun case_emqx_sn/0, fun case_stomp/0]). +-define(AUTHNS, [fun set_http_authn/1]). + +-type auth_controller() :: fun((start | stop) -> ok). + +all() -> + emqx_common_test_helpers:all(?MODULE). + +init_per_suite(Config) -> + _ = application:load(emqx_conf), + ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, init_conf()), + emqx_common_test_helpers:start_apps([emqx_authn, emqx_gateway]), + application:ensure_all_started(cowboy), + Config. + +end_per_suite(_) -> + clear_authn(), + ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, <<>>), + emqx_common_test_helpers:stop_apps([emqx_authn, emqx_gateway]), + application:stop(cowboy), + ok. + +init_per_testcase(_Case, Config) -> + {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), + Config. + +end_per_testcase(_Case, Config) -> + Config. + +%%------------------------------------------------------------------------------ +%% Tests +%%------------------------------------------------------------------------------ +t_authn(_) -> + test_gateway_with_auths(?CASES, ?AUTHNS). + +%%------------------------------------------------------------------------------ +%% Tests +%%------------------------------------------------------------------------------ + +case_coap() -> + Login = fun(URI, Checker) -> + Action = fun(Channel) -> + Req = emqx_coap_SUITE:make_req(post), + Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) + end, + emqx_coap_SUITE:do(Action) + end, + Prefix = emqx_coap_SUITE:mqtt_prefix(), + RightUrl = Prefix ++ + "/connection?clientid=client1&username=admin&password=public", + Login(RightUrl, ?checkMatch({ok, created, _Data})), + + LeftUrl = Prefix ++ + "/connection?clientid=client1&username=bad&password=bad", + Login(LeftUrl, ?checkMatch({error, bad_request, _Data})), + ok. + +-record(coap_content, {content_format, payload = <<>>}). + +case_lwm2m() -> + MsgId = 12, + Mod = emqx_lwm2m_SUITE, + Epn = "urn:oma:lwm2m:oma:3", + Port = emqx_lwm2m_SUITE:default_port(), + Login = fun(URI, Checker) -> + with_resource(?FUNCTOR(gen_udp:open(0, [binary, {active, false}])), + ?FUNCTOR(Socket, gen_udp:close(Socket)), + fun(Socket) -> + Mod:test_send_coap_request( + Socket, + post, + Mod:sprintf(URI, [Port, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), + + Checker(Mod:test_recv_coap_response(Socket)) + end) + end, + + MakeCheker = fun(Type, Method) -> + fun(Msg) -> + ?assertEqual(Type, emqx_coap_SUITE:get_field(type, Msg)), + ?assertEqual(Method, emqx_coap_SUITE:get_field(method, Msg)) + end + end, + + RightUrl = "coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1&imei=admin&password=public", + Login(RightUrl, MakeCheker(ack, {ok, created})), + + LeftUrl = "coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1&imei=bad&password=bad", + Login(LeftUrl, MakeCheker(ack, {error, bad_request})), + + NoInfoUrl = "coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", + Login(NoInfoUrl, MakeCheker(ack, {error, bad_request})), + ok. + +case_emqx_sn() -> + ok. + +case_stomp() -> + ok. + +%%------------------------------------------------------------------------------ +%% Authenticators +%%------------------------------------------------------------------------------ + +raw_http_auth_config() -> + #{ + mechanism => <<"password_based">>, + enable => <<"true">>, + + backend => <<"http">>, + method => <<"get">>, + url => <<"http://127.0.0.1:33333/auth">>, + body => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, + headers => #{<<"X-Test-Header">> => <<"Test Value">>} + }. + +set_http_authn(start) -> + {ok, _} = emqx_authn_http_test_server:start_link(?HTTP_PORT, ?HTTP_PATH), + + AuthConfig = raw_http_auth_config(), + + Set = fun(Protocol) -> + Chain = emqx_authentication:global_chain(Protocol), + emqx_authn_test_lib:delete_authenticators([authentication], Chain), + + {ok, _} = emqx:update_config( + ?PATH, + {create_authenticator, Chain, AuthConfig}), + + {ok, [#{provider := emqx_authn_http}]} = emqx_authentication:list_authenticators(Chain) + end, + lists:foreach(Set, ?PROTOCOLS), + + Handler = fun(Req0, State) -> + ct:pal("Req:~p State:~p~n", [Req0, State]), + case cowboy_req:match_qs([username, password], Req0) of + #{username := <<"admin">>, + password := <<"public">>} -> + Req = cowboy_req:reply(200, Req0); + _ -> + Req = cowboy_req:reply(400, Req0) + end, + {ok, Req, State} + end, + emqx_authn_http_test_server:set_handler(Handler); +set_http_authn(stop) -> + ok = emqx_authn_http_test_server:stop(). + +clear_authn() -> + Clear = fun(Protocol) -> + Chain = emqx_authentication:global_chain(Protocol), + emqx_authn_test_lib:delete_authenticators([authentication], Chain) + end, + lists:foreach(Clear, ?PROTOCOLS). + +%%------------------------------------------------------------------------------ +%% Helpers +%%------------------------------------------------------------------------------ +-spec test_gateway_with_auths(_, list(auth_controller())) -> ok. +test_gateway_with_auths(Gateways, Authenticators) -> + Cases = [{Auth, Gateways} || Auth <- Authenticators], + test_gateway_with_auths(Cases). + +test_gateway_with_auths([{Auth, Gateways} | T]) -> + {name, Name} = erlang:fun_info(Auth, name), + ct:pal("start auth:~p~n", [Name]), + Auth(start), + lists:foreach(fun(Gateway) -> + {name, GwName} = erlang:fun_info(Gateway, name), + ct:pal("start gateway case:~p~n", [GwName]), + Gateway() + end, Gateways), + ct:pal("stop auth:~p~n", [Name]), + Auth(stop), + test_gateway_with_auths(T); +test_gateway_with_auths([]) -> + ok. + +init_conf() -> + merge_conf([X:default_config() || X <- ?CONFS], []). + +merge_conf([Conf | T], Acc) -> + case re:run(Conf, "\s*gateway\\.(.*)", [global, {capture, all_but_first, list}, dotall]) of + {match, [[Content]]} -> + merge_conf(T, [Content | Acc]); + _ -> + merge_conf(T, Acc) + end; +merge_conf([ ], Acc) -> + erlang:list_to_binary("gateway{" ++ string:join(Acc, ",") ++ "}"). + +with_resource(Init, Close, Fun) -> + Res = case Init() of + {ok, X} -> X; + Other -> Other + end, + try + Fun(Res) + catch C:R:S -> + Close(Res), + erlang:raise(C, R, S) + end. diff --git a/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl b/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl index c32bf7b70..39a4ac7aa 100644 --- a/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl @@ -186,6 +186,12 @@ end_per_testcase(_AllTestCase, Config) -> emqtt:disconnect(?config(emqx_c, Config)), ok = application:stop(emqx_gateway). +default_config() -> + ?CONF_DEFAULT. + +default_port() -> + ?PORT. + %%-------------------------------------------------------------------- %% Cases %%-------------------------------------------------------------------- From 25ebe2535e62411a2be70347d4aefdfe4ee82499 Mon Sep 17 00:00:00 2001 From: firest Date: Fri, 1 Apr 2022 18:15:01 +0800 Subject: [PATCH 2/5] test(gateway): integration MQTT-SN test with http authn --- .../test/emqx_gateway_authn_http_SUITE.erl | 22 +++++++++++++++++-- .../test/emqx_sn_protocol_SUITE.erl | 3 +++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl index f21e6a353..7cc88a865 100644 --- a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl @@ -51,8 +51,8 @@ -define(FUNCTOR(Expr), fun() -> Expr end). -define(FUNCTOR(Arg, Expr), fun(Arg) -> Expr end). --define(PROTOCOLS, [coap, lwm2m] ). --define(CONFS, [emqx_coap_SUITE, emqx_lwm2m_SUITE]). +-define(PROTOCOLS, [coap, lwm2m, 'mqtt-sn'] ). +-define(CONFS, [emqx_coap_SUITE, emqx_lwm2m_SUITE, emqx_sn_protocol_SUITE]). -define(CASES, [fun case_coap/0, fun case_lwm2m/0, fun case_emqx_sn/0, fun case_stomp/0]). -define(AUTHNS, [fun set_http_authn/1]). @@ -151,7 +151,25 @@ case_lwm2m() -> Login(NoInfoUrl, MakeCheker(ack, {error, bad_request})), ok. +-define(SN_CONNACK, 16#05). + case_emqx_sn() -> + Mod = emqx_sn_protocol_SUITE, + Login = fun(Expect) -> + with_resource(?FUNCTOR(gen_udp:open(0, [binary])), + ?FUNCTOR(Socket, gen_udp:close(Socket)), + fun(Socket) -> + Mod:send_connect_msg(Socket, <<"client_id_test1">>), + ?assertEqual(Expect, Mod:receive_response(Socket)) + end) + end, + Login(<<>>), + + RawCfg = emqx_conf:get_raw([gateway, mqttsn], #{}), + NewCfg = RawCfg#{<<"clientinfo_override">> => #{<<"username">> => <<"admin">>, + <<"password">> => <<"public">>}}, + emqx_gateway_conf:update_gateway(mqttsn, NewCfg), + Login(<<3, ?SN_CONNACK, 0>>), ok. case_stomp() -> diff --git a/apps/emqx_gateway/test/emqx_sn_protocol_SUITE.erl b/apps/emqx_gateway/test/emqx_sn_protocol_SUITE.erl index cc1625c5e..084249764 100644 --- a/apps/emqx_gateway/test/emqx_sn_protocol_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_sn_protocol_SUITE.erl @@ -117,6 +117,9 @@ restart_mqttsn_with_subs_resume_off() -> #{<<"subs_resume">> => <<"false">>} ). +default_config() -> + ?CONF_DEFAULT. + %%-------------------------------------------------------------------- %% Test cases %%-------------------------------------------------------------------- From 0db6b8d47ea49aeaa124aef84e87d35586beb82d Mon Sep 17 00:00:00 2001 From: firest Date: Sat, 2 Apr 2022 13:54:59 +0800 Subject: [PATCH 3/5] test(gateway): integration stomp && exproto test with http authn --- apps/emqx_gateway/test/emqx_coap_SUITE.erl | 18 +- apps/emqx_gateway/test/emqx_exproto_SUITE.erl | 16 + .../test/emqx_gateway_authn_http_SUITE.erl | 296 ++++++++++++------ apps/emqx_gateway/test/emqx_stomp_SUITE.erl | 6 + 4 files changed, 229 insertions(+), 107 deletions(-) diff --git a/apps/emqx_gateway/test/emqx_coap_SUITE.erl b/apps/emqx_gateway/test/emqx_coap_SUITE.erl index 563fa9fa7..e17c20f9d 100644 --- a/apps/emqx_gateway/test/emqx_coap_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_coap_SUITE.erl @@ -106,19 +106,19 @@ t_connection(_) -> t_publish(_) -> Action = fun(Channel, Token) -> - Topic = <<"/abc">>, - Payload = <<"123">>, + Topic = <<"/abc">>, + Payload = <<"123">>, - TopicStr = binary_to_list(Topic), - URI = ?PS_PREFIX ++ TopicStr ++ "?clientid=client1&token=" ++ Token, + TopicStr = binary_to_list(Topic), + URI = ?PS_PREFIX ++ TopicStr ++ "?clientid=client1&token=" ++ Token, - %% Sub topic first - emqx:subscribe(Topic), + %% Sub topic first + emqx:subscribe(Topic), - Req = make_req(post, Payload), - {ok, changed, _} = do_request(Channel, URI, Req), + Req = make_req(post, Payload), + {ok, changed, _} = do_request(Channel, URI, Req), - receive + receive {deliver, Topic, Msg} -> ?assertEqual(Topic, Msg#message.topic), ?assertEqual(Payload, Msg#message.payload) diff --git a/apps/emqx_gateway/test/emqx_exproto_SUITE.erl b/apps/emqx_gateway/test/emqx_exproto_SUITE.erl index 5ca1ae52f..50d69cb0a 100644 --- a/apps/emqx_gateway/test/emqx_exproto_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_exproto_SUITE.erl @@ -40,6 +40,19 @@ -define(TCPOPTS, [binary, {active, false}]). -define(DTLSOPTS, [binary, {active, false}, {protocol, dtls}]). +%%-------------------------------------------------------------------- +-define(CONF_DEFAULT, + <<"\n" + "gateway.exproto {\n" + " server.bind = 9100,\n" + " handler.address = \"http://127.0.0.1:9001\"\n" + " listeners.tcp.default {\n" + " bind = 7993,\n" + " acceptors = 8\n" + " }\n" + "}\n">> +). + %%-------------------------------------------------------------------- %% Setups %%-------------------------------------------------------------------- @@ -84,6 +97,9 @@ listener_confs(Type) -> Default = #{bind => 7993, acceptors => 8}, #{Type => #{'default' => maps:merge(Default, socketopts(Type))}}. +default_config() -> + ?CONF_DEFAULT. + %%-------------------------------------------------------------------- %% Tests cases %%-------------------------------------------------------------------- diff --git a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl index 7cc88a865..f93995808 100644 --- a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl @@ -29,31 +29,45 @@ -define(HTTP_PORT, 33333). -define(HTTP_PATH, "/auth"). --define(CREDENTIALS, #{username => <<"admin">>, - password => <<"public">>, - listener => 'tcp:default', - protocol => mqtt - }). - -define(checkMatch(Guard), - (fun (Expr) -> - case (Expr) of - Guard -> ok; - X__V -> - erlang:error({assertMatch, - [{module, ?MODULE}, - {line, ?LINE}, - {expression, (??Expr)}, - {pattern, (??Guard)}, - {value, X__V}]}) - end - end)). + (fun(Expr) -> + case (Expr) of + Guard -> + ok; + X__V -> + erlang:error( + {assertMatch, [ + {module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {pattern, (??Guard)}, + {value, X__V} + ]} + ) + end + end) +). -define(FUNCTOR(Expr), fun() -> Expr end). -define(FUNCTOR(Arg, Expr), fun(Arg) -> Expr end). --define(PROTOCOLS, [coap, lwm2m, 'mqtt-sn'] ). --define(CONFS, [emqx_coap_SUITE, emqx_lwm2m_SUITE, emqx_sn_protocol_SUITE]). --define(CASES, [fun case_coap/0, fun case_lwm2m/0, fun case_emqx_sn/0, fun case_stomp/0]). +-define(PROTOCOLS, [coap, lwm2m, 'mqtt-sn', stomp, exproto]). + +-define(CONFS, [ + emqx_coap_SUITE, + emqx_lwm2m_SUITE, + emqx_sn_protocol_SUITE, + emqx_stomp_SUITE, + emqx_exproto_SUITE +]). + +-define(CASES, [ + fun case_coap/0, + fun case_lwm2m/0, + fun case_emqx_sn/0, + fun case_stomp/0, + fun case_exproto/0 +]). + -define(AUTHNS, [fun set_http_authn/1]). -type auth_controller() :: fun((start | stop) -> ok). @@ -94,19 +108,21 @@ t_authn(_) -> case_coap() -> Login = fun(URI, Checker) -> - Action = fun(Channel) -> - Req = emqx_coap_SUITE:make_req(post), - Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) - end, - emqx_coap_SUITE:do(Action) - end, + Action = fun(Channel) -> + Req = emqx_coap_SUITE:make_req(post), + Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) + end, + emqx_coap_SUITE:do(Action) + end, Prefix = emqx_coap_SUITE:mqtt_prefix(), - RightUrl = Prefix ++ - "/connection?clientid=client1&username=admin&password=public", + RightUrl = + Prefix ++ + "/connection?clientid=client1&username=admin&password=public", Login(RightUrl, ?checkMatch({ok, created, _Data})), - LeftUrl = Prefix ++ - "/connection?clientid=client1&username=bad&password=bad", + LeftUrl = + Prefix ++ + "/connection?clientid=client1&username=bad&password=bad", Login(LeftUrl, ?checkMatch({error, bad_request, _Data})), ok. @@ -118,28 +134,33 @@ case_lwm2m() -> Epn = "urn:oma:lwm2m:oma:3", Port = emqx_lwm2m_SUITE:default_port(), Login = fun(URI, Checker) -> - with_resource(?FUNCTOR(gen_udp:open(0, [binary, {active, false}])), - ?FUNCTOR(Socket, gen_udp:close(Socket)), - fun(Socket) -> - Mod:test_send_coap_request( - Socket, - post, - Mod:sprintf(URI, [Port, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<", , , , ">>}, - [], - MsgId), + with_resource( + ?FUNCTOR(gen_udp:open(0, [binary, {active, false}])), + ?FUNCTOR(Socket, gen_udp:close(Socket)), + fun(Socket) -> + Mod:test_send_coap_request( + Socket, + post, + Mod:sprintf(URI, [Port, Epn]), + #coap_content{ + content_format = <<"text/plain">>, + payload = <<", , , , ">> + }, + [], + MsgId + ), - Checker(Mod:test_recv_coap_response(Socket)) - end) - end, + Checker(Mod:test_recv_coap_response(Socket)) + end + ) + end, MakeCheker = fun(Type, Method) -> - fun(Msg) -> - ?assertEqual(Type, emqx_coap_SUITE:get_field(type, Msg)), - ?assertEqual(Method, emqx_coap_SUITE:get_field(method, Msg)) - end - end, + fun(Msg) -> + ?assertEqual(Type, emqx_coap_SUITE:get_field(type, Msg)), + ?assertEqual(Method, emqx_coap_SUITE:get_field(method, Msg)) + end + end, RightUrl = "coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1&imei=admin&password=public", Login(RightUrl, MakeCheker(ack, {ok, created})), @@ -156,23 +177,94 @@ case_lwm2m() -> case_emqx_sn() -> Mod = emqx_sn_protocol_SUITE, Login = fun(Expect) -> - with_resource(?FUNCTOR(gen_udp:open(0, [binary])), - ?FUNCTOR(Socket, gen_udp:close(Socket)), - fun(Socket) -> - Mod:send_connect_msg(Socket, <<"client_id_test1">>), - ?assertEqual(Expect, Mod:receive_response(Socket)) - end) - end, + with_resource( + ?FUNCTOR(gen_udp:open(0, [binary])), + ?FUNCTOR(Socket, gen_udp:close(Socket)), + fun(Socket) -> + Mod:send_connect_msg(Socket, <<"client_id_test1">>), + ?assertEqual(Expect, Mod:receive_response(Socket)) + end + ) + end, Login(<<>>), RawCfg = emqx_conf:get_raw([gateway, mqttsn], #{}), - NewCfg = RawCfg#{<<"clientinfo_override">> => #{<<"username">> => <<"admin">>, - <<"password">> => <<"public">>}}, + NewCfg = RawCfg#{ + <<"clientinfo_override">> => #{ + <<"username">> => <<"admin">>, + <<"password">> => <<"public">> + } + }, emqx_gateway_conf:update_gateway(mqttsn, NewCfg), Login(<<3, ?SN_CONNACK, 0>>), ok. case_stomp() -> + Mod = emqx_stomp_SUITE, + Login = fun(Username, Password, Checker) -> + Fun = fun(Sock) -> + gen_tcp:send( + Sock, + Mod:serialize( + <<"CONNECT">>, + [ + {<<"accept-version">>, Mod:stomp_ver()}, + {<<"host">>, <<"127.0.0.1:61613">>}, + {<<"login">>, Username}, + {<<"passcode">>, Password}, + {<<"heart-beat">>, <<"1000,2000">>} + ] + ) + ), + {ok, Data} = gen_tcp:recv(Sock, 0), + {ok, Frame, _, _} = Mod:parse(Data), + Checker(Frame) + end, + Mod:with_connection(Fun) + end, + Login( + <<"admin">>, + <<"public">>, + ?FUNCTOR( + Frame, + ?assertEqual(<<"CONNECTED">>, Mod:get_field(command, Frame)) + ) + ), + Login(<<"bad">>, <<"bad">>, fun(Frame) -> + ?assertEqual(<<"ERROR">>, Mod:get_field(command, Frame)), + ?assertEqual(<<"Login Failed: not_authorized">>, Mod:get_field(body, Frame)) + end), + + ok. + +case_exproto() -> + Mod = emqx_exproto_SUITE, + SvrMod = emqx_exproto_echo_svr, + Svrs = SvrMod:start(), + Login = fun(Username, Password, Expect) -> + with_resource( + ?FUNCTOR(Mod:open(tcp)), + ?FUNCTOR(Sock, Mod:close(Sock)), + fun(Sock) -> + Client = #{ + proto_name => <<"demo">>, + proto_ver => <<"v0.1">>, + clientid => <<"test_client_1">>, + username => Username + }, + + ConnBin = SvrMod:frame_connect(Client, Password), + + Mod:send(Sock, ConnBin), + {ok, Recv} = Mod:recv(Sock, 5000), + C = ?FUNCTOR(Bin, emqx_json:decode(Bin, [return_maps])), + ?assertEqual(C(Expect), C(Recv)) + end + ) + end, + Login(<<"admin">>, <<"public">>, SvrMod:frame_connack(0)), + Login(<<"bad">>, <<"bad">>, SvrMod:frame_connack(1)), + SvrMod:stop(Svrs), ok. %%------------------------------------------------------------------------------ @@ -181,15 +273,15 @@ case_stomp() -> raw_http_auth_config() -> #{ - mechanism => <<"password_based">>, - enable => <<"true">>, + mechanism => <<"password_based">>, + enable => <<"true">>, - backend => <<"http">>, - method => <<"get">>, - url => <<"http://127.0.0.1:33333/auth">>, - body => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, - headers => #{<<"X-Test-Header">> => <<"Test Value">>} - }. + backend => <<"http">>, + method => <<"get">>, + url => <<"http://127.0.0.1:33333/auth">>, + body => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, + headers => #{<<"X-Test-Header">> => <<"Test Value">>} + }. set_http_authn(start) -> {ok, _} = emqx_authn_http_test_server:start_link(?HTTP_PORT, ?HTTP_PATH), @@ -197,37 +289,40 @@ set_http_authn(start) -> AuthConfig = raw_http_auth_config(), Set = fun(Protocol) -> - Chain = emqx_authentication:global_chain(Protocol), - emqx_authn_test_lib:delete_authenticators([authentication], Chain), + Chain = emqx_authentication:global_chain(Protocol), + emqx_authn_test_lib:delete_authenticators([authentication], Chain), - {ok, _} = emqx:update_config( - ?PATH, - {create_authenticator, Chain, AuthConfig}), + {ok, _} = emqx:update_config( + ?PATH, + {create_authenticator, Chain, AuthConfig} + ), - {ok, [#{provider := emqx_authn_http}]} = emqx_authentication:list_authenticators(Chain) - end, + {ok, [#{provider := emqx_authn_http}]} = emqx_authentication:list_authenticators(Chain) + end, lists:foreach(Set, ?PROTOCOLS), Handler = fun(Req0, State) -> - ct:pal("Req:~p State:~p~n", [Req0, State]), - case cowboy_req:match_qs([username, password], Req0) of - #{username := <<"admin">>, - password := <<"public">>} -> - Req = cowboy_req:reply(200, Req0); - _ -> - Req = cowboy_req:reply(400, Req0) - end, - {ok, Req, State} - end, + ct:pal("Req:~p State:~p~n", [Req0, State]), + case cowboy_req:match_qs([username, password], Req0) of + #{ + username := <<"admin">>, + password := <<"public">> + } -> + Req = cowboy_req:reply(200, Req0); + _ -> + Req = cowboy_req:reply(400, Req0) + end, + {ok, Req, State} + end, emqx_authn_http_test_server:set_handler(Handler); set_http_authn(stop) -> ok = emqx_authn_http_test_server:stop(). clear_authn() -> Clear = fun(Protocol) -> - Chain = emqx_authentication:global_chain(Protocol), - emqx_authn_test_lib:delete_authenticators([authentication], Chain) - end, + Chain = emqx_authentication:global_chain(Protocol), + emqx_authn_test_lib:delete_authenticators([authentication], Chain) + end, lists:foreach(Clear, ?PROTOCOLS). %%------------------------------------------------------------------------------ @@ -242,11 +337,14 @@ test_gateway_with_auths([{Auth, Gateways} | T]) -> {name, Name} = erlang:fun_info(Auth, name), ct:pal("start auth:~p~n", [Name]), Auth(start), - lists:foreach(fun(Gateway) -> - {name, GwName} = erlang:fun_info(Gateway, name), - ct:pal("start gateway case:~p~n", [GwName]), - Gateway() - end, Gateways), + lists:foreach( + fun(Gateway) -> + {name, GwName} = erlang:fun_info(Gateway, name), + ct:pal("start gateway case:~p~n", [GwName]), + Gateway() + end, + Gateways + ), ct:pal("stop auth:~p~n", [Name]), Auth(stop), test_gateway_with_auths(T); @@ -263,17 +361,19 @@ merge_conf([Conf | T], Acc) -> _ -> merge_conf(T, Acc) end; -merge_conf([ ], Acc) -> +merge_conf([], Acc) -> erlang:list_to_binary("gateway{" ++ string:join(Acc, ",") ++ "}"). with_resource(Init, Close, Fun) -> - Res = case Init() of - {ok, X} -> X; - Other -> Other - end, + Res = + case Init() of + {ok, X} -> X; + Other -> Other + end, try Fun(Res) - catch C:R:S -> + catch + C:R:S -> Close(Res), erlang:raise(C, R, S) end. diff --git a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl index ca61a63a4..06e7ce318 100644 --- a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl @@ -61,6 +61,12 @@ end_per_suite(_Cfg) -> emqx_mgmt_api_test_util:end_suite([emqx_gateway]), ok. +default_config() -> + ?CONF_DEFAULT. + +stomp_ver() -> + ?STOMP_VER. + %%-------------------------------------------------------------------- %% Test Cases %%-------------------------------------------------------------------- From 786be82d07ceeb393cf036c63d6004e8a947c1a2 Mon Sep 17 00:00:00 2001 From: firest Date: Sat, 2 Apr 2022 14:22:29 +0800 Subject: [PATCH 4/5] test(gateway): optimize test codes organization --- .../src/simple_authn/emqx_authn_http.erl | 14 +- .../src/coap/emqx_coap_message.erl | 2 +- apps/emqx_gateway/test/emqx_exproto_SUITE.erl | 8 +- .../test/emqx_gateway_auth_ct.erl | 211 ++++++++++++++++ ...SUITE.erl => emqx_gateway_authn_SUITE.erl} | 228 ++++-------------- apps/emqx_gateway/test/emqx_stomp_SUITE.erl | 5 + 6 files changed, 285 insertions(+), 183 deletions(-) create mode 100644 apps/emqx_gateway/test/emqx_gateway_auth_ct.erl rename apps/emqx_gateway/test/{emqx_gateway_authn_http_SUITE.erl => emqx_gateway_authn_SUITE.erl} (54%) diff --git a/apps/emqx_authn/src/simple_authn/emqx_authn_http.erl b/apps/emqx_authn/src/simple_authn/emqx_authn_http.erl index 31fff4940..8c333f6a6 100644 --- a/apps/emqx_authn/src/simple_authn/emqx_authn_http.erl +++ b/apps/emqx_authn/src/simple_authn/emqx_authn_http.erl @@ -137,11 +137,12 @@ create( #{ method := Method, url := RawURL, - headers := Headers, + headers := HeadersT, body := Body, request_timeout := RequestTimeout } = Config ) -> + Headers = ensure_header_name_type(HeadersT), {BsaeUrlWithPath, Query} = parse_fullpath(RawURL), URIMap = parse_url(BsaeUrlWithPath), ResourceId = emqx_authn_utils:make_resource_id(?MODULE), @@ -383,3 +384,14 @@ to_bin(L) when is_list(L) -> get_conf_val(Name, Conf) -> hocon_maps:get(?CONF_NS ++ "." ++ Name, Conf). + +ensure_header_name_type(Headers) -> + Fun = fun + (Key, _Val, Acc) when is_binary(Key) -> + Acc; + (Key, Val, Acc) when is_atom(Key) -> + Acc2 = maps:remove(Key, Acc), + BinKey = erlang:atom_to_binary(Key), + Acc2#{BinKey => Val} + end, + maps:fold(Fun, Headers, Headers). diff --git a/apps/emqx_gateway/src/coap/emqx_coap_message.erl b/apps/emqx_gateway/src/coap/emqx_coap_message.erl index 41d42b165..d7a229532 100644 --- a/apps/emqx_gateway/src/coap/emqx_coap_message.erl +++ b/apps/emqx_gateway/src/coap/emqx_coap_message.erl @@ -43,7 +43,7 @@ set_payload_block/3, set_payload_block/4 ]). --include_lib("emqx_gateway/src/coap/include/emqx_coap.hrl"). +-include("src/coap/include/emqx_coap.hrl"). request(Type, Method) -> request(Type, Method, <<>>, []). diff --git a/apps/emqx_gateway/test/emqx_exproto_SUITE.erl b/apps/emqx_gateway/test/emqx_exproto_SUITE.erl index 50d69cb0a..07d9e8934 100644 --- a/apps/emqx_gateway/test/emqx_exproto_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_exproto_SUITE.erl @@ -41,8 +41,8 @@ -define(DTLSOPTS, [binary, {active, false}, {protocol, dtls}]). %%-------------------------------------------------------------------- --define(CONF_DEFAULT, - <<"\n" +-define(CONF_DEFAULT, << + "\n" "gateway.exproto {\n" " server.bind = 9100,\n" " handler.address = \"http://127.0.0.1:9001\"\n" @@ -50,8 +50,8 @@ " bind = 7993,\n" " acceptors = 8\n" " }\n" - "}\n">> -). + "}\n" +>>). %%-------------------------------------------------------------------- %% Setups diff --git a/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl b/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl new file mode 100644 index 000000000..7702a601f --- /dev/null +++ b/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl @@ -0,0 +1,211 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020-2022 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_gateway_auth_ct). + +-compile(nowarn_export_all). +-compile(export_all). + +-behaviour(gen_server). + +%% gen_server callbacks +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3, + format_status/2 +]). + +-import( + emqx_gateway_test_utils, + [ + request/2, + request/3 + ] +). + +-include("emqx_authn.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). +-include_lib("emqx/include/emqx_placeholder.hrl"). + +-define(CALL(Msg), gen_server:call(?MODULE, {?FUNCTION_NAME, Msg})). + +-define(HTTP_PORT, 37333). +-define(HTTP_PATH, "/auth"). +-define(GATEWAYS, [coap, lwm2m, mqttsn, stomp, exproto]). + +-define(CONFS, [ + emqx_coap_SUITE, + emqx_lwm2m_SUITE, + emqx_sn_protocol_SUITE, + emqx_stomp_SUITE, + emqx_exproto_SUITE +]). + +-record(state, {}). + +%%------------------------------------------------------------------------------ +%% API +%%------------------------------------------------------------------------------ + +group_names(Auths) -> + [{group, Auth} || Auth <- Auths]. + +init_groups(Suite, Auths) -> + All = emqx_common_test_helpers:all(Suite), + [{Auth, [], All} || Auth <- Auths]. + +start_auth(Name) -> + ?CALL(Name). + +stop_auth(Name) -> + ?CALL(Name). + +start() -> + gen_server:start({local, ?MODULE}, ?MODULE, [], []). + +stop() -> + gen_server:stop(?MODULE). + +%%------------------------------------------------------------------------------ +%% gen_server callbacks +%%------------------------------------------------------------------------------ + +init([]) -> + process_flag(trap_exit, true), + {ok, #state{}}. + +handle_call({start_auth, Name}, _From, State) -> + on_start_auth(Name), + {reply, ok, State}; +handle_call({stop_auth, Name}, _From, State) -> + on_stop_auth(Name), + {reply, ok, State}; +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +handle_cast(_Request, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +format_status(_Opt, Status) -> + Status. + +%%------------------------------------------------------------------------------ +%% Authenticators +%%------------------------------------------------------------------------------ + +on_start_auth(authn_http) -> + %% start test server + {ok, _} = emqx_authn_http_test_server:start_link(?HTTP_PORT, ?HTTP_PATH), + timer:sleep(1000), + + %% set authn for gateway + Setup = fun(Gateway) -> + Path = io_lib:format("/gateway/~ts/authentication", [Gateway]), + {204, _} = request(delete, Path), + {201, _} = request(post, Path, http_auth_config()) + end, + lists:foreach(Setup, ?GATEWAYS), + + %% set handler for test server + Handler = fun(Req0, State) -> + ct:pal("Authn Req:~p~nState:~p~n", [Req0, State]), + case cowboy_req:match_qs([username, password], Req0) of + #{ + username := <<"admin">>, + password := <<"public">> + } -> + Req = cowboy_req:reply(200, Req0); + _ -> + Req = cowboy_req:reply(400, Req0) + end, + {ok, Req, State} + end, + emqx_authn_http_test_server:set_handler(Handler), + + timer:sleep(500). + +on_stop_auth(authn_http) -> + Delete = fun(Gateway) -> + Path = io_lib:format("/gateway/~ts/authentication", [Gateway]), + {204, _} = request(delete, Path) + end, + lists:foreach(Delete, ?GATEWAYS), + ok = emqx_authn_http_test_server:stop(). + +%%------------------------------------------------------------------------------ +%% Configs +%%------------------------------------------------------------------------------ + +http_auth_config() -> + #{ + <<"mechanism">> => <<"password_based">>, + <<"enable">> => <<"true">>, + <<"backend">> => <<"http">>, + <<"method">> => <<"get">>, + <<"url">> => <<"http://127.0.0.1:37333/auth">>, + <<"body">> => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, + <<"headers">> => #{<<"X-Test-Header">> => <<"Test Value">>} + }. + +%%------------------------------------------------------------------------------ +%% Helpers +%%------------------------------------------------------------------------------ + +init_gateway_conf() -> + ok = emqx_common_test_helpers:load_config( + emqx_gateway_schema, + merge_conf([X:default_config() || X <- ?CONFS], []) + ). + +merge_conf([Conf | T], Acc) -> + case re:run(Conf, "\s*gateway\\.(.*)", [global, {capture, all_but_first, list}, dotall]) of + {match, [[Content]]} -> + merge_conf(T, [Content | Acc]); + _ -> + merge_conf(T, Acc) + end; +merge_conf([], Acc) -> + erlang:list_to_binary("gateway{" ++ string:join(Acc, ",") ++ "}"). + +with_resource(Init, Close, Fun) -> + Res = + case Init() of + {ok, X} -> X; + Other -> Other + end, + try + Fun(Res) + catch + C:R:S -> + erlang:raise(C, R, S) + after + Close(Res) + end. diff --git a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl similarity index 54% rename from apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl rename to apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl index f93995808..6b71f06b5 100644 --- a/apps/emqx_gateway/test/emqx_gateway_authn_http_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl @@ -14,20 +14,15 @@ %% limitations under the License. %%-------------------------------------------------------------------- --module(emqx_gateway_authn_http_SUITE). +-module(emqx_gateway_authn_SUITE). -compile(nowarn_export_all). -compile(export_all). --include("emqx_authn.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --include_lib("emqx/include/emqx_placeholder.hrl"). --define(PATH, [?CONF_NS_ATOM]). - --define(HTTP_PORT, 33333). --define(HTTP_PATH, "/auth"). +-import(emqx_gateway_auth_ct, [init_gateway_conf/0, with_resource/3]). -define(checkMatch(Guard), (fun(Expr) -> @@ -50,44 +45,40 @@ -define(FUNCTOR(Expr), fun() -> Expr end). -define(FUNCTOR(Arg, Expr), fun(Arg) -> Expr end). --define(PROTOCOLS, [coap, lwm2m, 'mqtt-sn', stomp, exproto]). - --define(CONFS, [ - emqx_coap_SUITE, - emqx_lwm2m_SUITE, - emqx_sn_protocol_SUITE, - emqx_stomp_SUITE, - emqx_exproto_SUITE -]). - --define(CASES, [ - fun case_coap/0, - fun case_lwm2m/0, - fun case_emqx_sn/0, - fun case_stomp/0, - fun case_exproto/0 -]). - --define(AUTHNS, [fun set_http_authn/1]). - --type auth_controller() :: fun((start | stop) -> ok). +-define(AUTHNS, [authn_http]). all() -> - emqx_common_test_helpers:all(?MODULE). + emqx_gateway_auth_ct:group_names(?AUTHNS). + +groups() -> + emqx_gateway_auth_ct:init_groups(?MODULE, ?AUTHNS). + +init_per_group(AuthName, Conf) -> + ct:pal("on group start:~p~n", [AuthName]), + {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), + emqx_gateway_auth_ct:start_auth(AuthName), + timer:sleep(500), + Conf. + +end_per_group(AuthName, Conf) -> + ct:pal("on group stop:~p~n", [AuthName]), + emqx_gateway_auth_ct:stop_auth(AuthName), + Conf. init_per_suite(Config) -> - _ = application:load(emqx_conf), - ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, init_conf()), - emqx_common_test_helpers:start_apps([emqx_authn, emqx_gateway]), + emqx_config:erase(gateway), + init_gateway_conf(), + emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_authn, emqx_gateway]), application:ensure_all_started(cowboy), + emqx_gateway_auth_ct:start(), + timer:sleep(500), Config. -end_per_suite(_) -> - clear_authn(), - ok = emqx_common_test_helpers:load_config(emqx_gateway_schema, <<>>), - emqx_common_test_helpers:stop_apps([emqx_authn, emqx_gateway]), - application:stop(cowboy), - ok. +end_per_suite(Config) -> + emqx_gateway_auth_ct:stop(), + emqx_config:erase(gateway), + emqx_mgmt_api_test_util:end_suite([cowboy, emqx_authn, emqx_gateway]), + Config. init_per_testcase(_Case, Config) -> {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000), @@ -99,20 +90,14 @@ end_per_testcase(_Case, Config) -> %%------------------------------------------------------------------------------ %% Tests %%------------------------------------------------------------------------------ -t_authn(_) -> - test_gateway_with_auths(?CASES, ?AUTHNS). -%%------------------------------------------------------------------------------ -%% Tests -%%------------------------------------------------------------------------------ - -case_coap() -> +t_case_coap(_) -> Login = fun(URI, Checker) -> - Action = fun(Channel) -> - Req = emqx_coap_SUITE:make_req(post), - Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) - end, - emqx_coap_SUITE:do(Action) + Action = fun(Channel) -> + Req = emqx_coap_SUITE:make_req(post), + Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) + end, + emqx_coap_SUITE:do(Action) end, Prefix = emqx_coap_SUITE:mqtt_prefix(), RightUrl = @@ -128,7 +113,7 @@ case_coap() -> -record(coap_content, {content_format, payload = <<>>}). -case_lwm2m() -> +t_case_lwm2m(_) -> MsgId = 12, Mod = emqx_lwm2m_SUITE, Epn = "urn:oma:lwm2m:oma:3", @@ -174,9 +159,18 @@ case_lwm2m() -> -define(SN_CONNACK, 16#05). -case_emqx_sn() -> +t_case_emqx_sn(_) -> Mod = emqx_sn_protocol_SUITE, - Login = fun(Expect) -> + Login = fun(Username, Password, Expect) -> + RawCfg = emqx_conf:get_raw([gateway, mqttsn], #{}), + NewCfg = RawCfg#{ + <<"clientinfo_override">> => #{ + <<"username">> => Username, + <<"password">> => Password + } + }, + emqx_gateway_conf:update_gateway(mqttsn, NewCfg), + with_resource( ?FUNCTOR(gen_udp:open(0, [binary])), ?FUNCTOR(Socket, gen_udp:close(Socket)), @@ -186,20 +180,11 @@ case_emqx_sn() -> end ) end, - Login(<<>>), - - RawCfg = emqx_conf:get_raw([gateway, mqttsn], #{}), - NewCfg = RawCfg#{ - <<"clientinfo_override">> => #{ - <<"username">> => <<"admin">>, - <<"password">> => <<"public">> - } - }, - emqx_gateway_conf:update_gateway(mqttsn, NewCfg), - Login(<<3, ?SN_CONNACK, 0>>), + Login(<<"badadmin">>, <<"badpassowrd">>, <<>>), + Login(<<"admin">>, <<"public">>, <<3, ?SN_CONNACK, 0>>), ok. -case_stomp() -> +t_case_stomp(_) -> Mod = emqx_stomp_SUITE, Login = fun(Username, Password, Checker) -> Fun = fun(Sock) -> @@ -237,7 +222,7 @@ case_stomp() -> ok. -case_exproto() -> +t_case_exproto(_) -> Mod = emqx_exproto_SUITE, SvrMod = emqx_exproto_echo_svr, Svrs = SvrMod:start(), @@ -266,114 +251,3 @@ case_exproto() -> Login(<<"bad">>, <<"bad">>, SvrMod:frame_connack(1)), SvrMod:stop(Svrs), ok. - -%%------------------------------------------------------------------------------ -%% Authenticators -%%------------------------------------------------------------------------------ - -raw_http_auth_config() -> - #{ - mechanism => <<"password_based">>, - enable => <<"true">>, - - backend => <<"http">>, - method => <<"get">>, - url => <<"http://127.0.0.1:33333/auth">>, - body => #{<<"username">> => ?PH_USERNAME, <<"password">> => ?PH_PASSWORD}, - headers => #{<<"X-Test-Header">> => <<"Test Value">>} - }. - -set_http_authn(start) -> - {ok, _} = emqx_authn_http_test_server:start_link(?HTTP_PORT, ?HTTP_PATH), - - AuthConfig = raw_http_auth_config(), - - Set = fun(Protocol) -> - Chain = emqx_authentication:global_chain(Protocol), - emqx_authn_test_lib:delete_authenticators([authentication], Chain), - - {ok, _} = emqx:update_config( - ?PATH, - {create_authenticator, Chain, AuthConfig} - ), - - {ok, [#{provider := emqx_authn_http}]} = emqx_authentication:list_authenticators(Chain) - end, - lists:foreach(Set, ?PROTOCOLS), - - Handler = fun(Req0, State) -> - ct:pal("Req:~p State:~p~n", [Req0, State]), - case cowboy_req:match_qs([username, password], Req0) of - #{ - username := <<"admin">>, - password := <<"public">> - } -> - Req = cowboy_req:reply(200, Req0); - _ -> - Req = cowboy_req:reply(400, Req0) - end, - {ok, Req, State} - end, - emqx_authn_http_test_server:set_handler(Handler); -set_http_authn(stop) -> - ok = emqx_authn_http_test_server:stop(). - -clear_authn() -> - Clear = fun(Protocol) -> - Chain = emqx_authentication:global_chain(Protocol), - emqx_authn_test_lib:delete_authenticators([authentication], Chain) - end, - lists:foreach(Clear, ?PROTOCOLS). - -%%------------------------------------------------------------------------------ -%% Helpers -%%------------------------------------------------------------------------------ --spec test_gateway_with_auths(_, list(auth_controller())) -> ok. -test_gateway_with_auths(Gateways, Authenticators) -> - Cases = [{Auth, Gateways} || Auth <- Authenticators], - test_gateway_with_auths(Cases). - -test_gateway_with_auths([{Auth, Gateways} | T]) -> - {name, Name} = erlang:fun_info(Auth, name), - ct:pal("start auth:~p~n", [Name]), - Auth(start), - lists:foreach( - fun(Gateway) -> - {name, GwName} = erlang:fun_info(Gateway, name), - ct:pal("start gateway case:~p~n", [GwName]), - Gateway() - end, - Gateways - ), - ct:pal("stop auth:~p~n", [Name]), - Auth(stop), - test_gateway_with_auths(T); -test_gateway_with_auths([]) -> - ok. - -init_conf() -> - merge_conf([X:default_config() || X <- ?CONFS], []). - -merge_conf([Conf | T], Acc) -> - case re:run(Conf, "\s*gateway\\.(.*)", [global, {capture, all_but_first, list}, dotall]) of - {match, [[Content]]} -> - merge_conf(T, [Content | Acc]); - _ -> - merge_conf(T, Acc) - end; -merge_conf([], Acc) -> - erlang:list_to_binary("gateway{" ++ string:join(Acc, ",") ++ "}"). - -with_resource(Init, Close, Fun) -> - Res = - case Init() of - {ok, X} -> X; - Other -> Other - end, - try - Fun(Res) - catch - C:R:S -> - Close(Res), - erlang:raise(C, R, S) - end. diff --git a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl index 06e7ce318..5dbcd8df1 100644 --- a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl @@ -849,3 +849,8 @@ parse(Data) -> }, Parser = emqx_stomp_frame:initial_parse_state(ProtoEnv), emqx_stomp_frame:parse(Data, Parser). + +get_field(command, #stomp_frame{command = Command}) -> + Command; +get_field(body, #stomp_frame{body = Body}) -> + Body. From 7f1bec5d7892b125aff2735cc7819eb8e6399869 Mon Sep 17 00:00:00 2001 From: firest Date: Fri, 8 Apr 2022 13:36:57 +0800 Subject: [PATCH 5/5] test(gateway): fix meck unload error and reformat some codes --- apps/emqx_gateway/test/emqx_gateway_auth_ct.erl | 8 ++++---- apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl | 10 +++++----- apps/emqx_gateway/test/emqx_gateway_ctx_SUITE.erl | 1 + 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl b/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl index 7702a601f..92c403b11 100644 --- a/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl +++ b/apps/emqx_gateway/test/emqx_gateway_auth_ct.erl @@ -136,8 +136,8 @@ on_start_auth(authn_http) -> %% set handler for test server Handler = fun(Req0, State) -> - ct:pal("Authn Req:~p~nState:~p~n", [Req0, State]), - case cowboy_req:match_qs([username, password], Req0) of + ct:pal("Authn Req:~p~nState:~p~n", [Req0, State]), + case cowboy_req:match_qs([username, password], Req0) of #{ username := <<"admin">>, password := <<"public">> @@ -154,8 +154,8 @@ on_start_auth(authn_http) -> on_stop_auth(authn_http) -> Delete = fun(Gateway) -> - Path = io_lib:format("/gateway/~ts/authentication", [Gateway]), - {204, _} = request(delete, Path) + Path = io_lib:format("/gateway/~ts/authentication", [Gateway]), + {204, _} = request(delete, Path) end, lists:foreach(Delete, ?GATEWAYS), ok = emqx_authn_http_test_server:stop(). diff --git a/apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl index 6b71f06b5..33c0a2eea 100644 --- a/apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_authn_SUITE.erl @@ -93,11 +93,11 @@ end_per_testcase(_Case, Config) -> t_case_coap(_) -> Login = fun(URI, Checker) -> - Action = fun(Channel) -> - Req = emqx_coap_SUITE:make_req(post), - Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) - end, - emqx_coap_SUITE:do(Action) + Action = fun(Channel) -> + Req = emqx_coap_SUITE:make_req(post), + Checker(emqx_coap_SUITE:do_request(Channel, URI, Req)) + end, + emqx_coap_SUITE:do(Action) end, Prefix = emqx_coap_SUITE:mqtt_prefix(), RightUrl = diff --git a/apps/emqx_gateway/test/emqx_gateway_ctx_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_ctx_SUITE.erl index f0ca75e24..32e155068 100644 --- a/apps/emqx_gateway/test/emqx_gateway_ctx_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_ctx_SUITE.erl @@ -42,6 +42,7 @@ init_per_suite(Conf) -> Conf. end_per_suite(_Conf) -> + meck:unload(emqx_access_control), ok. %%--------------------------------------------------------------------