From cf17a55079c96d5270a76ac8668492e7833ae5ca Mon Sep 17 00:00:00 2001 From: JianBo He Date: Fri, 22 Oct 2021 10:25:00 +0800 Subject: [PATCH 01/12] chore(gw): rename cm-registry shard name --- .../src/emqx_gateway_cm_registry.erl | 10 ++-------- .../src/mqttsn/emqx_sn_registry.erl | 17 ----------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/apps/emqx_gateway/src/emqx_gateway_cm_registry.erl b/apps/emqx_gateway/src/emqx_gateway_cm_registry.erl index e82537285..7cd45ef53 100644 --- a/apps/emqx_gateway/src/emqx_gateway_cm_registry.erl +++ b/apps/emqx_gateway/src/emqx_gateway_cm_registry.erl @@ -19,12 +19,8 @@ -behaviour(gen_server). - -export([start_link/1]). -%% XXX: needless -%-export([is_enabled/0]). - -export([ register_channel/2 , unregister_channel/2 ]). @@ -40,8 +36,7 @@ , code_change/3 ]). --include_lib("emqx/include/emqx.hrl"). - +-define(CM_SHARD, emqx_gateway_cm_shard). -define(LOCK, {?MODULE, cleanup_down}). -record(channel, {chid, pid}). @@ -113,8 +108,7 @@ handle_info({membership, {mnesia, down, Node}}, State = #{type := Type}) -> Tab = tabname(Type), global:trans({?LOCK, self()}, fun() -> - %% FIXME: The shard name should be fixed later - mria:transaction(?MODULE, fun cleanup_channels/2, [Node, Tab]) + mria:transaction(?CM_SHARD, fun cleanup_channels/2, [Node, Tab]) end), {noreply, State}; diff --git a/apps/emqx_gateway/src/mqttsn/emqx_sn_registry.erl b/apps/emqx_gateway/src/mqttsn/emqx_sn_registry.erl index 4f5734525..411a34aec 100644 --- a/apps/emqx_gateway/src/mqttsn/emqx_sn_registry.erl +++ b/apps/emqx_gateway/src/mqttsn/emqx_sn_registry.erl @@ -52,21 +52,6 @@ -record(emqx_sn_registry, {key, value}). -%% Mnesia bootstrap -%-export([mnesia/1]). - -%-boot_mnesia({mnesia, [boot]}). - -%%% @doc Create or replicate tables. -%-spec(mnesia(boot | copy) -> ok). -%mnesia(boot) -> -% %% Optimize storage -% StoreProps = [{ets, [{read_concurrency, true}]}], -% ok = mria:create_table(?MODULE, [ -% {attributes, record_info(fields, emqx_sn_registry)}, -% {ram_copies, [node()]}, -% {storage_properties, StoreProps}]). - -type registry() :: {Tab :: atom(), RegistryPid :: pid()}. @@ -145,8 +130,6 @@ init([InstaId, PredefTopics]) -> {rlog_shard, ?SN_SHARD} ]), ok = mria:wait_for_tables([Tab]), - % FIXME: - %ok = mria_rlog:wait_for_shards([?CM_SHARD], infinity), MaxPredefId = lists:foldl( fun(#{id := TopicId, topic := TopicName0}, AccId) -> TopicName = iolist_to_binary(TopicName0), From 0b36b73ee1a9d637f0b73d750cfe2c695f10e470 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Fri, 22 Oct 2021 17:53:11 +0800 Subject: [PATCH 02/12] fix(emqx_conf): fix badmatch for returned error value --- apps/emqx_conf/src/emqx_conf.erl | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/emqx_conf/src/emqx_conf.erl b/apps/emqx_conf/src/emqx_conf.erl index 7c039377a..c3dfa8c49 100644 --- a/apps/emqx_conf/src/emqx_conf.erl +++ b/apps/emqx_conf/src/emqx_conf.erl @@ -81,8 +81,7 @@ get_node_and_config(KeyPath) -> {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}. update(KeyPath, UpdateReq, Opts0) -> Args = [KeyPath, UpdateReq, Opts0], - {ok, _TnxId, Res} = emqx_cluster_rpc:multicall(emqx, update_config, Args), - Res. + multicall(emqx, update_config, Args). %% @doc Update the specified node's key path in local-override.conf. -spec update(node(), emqx_map_lib:config_key_path(), emqx_config:update_request(), @@ -98,8 +97,7 @@ update(Node, KeyPath, UpdateReq, Opts0) -> {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}. remove(KeyPath, Opts0) -> Args = [KeyPath, Opts0], - {ok, _TnxId, Res} = emqx_cluster_rpc:multicall(emqx, remove_config, Args), - Res. + multicall(emqx, remove_config, Args). %% @doc remove the specified node's key path in local-override.conf. -spec remove(node(), emqx_map_lib:config_key_path(), emqx_config:update_opts()) -> @@ -114,8 +112,7 @@ remove(Node, KeyPath, Opts) -> {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}. reset(KeyPath, Opts0) -> Args = [KeyPath, Opts0], - {ok, _TnxId, Res} = emqx_cluster_rpc:multicall(emqx, reset_config, Args), - Res. + multicall(emqx, reset_config, Args). %% @doc reset the specified node's key path in local-override.conf. -spec reset(node(), emqx_map_lib:config_key_path(), emqx_config:update_opts()) -> @@ -124,3 +121,15 @@ reset(Node, KeyPath, Opts) when Node =:= node() -> emqx:reset_config(KeyPath, Opts#{override_to => local}); reset(Node, KeyPath, Opts) -> rpc:call(Node, ?MODULE, reset, [KeyPath, Opts]). + +%%-------------------------------------------------------------------- +%% Internal funcs +%%-------------------------------------------------------------------- + +multicall(M, F, Args) -> + case emqx_cluster_rpc:multicall(M, F, Args) of + {ok, _TnxId, Res} -> + Res; + {error, Reason} -> + {error, Reason} + end. From 287859fe363ec6104699d13a7a4ddf806f714cff Mon Sep 17 00:00:00 2001 From: JianBo He Date: Fri, 22 Oct 2021 17:54:22 +0800 Subject: [PATCH 03/12] chore(gw): integrate emqx-conf --- apps/emqx_gateway/src/emqx_gateway_conf.erl | 4 ++-- .../emqx_gateway/test/emqx_gateway_api_SUITE.erl | 16 +++++++--------- .../test/emqx_gateway_conf_SUITE.erl | 7 ++----- apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl | 5 +++-- apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl | 5 +++-- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/apps/emqx_gateway/src/emqx_gateway_conf.erl b/apps/emqx_gateway/src/emqx_gateway_conf.erl index 557e46693..71b517730 100644 --- a/apps/emqx_gateway/src/emqx_gateway_conf.erl +++ b/apps/emqx_gateway/src/emqx_gateway_conf.erl @@ -224,10 +224,10 @@ remove_authn(GwName, ListenerRef) -> %% @private update(Req) -> - res(emqx:update_config([gateway], Req)). + res(emqx_conf:update([gateway], Req, #{override_to => cluster})). res({ok, _Result}) -> ok; -res({error, {pre_config_update,emqx_gateway_conf,Reason}}) -> {error, Reason}; +res({error, {error, {pre_config_update,emqx_gateway_conf,Reason}}}) -> {error, Reason}; res({error, Reason}) -> {error, Reason}. bin({LType, LName}) -> diff --git a/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl index 3f709fa5a..0998cab31 100644 --- a/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_api_SUITE.erl @@ -28,6 +28,10 @@ -include_lib("eunit/include/eunit.hrl"). +-define(CONF_DEFAULT, <<" +gateway {} +">>). + %%-------------------------------------------------------------------- %% Setup %%-------------------------------------------------------------------- @@ -35,18 +39,12 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Conf) -> - %% FIXME: Magic line. for saving gateway schema name for emqx_config - emqx_config:init_load(emqx_gateway_schema, <<"gateway {}">>), - emqx_mgmt_api_test_util:init_suite([emqx_gateway]), - %% Start emqx-authn separately, due to emqx_authn_schema - %% not implementing the roots/0 method, it cannot be started with - %% emqx-ct-helpers at the moment. - {ok, _} = application:ensure_all_started(emqx_authn), + emqx_config:init_load(emqx_gateway_schema, ?CONF_DEFAULT), + emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_authn, emqx_gateway]), Conf. end_per_suite(Conf) -> - application:stop(emqx_authn), - emqx_mgmt_api_test_util:end_suite([emqx_gateway]), + emqx_mgmt_api_test_util:end_suite([emqx_gateway, emqx_authn, emqx_conf]), Conf. %%-------------------------------------------------------------------- diff --git a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl index 5f8eed20a..58af7c91e 100644 --- a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl @@ -34,15 +34,12 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Conf) -> - %% FIXME: Magic line. for saving gateway schema name for emqx_config emqx_config:init_load(emqx_gateway_schema, <<"gateway {}">>), - emqx_common_test_helpers:start_apps([emqx_gateway]), - {ok, _} = application:ensure_all_started(emqx_authn), + emqx_common_test_helpers:start_apps([emqx_conf, emqx_authn, emqx_gateway]), Conf. end_per_suite(_Conf) -> - application:stop(emqx_authn), - emqx_common_test_helpers:stop_apps([emqx_gateway]). + emqx_common_test_helpers:stop_apps([emqx_gateway, emqx_authn, emqx_conf]). init_per_testcase(_CaseName, Conf) -> _ = emqx_gateway_conf:unload_gateway(stomp), diff --git a/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl b/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl index 8f9e6108f..49079d579 100644 --- a/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl @@ -150,12 +150,13 @@ groups() -> ]. init_per_suite(Config) -> - emqx_common_test_helpers:start_apps([]), + emqx_common_test_helpers:start_apps([emqx_conf]), Config. end_per_suite(Config) -> timer:sleep(300), - emqx_common_test_helpers:stop_apps([]), + {ok, _} = emqx_conf:remove([<<"gateway">>,<<"lwm2m">>], #{}), + emqx_common_test_helpers:stop_apps([emqx_conf]), Config. init_per_testcase(_AllTestCase, Config) -> diff --git a/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl b/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl index da3a3ed1f..8f11bca78 100644 --- a/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl @@ -70,12 +70,13 @@ all() -> init_per_suite(Config) -> ok = emqx_config:init_load(emqx_gateway_schema, ?CONF_DEFAULT), - emqx_mgmt_api_test_util:init_suite([emqx_gateway]), + emqx_mgmt_api_test_util:init_suite([emqx_conf, emqx_gateway]), Config. end_per_suite(Config) -> timer:sleep(300), - emqx_mgmt_api_test_util:end_suite([emqx_gateway]), + {ok, _} = emqx_conf:remove([<<"gateway">>,<<"lwm2m">>], #{}), + emqx_mgmt_api_test_util:end_suite([emqx_gateway, emqx_conf]), Config. init_per_testcase(_AllTestCase, Config) -> From bc3f3b4c550b3499cf86e5d24df90da586fb376e Mon Sep 17 00:00:00 2001 From: JianBo He Date: Mon, 25 Oct 2021 10:06:00 +0800 Subject: [PATCH 04/12] test(gw): more robust testing --- apps/emqx_gateway/test/emqx_stomp_SUITE.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl index 8d1a0cd75..d51eaaad6 100644 --- a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl @@ -407,6 +407,7 @@ t_rest_clienit_info(_) -> %% kickout {204, _} = request(delete, ClientPath), + ignored = gen_server:call(?CM, ignore, infinity). % sync ok = emqx_pool:flush_async_tasks(), {200, Clients2} = request(get, "/gateway/stomp/clients"), ?assertEqual(0, length(maps:get(data, Clients2))) From 1f067d6f3bc614a0b7e494cecf6e6c610761a478 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Mon, 25 Oct 2021 16:40:02 +0800 Subject: [PATCH 05/12] docs(gw): add docs for gateway schema --- apps/emqx_gateway/src/emqx_gateway_schema.erl | 394 ++++++++++++++---- .../src/mqttsn/emqx_sn_broadcast.erl | 1 + .../src/stomp/emqx_stomp_frame.erl | 2 +- 3 files changed, 311 insertions(+), 86 deletions(-) diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl index 9a28e5e0d..b793bcf37 100644 --- a/apps/emqx_gateway/src/emqx_gateway_schema.erl +++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl @@ -53,11 +53,26 @@ namespace() -> gateway. roots() -> [gateway]. fields(gateway) -> - [{stomp, sc_meta(ref(stomp) , #{nullable => {true, recursively}})}, - {mqttsn, sc_meta(ref(mqttsn) , #{nullable => {true, recursively}})}, - {coap, sc_meta(ref(coap) , #{nullable => {true, recursively}})}, - {lwm2m, sc_meta(ref(lwm2m) , #{nullable => {true, recursively}})}, - {exproto, sc_meta(ref(exproto), #{nullable => {true, recursively}})} + [{stomp, sc(ref(stomp), + #{ nullable => {true, recursively} + , desc => "The Stomp Gateway configuration." + })}, + {mqttsn, sc(ref(mqttsn), + #{ nullable => {true, recursively} + , desc => "The MQTT-SN Gateway configuration" + })}, + {coap, sc(ref(coap), + #{ nullable => {true, recursively} + , desc => "The CoAP Gateway configuration" + })}, + {lwm2m, sc(ref(lwm2m), + #{ nullable => {true, recursively} + , desc => "The LwM2M Gateway configuration" + })}, + {exproto, sc(ref(exproto), + #{ nullable => {true, recursively} + , desc => "The Extension Protocol configuration" + })} ]; fields(stomp) -> @@ -66,61 +81,198 @@ fields(stomp) -> ] ++ gateway_common_options(); fields(stomp_frame) -> - [ {max_headers, sc(integer(), 10)} - , {max_headers_length, sc(integer(), 1024)} - , {max_body_length, sc(integer(), 8192)} + [ {max_headers, + sc(integer(), + #{ default => 10 + , desc => "The maximum number of Header" + })} + , {max_headers_length, + sc(integer(), + #{ default => 1024 + , desc => "The maximum string length of the Header Value" + })} + , {max_body_length, + sc(integer(), + #{ default => 65536 + , desc => "Maximum number of bytes of Body allowed per Stomp packet" + })} ]; fields(mqttsn) -> - [ {gateway_id, sc(integer())} - , {broadcast, sc(boolean(), false)} - , {enable_qos3, sc(boolean(), true)} - , {predefined, hoconsc:array(ref(mqttsn_predefined))} + [ {gateway_id, + sc(integer(), + #{ default => 1 + , desc => +"MQTT-SN Gateway Id.
+When the broadcast option is enabled, +the gateway will broadcast ADVERTISE message with this value" + })} + , {broadcast, + sc(boolean(), + #{ default => false + , desc => "Whether to periodically broadcast ADVERTISE messages" + })} + %% TODO: rename + , {enable_qos3, + sc(boolean(), + #{ default => true + , desc => +"Allows connectionless clients to publish messages with a Qos of -1.
+This feature is defined for very simple client implementations +which do not support any other features except this one.
+There is no connection setup nor tear down, no registration nor subscription.
+The client just sends its PUBLISH messages to a GW" + })} + , {predefined, + sc(hoconsc:array(ref(mqttsn_predefined)), + #{ default => [] + , desc => +"The Pre-defined topic ids and topic names.
+A 'pre-defined' topic id is a topic id whose mapping to a topic name +is known in advance by both the client’s application and the gateway" + })} , {listeners, sc(ref(udp_listeners))} ] ++ gateway_common_options(); fields(mqttsn_predefined) -> - [ {id, sc(integer())} - , {topic, sc(binary())} + [ {id, sc(integer(), #{desc => "Topic Id.
Range: 1-65535"})} + , {topic, sc(binary(), #{desc => "Topic Name"})} ]; fields(coap) -> - [ {heartbeat, sc(duration(), <<"30s">>)} - , {connection_required, sc(boolean(), false)} - , {notify_type, sc(hoconsc:union([non, con, qos]), qos)} - , {subscribe_qos, sc(hoconsc:union([qos0, qos1, qos2, coap]), coap)} - , {publish_qos, sc(hoconsc:union([qos0, qos1, qos2, coap]), coap)} + [ {heartbeat, + sc(duration(), + #{ default => <<"30s">> + , desc => +"The gateway server required minimum hearbeat interval.
+When connection mode is enabled, this parameter is used to set the minimum +heartbeat interval for the connection to be alive." + })} + , {connection_required, + sc(boolean(), + #{ default => false + , desc => +"Enable or disable connection mode.
+Connection mode is a feature of non-standard protocols. When connection mode +is enabled, it is necessary to maintain the creation, authentication and alive +of connection resources" + })} + , {notify_type, + sc(hoconsc:union([non, con, qos]), + #{ default => qos + , desc => +"The Notification Message will be delivered to the CoAP client if a new message +received on an observed topic. +The type of delivered coap message can be set to:
+1. non: Non-confirmable;
+2. con: Confirmable;
+3. qos: Mapping from QoS type of recevied message, QoS0 -> non, QoS1,2 -> con" + })} + , {subscribe_qos, + sc(hoconsc:union([qos0, qos1, qos2, coap]), + #{ default => coap + , desc => +"The Default QoS Level indicator for subscribe request.
+This option specifies the QoS level for the CoAP Client when establishing a +subscription membership, if the subscribe request is not carried `qos` option. +The indicator can be set to: + - qos0, qos1, qos2: Fixed default QoS level + - coap: Dynamic QoS level by the message type of subscribe request + * qos0: If the subscribe request is non-confirmable + * qos1: If the subscribe request is confirmable" + })} + , {publish_qos, + sc(hoconsc:union([qos0, qos1, qos2, coap]), + #{ default => coap + , desc => +"The Default QoS Level indicator for publish request.
+This option specifies the QoS level for the CoAP Client when publishing a +message to EMQ X PUB/SUB system, if the publish request is not carried `qos` +option. The indicator can be set to: + - qos0, qos1, qos2: Fixed default QoS level + - coap: Dynamic QoS level by the message type of publish request + * qos0: If the publish request is non-confirmable + * qos1: If the publish request is confirmable" + })} , {listeners, sc(ref(udp_listeners))} ] ++ gateway_common_options(); fields(lwm2m) -> - [ {xml_dir, sc(binary(), "etc/lwm2m_xml")} - , {lifetime_min, sc(duration(), "1s")} - , {lifetime_max, sc(duration(), "86400s")} - , {qmode_time_window, sc(duration_s(), "22s")} + [ {xml_dir, + sc(binary(), + #{ default =>"etc/lwm2m_xml" + , desc => "The Directory for LwM2M Resource defination" + })} + , {lifetime_min, + sc(duration(), + #{ default => "1s" + , desc => "Minimum value of lifetime allowed to be set by the LwM2M client" + })} + , {lifetime_max, + sc(duration(), + #{ default => "86400s" + , desc => "Maximum value of lifetime allowed to be set by the LwM2M client" + })} + , {qmode_time_window, + sc(duration_s(), + #{ default => "22s" + , desc => +"The value of the time window during which the network link is considered +valid by the LwM2M Gateway in QMode mode.
+For example, after receiving an update message from a client, any messages +within this time window are sent directly to the LwM2M client, and all messages +beyond this time window are temporarily stored in memory." + })} %% TODO: Support config resource path - , {auto_observe, sc(boolean(), false)} - , {update_msg_publish_condition, sc(hoconsc:union([always, contains_object_list]))} - , {translators, sc_meta(ref(translators), #{nullable => false})} + , {auto_observe, + sc(boolean(), + #{ default => false + , desc => "Automatically observe the object list of REGISTER packet" + })} + %% FIXME: not working now + , {update_msg_publish_condition, + sc(hoconsc:union([always, contains_object_list]), + #{ default => "contains_object_list" + , desc => +"Policy for publishing UPDATE event message to EMQ X.
+ - always: send update events as long as the UPDATE request is received. + - contains_object_list: send update events only if the UPDATE request carries any Object List." + })} + , {translators, + sc(ref(lwm2m_translators), + #{ nullable => false + , desc => "Topic configuration for LwM2M's gateway publishing and subscription" + })} , {listeners, sc(ref(udp_listeners))} ] ++ gateway_common_options(); fields(exproto) -> - [ {server, sc(ref(exproto_grpc_server))} - , {handler, sc(ref(exproto_grpc_handler))} + [ {server, + sc(ref(exproto_grpc_server), + #{ desc => "Configurations for starting the ConnectionAdapter service" + })} + , {handler, + sc(ref(exproto_grpc_handler), + #{ desc => "Configurations for request to ConnectionHandler service" + })} , {listeners, sc(ref(udp_tcp_listeners))} ] ++ gateway_common_options(); fields(exproto_grpc_server) -> - [ {bind, sc(hoconsc:union([ip_port(), integer()]))} - , {ssl, sc_meta(ref(ssl_server_opts), - #{nullable => {true, recursively}})} + [ {bind, + sc(hoconsc:union([ip_port(), integer()]))} + , {ssl, + sc(ref(ssl_server_opts), + #{ nullable => {true, recursively} + })} ]; fields(exproto_grpc_handler) -> [ {address, sc(binary())} - , {ssl, sc_meta(ref(ssl_client_opts), - #{nullable => {true, recursively}})} + , {ssl, + sc(ref(ssl_client_opts), + #{ nullable => {true, recursively} + })} ]; fields(ssl_server_opts) -> @@ -140,12 +292,36 @@ fields(clientinfo_override) -> , {clientid, sc(binary())} ]; -fields(translators) -> - [ {command, sc(ref(translator))} - , {response, sc(ref(translator))} - , {notify, sc(ref(translator))} - , {register, sc(ref(translator))} - , {update, sc(ref(translator))} +fields(lwm2m_translators) -> + [ {command, + sc(ref(translator), + #{ desc => +"The topic for receiving downstream commands.
+For each new LwM2M client that succeeds in going online, the gateway creates +a the subscription relationship to receive downstream commands and send it to +the LwM2M client" + })} + , {response, + sc(ref(translator), + #{ desc => +"The topic for gateway to publish the acknowledge events from LwM2M client" + })} + , {notify, + sc(ref(translator), + #{ desc => +"The topic for gateway to publish the notify events from LwM2M client.
+After succeed observe a resource of LwM2M client, Gateway will send the notifyevents via this topic, if the client reports any resource changes" + })} + , {register, + sc(ref(translator), + #{ desc => +"The topic for gateway to publish the register events from LwM2M client.
" + })} + , {update, + sc(ref(translator), + #{ desc => +"The topic for gateway to publish the update events from LwM2M client.
" + })} ]; fields(translator) -> @@ -180,9 +356,11 @@ fields(tcp_listener) -> fields(ssl_listener) -> fields(tcp_listener) ++ - [{ssl, sc_meta(hoconsc:ref(emqx_schema, "listener_ssl_opts"), - #{desc => "SSL listener options"})}]; - + [{ssl, + sc(hoconsc:ref(emqx_schema, "listener_ssl_opts"), + #{ desc => "SSL listener options" + })} + ]; fields(udp_listener) -> [ @@ -192,11 +370,10 @@ fields(udp_listener) -> common_listener_opts(); fields(dtls_listener) -> - [ {acceptors, sc(integer(), 16)} + [ {acceptors, sc(integer(), #{default => 16})} ] ++ fields(udp_listener) ++ - [{dtls, sc_meta(ref(dtls_opts), - #{desc => "DTLS listener options"})}]; + [{dtls, sc(ref(dtls_opts), #{desc => "DTLS listener options"})}]; fields(udp_opts) -> [ {active_n, sc(integer(), 100)} @@ -215,66 +392,113 @@ fields(dtls_opts) -> }, false). authentication() -> - sc_meta(hoconsc:union( - [ hoconsc:ref(emqx_authn_mnesia, config) - , hoconsc:ref(emqx_authn_mysql, config) - , hoconsc:ref(emqx_authn_pgsql, config) - , hoconsc:ref(emqx_authn_mongodb, standalone) - , hoconsc:ref(emqx_authn_mongodb, 'replica-set') - , hoconsc:ref(emqx_authn_mongodb, 'sharded-cluster') - , hoconsc:ref(emqx_authn_redis, standalone) - , hoconsc:ref(emqx_authn_redis, cluster) - , hoconsc:ref(emqx_authn_redis, sentinel) - , hoconsc:ref(emqx_authn_http, get) - , hoconsc:ref(emqx_authn_http, post) - , hoconsc:ref(emqx_authn_jwt, 'hmac-based') - , hoconsc:ref(emqx_authn_jwt, 'public-key') - , hoconsc:ref(emqx_authn_jwt, 'jwks') - , hoconsc:ref(emqx_enhanced_authn_scram_mnesia, config) - ]), - #{nullable => {true, recursively}, - desc => + sc(hoconsc:union( + [ hoconsc:ref(emqx_authn_mnesia, config) + , hoconsc:ref(emqx_authn_mysql, config) + , hoconsc:ref(emqx_authn_pgsql, config) + , hoconsc:ref(emqx_authn_mongodb, standalone) + , hoconsc:ref(emqx_authn_mongodb, 'replica-set') + , hoconsc:ref(emqx_authn_mongodb, 'sharded-cluster') + , hoconsc:ref(emqx_authn_redis, standalone) + , hoconsc:ref(emqx_authn_redis, cluster) + , hoconsc:ref(emqx_authn_redis, sentinel) + , hoconsc:ref(emqx_authn_http, get) + , hoconsc:ref(emqx_authn_http, post) + , hoconsc:ref(emqx_authn_jwt, 'hmac-based') + , hoconsc:ref(emqx_authn_jwt, 'public-key') + , hoconsc:ref(emqx_authn_jwt, 'jwks') + , hoconsc:ref(emqx_enhanced_authn_scram_mnesia, config) + ]), + #{ nullable => {true, recursively} + , desc => """Default authentication configs for all of the gateway listeners.
For per-listener overrides see authentication -in listener configs"""}). +in listener configs""" + }). gateway_common_options() -> - [ {enable, sc(boolean(), true)} - , {enable_stats, sc(boolean(), true)} - , {idle_timeout, sc(duration(), <<"30s">>)} - , {mountpoint, sc(binary(), <<>>)} - , {clientinfo_override, sc(ref(clientinfo_override))} + [ {enable, + sc(boolean(), + #{ default => true + , desc => "Whether to enable this gateway" + })} + , {enable_stats, + sc(boolean(), + #{ default => true + , desc => "Whether to enable client process statistic" + })} + , {idle_timeout, + sc(duration(), + #{ default => <<"30s">> + , desc => +"The idle time of the client connection process.
+it has two purposes: +1. A newly created client process that does not receive any client requests + after that time will be closed directly. +2. A running client process that does not receive any client requests after + this time will go into hibernation to save resources." + })} + , {mountpoint, + sc(binary(), + #{ default => <<>> + %% TODO: variable support? + , desc => "" + })} + , {clientinfo_override, + sc(ref(clientinfo_override), + #{ desc => "" + })} , {authentication, authentication()} ]. common_listener_opts() -> - [ {enable, sc(boolean(), true)} - , {bind, sc(hoconsc:union([ip_port(), integer()]))} - , {max_connections, sc(integer(), 1024)} - , {max_conn_rate, sc(integer())} + [ {enable, + sc(boolean(), + #{ default => true + })} + , {bind, + sc(hoconsc:union([ip_port(), integer()]), + #{})} + , {max_connections, + sc(integer(), + #{ default => 1024 + })} + , {max_conn_rate, + sc(integer(), + #{ default => 1000 + })} , {authentication, authentication()} - , {mountpoint, sc(binary(), undefined)} - , {access_rules, sc(hoconsc:array(string()), [])} + , {mountpoint, + sc(binary(), + #{ default => undefined + })} + , {access_rules, + sc(hoconsc:array(string()), + #{ default => [] + })} ]. tcp_opts() -> - [{tcp, sc_meta(ref(emqx_schema, "tcp_opts"), #{})}]. + [{tcp, sc(ref(emqx_schema, "tcp_opts"), #{})}]. udp_opts() -> - [{udp, sc_meta(ref(udp_opts), #{})}]. + [{udp, sc(ref(udp_opts), #{})}]. proxy_protocol_opts() -> - [ {proxy_protocol, sc(boolean(), false)} - , {proxy_protocol_timeout, sc(duration(), "15s")} + [ {proxy_protocol, + sc(boolean(), + #{ default => false + })} + , {proxy_protocol_timeout, + sc(duration(), + #{ default => "15s" + })} ]. sc(Type) -> - sc_meta(Type, #{}). + sc(Type, #{}). -sc(Type, Default) -> - sc_meta(Type, #{default => Default}). - -sc_meta(Type, Meta) -> +sc(Type, Meta) -> hoconsc:mk(Type, Meta). map(Name, Type) -> diff --git a/apps/emqx_gateway/src/mqttsn/emqx_sn_broadcast.erl b/apps/emqx_gateway/src/mqttsn/emqx_sn_broadcast.erl index dc967681a..0b90d843c 100644 --- a/apps/emqx_gateway/src/mqttsn/emqx_sn_broadcast.erl +++ b/apps/emqx_gateway/src/mqttsn/emqx_sn_broadcast.erl @@ -51,6 +51,7 @@ stop() -> %%-------------------------------------------------------------------- init([GwId, Port]) -> + %% FIXME: Duration = application:get_env(emqx_sn, advertise_duration, ?DEFAULT_DURATION), {ok, Sock} = gen_udp:open(0, [binary, {broadcast, true}]), {ok, ensure_advertise(#state{gwid = GwId, addrs = boradcast_addrs(), diff --git a/apps/emqx_gateway/src/stomp/emqx_stomp_frame.erl b/apps/emqx_gateway/src/stomp/emqx_stomp_frame.erl index 1000eec58..d75f77abe 100644 --- a/apps/emqx_gateway/src/stomp/emqx_stomp_frame.erl +++ b/apps/emqx_gateway/src/stomp/emqx_stomp_frame.erl @@ -123,7 +123,7 @@ initial_parse_state(Opts) -> limit(Opts) -> #frame_limit{ max_header_num = g(max_header_num, Opts, ?MAX_HEADER_NUM), - max_header_length = g(max_header_length, Opts, ?MAX_BODY_LENGTH), + max_header_length = g(max_header_length, Opts, ?MAX_HEADER_LENGTH), max_body_length = g(max_body_length, Opts, ?MAX_BODY_LENGTH) }. From 5a08fa6a0358cce3a294916b79ccd686a0a4d38e Mon Sep 17 00:00:00 2001 From: JianBo He Date: Tue, 26 Oct 2021 09:40:48 +0800 Subject: [PATCH 06/12] docs(gw): add gateway comment --- apps/emqx_gateway/src/emqx_gateway_schema.erl | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl index b793bcf37..bdc3bf659 100644 --- a/apps/emqx_gateway/src/emqx_gateway_schema.erl +++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl @@ -53,26 +53,40 @@ namespace() -> gateway. roots() -> [gateway]. fields(gateway) -> - [{stomp, sc(ref(stomp), - #{ nullable => {true, recursively} - , desc => "The Stomp Gateway configuration." - })}, - {mqttsn, sc(ref(mqttsn), - #{ nullable => {true, recursively} - , desc => "The MQTT-SN Gateway configuration" - })}, - {coap, sc(ref(coap), - #{ nullable => {true, recursively} - , desc => "The CoAP Gateway configuration" - })}, - {lwm2m, sc(ref(lwm2m), - #{ nullable => {true, recursively} - , desc => "The LwM2M Gateway configuration" - })}, - {exproto, sc(ref(exproto), - #{ nullable => {true, recursively} - , desc => "The Extension Protocol configuration" - })} + [{stomp, + sc(ref(stomp), + #{ nullable => {true, recursively} + , desc => +"The Stomp Gateway configuration.
+This gateway supports v1.2/1.1/1.0" + })}, + {mqttsn, + sc(ref(mqttsn), + #{ nullable => {true, recursively} + , desc => +"The MQTT-SN Gateway configuration.
+This gateway only supports the v1.2 protocol" + })}, + {coap, + sc(ref(coap), + #{ nullable => {true, recursively} + , desc => +"The CoAP Gateway configuration.
+This gateway is implemented based on RFC-7252 and +https://core-wg.github.io/coap-pubsub/draft-ietf-core-pubsub.html" + })}, + {lwm2m, + sc(ref(lwm2m), + #{ nullable => {true, recursively} + , desc => +"The LwM2M Gateway configuration.
+This gateway only supports the v1.0.1 protocol" + })}, + {exproto, + sc(ref(exproto), + #{ nullable => {true, recursively} + , desc => "The Extension Protocol configuration" + })} ]; fields(stomp) -> From cf1d98adc60da93d5dc61c13e0112e27ba881d08 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Tue, 26 Oct 2021 16:40:19 +0800 Subject: [PATCH 07/12] chore(gw): save cert files --- apps/emqx_gateway/src/emqx_gateway_conf.erl | 82 +++++- apps/emqx_gateway/src/emqx_gateway_schema.erl | 8 +- .../test/emqx_gateway_conf_SUITE.erl | 241 +++++++++++++++++- .../test/emqx_gateway_test_utils.erl | 33 ++- 4 files changed, 343 insertions(+), 21 deletions(-) diff --git a/apps/emqx_gateway/src/emqx_gateway_conf.erl b/apps/emqx_gateway/src/emqx_gateway_conf.erl index 71b517730..b5417b0d6 100644 --- a/apps/emqx_gateway/src/emqx_gateway_conf.erl +++ b/apps/emqx_gateway/src/emqx_gateway_conf.erl @@ -17,6 +17,8 @@ %% @doc The gateway configuration management module -module(emqx_gateway_conf). +-include_lib("emqx/include/logger.hrl"). + %% Load/Unload -export([ load/0 , unload/0 @@ -107,6 +109,8 @@ update_gateway(GwName, Conf0) -> <<"listeners">>, <<"authentication">>], Conf0), update({?FUNCTION_NAME, bin(GwName), Conf}). +%% FIXME: delete cert files ?? + -spec unload_gateway(atom_or_bin()) -> ok_or_err(). unload_gateway(GwName) -> update({?FUNCTION_NAME, bin(GwName)}). @@ -247,7 +251,8 @@ bin(B) when is_binary(B) -> pre_config_update({load_gateway, GwName, Conf}, RawConf) -> case maps:get(GwName, RawConf, undefined) of undefined -> - {ok, emqx_map_lib:deep_merge(RawConf, #{GwName => Conf})}; + NConf = tune_gw_certs(fun convert_certs/2, GwName, Conf), + {ok, emqx_map_lib:deep_merge(RawConf, #{GwName => NConf})}; _ -> {error, already_exist} end; @@ -261,13 +266,18 @@ pre_config_update({update_gateway, GwName, Conf}, RawConf) -> {ok, emqx_map_lib:deep_merge(RawConf, #{GwName => NConf})} end; pre_config_update({unload_gateway, GwName}, RawConf) -> + _ = tune_gw_certs(fun clear_certs/2, + GwName, + maps:get(GwName, RawConf, #{}) + ), {ok, maps:remove(GwName, RawConf)}; pre_config_update({add_listener, GwName, {LType, LName}, Conf}, RawConf) -> case emqx_map_lib:deep_get( [GwName, <<"listeners">>, LType, LName], RawConf, undefined) of undefined -> - NListener = #{LType => #{LName => Conf}}, + NConf = convert_certs(certs_dir(GwName), Conf), + NListener = #{LType => #{LName => NConf}}, {ok, emqx_map_lib:deep_merge( RawConf, #{GwName => #{<<"listeners">> => NListener}})}; @@ -279,16 +289,23 @@ pre_config_update({update_listener, GwName, {LType, LName}, Conf}, RawConf) -> [GwName, <<"listeners">>, LType, LName], RawConf, undefined) of undefined -> {error, not_found}; - _OldConf -> - NListener = #{LType => #{LName => Conf}}, + OldConf -> + NConf = convert_certs(certs_dir(GwName), Conf, OldConf), + NListener = #{LType => #{LName => NConf}}, {ok, emqx_map_lib:deep_merge( RawConf, #{GwName => #{<<"listeners">> => NListener}})} end; pre_config_update({remove_listener, GwName, {LType, LName}}, RawConf) -> - {ok, emqx_map_lib:deep_remove( - [GwName, <<"listeners">>, LType, LName], RawConf)}; + Path = [GwName, <<"listeners">>, LType, LName], + case emqx_map_lib:deep_get(Path, RawConf, undefined) of + undefined -> + {ok, RawConf}; + OldConf -> + clear_certs(certs_dir(GwName), OldConf), + {ok, emqx_map_lib:deep_remove(Path, RawConf)} + end; pre_config_update({add_authn, GwName, Conf}, RawConf) -> case emqx_map_lib:deep_get( @@ -382,3 +399,56 @@ post_config_update(Req, NewConfig, OldConfig, _AppEnvs) when is_tuple(Req) -> end; post_config_update(_Req, _NewConfig, _OldConfig, _AppEnvs) -> ok. + +%%-------------------------------------------------------------------- +%% Internal funcs +%%-------------------------------------------------------------------- + + +tune_gw_certs(Fun, GwName, Conf) -> + SubDir = certs_dir(GwName), + case maps:get(<<"listeners">>, Conf, undefined) of + undefined -> Conf; + Liss -> + maps:put(<<"listeners">>, + maps:map(fun(_, Lis) -> + maps:map(fun(_, LisConf) -> + erlang:apply(Fun, [SubDir, LisConf]) + end, Lis) + end, Liss), + Conf) + end. + +certs_dir(GwName) when is_binary(GwName) -> + GwName. + +convert_certs(SubDir, Conf) -> + case emqx_tls_lib:ensure_ssl_files( + SubDir, + maps:get(<<"ssl">>, Conf, undefined) + ) of + {ok, SSL} -> + new_ssl_config(Conf, SSL); + {error, Reason} -> + ?SLOG(error, Reason#{msg => bad_ssl_config}), + throw({bad_ssl_config, Reason}) + end. + +convert_certs(SubDir, NConf, OConf) -> + OSSL = maps:get(<<"ssl">>, OConf, undefined), + NSSL = maps:get(<<"ssl">>, NConf, undefined), + case emqx_tls_lib:ensure_ssl_files(SubDir, NSSL) of + {ok, NSSL1} -> + ok = emqx_tls_lib:delete_ssl_files(SubDir, NSSL1, OSSL), + new_ssl_config(NConf, NSSL1); + {error, Reason} -> + ?SLOG(error, Reason#{msg => bad_ssl_config}), + throw({bad_ssl_config, Reason}) + end. + +new_ssl_config(Conf, undefined) -> Conf; +new_ssl_config(Conf, SSL) -> Conf#{<<"ssl">> => SSL}. + +clear_certs(SubDir, Conf) -> + SSL = maps:get(<<"ssl">>, Conf, undefined), + ok = emqx_tls_lib:delete_ssl_files(SubDir, undefined, SSL). diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl index bdc3bf659..71fac2743 100644 --- a/apps/emqx_gateway/src/emqx_gateway_schema.erl +++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl @@ -340,7 +340,7 @@ After succeed observe a resource of LwM2M client, Gateway will send the notifyev fields(translator) -> [ {topic, sc(binary())} - , {qos, sc(range(0, 2), 0)} + , {qos, sc(range(0, 2), #{default => 0})} ]; fields(udp_listeners) -> @@ -362,7 +362,7 @@ fields(udp_tcp_listeners) -> fields(tcp_listener) -> [ %% some special confs for tcp listener - {acceptors, sc(integer(), 16)} + {acceptors, sc(integer(), #{default => 16})} ] ++ tcp_opts() ++ proxy_protocol_opts() ++ @@ -390,11 +390,11 @@ fields(dtls_listener) -> [{dtls, sc(ref(dtls_opts), #{desc => "DTLS listener options"})}]; fields(udp_opts) -> - [ {active_n, sc(integer(), 100)} + [ {active_n, sc(integer(), #{default => 100})} , {recbuf, sc(bytesize())} , {sndbuf, sc(bytesize())} , {buffer, sc(bytesize())} - , {reuseaddr, sc(boolean(), true)} + , {reuseaddr, sc(boolean(), #{default => true})} ]; fields(dtls_opts) -> diff --git a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl index 58af7c91e..15dded923 100644 --- a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl @@ -49,6 +49,133 @@ init_per_testcase(_CaseName, Conf) -> %% Cases %%-------------------------------------------------------------------- +-define(SVR_CA, +<<"-----BEGIN CERTIFICATE----- +MIIDUTCCAjmgAwIBAgIJAPPYCjTmxdt/MA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV +BAYTAkNOMREwDwYDVQQIDAhoYW5nemhvdTEMMAoGA1UECgwDRU1RMQ8wDQYDVQQD +DAZSb290Q0EwHhcNMjAwNTA4MDgwNjUyWhcNMzAwNTA2MDgwNjUyWjA/MQswCQYD +VQQGEwJDTjERMA8GA1UECAwIaGFuZ3pob3UxDDAKBgNVBAoMA0VNUTEPMA0GA1UE +AwwGUm9vdENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzcgVLex1 +EZ9ON64EX8v+wcSjzOZpiEOsAOuSXOEN3wb8FKUxCdsGrsJYB7a5VM/Jot25Mod2 +juS3OBMg6r85k2TWjdxUoUs+HiUB/pP/ARaaW6VntpAEokpij/przWMPgJnBF3Ur +MjtbLayH9hGmpQrI5c2vmHQ2reRZnSFbY+2b8SXZ+3lZZgz9+BaQYWdQWfaUWEHZ +uDaNiViVO0OT8DRjCuiDp3yYDj3iLWbTA/gDL6Tf5XuHuEwcOQUrd+h0hyIphO8D +tsrsHZ14j4AWYLk1CPA6pq1HIUvEl2rANx2lVUNv+nt64K/Mr3RnVQd9s8bK+TXQ +KGHd2Lv/PALYuwIDAQABo1AwTjAdBgNVHQ4EFgQUGBmW+iDzxctWAWxmhgdlE8Pj +EbQwHwYDVR0jBBgwFoAUGBmW+iDzxctWAWxmhgdlE8PjEbQwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAQEAGbhRUjpIred4cFAFJ7bbYD9hKu/yzWPWkMRa +ErlCKHmuYsYk+5d16JQhJaFy6MGXfLgo3KV2itl0d+OWNH0U9ULXcglTxy6+njo5 +CFqdUBPwN1jxhzo9yteDMKF4+AHIxbvCAJa17qcwUKR5MKNvv09C6pvQDJLzid7y +E2dkgSuggik3oa0427KvctFf8uhOV94RvEDyqvT5+pgNYZ2Yfga9pD/jjpoHEUlo +88IGU8/wJCx3Ds2yc8+oBg/ynxG8f/HmCC1ET6EHHoe2jlo8FpU/SgGtghS1YL30 +IWxNsPrUP+XsZpBJy/mvOhE5QXo6Y35zDqqj8tI7AGmAWu22jg== +-----END CERTIFICATE----- +">>). + +-define(SVR_CERT, +<<"-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIBAjANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJDTjER +MA8GA1UECAwIaGFuZ3pob3UxDDAKBgNVBAoMA0VNUTEPMA0GA1UEAwwGUm9vdENB +MB4XDTIwMDUwODA4MDcwNVoXDTMwMDUwNjA4MDcwNVowPzELMAkGA1UEBhMCQ04x +ETAPBgNVBAgMCGhhbmd6aG91MQwwCgYDVQQKDANFTVExDzANBgNVBAMMBlNlcnZl +cjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALNeWT3pE+QFfiRJzKmn +AMUrWo3K2j/Tm3+Xnl6WLz67/0rcYrJbbKvS3uyRP/stXyXEKw9CepyQ1ViBVFkW +Aoy8qQEOWFDsZc/5UzhXUnb6LXr3qTkFEjNmhj+7uzv/lbBxlUG1NlYzSeOB6/RT +8zH/lhOeKhLnWYPXdXKsa1FL6ij4X8DeDO1kY7fvAGmBn/THh1uTpDizM4YmeI+7 +4dmayA5xXvARte5h4Vu5SIze7iC057N+vymToMk2Jgk+ZZFpyXrnq+yo6RaD3ANc +lrc4FbeUQZ5a5s5Sxgs9a0Y3WMG+7c5VnVXcbjBRz/aq2NtOnQQjikKKQA8GF080 +BQkCAwEAAaMaMBgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEL +BQADggEBAJefnMZpaRDHQSNUIEL3iwGXE9c6PmIsQVE2ustr+CakBp3TZ4l0enLt +iGMfEVFju69cO4oyokWv+hl5eCMkHBf14Kv51vj448jowYnF1zmzn7SEzm5Uzlsa +sqjtAprnLyof69WtLU1j5rYWBuFX86yOTwRAFNjm9fvhAcrEONBsQtqipBWkMROp +iUYMkRqbKcQMdwxov+lHBYKq9zbWRoqLROAn54SRqgQk6c15JdEfgOOjShbsOkIH +UhqcwRkQic7n1zwHVGVDgNIZVgmJ2IdIWBlPEC7oLrRrBD/X1iEEXtKab6p5o22n +KB5mN+iQaE+Oe2cpGKZJiJRdM+IqDDQ= +-----END CERTIFICATE----- +">>). + +-define(SVR_KEY, +<<"-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAs15ZPekT5AV+JEnMqacAxStajcraP9Obf5eeXpYvPrv/Stxi +sltsq9Le7JE/+y1fJcQrD0J6nJDVWIFUWRYCjLypAQ5YUOxlz/lTOFdSdvotevep +OQUSM2aGP7u7O/+VsHGVQbU2VjNJ44Hr9FPzMf+WE54qEudZg9d1cqxrUUvqKPhf +wN4M7WRjt+8AaYGf9MeHW5OkOLMzhiZ4j7vh2ZrIDnFe8BG17mHhW7lIjN7uILTn +s36/KZOgyTYmCT5lkWnJeuer7KjpFoPcA1yWtzgVt5RBnlrmzlLGCz1rRjdYwb7t +zlWdVdxuMFHP9qrY206dBCOKQopADwYXTzQFCQIDAQABAoIBAQCuvCbr7Pd3lvI/ +n7VFQG+7pHRe1VKwAxDkx2t8cYos7y/QWcm8Ptwqtw58HzPZGWYrgGMCRpzzkRSF +V9g3wP1S5Scu5C6dBu5YIGc157tqNGXB+SpdZddJQ4Nc6yGHXYERllT04ffBGc3N +WG/oYS/1cSteiSIrsDy/91FvGRCi7FPxH3wIgHssY/tw69s1Cfvaq5lr2NTFzxIG +xCvpJKEdSfVfS9I7LYiymVjst3IOR/w76/ZFY9cRa8ZtmQSWWsm0TUpRC1jdcbkm +ZoJptYWlP+gSwx/fpMYftrkJFGOJhHJHQhwxT5X/ajAISeqjjwkWSEJLwnHQd11C +Zy2+29lBAoGBANlEAIK4VxCqyPXNKfoOOi5dS64NfvyH4A1v2+KaHWc7lqaqPN49 +ezfN2n3X+KWx4cviDD914Yc2JQ1vVJjSaHci7yivocDo2OfZDmjBqzaMp/y+rX1R +/f3MmiTqMa468rjaxI9RRZu7vDgpTR+za1+OBCgMzjvAng8dJuN/5gjlAoGBANNY +uYPKtearBmkqdrSV7eTUe49Nhr0XotLaVBH37TCW0Xv9wjO2xmbm5Ga/DCtPIsBb +yPeYwX9FjoasuadUD7hRvbFu6dBa0HGLmkXRJZTcD7MEX2Lhu4BuC72yDLLFd0r+ +Ep9WP7F5iJyagYqIZtz+4uf7gBvUDdmvXz3sGr1VAoGAdXTD6eeKeiI6PlhKBztF +zOb3EQOO0SsLv3fnodu7ZaHbUgLaoTMPuB17r2jgrYM7FKQCBxTNdfGZmmfDjlLB +0xZ5wL8ibU30ZXL8zTlWPElST9sto4B+FYVVF/vcG9sWeUUb2ncPcJ/Po3UAktDG +jYQTTyuNGtSJHpad/YOZctkCgYBtWRaC7bq3of0rJGFOhdQT9SwItN/lrfj8hyHA +OjpqTV4NfPmhsAtu6j96OZaeQc+FHvgXwt06cE6Rt4RG4uNPRluTFgO7XYFDfitP +vCppnoIw6S5BBvHwPP+uIhUX2bsi/dm8vu8tb+gSvo4PkwtFhEr6I9HglBKmcmog +q6waEQKBgHyecFBeM6Ls11Cd64vborwJPAuxIW7HBAFj/BS99oeG4TjBx4Sz2dFd +rzUibJt4ndnHIvCN8JQkjNG14i9hJln+H3mRss8fbZ9vQdqG+2vOWADYSzzsNI55 +RFY7JjluKcVkp/zCDeUxTU3O6sS+v6/3VE11Cob6OYQx3lN5wrZ3 +-----END RSA PRIVATE KEY----- +">>). + +-define(SVR_CERT2, +<<"-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MQswCQYDVQQGEwJDTjER +MA8GA1UECAwIaGFuZ3pob3UxDDAKBgNVBAoMA0VNUTEPMA0GA1UEAwwGUm9vdENB +MB4XDTIwMDUwODA4MDY1N1oXDTMwMDUwNjA4MDY1N1owPzELMAkGA1UEBhMCQ04x +ETAPBgNVBAgMCGhhbmd6aG91MQwwCgYDVQQKDANFTVExDzANBgNVBAMMBkNsaWVu +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMy4hoksKcZBDbY680u6 +TS25U51nuB1FBcGMlF9B/t057wPOlxF/OcmbxY5MwepS41JDGPgulE1V7fpsXkiW +1LUimYV/tsqBfymIe0mlY7oORahKji7zKQ2UBIVFhdlvQxunlIDnw6F9popUgyHt +dMhtlgZK8oqRwHxO5dbfoukYd6J/r+etS5q26sgVkf3C6dt0Td7B25H9qW+f7oLV +PbcHYCa+i73u9670nrpXsC+Qc7Mygwa2Kq/jwU+ftyLQnOeW07DuzOwsziC/fQZa +nbxR+8U9FNftgRcC3uP/JMKYUqsiRAuaDokARZxVTV5hUElfpO6z6/NItSDvvh3i +eikCAwEAAaMaMBgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEL +BQADggEBABchYxKo0YMma7g1qDswJXsR5s56Czx/I+B41YcpMBMTrRqpUC0nHtLk +M7/tZp592u/tT8gzEnQjZLKBAhFeZaR3aaKyknLqwiPqJIgg0pgsBGITrAK3Pv4z +5/YvAJJKgTe5UdeTz6U4lvNEux/4juZ4pmqH4qSFJTOzQS7LmgSmNIdd072rwXBd +UzcSHzsJgEMb88u/LDLjj1pQ7AtZ4Tta8JZTvcgBFmjB0QUi6fgkHY6oGat/W4kR +jSRUBlMUbM/drr2PVzRc2dwbFIl3X+ZE6n5Sl3ZwRAC/s92JU6CPMRW02muVu6xl +goraNgPISnrbpR6KjxLZkVembXzjNNc= +-----END CERTIFICATE----- +">>). + +-define(SVR_KEY2, +<<"-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAzLiGiSwpxkENtjrzS7pNLblTnWe4HUUFwYyUX0H+3TnvA86X +EX85yZvFjkzB6lLjUkMY+C6UTVXt+mxeSJbUtSKZhX+2yoF/KYh7SaVjug5FqEqO +LvMpDZQEhUWF2W9DG6eUgOfDoX2milSDIe10yG2WBkryipHAfE7l1t+i6Rh3on+v +561LmrbqyBWR/cLp23RN3sHbkf2pb5/ugtU9twdgJr6Lve73rvSeulewL5BzszKD +BrYqr+PBT5+3ItCc55bTsO7M7CzOIL99BlqdvFH7xT0U1+2BFwLe4/8kwphSqyJE +C5oOiQBFnFVNXmFQSV+k7rPr80i1IO++HeJ6KQIDAQABAoIBAGWgvPjfuaU3qizq +uti/FY07USz0zkuJdkANH6LiSjlchzDmn8wJ0pApCjuIE0PV/g9aS8z4opp5q/gD +UBLM/a8mC/xf2EhTXOMrY7i9p/I3H5FZ4ZehEqIw9sWKK9YzC6dw26HabB2BGOnW +5nozPSQ6cp2RGzJ7BIkxSZwPzPnVTgy3OAuPOiJytvK+hGLhsNaT+Y9bNDvplVT2 +ZwYTV8GlHZC+4b2wNROILm0O86v96O+Qd8nn3fXjGHbMsAnONBq10bZS16L4fvkH +5G+W/1PeSXmtZFppdRRDxIW+DWcXK0D48WRliuxcV4eOOxI+a9N2ZJZZiNLQZGwg +w3A8+mECgYEA8HuJFrlRvdoBe2U/EwUtG74dcyy30L4yEBnN5QscXmEEikhaQCfX +Wm6EieMcIB/5I5TQmSw0cmBMeZjSXYoFdoI16/X6yMMuATdxpvhOZGdUGXxhAH+x +xoTUavWZnEqW3fkUU71kT5E2f2i+0zoatFESXHeslJyz85aAYpP92H0CgYEA2e5A +Yozt5eaA1Gyhd8SeptkEU4xPirNUnVQHStpMWUb1kzTNXrPmNWccQ7JpfpG6DcYl +zUF6p6mlzY+zkMiyPQjwEJlhiHM2NlL1QS7td0R8ewgsFoyn8WsBI4RejWrEG9td +EDniuIw+pBFkcWthnTLHwECHdzgquToyTMjrBB0CgYEA28tdGbrZXhcyAZEhHAZA +Gzog+pKlkpEzeonLKIuGKzCrEKRecIK5jrqyQsCjhS0T7ZRnL4g6i0s+umiV5M5w +fcc292pEA1h45L3DD6OlKplSQVTv55/OYS4oY3YEJtf5mfm8vWi9lQeY8sxOlQpn +O+VZTdBHmTC8PGeTAgZXHZUCgYA6Tyv88lYowB7SN2qQgBQu8jvdGtqhcs/99GCr +H3N0I69LPsKAR0QeH8OJPXBKhDUywESXAaEOwS5yrLNP1tMRz5Vj65YUCzeDG3kx +gpvY4IMp7ArX0bSRvJ6mYSFnVxy3k174G3TVCfksrtagHioVBGQ7xUg5ltafjrms +n8l55QKBgQDVzU8tQvBVqY8/1lnw11Vj4fkE/drZHJ5UkdC1eenOfSWhlSLfUJ8j +ds7vEWpRPPoVuPZYeR1y78cyxKe1GBx6Wa2lF5c7xjmiu0xbRnrxYeLolce9/ntp +asClqpnHT8/VJYTD7Kqj0fouTTZf0zkig/y+2XERppd8k+pSKjUCPQ== +-----END RSA PRIVATE KEY----- +">>). + -define(CONF_STOMP_BAISC_1, #{ <<"idle_timeout">> => <<"10s">>, <<"mountpoint">> => <<"t/">>, @@ -73,6 +200,31 @@ init_per_testcase(_CaseName, Conf) -> -define(CONF_STOMP_LISTENER_2, #{ <<"bind">> => <<"61614">> }). +-define(CONF_STOMP_LISTENER_SSL, + #{ <<"bind">> => <<"61614">>, + <<"ssl">> => + #{ <<"cacertfile">> => ?SVR_CA, + <<"certfile">> => ?SVR_CERT, + <<"keyfile">> => ?SVR_KEY + } + }). +-define(CONF_STOMP_LISTENER_SSL_2, + #{ <<"bind">> => <<"61614">>, + <<"ssl">> => + #{ <<"cacertfile">> => ?SVR_CA, + <<"certfile">> => ?SVR_CERT2, + <<"keyfile">> => ?SVR_KEY2 + } + }). +-define(CERTS_PATH(CertName), filename:join(["../../lib/emqx/etc/certs/", CertName])). +-define(CONF_STOMP_LISTENER_SSL_PATH, + #{ <<"bind">> => <<"61614">>, + <<"ssl">> => + #{ <<"cacertfile">> => ?CERTS_PATH("cacert.pem"), + <<"certfile">> => ?CERTS_PATH("cert.pem"), + <<"keyfile">> => ?CERTS_PATH("key.pem") + } + }). -define(CONF_STOMP_AUTHN_1, #{ <<"mechanism">> => <<"password-based">>, <<"backend">> => <<"built-in-database">>, @@ -92,7 +244,6 @@ t_load_unload_gateway(_) -> StompConf2 = compose(?CONF_STOMP_BAISC_2, ?CONF_STOMP_AUTHN_1, ?CONF_STOMP_LISTENER_1), - ok = emqx_gateway_conf:load_gateway(stomp, StompConf1), {error, already_exist} = emqx_gateway_conf:load_gateway(stomp, StompConf1), @@ -210,6 +361,87 @@ t_load_remove_listener_authn(_) -> ), ok. +t_load_gateway_with_certs_content(_) -> + StompConf = compose_ssl_listener( + ?CONF_STOMP_BAISC_1, + ?CONF_STOMP_LISTENER_SSL + ), + ok = emqx_gateway_conf:load_gateway(<<"stomp">>, StompConf), + assert_confs(StompConf, emqx:get_raw_config([gateway, stomp])), + SslConf = emqx_map_lib:deep_get( + [<<"listeners">>, <<"ssl">>, <<"default">>, <<"ssl">>], + emqx:get_raw_config([gateway, stomp]) + ), + ok = emqx_gateway_conf:unload_gateway(<<"stomp">>), + assert_ssl_confs_files_deleted(SslConf), + ?assertException(error, {config_not_found, [gateway, stomp]}, + emqx:get_raw_config([gateway, stomp])), + ok. + +%% TODO: Comment out this test case for now, because emqx_tls_lib +%% will delete the configured certificate file. + +%t_load_gateway_with_certs_path(_) -> +% StompConf = compose_ssl_listener( +% ?CONF_STOMP_BAISC_1, +% ?CONF_STOMP_LISTENER_SSL_PATH +% ), +% ok = emqx_gateway_conf:load_gateway(<<"stomp">>, StompConf), +% assert_confs(StompConf, emqx:get_raw_config([gateway, stomp])), +% SslConf = emqx_map_lib:deep_get( +% [<<"listeners">>, <<"ssl">>, <<"default">>, <<"ssl">>], +% emqx:get_raw_config([gateway, stomp]) +% ), +% ok = emqx_gateway_conf:unload_gateway(<<"stomp">>), +% assert_ssl_confs_files_deleted(SslConf), +% ?assertException(error, {config_not_found, [gateway, stomp]}, +% emqx:get_raw_config([gateway, stomp])), +% ok. + +t_add_listener_with_certs_content(_) -> + StompConf = ?CONF_STOMP_BAISC_1, + StompConf1 = compose_ssl_listener( + ?CONF_STOMP_BAISC_1, + ?CONF_STOMP_LISTENER_SSL + ), + ok = emqx_gateway_conf:load_gateway(<<"stomp">>, StompConf), + assert_confs(StompConf, emqx:get_raw_config([gateway, stomp])), + + ok = emqx_gateway_conf:add_listener( + <<"stomp">>, {<<"ssl">>, <<"default">>}, ?CONF_STOMP_LISTENER_SSL), + assert_confs( + maps:merge(StompConf, ssl_listener(?CONF_STOMP_LISTENER_SSL)), + emqx:get_raw_config([gateway, stomp])), + + ok = emqx_gateway_conf:update_listener( + <<"stomp">>, {<<"ssl">>, <<"default">>}, ?CONF_STOMP_LISTENER_SSL_2), + assert_confs( + maps:merge(StompConf, ssl_listener(?CONF_STOMP_LISTENER_SSL_2)), + emqx:get_raw_config([gateway, stomp])), + + SslConf = emqx_map_lib:deep_get( + [<<"listeners">>, <<"ssl">>, <<"default">>, <<"ssl">>], + emqx:get_raw_config([gateway, stomp]) + ), + ok = emqx_gateway_conf:remove_listener( + <<"stomp">>, {<<"ssl">>, <<"default">>}), + assert_ssl_confs_files_deleted(SslConf), + {error, not_found} = + emqx_gateway_conf:update_listener( + <<"stomp">>, {<<"ssl">>, <<"default">>}, ?CONF_STOMP_LISTENER_SSL_2), + ?assertException( + error, {config_not_found, [gateway, stomp, listeners, ssl, default]}, + emqx:get_raw_config([gateway, stomp, listeners, ssl, default]) + ), + ok. + +assert_ssl_confs_files_deleted(SslConf) when is_map(SslConf) -> + Ks = [<<"cacertfile">>, <<"certfile">>, <<"keyfile">>], + lists:foreach(fun(K) -> + Path = maps:get(K, SslConf), + {error, enoent} = file:read_file(Path) + end, Ks). + %%-------------------------------------------------------------------- %% Utils @@ -221,6 +453,9 @@ compose(Basic, Authn, Listener) -> compose_listener(Basic, Listener) -> maps:merge(Basic, listener(Listener)). +compose_ssl_listener(Basic, Listener) -> + maps:merge(Basic, ssl_listener(Listener)). + compose_authn(Basic, Authn) -> maps:merge(Basic, #{<<"authentication">> => Authn}). @@ -232,3 +467,7 @@ compose_listener_authn(Basic, Listener, Authn) -> listener(L) -> #{<<"listeners">> => [L#{<<"type">> => <<"tcp">>, <<"name">> => <<"default">>}]}. + +ssl_listener(L) -> + #{<<"listeners">> => [L#{<<"type">> => <<"ssl">>, + <<"name">> => <<"default">>}]}. diff --git a/apps/emqx_gateway/test/emqx_gateway_test_utils.erl b/apps/emqx_gateway/test/emqx_gateway_test_utils.erl index d7fd12c3d..329e97e8f 100644 --- a/apps/emqx_gateway/test/emqx_gateway_test_utils.erl +++ b/apps/emqx_gateway/test/emqx_gateway_test_utils.erl @@ -21,7 +21,7 @@ assert_confs(Expected0, Effected) -> Expected = maybe_unconvert_listeners(Expected0), - case do_assert_confs(Expected, Effected) of + case do_assert_confs(root, Expected, Effected) of false -> io:format(standard_error, "Expected config: ~p,\n" "Effected config: ~p", @@ -31,23 +31,36 @@ assert_confs(Expected0, Effected) -> ok end. -do_assert_confs(Expected, Effected) when is_map(Expected), - is_map(Effected) -> +do_assert_confs(_Key, Expected, Effected) when is_map(Expected), + is_map(Effected) -> Ks1 = maps:keys(Expected), lists:all(fun(K) -> - do_assert_confs(maps:get(K, Expected), + do_assert_confs(K, + maps:get(K, Expected), maps:get(K, Effected, undefined)) end, Ks1); -do_assert_confs([Expected|More1], [Effected|More2]) -> - do_assert_confs(Expected, Effected) andalso do_assert_confs(More1, More2); -do_assert_confs([], []) -> +do_assert_confs(Key, Expected, Effected) when Key == <<"cacertfile">>; + Key == <<"certfile">>; + Key == <<"keyfile">> -> + case Expected == Effected of + true -> true; + false -> + case file:read_file(Effected) of + {ok, Content} -> Expected == Content; + _ -> false + end + end; +do_assert_confs(Key, [Expected|More1], [Effected|More2]) -> + do_assert_confs(Key, Expected, Effected) + andalso do_assert_confs(Key, More1, More2); +do_assert_confs(_Key, [], []) -> true; -do_assert_confs(Expected, Effected) -> +do_assert_confs(Key, Expected, Effected) -> Res = Expected =:= Effected, Res == false andalso - ct:pal("Errors: conf not match, " - "expected: ~p, got: ~p~n", [Expected, Effected]), + ct:pal("Errors: ~p value not match, " + "expected: ~p, got: ~p~n", [Key, Expected, Effected]), Res. maybe_unconvert_listeners(Conf) when is_map(Conf) -> From 883c1b2e59be7c96d0528faf34fa0306f7d969f9 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Wed, 27 Oct 2021 10:10:31 +0800 Subject: [PATCH 08/12] chore(gw): remove needless lines --- apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl index 15dded923..810f56e76 100644 --- a/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_gateway_conf_SUITE.erl @@ -400,10 +400,6 @@ t_load_gateway_with_certs_content(_) -> t_add_listener_with_certs_content(_) -> StompConf = ?CONF_STOMP_BAISC_1, - StompConf1 = compose_ssl_listener( - ?CONF_STOMP_BAISC_1, - ?CONF_STOMP_LISTENER_SSL - ), ok = emqx_gateway_conf:load_gateway(<<"stomp">>, StompConf), assert_confs(StompConf, emqx:get_raw_config([gateway, stomp])), From 814e01c0cbf92e6f10edac3fa229d09b531c2e3c Mon Sep 17 00:00:00 2001 From: JianBo He Date: Wed, 27 Oct 2021 15:28:21 +0800 Subject: [PATCH 09/12] test(authz): deps on emqx_conf instead of meck emqx_schema --- apps/emqx_authz/test/emqx_authz_SUITE.erl | 26 +++++++-------- .../test/emqx_authz_api_mnesia_SUITE.erl | 25 ++++----------- .../test/emqx_authz_api_settings_SUITE.erl | 15 +++++---- .../test/emqx_authz_api_sources_SUITE.erl | 25 ++++----------- .../emqx_authz/test/emqx_authz_http_SUITE.erl | 26 +++++++-------- .../test/emqx_authz_mnesia_SUITE.erl | 32 ++++++++----------- .../test/emqx_authz_mongodb_SUITE.erl | 29 ++++++++--------- .../test/emqx_authz_mysql_SUITE.erl | 25 +++++++-------- .../test/emqx_authz_postgresql_SUITE.erl | 27 +++++++--------- .../test/emqx_authz_redis_SUITE.erl | 23 +++++++------ .../emqx_authz/test/emqx_authz_rule_SUITE.erl | 15 +++++++-- apps/emqx_gateway/src/emqx_gateway_conf.erl | 3 +- 12 files changed, 123 insertions(+), 148 deletions(-) diff --git a/apps/emqx_authz/test/emqx_authz_SUITE.erl b/apps/emqx_authz/test/emqx_authz_SUITE.erl index d7df8eaa0..5f0371c49 100644 --- a/apps/emqx_authz/test/emqx_authz_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_SUITE.erl @@ -22,8 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). - all() -> emqx_common_test_helpers:all(?MODULE). @@ -31,35 +29,33 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, update, fun(_, _, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], fun set_special_configs/1), Config. end_per_suite(_Config) -> {ok, _} = emqx_authz:update(?CMD_REPLACE, []), - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), - meck:unload(emqx_schema), ok. init_per_testcase(_, Config) -> {ok, _} = emqx_authz:update(?CMD_REPLACE, []), Config. +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> + ok. + -define(SOURCE1, #{<<"type">> => <<"http">>, <<"enable">> => true, <<"url">> => <<"https://fake.com:443/">>, diff --git a/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl index d07619146..1613df2d1 100644 --- a/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl @@ -22,26 +22,11 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<""" -authorization - {sources = [ - { type = \"built-in-database\" - enable = true - } - ]} -""">>). - -define(HOST, "http://127.0.0.1:18083/"). -define(API_VERSION, "v5"). -define(BASE_PATH, "api"). -roots() -> ["authorization"]. - -fields("authorization") -> - emqx_authz_schema:fields("authorization") ++ - emqx_schema:fields("authorization"). - all() -> emqx_common_test_helpers:all(?MODULE). @@ -49,13 +34,14 @@ groups() -> []. init_per_suite(Config) -> - ok = emqx_common_test_helpers:start_apps([emqx_authz, emqx_dashboard], - fun set_special_configs/1), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz, emqx_dashboard], + fun set_special_configs/1), Config. end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_dashboard]), + emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_authz, emqx_conf]), ok. set_special_configs(emqx_dashboard) -> @@ -70,9 +56,10 @@ set_special_configs(emqx_dashboard) -> emqx_config:put([emqx_dashboard], Config), ok; set_special_configs(emqx_authz) -> - ok = emqx_config:init_load(?MODULE, ?CONF_DEFAULT), {ok, _} = emqx:update_config([authorization, cache, enable], false), {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], + [#{<<"type">> => <<"built-in-database">>}]), ok; set_special_configs(_App) -> ok. diff --git a/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl index 6e6207bbc..f8d83eee9 100644 --- a/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl @@ -22,8 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). - -define(HOST, "http://127.0.0.1:18083/"). -define(API_VERSION, "v5"). -define(BASE_PATH, "api"). @@ -35,14 +33,14 @@ groups() -> []. init_per_suite(Config) -> - ok = emqx_common_test_helpers:start_apps([emqx_authz, emqx_dashboard], fun set_special_configs/1), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz, emqx_dashboard], + fun set_special_configs/1), Config. end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_resource, emqx_authz, emqx_dashboard]), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_dashboard]), ok. set_special_configs(emqx_dashboard) -> @@ -56,6 +54,11 @@ set_special_configs(emqx_dashboard) -> }, emqx_config:put([emqx_dashboard], Config), ok; +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; set_special_configs(_App) -> ok. diff --git a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl index fb1e381e3..d5a245819 100644 --- a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl @@ -22,8 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). - -define(HOST, "http://127.0.0.1:18083/"). -define(API_VERSION, "v5"). -define(BASE_PATH, "api"). @@ -94,13 +92,6 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, create_dry_run, fun(emqx_connector_mysql, _) -> {ok, meck_data}; @@ -110,19 +101,15 @@ init_per_suite(Config) -> meck:expect(emqx_resource, health_check, fun(_) -> ok end), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - - ok = emqx_common_test_helpers:start_apps([emqx_authz, emqx_dashboard], fun set_special_configs/1), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), - + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz, emqx_dashboard], + fun set_special_configs/1), Config. end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_resource, emqx_authz, emqx_dashboard]), + emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_authz, emqx_conf]), meck:unload(emqx_resource), - meck:unload(emqx_schema), ok. set_special_configs(emqx_dashboard) -> @@ -137,7 +124,9 @@ set_special_configs(emqx_dashboard) -> emqx_config:put([emqx_dashboard], Config), ok; set_special_configs(emqx_authz) -> - emqx_config:put([authorization], #{sources => []}), + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), ok; set_special_configs(_App) -> ok. diff --git a/apps/emqx_authz/test/emqx_authz_http_SUITE.erl b/apps/emqx_authz/test/emqx_authz_http_SUITE.erl index c0e66751a..848179687 100644 --- a/apps/emqx_authz/test/emqx_authz_http_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_http_SUITE.erl @@ -21,7 +21,6 @@ -include("emqx_authz.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). all() -> emqx_common_test_helpers:all(?MODULE). @@ -30,22 +29,14 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), Rules = [#{<<"type">> => <<"http">>, <<"url">> => <<"https://fake.com:443/">>, <<"headers">> => #{}, @@ -58,9 +49,16 @@ init_per_suite(Config) -> end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), - meck:unload(emqx_schema), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> ok. %%------------------------------------------------------------------------------ diff --git a/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl index f2562becc..70e7b6608 100644 --- a/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl @@ -22,8 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). - all() -> emqx_common_test_helpers:all(?MODULE). @@ -31,26 +29,24 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), - - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), - Rules = [#{<<"type">> => <<"built-in-database">>}], - {ok, _} = emqx_authz:update(replace, Rules), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1 + ), Config. end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_authz]), - meck:unload(emqx_schema), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], + [#{<<"type">> => <<"built-in-database">>}]), + ok; +set_special_configs(_App) -> ok. init_per_testcase(t_authz, Config) -> diff --git a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl index 357d8a9ed..682a193a7 100644 --- a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl @@ -22,8 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). - all() -> emqx_common_test_helpers:all(?MODULE). @@ -31,21 +29,15 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1 + ), + Rules = [#{<<"type">> => <<"mongodb">>, <<"mongo_type">> => <<"single">>, <<"server">> => <<"127.0.0.1:27017">>, @@ -60,9 +52,16 @@ init_per_suite(Config) -> end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), - meck:unload(emqx_schema), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> ok. -define(SOURCE1,[#{<<"topics">> => [<<"#">>], diff --git a/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl index c85422122..1db5374d3 100644 --- a/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl @@ -31,22 +31,14 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end ), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), Rules = [#{<<"type">> => <<"mysql">>, <<"server">> => <<"127.0.0.1:27017">>, <<"pool_size">> => 1, @@ -62,9 +54,16 @@ init_per_suite(Config) -> end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), - meck:unload(emqx_schema), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> ok. -define(COLUMNS, [ <<"action">> diff --git a/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl b/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl index 2b9d4c62e..0f88b6440 100644 --- a/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl @@ -22,8 +22,6 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). --define(CONF_DEFAULT, <<"authorization: {sources: []}">>). - all() -> emqx_common_test_helpers:all(?MODULE). @@ -31,22 +29,14 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end ), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), Rules = [#{<<"type">> => <<"postgresql">>, <<"server">> => <<"127.0.0.1:27017">>, <<"pool_size">> => 1, @@ -62,9 +52,16 @@ init_per_suite(Config) -> end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), - meck:unload(emqx_schema), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> ok. -define(COLUMNS, [ {column, <<"action">>, meck, meck, meck, meck, meck, meck, meck} diff --git a/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl b/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl index b1657d558..4b76bcfab 100644 --- a/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl @@ -30,22 +30,14 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_schema, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_schema, fields, fun("authorization") -> - meck:passthrough(["authorization"]) ++ - emqx_authz_schema:fields("authorization"); - (F) -> meck:passthrough([F]) - end), - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end ), meck:expect(emqx_resource, remove, fun(_) -> ok end ), - ok = emqx_config:init_load(emqx_authz_schema, ?CONF_DEFAULT), - ok = emqx_common_test_helpers:start_apps([emqx_authz]), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1), - {ok, _} = emqx:update_config([authorization, cache, enable], false), - {ok, _} = emqx:update_config([authorization, no_match], deny), Rules = [#{<<"type">> => <<"redis">>, <<"server">> => <<"127.0.0.1:27017">>, <<"pool_size">> => 1, @@ -62,7 +54,14 @@ end_per_suite(_Config) -> {ok, _} = emqx_authz:update(replace, []), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), meck:unload(emqx_resource), - meck:unload(emqx_schema), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> ok. -define(SOURCE1, [<<"test/%u">>, <<"publish">>]). diff --git a/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl b/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl index ec8ca929a..601958609 100644 --- a/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl @@ -32,11 +32,22 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> - ok = emqx_common_test_helpers:start_apps([emqx_authz]), + ok = emqx_common_test_helpers:start_apps( + [emqx_conf, emqx_authz], + fun set_special_configs/1), Config. end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_authz]), + {ok, _} = emqx_authz:update(replace, []), + emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), + ok. + +set_special_configs(emqx_authz) -> + {ok, _} = emqx:update_config([authorization, cache, enable], false), + {ok, _} = emqx:update_config([authorization, no_match], deny), + {ok, _} = emqx:update_config([authorization, sources], []), + ok; +set_special_configs(_App) -> ok. t_compile(_) -> diff --git a/apps/emqx_gateway/src/emqx_gateway_conf.erl b/apps/emqx_gateway/src/emqx_gateway_conf.erl index b5417b0d6..66323c53c 100644 --- a/apps/emqx_gateway/src/emqx_gateway_conf.erl +++ b/apps/emqx_gateway/src/emqx_gateway_conf.erl @@ -89,7 +89,8 @@ load_gateway(GwName, Conf) -> unconvert_listeners(Ls) when is_list(Ls) -> lists:foldl(fun(Lis, Acc) -> {[Type, Name], Lis1} = maps_key_take([<<"type">>, <<"name">>], Lis), - emqx_map_lib:deep_merge(Acc, #{Type => #{Name => Lis1}}) + NLis1 = maps:without([<<"id">>], Lis1), + emqx_map_lib:deep_merge(Acc, #{Type => #{Name => NLis1}}) end, #{}, Ls). maps_key_take(Ks, M) -> From f23d2f2c92f5199a789c7cfc735ab27481df35c6 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Fri, 5 Nov 2021 15:53:20 +0800 Subject: [PATCH 10/12] chore: refine case side-effect --- apps/emqx_gateway/src/emqx_gateway_conf.erl | 6 +++--- apps/emqx_machine/test/emqx_machine_SUITE.erl | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/emqx_gateway/src/emqx_gateway_conf.erl b/apps/emqx_gateway/src/emqx_gateway_conf.erl index 66323c53c..9e5893639 100644 --- a/apps/emqx_gateway/src/emqx_gateway_conf.erl +++ b/apps/emqx_gateway/src/emqx_gateway_conf.erl @@ -97,11 +97,11 @@ maps_key_take(Ks, M) -> maps_key_take(Ks, M, []). maps_key_take([], M, Acc) -> {lists:reverse(Acc), M}; -maps_key_take([K|Ks], M, Acc) -> +maps_key_take([K | Ks], M, Acc) -> case maps:take(K, M) of error -> throw(bad_key); {V, M1} -> - maps_key_take(Ks, M1, [V|Acc]) + maps_key_take(Ks, M1, [V | Acc]) end. -spec update_gateway(atom_or_bin(), map()) -> ok_or_err(). @@ -384,7 +384,7 @@ pre_config_update(UnknownReq, _RawConf) -> -> ok | {ok, Result::any()} | {error, Reason::term()}. post_config_update(Req, NewConfig, OldConfig, _AppEnvs) when is_tuple(Req) -> - [_Tag, GwName0|_] = tuple_to_list(Req), + [_Tag, GwName0 | _] = tuple_to_list(Req), GwName = binary_to_existing_atom(GwName0), case {maps:get(GwName, NewConfig, undefined), diff --git a/apps/emqx_machine/test/emqx_machine_SUITE.erl b/apps/emqx_machine/test/emqx_machine_SUITE.erl index cce0778e2..03d9e6ba9 100644 --- a/apps/emqx_machine/test/emqx_machine_SUITE.erl +++ b/apps/emqx_machine/test/emqx_machine_SUITE.erl @@ -26,6 +26,23 @@ all() -> emqx_common_test_helpers:all(?MODULE). init_per_suite(Config) -> + %% CASE-SIDE-EFFICT: + %% + %% Running-Seq: + %% emqx_authz_api_mnesia_SUITE.erl + %% emqx_gateway_api_SUITE.erl + %% emqx_machine_SUITE.erl + %% + %% Reason: + %% the `emqx_machine_boot:ensure_apps_started()` will crashed + %% on starting `emqx_authz` with dirty confs, which caused the file + %% `.._build/test/lib/emqx_conf/etc/acl.conf` could not be found + %% + %% Workaround: + %% Unload emqx_authz to avoid reboot this application + %% + application:unload(emqx_authz), + emqx_common_test_helpers:start_apps([]), Config. From d0bdf27e0c38f6ce1ff9798425e4428c2869820a Mon Sep 17 00:00:00 2001 From: JianBo He Date: Tue, 9 Nov 2021 17:43:31 +0800 Subject: [PATCH 11/12] chore: fix elvis warnings --- apps/emqx/src/emqx_schema.erl | 13 +- apps/emqx_authz/test/emqx_authz_SUITE.erl | 4 +- .../test/emqx_authz_api_mnesia_SUITE.erl | 5 +- .../test/emqx_authz_api_settings_SUITE.erl | 4 +- .../test/emqx_authz_api_sources_SUITE.erl | 52 +- .../test/emqx_authz_mnesia_SUITE.erl | 18 +- .../test/emqx_authz_mongodb_SUITE.erl | 18 +- .../test/emqx_authz_mysql_SUITE.erl | 18 +- .../test/emqx_authz_postgresql_SUITE.erl | 18 +- .../emqx_authz/test/emqx_authz_rule_SUITE.erl | 73 +- apps/emqx_conf/src/emqx_conf_schema.erl | 9 +- apps/emqx_gateway/src/emqx_gateway_schema.erl | 4 +- apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl | 1474 +++++++++-------- .../test/emqx_lwm2m_api_SUITE.erl | 31 +- apps/emqx_gateway/test/emqx_stomp_SUITE.erl | 53 +- elvis.config | 3 +- 16 files changed, 1022 insertions(+), 775 deletions(-) diff --git a/apps/emqx/src/emqx_schema.erl b/apps/emqx/src/emqx_schema.erl index e319dbe15..3e3318475 100644 --- a/apps/emqx/src/emqx_schema.erl +++ b/apps/emqx/src/emqx_schema.erl @@ -75,6 +75,8 @@ -export([server_ssl_opts_schema/2, client_ssl_opts_schema/1, ciphers_schema/1, default_ciphers/1]). -export([sc/2, map/2]). +-elvis([{elvis_style, god_modules, disable}]). + namespace() -> undefined. roots() -> @@ -898,7 +900,8 @@ fields("alarm") -> Currently supports two actions, 'log' and 'publish'. 'log' is to write the alarm to log (console or file). 'publish' is to publish the alarm as an MQTT message to the system topics: -$SYS/brokers/emqx@xx.xx.xx.x/alarms/activate and $SYS/brokers/emqx@xx.xx.xx.x/alarms/deactivate""" +$SYS/brokers/emqx@xx.xx.xx.x/alarms/activate and +$SYS/brokers/emqx@xx.xx.xx.x/alarms/deactivate""" }) } , {"size_limit", @@ -916,8 +919,9 @@ When this limit is exceeded, the oldest deactivated alarms are deleted to cap th #{ default => "24h", example => "24h", desc => - """Retention time of deactivated alarms. Alarms are not deleted immediately when deactivated, but after the retention time. - """ +"""Retention time of deactivated alarms. Alarms are not deleted immediately +when deactivated, but after the retention time. +""" }) } ]. @@ -1181,7 +1185,8 @@ default_tls_vsns(dtls_all_available) -> default_tls_vsns(tls_all_available) -> emqx_tls_lib:default_versions(). --spec ciphers_schema(quic | dtls_all_available | tls_all_available | undefined) -> hocon_schema:field_schema(). +-spec ciphers_schema(quic | dtls_all_available | tls_all_available | undefined) + -> hocon_schema:field_schema(). ciphers_schema(Default) -> sc(hoconsc:array(string()), #{ default => default_ciphers(Default) diff --git a/apps/emqx_authz/test/emqx_authz_SUITE.erl b/apps/emqx_authz/test/emqx_authz_SUITE.erl index 5f0371c49..df4c904c3 100644 --- a/apps/emqx_authz/test/emqx_authz_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_SUITE.erl @@ -149,7 +149,9 @@ t_update_source(_) -> {ok, _} = emqx_authz:update(?CMD_REPLACE, []). t_move_source(_) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5, ?SOURCE6]), + {ok, _} = emqx_authz:update(?CMD_REPLACE, + [?SOURCE1, ?SOURCE2, ?SOURCE3, + ?SOURCE4, ?SOURCE5, ?SOURCE6]), ?assertMatch([ #{type := http} , #{type := mongodb} , #{type := mysql} diff --git a/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl index 1613df2d1..737a089a2 100644 --- a/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl @@ -26,7 +26,6 @@ -define(API_VERSION, "v5"). -define(BASE_PATH, "api"). - all() -> emqx_common_test_helpers:all(?MODULE). @@ -82,7 +81,9 @@ t_api(_) -> , uri(["authorization", "sources", "built-in-database", "username", "user1"]) , []), #{<<"data">> := [#{<<"username">> := <<"user1">>, <<"rules">> := Rules1}], - <<"meta">> := #{<<"count">> := 1,<<"limit">> := 100,<<"page">> := 1}} = jsx:decode(Request1), + <<"meta">> := #{<<"count">> := 1, + <<"limit">> := 100, + <<"page">> := 1}} = jsx:decode(Request1), #{<<"username">> := <<"user1">>, <<"rules">> := Rules1} = jsx:decode(Request2), ?assertEqual(3, length(Rules1)), diff --git a/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl index f8d83eee9..5ad8f1f29 100644 --- a/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl @@ -36,11 +36,11 @@ init_per_suite(Config) -> ok = emqx_common_test_helpers:start_apps( [emqx_conf, emqx_authz, emqx_dashboard], fun set_special_configs/1), - Config. end_per_suite(_Config) -> - emqx_common_test_helpers:stop_apps([emqx_authz, emqx_dashboard]), + {ok, _} = emqx_authz:update(replace, []), + emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_authz, emqx_conf]), ok. set_special_configs(emqx_dashboard) -> diff --git a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl index d5a245819..4fbbed84d 100644 --- a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl @@ -81,7 +81,9 @@ }). -define(SOURCE6, #{<<"type">> => <<"file">>, <<"enable">> => true, - <<"rules">> => <<"{allow,{username,\"^dashboard?\"},subscribe,[\"$SYS/#\"]}.\n{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">> + <<"rules">> => +<<"{allow,{username,\"^dashboard?\"},subscribe,[\"$SYS/#\"]}." + "\n{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">> }). all() -> @@ -94,9 +96,10 @@ groups() -> init_per_suite(Config) -> meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), meck:expect(emqx_resource, create, fun(_, _, _) -> {ok, meck_data} end), - meck:expect(emqx_resource, create_dry_run, fun(emqx_connector_mysql, _) -> {ok, meck_data}; - (T, C) -> meck:passthrough([T, C]) - end), + meck:expect(emqx_resource, create_dry_run, + fun(emqx_connector_mysql, _) -> {ok, meck_data}; + (T, C) -> meck:passthrough([T, C]) + end), meck:expect(emqx_resource, update, fun(_, _, _, _) -> {ok, meck_data} end), meck:expect(emqx_resource, health_check, fun(_) -> ok end), meck:expect(emqx_resource, remove, fun(_) -> ok end ), @@ -136,10 +139,11 @@ init_per_testcase(t_api, Config) -> meck:expect(emqx_misc, gen_id, fun() -> "fake" end), meck:new(emqx, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx, data_dir, fun() -> - {data_dir, Data} = lists:keyfind(data_dir, 1, Config), - Data - end), + meck:expect(emqx, data_dir, + fun() -> + {data_dir, Data} = lists:keyfind(data_dir, 1, Config), + Data + end), Config; init_per_testcase(_, Config) -> Config. @@ -157,7 +161,8 @@ t_api(_) -> {ok, 200, Result1} = request(get, uri(["authorization", "sources"]), []), ?assertEqual([], get_sources(Result1)), - {ok, 204, _} = request(put, uri(["authorization", "sources"]), [?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5, ?SOURCE6]), + {ok, 204, _} = request(put, uri(["authorization", "sources"]), + [?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5, ?SOURCE6]), {ok, 204, _} = request(post, uri(["authorization", "sources"]), ?SOURCE1), {ok, 200, Result2} = request(get, uri(["authorization", "sources"]), []), @@ -171,7 +176,8 @@ t_api(_) -> ], Sources), ?assert(filelib:is_file(emqx_authz:acl_conf_file())), - {ok, 204, _} = request(put, uri(["authorization", "sources", "http"]), ?SOURCE1#{<<"enable">> := false}), + {ok, 204, _} = request(put, uri(["authorization", "sources", "http"]), + ?SOURCE1#{<<"enable">> := false}), {ok, 200, Result3} = request(get, uri(["authorization", "sources", "http"]), []), ?assertMatch(#{<<"type">> := <<"http">>, <<"enable">> := false}, jsx:decode(Result3)), @@ -196,14 +202,28 @@ t_api(_) -> ?assert(filelib:is_file(filename:join([data_dir(), "certs", "cert-fake.pem"]))), ?assert(filelib:is_file(filename:join([data_dir(), "certs", "key-fake.pem"]))), - {ok, 204, _} = request(put, uri(["authorization", "sources", "mysql"]), ?SOURCE3#{<<"server">> := <<"192.168.1.100:3306">>}), + {ok, 204, _} = request( + put, + uri(["authorization", "sources", "mysql"]), + ?SOURCE3#{<<"server">> := <<"192.168.1.100:3306">>}), - {ok, 400, _} = request(put, uri(["authorization", "sources", "postgresql"]), ?SOURCE4#{<<"server">> := <<"fake">>}), - {ok, 400, _} = request(put, uri(["authorization", "sources", "redis"]), ?SOURCE5#{<<"servers">> := [<<"192.168.1.100:6379">>, <<"192.168.1.100:6380">>]}), + {ok, 400, _} = request( + put, + uri(["authorization", "sources", "postgresql"]), + ?SOURCE4#{<<"server">> := <<"fake">>}), + {ok, 400, _} = request( + put, + uri(["authorization", "sources", "redis"]), + ?SOURCE5#{<<"servers">> := [<<"192.168.1.100:6379">>, + <<"192.168.1.100:6380">>]}), - lists:foreach(fun(#{<<"type">> := Type}) -> - {ok, 204, _} = request(delete, uri(["authorization", "sources", binary_to_list(Type)]), []) - end, Sources), + lists:foreach( + fun(#{<<"type">> := Type}) -> + {ok, 204, _} = request( + delete, + uri(["authorization", "sources", binary_to_list(Type)]), + []) + end, Sources), {ok, 200, Result5} = request(get, uri(["authorization", "sources"]), []), ?assertEqual([], get_sources(Result5)), ?assertEqual([], emqx:get_config([authorization, sources])), diff --git a/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl index 70e7b6608..875ff3d09 100644 --- a/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl @@ -92,13 +92,19 @@ t_authz(_) -> listener => {tcp, default} }, - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo1, subscribe, <<"#">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo1, publish, <<"#">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo1, subscribe, <<"#">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo1, publish, <<"#">>)), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_username">>)), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, subscribe, <<"#">>)), + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_username">>)), + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"#">>)), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo3, publish, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, subscribe, <<"#">>)), + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo3, publish, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, subscribe, <<"#">>)), ok. diff --git a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl index 682a193a7..2e3edd42a 100644 --- a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl @@ -114,11 +114,17 @@ t_authz(_) -> ?assertEqual(deny, emqx_access_control:authorize(ClientInfo1, subscribe, <<"+">>)), meck:expect(emqx_resource, query, fun(_, _) -> ?SOURCE3 ++ ?SOURCE4 end), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, subscribe, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, subscribe, <<"test/test_username">>)), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_username">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, subscribe, <<"test">>)), % nomatch - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, publish, <<"test">>)), % nomatch + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"test/test_username">>)), + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_username">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, subscribe, <<"test">>)), % nomatch + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, publish, <<"test">>)), % nomatch ok. diff --git a/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl index 1db5374d3..a2d264fc9 100644 --- a/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl @@ -112,11 +112,17 @@ t_authz(_) -> ?assertEqual(deny, emqx_access_control:authorize(ClientInfo1, subscribe, <<"+">>)), meck:expect(emqx_resource, query, fun(_, _) -> {ok, ?COLUMNS, ?SOURCE3 ++ ?SOURCE4} end), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, subscribe, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, subscribe, <<"test/test_username">>)), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_username">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, subscribe, <<"test">>)), % nomatch - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, publish, <<"test">>)), % nomatch + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"test/test_username">>)), + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_username">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, subscribe, <<"test">>)), % nomatch + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, publish, <<"test">>)), % nomatch ok. diff --git a/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl b/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl index 0f88b6440..233701b34 100644 --- a/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl @@ -110,11 +110,17 @@ t_authz(_) -> ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, subscribe, <<"+">>)), meck:expect(emqx_resource, query, fun(_, _) -> {ok, ?COLUMNS, ?SOURCE3 ++ ?SOURCE4} end), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, subscribe, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_clientid">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo2, subscribe, <<"test/test_username">>)), - ?assertEqual(allow, emqx_access_control:authorize(ClientInfo2, publish, <<"test/test_username">>)), - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, subscribe, <<"test">>)), % nomatch - ?assertEqual(deny, emqx_access_control:authorize(ClientInfo3, publish, <<"test">>)), % nomatch + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_clientid">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo2, subscribe, <<"test/test_username">>)), + ?assertEqual(allow, emqx_access_control:authorize( + ClientInfo2, publish, <<"test/test_username">>)), + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, subscribe, <<"test">>)), % nomatch + ?assertEqual(deny, emqx_access_control:authorize( + ClientInfo3, publish, <<"test">>)), % nomatch ok. diff --git a/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl b/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl index 601958609..630d42dce 100644 --- a/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl @@ -26,7 +26,10 @@ -define(SOURCE2, {allow, {ipaddr, "127.0.0.1"}, all, [{eq, "#"}, {eq, "+"}]}). -define(SOURCE3, {allow, {ipaddrs, ["127.0.0.1", "192.168.1.0/24"]}, subscribe, ["%c"]}). -define(SOURCE4, {allow, {'and', [{client, "test"}, {user, "test"}]}, publish, ["topic/test"]}). --define(SOURCE5, {allow, {'or', [{username, {re, "^test"}}, {clientid, {re, "test?"}}]}, publish, ["%u", "%c"]}). +-define(SOURCE5, {allow, {'or', + [{username, {re, "^test"}}, + {clientid, {re, "test?"}}]}, + publish, ["%u", "%c"]}). all() -> emqx_common_test_helpers:all(?MODULE). @@ -53,7 +56,8 @@ set_special_configs(_App) -> t_compile(_) -> ?assertEqual({deny, all, all, [['#']]}, emqx_authz_rule:compile(?SOURCE1)), - ?assertEqual({allow, {ipaddr, {{127,0,0,1}, {127,0,0,1}, 32}}, all, [{eq, ['#']}, {eq, ['+']}]}, emqx_authz_rule:compile(?SOURCE2)), + ?assertEqual({allow, {ipaddr, {{127,0,0,1}, {127,0,0,1}, 32}}, + all, [{eq, ['#']}, {eq, ['+']}]}, emqx_authz_rule:compile(?SOURCE2)), ?assertEqual({allow, {ipaddrs,[{{127,0,0,1},{127,0,0,1},32}, @@ -69,9 +73,9 @@ t_compile(_) -> }, emqx_authz_rule:compile(?SOURCE4)), ?assertMatch({allow, - {'or', [{username, {re_pattern, _, _, _, _}}, {clientid, {re_pattern, _, _, _, _}}]}, - publish, - [{pattern, [<<"%u">>]}, {pattern, [<<"%c">>]}] + {'or', [{username, {re_pattern, _, _, _, _}}, + {clientid, {re_pattern, _, _, _, _}}]}, + publish, [{pattern, [<<"%u">>]}, {pattern, [<<"%c">>]}] }, emqx_authz_rule:compile(?SOURCE5)), ok. @@ -103,47 +107,64 @@ t_match(_) -> }, ?assertEqual({matched, deny}, - emqx_authz_rule:match(ClientInfo1, subscribe, <<"#">>, emqx_authz_rule:compile(?SOURCE1))), + emqx_authz_rule:match(ClientInfo1, subscribe, <<"#">>, + emqx_authz_rule:compile(?SOURCE1))), ?assertEqual({matched, deny}, - emqx_authz_rule:match(ClientInfo2, subscribe, <<"+">>, emqx_authz_rule:compile(?SOURCE1))), + emqx_authz_rule:match(ClientInfo2, subscribe, <<"+">>, + emqx_authz_rule:compile(?SOURCE1))), ?assertEqual({matched, deny}, - emqx_authz_rule:match(ClientInfo3, subscribe, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE1))), + emqx_authz_rule:match(ClientInfo3, subscribe, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE1))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo1, subscribe, <<"#">>, emqx_authz_rule:compile(?SOURCE2))), + emqx_authz_rule:match(ClientInfo1, subscribe, <<"#">>, + emqx_authz_rule:compile(?SOURCE2))), ?assertEqual(nomatch, - emqx_authz_rule:match(ClientInfo1, subscribe, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE2))), + emqx_authz_rule:match(ClientInfo1, subscribe, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE2))), ?assertEqual(nomatch, - emqx_authz_rule:match(ClientInfo2, subscribe, <<"#">>, emqx_authz_rule:compile(?SOURCE2))), + emqx_authz_rule:match(ClientInfo2, subscribe, <<"#">>, + emqx_authz_rule:compile(?SOURCE2))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo1, subscribe, <<"test">>, emqx_authz_rule:compile(?SOURCE3))), + emqx_authz_rule:match(ClientInfo1, subscribe, <<"test">>, + emqx_authz_rule:compile(?SOURCE3))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo2, subscribe, <<"test">>, emqx_authz_rule:compile(?SOURCE3))), + emqx_authz_rule:match(ClientInfo2, subscribe, <<"test">>, + emqx_authz_rule:compile(?SOURCE3))), ?assertEqual(nomatch, - emqx_authz_rule:match(ClientInfo2, subscribe, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE3))), + emqx_authz_rule:match(ClientInfo2, subscribe, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE3))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo1, publish, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE4))), + emqx_authz_rule:match(ClientInfo1, publish, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE4))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo2, publish, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE4))), + emqx_authz_rule:match(ClientInfo2, publish, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE4))), ?assertEqual(nomatch, - emqx_authz_rule:match(ClientInfo3, publish, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE4))), + emqx_authz_rule:match(ClientInfo3, publish, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE4))), ?assertEqual(nomatch, - emqx_authz_rule:match(ClientInfo4, publish, <<"topic/test">>, emqx_authz_rule:compile(?SOURCE4))), + emqx_authz_rule:match(ClientInfo4, publish, <<"topic/test">>, + emqx_authz_rule:compile(?SOURCE4))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo1, publish, <<"test">>, emqx_authz_rule:compile(?SOURCE5))), + emqx_authz_rule:match(ClientInfo1, publish, <<"test">>, + emqx_authz_rule:compile(?SOURCE5))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo2, publish, <<"test">>, emqx_authz_rule:compile(?SOURCE5))), + emqx_authz_rule:match(ClientInfo2, publish, <<"test">>, + emqx_authz_rule:compile(?SOURCE5))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo3, publish, <<"test">>, emqx_authz_rule:compile(?SOURCE5))), + emqx_authz_rule:match(ClientInfo3, publish, <<"test">>, + emqx_authz_rule:compile(?SOURCE5))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo3, publish, <<"fake">>, emqx_authz_rule:compile(?SOURCE5))), + emqx_authz_rule:match(ClientInfo3, publish, <<"fake">>, + emqx_authz_rule:compile(?SOURCE5))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo4, publish, <<"test">>, emqx_authz_rule:compile(?SOURCE5))), + emqx_authz_rule:match(ClientInfo4, publish, <<"test">>, + emqx_authz_rule:compile(?SOURCE5))), ?assertEqual({matched, allow}, - emqx_authz_rule:match(ClientInfo4, publish, <<"fake">>, emqx_authz_rule:compile(?SOURCE5))), - + emqx_authz_rule:match(ClientInfo4, publish, <<"fake">>, + emqx_authz_rule:compile(?SOURCE5))), ok. - diff --git a/apps/emqx_conf/src/emqx_conf_schema.erl b/apps/emqx_conf/src/emqx_conf_schema.erl index a187bc58c..ba3ac31b6 100644 --- a/apps/emqx_conf/src/emqx_conf_schema.erl +++ b/apps/emqx_conf/src/emqx_conf_schema.erl @@ -341,8 +341,9 @@ fields("cluster_call") -> })} , {"cleanup_interval", sc(emqx_schema:duration(), - #{ desc => "Time interval to clear completed but stale transactions. - Ensure that the number of completed transactions is less than the max_history." + #{ desc => +"Time interval to clear completed but stale transactions. +Ensure that the number of completed transactions is less than the max_history." , default => "5m" })} ]; @@ -505,7 +506,7 @@ fields("authorization") -> translations() -> ["ekka", "kernel", "emqx"]. translation("ekka") -> - [ {"cluster_discovery", fun tr_cluster__discovery/1}]; + [ {"cluster_discovery", fun tr_cluster_discovery/1}]; translation("kernel") -> [ {"logger_level", fun tr_logger_level/1} , {"logger", fun tr_logger/1}]; @@ -540,7 +541,7 @@ tr_override_conf_file(Conf, Filename) -> [_ | _] = DataDir, filename:join([DataDir, "configs", Filename]). -tr_cluster__discovery(Conf) -> +tr_cluster_discovery(Conf) -> Strategy = conf_get("cluster.discovery_strategy", Conf), {Strategy, filter(options(Strategy, Conf))}. diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl index 71fac2743..9f35225b7 100644 --- a/apps/emqx_gateway/src/emqx_gateway_schema.erl +++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl @@ -45,6 +45,7 @@ , comma_separated_list/0 , ip_port/0 ]). +-elvis([{elvis_style, dont_repeat_yourself, disable}]). -export([namespace/0, roots/0 , fields/1]). @@ -324,7 +325,8 @@ the LwM2M client" sc(ref(translator), #{ desc => "The topic for gateway to publish the notify events from LwM2M client.
-After succeed observe a resource of LwM2M client, Gateway will send the notifyevents via this topic, if the client reports any resource changes" +After succeed observe a resource of LwM2M client, Gateway will send the +notifyevents via this topic, if the client reports any resource changes" })} , {register, sc(ref(translator), diff --git a/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl b/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl index 49079d579..c3331eccd 100644 --- a/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_lwm2m_SUITE.erl @@ -80,7 +80,8 @@ groups() -> [ case01_register, case01_register_additional_opts, - %% case01_register_incorrect_opts, %% TODO now we can't handle partial decode packet + %% TODO now we can't handle partial decode packet + %% case01_register_incorrect_opts, case01_register_report, case02_update_deregister, case03_register_wrong_version, @@ -164,7 +165,9 @@ init_per_testcase(_AllTestCase, Config) -> {ok, _} = application:ensure_all_started(emqx_gateway), {ok, ClientUdpSock} = gen_udp:open(0, [binary, {active, false}]), - {ok, C} = emqtt:start_link([{host, "localhost"},{port, 1883},{clientid, <<"c1">>}]), + {ok, C} = emqtt:start_link([{host, "localhost"}, + {port, 1883}, + {clientid, <<"c1">>}]), {ok, _} = emqtt:connect(C), timer:sleep(100), @@ -189,12 +192,14 @@ case01_register(Config) -> MsgId = 12, SubTopic = list_to_binary("lwm2m/"++Epn++"/dn/#"), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), %% checkpoint 1 - response #coap_message{type = Type, method = Method, id = RspId, options = Opts} = @@ -215,13 +220,16 @@ case01_register(Config) -> %%---------------------------------------- ?LOGT("start to send DE-REGISTER command", []), MsgId3 = 52, - test_send_coap_request( UdpSock, - delete, - sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), - #coap_content{payload = <<>>}, - [], - MsgId3), - #coap_message{type = ack, id = RspId3, method = Method3} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + delete, + sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), + #coap_content{payload = <<>>}, + [], + MsgId3), + #coap_message{type = ack, + id = RspId3, + method = Method3} = test_recv_coap_response(UdpSock), {ok,deleted} = Method3, MsgId3 = RspId3, timer:sleep(50), @@ -236,13 +244,16 @@ case01_register_additional_opts(Config) -> MsgId = 12, SubTopic = list_to_binary("lwm2m/"++Epn++"/dn/#"), - AddOpts = "ep=~ts<=345&lwm2m=1&apn=psmA.eDRX0.ctnb&cust_opt=shawn&im=123&ct=1.4&mt=mdm9620&mv=1.2", - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?" ++ AddOpts, [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + AddOpts = "ep=~ts<=345&lwm2m=1&apn=psmA.eDRX0.ctnb&cust_opt=shawn&" + "im=123&ct=1.4&mt=mdm9620&mv=1.2", + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?" ++ AddOpts, [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), %% checkpoint 1 - response #coap_message{type = Type, method = Method, id = RspId, options = Opts} = @@ -263,13 +274,16 @@ case01_register_additional_opts(Config) -> %%---------------------------------------- ?LOGT("start to send DE-REGISTER command", []), MsgId3 = 52, - test_send_coap_request( UdpSock, - delete, - sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), - #coap_content{payload = <<>>}, - [], - MsgId3), - #coap_message{type = ack, id = RspId3, method = Method3} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + delete, + sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), + #coap_content{payload = <<>>}, + [], + MsgId3), + #coap_message{type = ack, + id = RspId3, + method = Method3} = test_recv_coap_response(UdpSock), {ok,deleted} = Method3, MsgId3 = RspId3, timer:sleep(50), @@ -285,12 +299,14 @@ case01_register_incorrect_opts(Config) -> AddOpts = "ep=~ts<=345&lwm2m=1&incorrect_opt", - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?" ++ AddOpts, [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?" ++ AddOpts, [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), %% checkpoint 1 - response #coap_message{type = ack, method = Method, id = MsgId} = @@ -309,12 +325,14 @@ case01_register_report(Config) -> emqtt:subscribe(?config(emqx_c, Config), ReportTopic, qos0), timer:sleep(200), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), #coap_message{type = Type, method = Method, id = RspId, options = Opts} = test_recv_coap_response(UdpSock), @@ -327,16 +345,16 @@ case01_register_report(Config) -> timer:sleep(50), true = lists:member(SubTopic, test_mqtt_broker:get_subscrbied_topics()), - ReadResult = emqx_json:encode(#{ - <<"msgType">> => <<"register">>, - <<"data">> => #{ - <<"alternatePath">> => <<"/">>, - <<"ep">> => list_to_binary(Epn), - <<"lt">> => 345, - <<"lwm2m">> => <<"1">>, - <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, <<"/4">>, <<"/5">>] - } - }), + ReadResult = emqx_json:encode( + #{<<"msgType">> => <<"register">>, + <<"data">> => #{ + <<"alternatePath">> => <<"/">>, + <<"ep">> => list_to_binary(Epn), + <<"lt">> => 345, + <<"lwm2m">> => <<"1">>, + <<"objectList">> => [<<"/1">>, <<"/2">>, + <<"/3">>, <<"/4">>, <<"/5">>] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(ReportTopic)), %%---------------------------------------- @@ -344,13 +362,16 @@ case01_register_report(Config) -> %%---------------------------------------- ?LOGT("start to send DE-REGISTER command", []), MsgId3 = 52, - test_send_coap_request( UdpSock, - delete, - sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), - #coap_content{payload = <<>>}, - [], - MsgId3), - #coap_message{type = ack, id = RspId3, method = Method3} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + delete, + sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), + #coap_content{payload = <<>>}, + [], + MsgId3), + #coap_message{type = ack, + id = RspId3, + method = Method3} = test_recv_coap_response(UdpSock), {ok,deleted} = Method3, MsgId3 = RspId3, timer:sleep(50), @@ -368,28 +389,32 @@ case02_update_deregister(Config) -> emqtt:subscribe(?config(emqx_c, Config), ReportTopic, qos0), timer:sleep(200), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), timer:sleep(100), - #coap_message{type = ack, method = Method, options = Opts} = test_recv_coap_response(UdpSock), + #coap_message{type = ack, + method = Method, + options = Opts} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method), ?LOGT("Options got: ~p", [Opts]), Location = maps:get(location_path, Opts), - Register = emqx_json:encode(#{ - <<"msgType">> => <<"register">>, - <<"data">> => #{ - <<"alternatePath">> => <<"/">>, - <<"ep">> => list_to_binary(Epn), - <<"lt">> => 345, - <<"lwm2m">> => <<"1">>, - <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, <<"/4">>, <<"/5">>] - } - }), + Register = emqx_json:encode( + #{<<"msgType">> => <<"register">>, + <<"data">> => #{ + <<"alternatePath">> => <<"/">>, + <<"ep">> => list_to_binary(Epn), + <<"lt">> => 345, + <<"lwm2m">> => <<"1">>, + <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, + <<"/4">>, <<"/5">>] + }}), ?assertEqual(Register, test_recv_mqtt_response(ReportTopic)), %%---------------------------------------- @@ -397,25 +422,29 @@ case02_update_deregister(Config) -> %%---------------------------------------- ?LOGT("start to send UPDATE command", []), MsgId2 = 27, - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b~ts?lt=789", [?PORT, join_path(Location, <<>>)]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , , ">>}, - [], - MsgId2), - #coap_message{type = ack, id = RspId2, method = Method2} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b~ts?lt=789", [?PORT, join_path(Location, <<>>)]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , , ">>}, + [], + MsgId2), + #coap_message{type = ack, + id = RspId2, + method = Method2} = test_recv_coap_response(UdpSock), {ok,changed} = Method2, MsgId2 = RspId2, - Update = emqx_json:encode(#{ - <<"msgType">> => <<"update">>, - <<"data">> => #{ - <<"alternatePath">> => <<"/">>, - <<"ep">> => list_to_binary(Epn), - <<"lt">> => 789, - <<"lwm2m">> => <<"1">>, - <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, <<"/4">>, <<"/5">>, <<"/6">>] - } - }), + Update = emqx_json:encode( + #{<<"msgType">> => <<"update">>, + <<"data">> => #{ + <<"alternatePath">> => <<"/">>, + <<"ep">> => list_to_binary(Epn), + <<"lt">> => 789, + <<"lwm2m">> => <<"1">>, + <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, + <<"/4">>, <<"/5">>, <<"/6">>] + }}), ?assertEqual(Update, test_recv_mqtt_response(ReportTopic)), %%---------------------------------------- @@ -423,13 +452,16 @@ case02_update_deregister(Config) -> %%---------------------------------------- ?LOGT("start to send DE-REGISTER command", []), MsgId3 = 52, - test_send_coap_request( UdpSock, - delete, - sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), - #coap_content{payload = <<>>}, - [], - MsgId3), - #coap_message{type = ack, id = RspId3, method = Method3} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + delete, + sprintf("coap://127.0.0.1:~b~ts", [?PORT, join_path(Location, <<>>)]), + #coap_content{payload = <<>>}, + [], + MsgId3), + #coap_message{type = ack, + id = RspId3, + method = Method3} = test_recv_coap_response(UdpSock), {ok,deleted} = Method3, MsgId3 = RspId3, @@ -444,12 +476,14 @@ case03_register_wrong_version(Config) -> Epn = "urn:oma:lwm2m:oma:3", MsgId = 12, SubTopic = list_to_binary("lwm2m/"++Epn++"/dn/#"), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=8.3", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=8.3", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), #coap_message{type = ack, method = Method} = test_recv_coap_response(UdpSock), ?assertEqual({error, bad_request}, Method), timer:sleep(50), @@ -465,12 +499,14 @@ case04_register_and_lifetime_timeout(Config) -> MsgId = 12, SubTopic = list_to_binary("lwm2m/"++Epn++"/dn/#"), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=2&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=2&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), timer:sleep(100), #coap_message{type = ack, method = Method} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method), @@ -491,12 +527,14 @@ case05_register_wrong_epn(Config) -> MsgId = 12, UdpSock = ?config(sock, Config), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?lt=345&lwm2m=1.0", [?PORT]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?lt=345&lwm2m=1.0", [?PORT]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId), #coap_message{type = ack, method = Method} = test_recv_coap_response(UdpSock), ?assertEqual({error,bad_request}, Method). @@ -508,13 +546,16 @@ case05_register_wrong_epn(Config) -> %% Epn = "urn:oma:lwm2m:oma:3", %% MsgId = 12, -%% test_send_coap_request( UdpSock, -%% post, -%% sprintf("coap://127.0.0.1:~b/rd?ep=~ts&lwm2m=1", [?PORT, Epn]), -%% #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, -%% [], -%% MsgId), -%% #coap_message{type = ack, method = Method} = test_recv_coap_response(UdpSock), +%% test_send_coap_request( +%% UdpSock, +%% post, +%% sprintf("coap://127.0.0.1:~b/rd?ep=~ts&lwm2m=1", [?PORT, Epn]), +%% #coap_content{content_format = <<"text/plain">>, +%% payload = <<", , , , ">>}, +%% [], +%% MsgId), +%% #coap_message{type = ack, +%% method = Method} = test_recv_coap_response(UdpSock), %% ?assertEqual({error,bad_request}, Method), %% timer:sleep(50), %% ?assertEqual([], test_mqtt_broker:get_subscrbied_topics()). @@ -531,13 +572,15 @@ case07_register_alternate_path_01(Config) -> emqtt:subscribe(?config(emqx_c, Config), ReportTopic, qos0), timer:sleep(200), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId), timer:sleep(50), true = lists:member(SubTopic, test_mqtt_broker:get_subscrbied_topics()). @@ -553,13 +596,15 @@ case07_register_alternate_path_02(Config) -> emqtt:subscribe(?config(emqx_c, Config), ReportTopic, qos0), timer:sleep(200), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId), timer:sleep(50), true = lists:member(SubTopic, test_mqtt_broker:get_subscrbied_topics()). @@ -575,39 +620,40 @@ case08_reregister(Config) -> emqtt:subscribe(?config(emqx_c, Config), ReportTopic, qos0), timer:sleep(200), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId), timer:sleep(50), true = lists:member(SubTopic, test_mqtt_broker:get_subscrbied_topics()), ReadResult = emqx_json:encode( - #{ - <<"msgType">> => <<"register">>, + #{<<"msgType">> => <<"register">>, <<"data">> => #{ - <<"alternatePath">> => <<"/lwm2m">>, - <<"ep">> => list_to_binary(Epn), - <<"lt">> => 345, - <<"lwm2m">> => <<"1">>, - <<"objectList">> => [<<"/1/0">>, <<"/2/0">>, <<"/3/0">>] - } - } - ), + <<"alternatePath">> => <<"/lwm2m">>, + <<"ep">> => list_to_binary(Epn), + <<"lt">> => 345, + <<"lwm2m">> => <<"1">>, + <<"objectList">> => [<<"/1/0">>, <<"/2/0">>, <<"/3/0">>] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(ReportTopic)), timer:sleep(1000), %% the same lwm2mc client registers to server again - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId + 1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId + 1), %% verify the lwm2m client is still online ?assertEqual(ReadResult, test_recv_mqtt_response(ReportTopic)). @@ -620,13 +666,15 @@ case10_read(Config) -> emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), timer:sleep(200), %% step 1, device register ... - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId1), #coap_message{method = Method1} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method1), test_recv_mqtt_response(RespTopic), @@ -646,7 +694,9 @@ case10_read(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options=Options2, + payload=Payload2} = Request2, ?LOGT("LwM2M client got ~p", [Request2]), ?assertEqual(get, Method2), @@ -654,21 +704,29 @@ case10_read(Config) -> ?assertEqual(<<>>, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"text/plain">>, payload = <<"EMQ">>}, Request2, true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, + payload = <<"EMQ">>}, + Request2, + true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"reqPath">> => <<"/3/0/0">>, - <<"content">> => [#{ - path => <<"/3/0/0">>, - value => <<"EMQ">> - }] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"reqPath">> => <<"/3/0/0">>, + <<"content">> => [#{path => <<"/3/0/0">>, + value => <<"EMQ">>} + ] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case10_read_separate_ack(Config) -> @@ -699,7 +757,8 @@ case10_read_separate_ack(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, payload = Payload2} = Request2, ?LOGT("LwM2M client got ~p", [Request2]), ?assertEqual(get, Method2), @@ -707,31 +766,36 @@ case10_read_separate_ack(Config) -> ?assertEqual(<<>>, Payload2), test_send_empty_ack(UdpSock, "127.0.0.1", ?PORT, Request2), - ReadResultACK = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"ack">>, - <<"data">> => #{ - <<"path">> => <<"/3/0/0">> - } - }), + ReadResultACK = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"ack">>, + <<"data">> => #{ <<"path">> => <<"/3/0/0">> } + }), ?assertEqual(ReadResultACK, test_recv_mqtt_response(RespTopic)), timer:sleep(100), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"text/plain">>, payload = <<"EMQ">>}, Request2, false), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, + payload = <<"EMQ">>}, + Request2, + false), timer:sleep(100), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"reqPath">> => <<"/3/0/0">>, - <<"content">> => [#{ - path => <<"/3/0/0">>, - value => <<"EMQ">> - }] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"reqPath">> => <<"/3/0/0">>, + <<"content">> => [#{path => <<"/3/0/0">>, + value => <<"EMQ">>}] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case11_read_object_tlv(Config) -> @@ -767,32 +831,41 @@ case11_read_object_tlv(Config) -> ?assertEqual(get, Method2), timer:sleep(50), - Tlv = <<16#08, 16#00, 16#3C, 16#C8, 16#00, 16#14, 16#4F, 16#70, 16#65, 16#6E, 16#20, 16#4D, 16#6F, 16#62, 16#69, 16#6C, 16#65, 16#20, 16#41, 16#6C, 16#6C, 16#69, 16#61, 16#6E, 16#63, 16#65, 16#C8, 16#01, 16#16, 16#4C, 16#69, 16#67, 16#68, 16#74, 16#77, 16#65, 16#69, 16#67, 16#68, 16#74, 16#20, 16#4D, 16#32, 16#4D, 16#20, 16#43, 16#6C, 16#69, 16#65, 16#6E, 16#74, 16#C8, 16#02, 16#09, 16#33, 16#34, 16#35, 16#30, 16#30, 16#30, 16#31, 16#32, 16#33>>, - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"application/vnd.oma.lwm2m+tlv">>, payload = Tlv}, Request2, true), + Tlv = <<16#08, 16#00, 16#3C, 16#C8, 16#00, 16#14, 16#4F, 16#70, 16#65, + 16#6E, 16#20, 16#4D, 16#6F, 16#62, 16#69, 16#6C, 16#65, 16#20, + 16#41, 16#6C, 16#6C, 16#69, 16#61, 16#6E, 16#63, 16#65, 16#C8, + 16#01, 16#16, 16#4C, 16#69, 16#67, 16#68, 16#74, 16#77, 16#65, + 16#69, 16#67, 16#68, 16#74, 16#20, 16#4D, 16#32, 16#4D, 16#20, + 16#43, 16#6C, 16#69, 16#65, 16#6E, 16#74, 16#C8, 16#02, 16#09, + 16#33, 16#34, 16#35, 16#30, 16#30, 16#30, 16#31, 16#32, 16#33>>, + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"application/vnd.oma.lwm2m+tlv">>, + payload = Tlv}, + Request2, + true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"reqPath">> => <<"/3/0">>, - <<"content">> => [ - #{ - path => <<"/3/0/0">>, - value => <<"Open Mobile Alliance">> - }, - #{ - path => <<"/3/0/1">>, - value => <<"Lightweight M2M Client">> - }, - #{ - path => <<"/3/0/2">>, - value => <<"345000123">> - } - ] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"reqPath">> => <<"/3/0">>, + <<"content">> => + [#{path => <<"/3/0/0">>, + value => <<"Open Mobile Alliance">>}, + #{path => <<"/3/0/1">>, + value => <<"Lightweight M2M Client">>}, + #{path => <<"/3/0/2">>, + value => <<"345000123">>} + ] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case11_read_object_json(Config) -> @@ -829,32 +902,37 @@ case11_read_object_json(Config) -> ?assertEqual(get, Method2), timer:sleep(50), - Json = <<"{\"bn\":\"/3/0\",\"e\":[{\"n\":\"0\",\"sv\":\"Open Mobile Alliance\"},{\"n\":\"1\",\"sv\":\"Lightweight M2M Client\"},{\"n\":\"2\",\"sv\":\"345000123\"}]}">>, - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"application/vnd.oma.lwm2m+json">>, payload = Json}, Request2, true), + Json = <<"{\"bn\":\"/3/0\",\"e\":[{\"n\":\"0\",\"sv\":\"Open Mobile " + "Alliance\"},{\"n\":\"1\",\"sv\":\"Lightweight M2M Client\"}," + "{\"n\":\"2\",\"sv\":\"345000123\"}]}">>, + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"application/vnd.oma.lwm2m+json">>, + payload = Json}, + Request2, + true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"reqPath">> => <<"/3/0">>, - <<"content">> => [ - #{ - path => <<"/3/0/0">>, - value => <<"Open Mobile Alliance">> - }, - #{ - path => <<"/3/0/1">>, - value => <<"Lightweight M2M Client">> - }, - #{ - path => <<"/3/0/2">>, - value => <<"345000123">> - } - ] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"reqPath">> => <<"/3/0">>, + <<"content">> => + [#{path => <<"/3/0/0">>, + value => <<"Open Mobile Alliance">>}, + #{path => <<"/3/0/1">>, + value => <<"Lightweight M2M Client">>}, + #{path => <<"/3/0/2">>, + value => <<"345000123">>} + ] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case12_read_resource_opaque(Config) -> @@ -891,23 +969,29 @@ case12_read_resource_opaque(Config) -> timer:sleep(50), Opaque = <<20, 21, 22, 23>>, - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"application/octet-stream">>, payload = Opaque}, Request2, true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"application/octet-stream">>, + payload = Opaque}, + Request2, + true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"reqPath">> => <<"/3/0/8">>, - <<"content">> => [ - #{ - path => <<"/3/0/8">>, - value => base64:encode(Opaque) - } - ] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"reqPath">> => <<"/3/0/8">>, + <<"content">> => + [#{path => <<"/3/0/8">>, + value => base64:encode(Opaque)} + ] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case13_read_no_xml(Config) -> @@ -925,12 +1009,10 @@ case13_read_no_xml(Config) -> %% step2, send a READ command to device CmdId = 206, CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, - Command = #{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, + Command = #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"path">> => <<"/9723/0/0">> - } + <<"data">> => #{ <<"path">> => <<"/9723/0/0">> } }, CommandJson = emqx_json:encode(Command), ?LOGT("CommandJson=~p", [CommandJson]), @@ -943,17 +1025,26 @@ case13_read_no_xml(Config) -> ?assertEqual(get, Method2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"text/plain">>, payload = <<"EMQ">>}, Request2, true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, + payload = <<"EMQ">>}, + Request2, + true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"reqPath">> => <<"/9723/0/0">>, - <<"code">> => <<"4.00">>, - <<"codeMsg">> => <<"bad_request">> - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"reqPath">> => <<"/9723/0/0">>, + <<"code">> => <<"4.00">>, + <<"codeMsg">> => <<"bad_request">> + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case20_single_write(Config) -> @@ -983,7 +1074,8 @@ case20_single_write(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(put, Method2), ?assertEqual(<<"/3/0/13">>, Path2), @@ -991,18 +1083,19 @@ case20_single_write(Config) -> ?assertEqual(Tlv_Value, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, changed}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, changed}, #coap_content{}, Request2, true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/13">>, - <<"code">> => <<"2.04">>, - <<"codeMsg">> => <<"changed">> - }, - <<"msgType">> => <<"write">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/13">>, + <<"code">> => <<"2.04">>, + <<"codeMsg">> => <<"changed">>}, + <<"msgType">> => <<"write">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case20_write(Config) -> @@ -1020,21 +1113,22 @@ case20_write(Config) -> %% step2, send a WRITE command to device CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, CmdId = 307, - Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + Command = #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, <<"msgType">> => <<"write">>, <<"data">> => #{ - <<"basePath">> => <<"/3/0/13">>, - <<"content">> => [#{ - type => <<"Float">>, - value => <<"12345.0">> - }] - } - }, + <<"basePath">> => <<"/3/0/13">>, + <<"content">> => + [#{type => <<"Float">>, + value => <<"12345.0">>}] + }}, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(put, Method2), ?assertEqual(<<"/3/0/13">>, Path2), @@ -1042,18 +1136,18 @@ case20_write(Config) -> ?assertEqual(Tlv_Value, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, changed}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, changed}, #coap_content{}, Request2, true), timer:sleep(100), - WriteResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/13">>, - <<"code">> => <<"2.04">>, - <<"codeMsg">> => <<"changed">> - }, - <<"msgType">> => <<"write">> - }), + WriteResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/13">>, + <<"code">> => <<"2.04">>, + <<"codeMsg">> => <<"changed">> }, + <<"msgType">> => <<"write">>}), ?assertEqual(WriteResult, test_recv_mqtt_response(RespTopic)). case21_write_object(Config) -> @@ -1071,26 +1165,26 @@ case21_write_object(Config) -> %% step2, send a WRITE command to device CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, CmdId = 307, - Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + Command = #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, <<"msgType">> => <<"write">>, <<"data">> => #{ - <<"basePath">> => <<"/3/0/">>, - <<"content">> => [#{ - path => <<"13">>, - type => <<"Integer">>, - value => <<"12345">> - },#{ - path => <<"14">>, - type => <<"String">>, - value => <<"87x">> - }] - } - }, + <<"basePath">> => <<"/3/0/">>, + <<"content">> => + [#{path => <<"13">>, + type => <<"Integer">>, + value => <<"12345">>}, + #{path => <<"14">>, + type => <<"String">>, + value => <<"87x">>}] + }}, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload=Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(post, Method2), ?assertEqual(<<"/3/0">>, Path2), @@ -1099,19 +1193,19 @@ case21_write_object(Config) -> ?assertEqual(Tlv_Value, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, changed}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, changed}, #coap_content{}, Request2, true), timer:sleep(100), - - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"write">>, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/">>, - <<"code">> => <<"2.04">>, - <<"codeMsg">> => <<"changed">> - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"msgType">> => <<"write">>, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/">>, + <<"code">> => <<"2.04">>, + <<"codeMsg">> => <<"changed">> + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case22_write_error(Config) -> @@ -1132,15 +1226,11 @@ case22_write_error(Config) -> Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, <<"msgType">> => <<"write">>, <<"data">> => #{ - <<"basePath">> => <<"/3/0/1">>, - <<"content">> => [ - #{ - type => <<"Integer">>, - value => <<"12345">> - } - ] - } - }, + <<"basePath">> => <<"/3/0/1">>, + <<"content">> => + [#{type => <<"Integer">>, + value => <<"12345">>}] + }}, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), @@ -1151,18 +1241,20 @@ case22_write_error(Config) -> ?assertEqual(<<"/3/0/1">>, Path2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {error, bad_request}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {error, bad_request}, #coap_content{}, + Request2, true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/1">>, - <<"code">> => <<"4.00">>, - <<"codeMsg">> => <<"bad_request">> - }, - <<"msgType">> => <<"write">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/1">>, + <<"code">> => <<"4.00">>, + <<"codeMsg">> => <<"bad_request">>}, + <<"msgType">> => <<"write">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case_create_basic(Config) -> @@ -1189,25 +1281,28 @@ case_create_basic(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(post, Method2), ?assertEqual(<<"/5">>, Path2), ?assertEqual(<<"">>, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, created}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, created}, #coap_content{}, Request2, true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/5">>, - <<"code">> => <<"2.01">>, - <<"codeMsg">> => <<"created">> - }, - <<"msgType">> => <<"create">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/5">>, + <<"code">> => <<"2.01">>, + <<"codeMsg">> => <<"created">>}, + <<"msgType">> => <<"create">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case_delete_basic(Config) -> @@ -1227,33 +1322,34 @@ case_delete_basic(Config) -> CmdId = 307, Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, <<"msgType">> => <<"delete">>, - <<"data">> => #{ - <<"path">> => <<"/5/0">> - } + <<"data">> => #{ <<"path">> => <<"/5/0">> } }, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(delete, Method2), ?assertEqual(<<"/5/0">>, Path2), ?assertEqual(<<"">>, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, deleted}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, deleted}, #coap_content{}, Request2, true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/5/0">>, - <<"code">> => <<"2.02">>, - <<"codeMsg">> => <<"deleted">> - }, - <<"msgType">> => <<"delete">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/5/0">>, + <<"code">> => <<"2.02">>, + <<"codeMsg">> => <<"deleted">>}, + <<"msgType">> => <<"delete">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case30_execute(Config) -> @@ -1271,37 +1367,41 @@ case30_execute(Config) -> %% step2, send a WRITE command to device CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, CmdId = 307, - Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + Command = #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, <<"msgType">> => <<"execute">>, <<"data">> => #{ - <<"path">> => <<"/3/0/4">>, - %% "args" should not be present for "/3/0/4", only for testing the encoding here - <<"args">> => <<"2,7">> - } + <<"path">> => <<"/3/0/4">>, + %% "args" should not be present for "/3/0/4", only for + %% testing the encoding here + <<"args">> => <<"2,7">>} }, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(post, Method2), ?assertEqual(<<"/3/0/4">>, Path2), ?assertEqual(<<"2,7">>, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, changed}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, changed}, #coap_content{}, Request2, true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/4">>, - <<"code">> => <<"2.04">>, - <<"codeMsg">> => <<"changed">> - }, - <<"msgType">> => <<"execute">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/4">>, + <<"code">> => <<"2.04">>, + <<"codeMsg">> => <<"changed">>}, + <<"msgType">> => <<"execute">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case31_execute_error(Config) -> @@ -1322,33 +1422,36 @@ case31_execute_error(Config) -> Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, <<"msgType">> => <<"execute">>, <<"data">> => #{ - <<"path">> => <<"/3/0/4">>, - <<"args">> => <<"2,7">> - } + <<"path">> => <<"/3/0/4">>, + <<"args">> => <<"2,7">>} }, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(post, Method2), ?assertEqual(<<"/3/0/4">>, Path2), ?assertEqual(<<"2,7">>, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {error, unauthorized}, #coap_content{}, Request2, true), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {error, unauthorized}, #coap_content{}, + Request2, true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/4">>, - <<"code">> => <<"4.01">>, - <<"codeMsg">> => <<"unauthorized">> - }, - <<"msgType">> => <<"execute">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, + <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/4">>, + <<"code">> => <<"4.01">>, + <<"codeMsg">> => <<"unauthorized">>}, + <<"msgType">> => <<"execute">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case40_discover(Config) -> @@ -1375,7 +1478,9 @@ case40_discover(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), ?assertEqual(get, Method2), ?assertEqual(<<"/3/0/7">>, Path2), @@ -1383,26 +1488,28 @@ case40_discover(Config) -> timer:sleep(50), PayloadDiscover = <<";dim=8;pmin=10;pmax=60;gt=50;lt=42.2,">>, - test_send_coap_response(UdpSock, - "127.0.0.1", - ?PORT, - {ok, content}, - #coap_content{content_format = <<"application/link-format">>, payload = PayloadDiscover}, - Request2, - true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"application/link-format">>, + payload = PayloadDiscover}, + Request2, + true), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"discover">>, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/7">>, - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"content">> => - [<<";dim=8;pmin=10;pmax=60;gt=50;lt=42.2">>, <<"">>] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"discover">>, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/7">>, + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"content">> => + [<<";dim=8;pmin=10;pmax=60;gt=50;lt=42.2">>, + <<"">>] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case50_write_attribute(Config) -> @@ -1432,34 +1539,33 @@ case50_write_attribute(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(100), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, ?LOGT("got options: ~p", [Options2]), Path2 = get_coap_path(Options2), Query2 = lists:sort(maps:to_list(get_coap_query(Options2))), ?assertEqual(put, Method2), ?assertEqual(<<"/3/0/9">>, Path2), - ?assertEqual(lists:sort([{<<"pmax">>, <<"5">>},{<<"lt">>, <<"5">>},{<<"pmin">>,<<"1">>}]), Query2), + ?assertEqual(lists:sort([{<<"pmax">>, <<"5">>}, + {<<"lt">>, <<"5">>}, + {<<"pmin">>,<<"1">>}]), Query2), ?assertEqual(<<>>, Payload2), timer:sleep(50), - test_send_coap_response(UdpSock, - "127.0.0.1", - ?PORT, - {ok, changed}, - #coap_content{}, - Request2, - true), - timer:sleep(100), + test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, + {ok, changed}, #coap_content{}, + Request2, true), + timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/9">>, - <<"code">> => <<"2.04">>, - <<"codeMsg">> => <<"changed">> - }, - <<"msgType">> => <<"write-attr">> - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/9">>, + <<"code">> => <<"2.04">>, + <<"codeMsg">> => <<"changed">>}, + <<"msgType">> => <<"write-attr">> + }), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case60_observe(Config) -> @@ -1481,15 +1587,15 @@ case60_observe(Config) -> CmdId = 307, Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, <<"msgType">> => <<"observe">>, - <<"data">> => #{ - <<"path">> => <<"/3/0/10">> - } + <<"data">> => #{<<"path">> => <<"/3/0/10">>} }, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50), Request2 = test_recv_coap_request(UdpSock), - #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, + #coap_message{method = Method2, + options = Options2, + payload = Payload2} = Request2, Path2 = get_coap_path(Options2), Observe = get_coap_observe(Options2), ?assertEqual(get, Method2), @@ -1498,55 +1604,53 @@ case60_observe(Config) -> ?assertEqual(<<>>, Payload2), timer:sleep(50), - test_send_coap_observe_ack( UdpSock, - "127.0.0.1", - ?PORT, - {ok, content}, - #coap_content{content_format = <<"text/plain">>, payload = <<"2048">>}, - Request2), + test_send_coap_observe_ack( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, payload = <<"2048">>}, + Request2), timer:sleep(100), - ReadResult = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"observe">>, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/10">>, - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"content">> => [#{ - path => <<"/3/0/10">>, - value => 2048 - }] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"observe">>, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/10">>, + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"content">> => + [#{path => <<"/3/0/10">>, + value => 2048}] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)), %% step3 the notifications timer:sleep(200), ObSeq = 3, - test_send_coap_notif( UdpSock, - "127.0.0.1", - ?PORT, - #coap_content{content_format = <<"text/plain">>, payload = <<"4096">>}, - ObSeq, - Request2), + test_send_coap_notif( + UdpSock, + "127.0.0.1", + ?PORT, + #coap_content{content_format = <<"text/plain">>, payload = <<"4096">>}, + ObSeq, + Request2), timer:sleep(100), #coap_message{} = test_recv_coap_response(UdpSock), - ReadResult2 = emqx_json:encode(#{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"notify">>, - <<"seqNum">> => ObSeq, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/10">>, - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"content">> => [#{ - path => <<"/3/0/10">>, - value => 4096 - }] - } - }), + ReadResult2 = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"notify">>, + <<"seqNum">> => ObSeq, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/10">>, + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"content">> => + [#{path => <<"/3/0/10">>, + value => 4096}] + }}), ?assertEqual(ReadResult2, test_recv_mqtt_response(RespTopicAD)), %% Step3. cancel observe @@ -1561,7 +1665,9 @@ case60_observe(Config) -> test_mqtt_broker:publish(CommandTopic, CommandJson3, 0), timer:sleep(50), Request3 = test_recv_coap_request(UdpSock), - #coap_message{method = Method3, options=Options3, payload=Payload3} = Request3, + #coap_message{method = Method3, + options = Options3, + payload = Payload3} = Request3, Path3 = get_coap_path(Options3), Observe3 = get_coap_observe(Options3), ?assertEqual(get, Method3), @@ -1570,31 +1676,31 @@ case60_observe(Config) -> ?assertEqual(<<>>, Payload3), timer:sleep(50), - test_send_coap_observe_ack( UdpSock, - "127.0.0.1", - ?PORT, - {ok, content}, - #coap_content{content_format = <<"text/plain">>, payload = <<"1150">>}, - Request3), + test_send_coap_observe_ack( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, payload = <<"1150">>}, + Request3), timer:sleep(100), - ReadResult3 = emqx_json:encode(#{ - <<"requestID">> => CmdId3, <<"cacheID">> => CmdId3, - <<"msgType">> => <<"cancel-observe">>, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/10">>, - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"content">> => [#{ - path => <<"/3/0/10">>, - value => 1150 - }] - } - }), + ReadResult3 = emqx_json:encode( + #{<<"requestID">> => CmdId3, + <<"cacheID">> => CmdId3, + <<"msgType">> => <<"cancel-observe">>, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/10">>, + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"content">> => + [#{path => <<"/3/0/10">>, + value => 1150}] + }}), ?assertEqual(ReadResult3, test_recv_mqtt_response(RespTopic)). %% case80_specail_object_19_0_0_notify(Config) -> -%% %% step 1, device register, with extra register options +%% %% step 1, device register, with extra register options %% Epn = "urn:oma:lwm2m:oma:3", %% RegOptionWangYi = "&apn=psmA.eDRX0.ctnb&im=13456&ct=2.0&mt=MDM9206&mv=4.0", %% MsgId1 = 15, @@ -1603,64 +1709,67 @@ case60_observe(Config) -> %% RespTopic = list_to_binary("lwm2m/"++Epn++"/up/resp"), %% emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), %% timer:sleep(200), - -%% test_send_coap_request( UdpSock, -%% post, -%% sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1"++RegOptionWangYi, [?PORT, Epn]), -%% #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, -%% [], -%% MsgId1), -%% #coap_message{method = Method1} = test_recv_coap_response(UdpSock), -%% ?assertEqual({ok,created}, Method1), -%% ReadResult = emqx_json:encode(#{ -%% <<"msgType">> => <<"register">>, -%% <<"data">> => #{ -%% <<"alternatePath">> => <<"/">>, -%% <<"ep">> => list_to_binary(Epn), -%% <<"lt">> => 345, -%% <<"lwm2m">> => <<"1">>, -%% <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, <<"/4">>, <<"/5">>], -%% <<"apn">> => <<"psmA.eDRX0.ctnb">>, -%% <<"im">> => <<"13456">>, -%% <<"ct">> => <<"2.0">>, -%% <<"mt">> => <<"MDM9206">>, -%% <<"mv">> => <<"4.0">> -%% } -%% }), -%% ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)), - -%% %% step2, send a OBSERVE command to device -%% CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, -%% CmdId = 307, -%% Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, -%% <<"msgType">> => <<"observe">>, -%% <<"data">> => #{ -%% <<"path">> => <<"/19/0/0">> -%% } -%% }, -%% CommandJson = emqx_json:encode(Command), -%% test_mqtt_broker:publish(CommandTopic, CommandJson, 0), -%% timer:sleep(50), -%% Request2 = test_recv_coap_request(UdpSock), -%% #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, -%% Path2 = get_coap_path(Options2), -%% Observe = get_coap_observe(Options2), -%% ?assertEqual(get, Method2), -%% ?assertEqual(<<"/19/0/0">>, Path2), -%% ?assertEqual(Observe, 0), -%% ?assertEqual(<<>>, Payload2), -%% timer:sleep(50), - -%% test_send_coap_observe_ack( UdpSock, -%% "127.0.0.1", -%% ?PORT, -%% {ok, content}, -%% #coap_content{content_format = <<"text/plain">>, payload = <<"2048">>}, -%% Request2), -%% timer:sleep(100). - -%% step 3, device send uplink data notifications - +%% +%% test_send_coap_request( +%% UdpSock, +%% post, +%% sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1"++RegOptionWangYi, [?PORT, Epn]), +%% #coap_content{content_format = <<"text/plain">>, +%% payload = <<", , , , ">>}, +%% [], +%% MsgId1), +%% #coap_message{method = Method1} = test_recv_coap_response(UdpSock), +%% ?assertEqual({ok,created}, Method1), +%% ReadResult = emqx_json:encode( +%% #{<<"msgType">> => <<"register">>, +%% <<"data">> => #{ +%% <<"alternatePath">> => <<"/">>, +%% <<"ep">> => list_to_binary(Epn), +%% <<"lt">> => 345, +%% <<"lwm2m">> => <<"1">>, +%% <<"objectList">> => [<<"/1">>, <<"/2">>, <<"/3">>, +%% <<"/4">>, <<"/5">>], +%% <<"apn">> => <<"psmA.eDRX0.ctnb">>, +%% <<"im">> => <<"13456">>, +%% <<"ct">> => <<"2.0">>, +%% <<"mt">> => <<"MDM9206">>, +%% <<"mv">> => <<"4.0">>} +%% }), +%% ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)), +%% +%% %% step2, send a OBSERVE command to device +%% CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, +%% CmdId = 307, +%% Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, +%% <<"msgType">> => <<"observe">>, +%% <<"data">> => #{ +%% <<"path">> => <<"/19/0/0">> +%% } +%% }, +%% CommandJson = emqx_json:encode(Command), +%% test_mqtt_broker:publish(CommandTopic, CommandJson, 0), +%% timer:sleep(50), +%% Request2 = test_recv_coap_request(UdpSock), +%% #coap_message{method = Method2, +%% options = Options2, +%% payload = Payload2} = Request2, +%% Path2 = get_coap_path(Options2), +%% Observe = get_coap_observe(Options2), +%% ?assertEqual(get, Method2), +%% ?assertEqual(<<"/19/0/0">>, Path2), +%% ?assertEqual(Observe, 0), +%% ?assertEqual(<<>>, Payload2), +%% timer:sleep(50), +%% +%% test_send_coap_observe_ack( +%% UdpSock, +%% "127.0.0.1", +%% ?PORT, +%% {ok, content}, +%% #coap_content{content_format = <<"text/plain">>, payload = <<"2048">>}, +%% Request2), +%% timer:sleep(100). +%% %% case80_specail_object_19_1_0_write(Config) -> %% Epn = "urn:oma:lwm2m:oma:3", %% RegOptionWangYi = "&apn=psmA.eDRX0.ctnb&im=13456&ct=2.0&mt=MDM9206&mv=4.0", @@ -1669,52 +1778,57 @@ case60_observe(Config) -> %% RespTopic = list_to_binary("lwm2m/"++Epn++"/up/resp"), %% emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), %% timer:sleep(200), - -%% test_send_coap_request( UdpSock, -%% post, -%% sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1"++RegOptionWangYi, [?PORT, Epn]), -%% #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, -%% [], -%% MsgId1), +%% +%% test_send_coap_request( +%% UdpSock, +%% post, +%% sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1"++RegOptionWangYi, [?PORT, Epn]), +%% #coap_content{content_format = <<"text/plain">>, +%% payload = <<", , , , ">>}, +%% [], +%% MsgId1), %% #coap_message{method = Method1} = test_recv_coap_response(UdpSock), %% ?assertEqual({ok,created}, Method1), %% test_recv_mqtt_response(RespTopic), - -%% %% step2, send a WRITE command to device +%% +%% %% step2, send a WRITE command to device %% CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, %% CmdId = 307, -%% Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, +%% Command = #{<<"requestID">> => CmdId, +%% <<"cacheID">> => CmdId, %% <<"msgType">> => <<"write">>, %% <<"data">> => #{ -%% <<"path">> => <<"/19/1/0">>, -%% <<"type">> => <<"Opaque">>, -%% <<"value">> => base64:encode(<<12345:32>>) -%% } -%% }, - +%% <<"path">> => <<"/19/1/0">>, +%% <<"type">> => <<"Opaque">>, +%% <<"value">> => base64:encode(<<12345:32>>) +%% }}, +%% %% CommandJson = emqx_json:encode(Command), %% test_mqtt_broker:publish(CommandTopic, CommandJson, 0), %% timer:sleep(50), %% Request2 = test_recv_coap_request(UdpSock), -%% #coap_message{method = Method2, options=Options2, payload=Payload2} = Request2, +%% #coap_message{method = Method2, +%% options = Options2, +%% payload = Payload2} = Request2, %% Path2 = get_coap_path(Options2), %% ?assertEqual(put, Method2), %% ?assertEqual(<<"/19/1/0">>, Path2), %% ?assertEqual(<<3:2, 0:1, 0:2, 4:3, 0, 12345:32>>, Payload2), %% timer:sleep(50), - -%% test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, changed}, #coap_content{}, Request2, true), +%% +%% test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, +%% {ok, changed}, #coap_content{}, Request2, true), %% timer:sleep(100), - -%% ReadResult = emqx_json:encode(#{ -%% <<"requestID">> => CmdId, <<"cacheID">> => CmdId, -%% <<"data">> => #{ -%% <<"reqPath">> => <<"/19/1/0">>, -%% <<"code">> => <<"2.04">>, -%% <<"codeMsg">> => <<"changed">> -%% }, -%% <<"msgType">> => <<"write">> -%% }), +%% +%% ReadResult = emqx_json:encode( +%% #{<<"requestID">> => CmdId, +%% <<"cacheID">> => CmdId, +%% <<"data">> => #{ +%% <<"reqPath">> => <<"/19/1/0">>, +%% <<"code">> => <<"2.04">>, +%% <<"codeMsg">> => <<"changed">>}, +%% <<"msgType">> => <<"write">> +%% }), %% ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). case90_psm_mode(Config) -> @@ -1736,13 +1850,17 @@ server_cache_mode(Config, RegOption) -> emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), timer:sleep(200), - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?"++RegOption, [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = <<", , , , ">>}, - [], - MsgId1), - #coap_message{type = ack, method = Method1, options = Opts} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?"++RegOption, [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<", , , , ">>}, + [], + MsgId1), + #coap_message{type = ack, + method = Method1, + options = Opts} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method1), ?LOGT("Options got: ~p", [Opts]), Location = maps:get(location_path, Opts), @@ -1760,7 +1878,8 @@ server_cache_mode(Config, RegOption) -> send_read_command_1(2, UdpSock), send_read_command_1(3, UdpSock), - ?assertEqual(timeout_test_recv_coap_request, test_recv_coap_request(UdpSock)), + ?assertEqual(timeout_test_recv_coap_request, + test_recv_coap_request(UdpSock)), device_update_1(UdpSock, Location), @@ -1775,13 +1894,10 @@ server_cache_mode(Config, RegOption) -> send_read_command_1(CmdId, _UdpSock) -> Epn = "urn:oma:lwm2m:oma:3", CommandTopic = <<"lwm2m/", (list_to_binary(Epn))/binary, "/dn/dm">>, - Command = #{ - <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"path">> => <<"/3/0/0">> - } - }, + Command = #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{<<"path">> => <<"/3/0/0">>} + }, CommandJson = emqx_json:encode(Command), test_mqtt_broker:publish(CommandTopic, CommandJson, 0), timer:sleep(50). @@ -1795,20 +1911,28 @@ verify_read_response_1(CmdId, UdpSock) -> ?LOGT("LwM2M client got ~p", [Request]), %% device replies the commond - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"text/plain">>, payload = <<"EMQ">>}, Request, true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, + payload = <<"EMQ">>}, + Request, + true), - ReadResult = emqx_json:encode(#{ <<"requestID">> => CmdId, <<"cacheID">> => CmdId, - <<"msgType">> => <<"read">>, - <<"data">> => #{ - <<"reqPath">> => <<"/3/0/0">>, - <<"code">> => <<"2.05">>, - <<"codeMsg">> => <<"content">>, - <<"content">> => [#{ - path => <<"/3/0/0">>, - value => <<"EMQ">> - }] - } - }), + ReadResult = emqx_json:encode( + #{<<"requestID">> => CmdId, <<"cacheID">> => CmdId, + <<"msgType">> => <<"read">>, + <<"data">> => #{ + <<"reqPath">> => <<"/3/0/0">>, + <<"code">> => <<"2.05">>, + <<"codeMsg">> => <<"content">>, + <<"content">> => + [#{path => <<"/3/0/0">>, + value => <<"EMQ">> + }] + }}), ?assertEqual(ReadResult, test_recv_mqtt_response(RespTopic)). device_update_1(UdpSock, Location) -> @@ -1816,13 +1940,16 @@ device_update_1(UdpSock, Location) -> RespTopic = list_to_binary("lwm2m/"++Epn++"/up/resp"), ?LOGT("send UPDATE command", []), MsgId2 = 27, - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b~ts?lt=789", [?PORT, join_path(Location, <<>>)]), - #coap_content{payload = <<>>}, - [], - MsgId2), - #coap_message{type = ack, id = MsgId2, method = Method2} = test_recv_coap_response(UdpSock), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b~ts?lt=789", [?PORT, join_path(Location, <<>>)]), + #coap_content{payload = <<>>}, + [], + MsgId2), + #coap_message{type = ack, + id = MsgId2, + method = Method2} = test_recv_coap_response(UdpSock), {ok,changed} = Method2, test_recv_mqtt_response(RespTopic). @@ -1835,34 +1962,56 @@ test_recv_mqtt_response(RespTopic) -> end. test_send_coap_request(UdpSock, Method, Uri, Content, Options, MsgId) -> - is_record(Content, coap_content) orelse error("Content must be a #coap_content!"), - is_list(Options) orelse error("Options must be a list"), + is_record(Content, coap_content) orelse + error("Content must be a #coap_content!"), + is_list(Options) orelse + error("Options must be a list"), case resolve_uri(Uri) of {coap, {IpAddr, Port}, Path, Query} -> - Request0 = request(con, Method, Content, [{uri_path, Path}, {uri_query, Query} | Options]), + Request0 = request( + con, Method, Content, + [{uri_path, Path}, {uri_query, Query} | Options] + ), Request = Request0#coap_message{id = MsgId}, ?LOGT("send_coap_request Request=~p", [Request]), + RequestBinary = emqx_coap_frame:serialize_pkt(Request, undefined), - ?LOGT("test udp socket send to ~p:~p, data=~p", [IpAddr, Port, RequestBinary]), + ?LOGT("test udp socket send to ~p:~p, data=~p", + [IpAddr, Port, RequestBinary]), ok = gen_udp:send(UdpSock, IpAddr, Port, RequestBinary); {SchemeDiff, ChIdDiff, _, _} -> - error(lists:flatten(io_lib:format("scheme ~ts or ChId ~ts does not match with socket", [SchemeDiff, ChIdDiff]))) + error( + lists:flatten( + io_lib:format( + "scheme ~ts or ChId ~ts does not match with socket", + [SchemeDiff, ChIdDiff]))) end. test_recv_coap_response(UdpSock) -> {ok, {Address, Port, Packet}} = gen_udp:recv(UdpSock, 0, 2000), {ok, Response, _, _} = emqx_coap_frame:parse(Packet, undefined), - ?LOGT("test udp receive from ~p:~p, data1=~p, Response=~p", [Address, Port, Packet, Response]), - #coap_message{type = ack, method = Method, id=Id, token = Token, options = Options, payload = Payload} = Response, - ?LOGT("receive coap response Method=~p, Id=~p, Token=~p, Options=~p, Payload=~p", [Method, Id, Token, Options, Payload]), + ?LOGT("test udp receive from ~p:~p, data1=~p, Response=~p", + [Address, Port, Packet, Response]), + #coap_message{type = ack, method = Method, id = Id, + token = Token, options = Options, payload = Payload} = Response, + ?LOGT("receive coap response Method=~p, Id=~p, Token=~p, " + "Options=~p, Payload=~p", [Method, Id, Token, Options, Payload]), Response. test_recv_coap_request(UdpSock) -> case gen_udp:recv(UdpSock, 0, 2000) of {ok, {_Address, _Port, Packet}} -> {ok, Request, _, _} = emqx_coap_frame:parse(Packet, undefined), - #coap_message{type = con, method = Method, id=Id, token = Token, payload = Payload, options = Options} = Request, - ?LOGT("receive coap request Method=~p, Id=~p, Token=~p, Options=~p, Payload=~p", [Method, Id, Token, Options, Payload]), + #coap_message{ + type = con, + id = Id, + method = Method, + token = Token, + payload = Payload, + options = Options} = Request, + ?LOGT("receive coap request Method=~p, Id=~p, Token=~p, " + "Options=~p, Payload=~p", + [Method, Id, Token, Options, Payload]), Request; {error, Reason} -> ?LOGT("test_recv_coap_request failed, Reason=~p", [Reason]), @@ -1870,7 +2019,8 @@ test_recv_coap_request(UdpSock) -> end. test_send_coap_response(UdpSock, Host, Port, Code, Content, Request, Ack) -> - is_record(Content, coap_content) orelse error("Content must be a #coap_content!"), + is_record(Content, coap_content) orelse + error("Content must be a #coap_content!"), is_list(Host) orelse error("Host is not a string"), {ok, IpAddr} = inet:getaddr(Host, inet), @@ -1880,17 +2030,20 @@ test_send_coap_response(UdpSock, Host, Port, Code, Content, Request, Ack) -> false -> Response end, ?LOGT("test_send_coap_response Response=~p", [Response2]), - ok = gen_udp:send(UdpSock, IpAddr, Port, emqx_coap_frame:serialize_pkt(Response2, undefined)). + ok = gen_udp:send(UdpSock, IpAddr, Port, + emqx_coap_frame:serialize_pkt(Response2, undefined)). test_send_empty_ack(UdpSock, Host, Port, Request) -> is_list(Host) orelse error("Host is not a string"), {ok, IpAddr} = inet:getaddr(Host, inet), EmptyACK = emqx_coap_message:ack(Request), ?LOGT("test_send_empty_ack EmptyACK=~p", [EmptyACK]), - ok = gen_udp:send(UdpSock, IpAddr, Port, emqx_coap_frame:serialize_pkt(EmptyACK, undefined)). + ok = gen_udp:send(UdpSock, IpAddr, Port, + emqx_coap_frame:serialize_pkt(EmptyACK, undefined)). test_send_coap_observe_ack(UdpSock, Host, Port, Code, Content, Request) -> - is_record(Content, coap_content) orelse error("Content must be a #coap_content!"), + is_record(Content, coap_content) orelse + error("Content must be a #coap_content!"), is_list(Host) orelse error("Host is not a string"), {ok, IpAddr} = inet:getaddr(Host, inet), @@ -1903,7 +2056,8 @@ test_send_coap_observe_ack(UdpSock, Host, Port, Code, Content, Request) -> ok = gen_udp:send(UdpSock, IpAddr, Port, ResponseBinary). test_send_coap_notif(UdpSock, Host, Port, Content, ObSeq, Request) -> - is_record(Content, coap_content) orelse error("Content must be a #coap_content!"), + is_record(Content, coap_content) orelse + error("Content must be a #coap_content!"), is_list(Host) orelse error("Host is not a string"), {ok, IpAddr} = inet:getaddr(Host, inet), @@ -1915,12 +2069,13 @@ test_send_coap_notif(UdpSock, Host, Port, Content, ObSeq, Request) -> ok = gen_udp:send(UdpSock, IpAddr, Port, NotifBinary). std_register(UdpSock, Epn, ObjectList, MsgId1, RespTopic) -> - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, payload = ObjectList}, - [], - MsgId1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=345&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, payload = ObjectList}, + [], + MsgId1), #coap_message{method = {ok,created}} = test_recv_coap_response(UdpSock), test_recv_mqtt_response(RespTopic), timer:sleep(100). @@ -1978,8 +2133,11 @@ sprintf(Format, Args) -> lists:flatten(io_lib:format(Format, Args)). response(Code, #coap_content{content_format = Format, payload = Payload}, Req) -> - #coap_message{options = Opts} = Msg = emqx_coap_message:response(Code, Payload, Req), + Msg = #coap_message{options = Opts} + = emqx_coap_message:response(Code, Payload, Req), Msg#coap_message{options = Opts#{content_format => Format}}. -request(Type, Method, #coap_content{content_format = Format, payload = Payload}, Opts) -> - emqx_coap_message:request(Type, Method, Payload, [{content_format, Format} | Opts]). +request(Type, Method, #coap_content{content_format = Format, + payload = Payload}, Opts) -> + emqx_coap_message:request(Type, Method, + Payload, [{content_format, Format} | Opts]). diff --git a/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl b/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl index 8f11bca78..babf9d36c 100644 --- a/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl @@ -110,8 +110,11 @@ t_lookup_cmd_read(Config) -> test_send_coap_request( UdpSock, post, sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, + #coap_content{ + content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">> + }, [], MsgId1), #coap_message{method = Method1} = test_recv_coap_response(UdpSock), @@ -141,7 +144,14 @@ t_lookup_cmd_read(Config) -> ?LOGT("LwM2M client got ~p", [Request2]), timer:sleep(50), - test_send_coap_response(UdpSock, "127.0.0.1", ?PORT, {ok, content}, #coap_content{content_format = <<"text/plain">>, payload = <<"EMQ">>}, Request2, true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"text/plain">>, payload = <<"EMQ">>}, + Request2, + true), timer:sleep(200), normal_received_request(Epn, <<"/3/0/0">>, <<"read">>). @@ -177,13 +187,14 @@ t_lookup_cmd_discover(Config) -> timer:sleep(50), PayloadDiscover = <<";dim=8;pmin=10;pmax=60;gt=50;lt=42.2,">>, - test_send_coap_response(UdpSock, - "127.0.0.1", - ?PORT, - {ok, content}, - #coap_content{content_format = <<"application/link-format">>, payload = PayloadDiscover}, - Request2, - true), + test_send_coap_response( + UdpSock, + "127.0.0.1", + ?PORT, + {ok, content}, + #coap_content{content_format = <<"application/link-format">>, payload = PayloadDiscover}, + Request2, + true), timer:sleep(200), discover_received_request(Epn, <<"/3/0/7">>, <<"discover">>). diff --git a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl index d51eaaad6..179471127 100644 --- a/apps/emqx_gateway/test/emqx_stomp_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_stomp_SUITE.erl @@ -87,35 +87,36 @@ t_connect(_) -> %% Connect will be failed, because of bad login or passcode %% FIXME: Waiting for authentication works - %with_connection(fun(Sock) -> - % gen_tcp:send(Sock, serialize(<<"CONNECT">>, - % [{<<"accept-version">>, ?STOMP_VER}, - % {<<"host">>, <<"127.0.0.1:61613">>}, - % {<<"login">>, <<"admin">>}, - % {<<"passcode">>, <<"admin">>}, - % {<<"heart-beat">>, <<"1000,2000">>}])), - % {ok, Data} = gen_tcp:recv(Sock, 0), - % {ok, #stomp_frame{command = <<"ERROR">>, - % headers = _, - % body = <<"Login or passcode error!">>}, _, _} = - % parse(Data) - % end), + %with_connection( + % fun(Sock) -> + % gen_tcp:send(Sock, serialize(<<"CONNECT">>, + % [{<<"accept-version">>, ?STOMP_VER}, + % {<<"host">>, <<"127.0.0.1:61613">>}, + % {<<"login">>, <<"admin">>}, + % {<<"passcode">>, <<"admin">>}, + % {<<"heart-beat">>, <<"1000,2000">>}])), + % {ok, Data} = gen_tcp:recv(Sock, 0), + % {ok, Frame, _, _} = parse(Data), + % #stomp_frame{command = <<"ERROR">>, + % headers = _, + % body = <<"Login or passcode error!">>} = Frame + % end), %% Connect will be failed, because of bad version with_connection(fun(Sock) -> - gen_tcp:send(Sock, serialize(<<"CONNECT">>, - [{<<"accept-version">>, <<"2.0,2.1">>}, - {<<"host">>, <<"127.0.0.1:61613">>}, - {<<"login">>, <<"guest">>}, - {<<"passcode">>, <<"guest">>}, - {<<"heart-beat">>, <<"1000,2000">>}])), + gen_tcp:send(Sock, + serialize(<<"CONNECT">>, + [{<<"accept-version">>, <<"2.0,2.1">>}, + {<<"host">>, <<"127.0.0.1:61613">>}, + {<<"login">>, <<"guest">>}, + {<<"passcode">>, <<"guest">>}, + {<<"heart-beat">>, <<"1000,2000">>}])), {ok, Data} = gen_tcp:recv(Sock, 0), - {ok, - #stomp_frame{command = <<"ERROR">>, - headers = _, - body = <<"Login Failed: Supported protocol versions < 1.2">>}, - _, - _ } = parse(Data) + {ok, Frame, _, _} = parse(Data), + #stomp_frame{ + command = <<"ERROR">>, + headers = _, + body = <<"Login Failed: Supported protocol versions < 1.2">>} = Frame end). t_heartbeat(_) -> @@ -407,7 +408,7 @@ t_rest_clienit_info(_) -> %% kickout {204, _} = request(delete, ClientPath), - ignored = gen_server:call(?CM, ignore, infinity). % sync + ignored = gen_server:call(emqx_cm, ignore, infinity), % sync ok = emqx_pool:flush_async_tasks(), {200, Clients2} = request(get, "/gateway/stomp/clients"), ?assertEqual(0, length(maps:get(data, Clients2))) diff --git a/elvis.config b/elvis.config index 30178622a..fb8ee9df1 100644 --- a/elvis.config +++ b/elvis.config @@ -17,7 +17,8 @@ {elvis_style, operator_spaces, #{rules => [{right, "|"}, {left, "|"}, {right, "||"}, - {left, "||"}]}} + {left, "||"}]}}, + {elvis_style, dont_repeat_yourself, #{ min_complexity => 20 }} ] }, #{dirs => ["test", "apps/**/test"], From ad2dbb5a493bf3d2a4c6e1700921aae455391160 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Mon, 15 Nov 2021 16:03:18 +0800 Subject: [PATCH 12/12] chore(gw-sn): append messge headers --- apps/emqx_authz/test/emqx_authz_SUITE.erl | 6 +- .../test/emqx_authz_api_mnesia_SUITE.erl | 6 +- .../test/emqx_authz_api_settings_SUITE.erl | 6 +- .../test/emqx_authz_api_sources_SUITE.erl | 6 +- .../emqx_authz/test/emqx_authz_http_SUITE.erl | 6 +- .../test/emqx_authz_mnesia_SUITE.erl | 6 +- .../test/emqx_authz_mongodb_SUITE.erl | 6 +- .../test/emqx_authz_mysql_SUITE.erl | 6 +- .../test/emqx_authz_postgresql_SUITE.erl | 6 +- .../test/emqx_authz_redis_SUITE.erl | 6 +- .../emqx_authz/test/emqx_authz_rule_SUITE.erl | 6 +- .../coap/handler/emqx_coap_pubsub_handler.erl | 1 + .../src/lwm2m/emqx_lwm2m_session.erl | 1 + .../src/mqttsn/emqx_sn_channel.erl | 28 +++++--- .../test/emqx_lwm2m_api_SUITE.erl | 71 ++++++++++--------- 15 files changed, 115 insertions(+), 52 deletions(-) diff --git a/apps/emqx_authz/test/emqx_authz_SUITE.erl b/apps/emqx_authz/test/emqx_authz_SUITE.erl index df4c904c3..b4c9841f8 100644 --- a/apps/emqx_authz/test/emqx_authz_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_SUITE.erl @@ -39,7 +39,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl index 737a089a2..b4a8f2756 100644 --- a/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_mnesia_SUITE.erl @@ -39,7 +39,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_authz, emqx_conf]), ok. diff --git a/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl index 5ad8f1f29..cf1110a2a 100644 --- a/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_settings_SUITE.erl @@ -39,7 +39,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_authz, emqx_conf]), ok. diff --git a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl index 4fbbed84d..94d1d0995 100644 --- a/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_sources_SUITE.erl @@ -110,7 +110,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_authz, emqx_conf]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_http_SUITE.erl b/apps/emqx_authz/test/emqx_authz_http_SUITE.erl index 848179687..441395282 100644 --- a/apps/emqx_authz/test/emqx_authz_http_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_http_SUITE.erl @@ -48,7 +48,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl index 875ff3d09..39579c1f5 100644 --- a/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mnesia_SUITE.erl @@ -36,7 +36,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), ok. diff --git a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl index 2e3edd42a..9c9cbad17 100644 --- a/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mongodb_SUITE.erl @@ -51,7 +51,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl b/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl index a2d264fc9..2fa01898b 100644 --- a/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_mysql_SUITE.erl @@ -53,7 +53,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl b/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl index 233701b34..9f963d926 100644 --- a/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_postgresql_SUITE.erl @@ -51,7 +51,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl b/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl index 4b76bcfab..02f70c8cc 100644 --- a/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_redis_SUITE.erl @@ -51,7 +51,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_resource]), meck:unload(emqx_resource), ok. diff --git a/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl b/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl index 630d42dce..8d1146ddb 100644 --- a/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_rule_SUITE.erl @@ -41,7 +41,11 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - {ok, _} = emqx_authz:update(replace, []), + {ok, _} = emqx:update_config( + [authorization], + #{<<"no_match">> => <<"allow">>, + <<"cache">> => #{<<"enable">> => <<"true">>}, + <<"sources">> => []}), emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), ok. diff --git a/apps/emqx_gateway/src/coap/handler/emqx_coap_pubsub_handler.erl b/apps/emqx_gateway/src/coap/handler/emqx_coap_pubsub_handler.erl index d1d73e9b9..76d065523 100644 --- a/apps/emqx_gateway/src/coap/handler/emqx_coap_pubsub_handler.erl +++ b/apps/emqx_gateway/src/coap/handler/emqx_coap_pubsub_handler.erl @@ -56,6 +56,7 @@ handle_method(post, Topic, #coap_message{payload = Payload} = Msg, Ctx, CInfo) - #{clientid := ClientId} = CInfo, MountTopic = mount(CInfo, Topic), QOS = get_publish_qos(Msg), + %% TODO: Append message metadata into headers MQTTMsg = emqx_message:make(ClientId, QOS, MountTopic, Payload), MQTTMsg2 = apply_publish_opts(Msg, MQTTMsg), _ = emqx_broker:publish(MQTTMsg2), diff --git a/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_session.erl b/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_session.erl index f59ec219e..950b0a5e0 100644 --- a/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_session.erl +++ b/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_session.erl @@ -603,6 +603,7 @@ send_to_mqtt(Ctx, EventType, Payload, {Topic, Qos}, proto_publish(Topic, Payload, Qos, Headers, WithContext, #session{endpoint_name = Epn} = Session) -> MountedTopic = mount(Topic, Session), + %% TODO: Append message metadata into headers Msg = emqx_message:make(Epn, Qos, MountedTopic, emqx_json:encode(Payload), #{}, Headers), WithContext(publish, [MountedTopic, Msg]), diff --git a/apps/emqx_gateway/src/mqttsn/emqx_sn_channel.erl b/apps/emqx_gateway/src/mqttsn/emqx_sn_channel.erl index 550f89413..9c2a15593 100644 --- a/apps/emqx_gateway/src/mqttsn/emqx_sn_channel.erl +++ b/apps/emqx_gateway/src/mqttsn/emqx_sn_channel.erl @@ -790,16 +790,26 @@ check_pub_authz({TopicName, _Flags, _Data}, end. convert_pub_to_msg({TopicName, Flags, Data}, - Channel = #channel{ - clientinfo = #{clientid := ClientId}}) -> + Channel = #channel{clientinfo = #{clientid := ClientId}}) -> #mqtt_sn_flags{qos = QoS, dup = Dup, retain = Retain} = Flags, NewQoS = get_corrected_qos(QoS), - Message = emqx_message:make(ClientId, NewQoS, TopicName, Data), - NMessage = emqx_message:set_flags( - #{dup => Dup, retain => Retain}, - Message - ), - {ok, NMessage, Channel}. + Message = put_message_headers( + emqx_message:make( + ClientId, NewQoS, TopicName, Data, + #{dup => Dup, retain => Retain}, #{}), Channel), + {ok, Message, Channel}. + +put_message_headers(Msg, #channel{ + conninfo = #{proto_ver := ProtoVer}, + clientinfo = #{ + protocol := Protocol, + username := Username, + peerhost := PeerHost}}) -> + emqx_message:set_headers( + #{proto_ver => ProtoVer, + protocol => Protocol, + username => Username, + peerhost => PeerHost}, Msg). get_corrected_qos(?QOS_NEG1) -> ?QOS_0; get_corrected_qos(QoS) -> QoS. @@ -1307,7 +1317,7 @@ ensure_disconnected(Reason, Channel = #channel{ mabye_publish_will_msg(Channel = #channel{will_msg = undefined}) -> Channel; mabye_publish_will_msg(Channel = #channel{will_msg = WillMsg}) -> - ok = publish_will_msg(WillMsg), + ok = publish_will_msg(put_message_headers(WillMsg, Channel)), Channel#channel{will_msg = undefined}. publish_will_msg(Msg) -> diff --git a/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl b/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl index babf9d36c..85975d37b 100644 --- a/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl +++ b/apps/emqx_gateway/test/emqx_lwm2m_api_SUITE.erl @@ -107,16 +107,16 @@ t_lookup_cmd_read(Config) -> emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), timer:sleep(200), %% step 1, device register ... - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), - #coap_content{ - content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543," - ",,">> - }, - [], - MsgId1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), + #coap_content{ + content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId1), #coap_message{method = Method1} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method1), @@ -192,7 +192,8 @@ t_lookup_cmd_discover(Config) -> "127.0.0.1", ?PORT, {ok, content}, - #coap_content{content_format = <<"application/link-format">>, payload = PayloadDiscover}, + #coap_content{content_format = <<"application/link-format">>, + payload = PayloadDiscover}, Request2, true), timer:sleep(200), @@ -206,13 +207,15 @@ t_read(Config) -> emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), timer:sleep(200), %% step 1, device register ... - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId1), #coap_message{method = Method1} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method1), @@ -236,13 +239,15 @@ t_write(Config) -> emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), timer:sleep(200), %% step 1, device register ... - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId1), #coap_message{method = Method1} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method1), @@ -268,13 +273,15 @@ t_observe(Config) -> emqtt:subscribe(?config(emqx_c, Config), RespTopic, qos0), timer:sleep(200), %% step 1, device register ... - test_send_coap_request( UdpSock, - post, - sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), - #coap_content{content_format = <<"text/plain">>, - payload = <<";rt=\"oma.lwm2m\";ct=11543,,,">>}, - [], - MsgId1), + test_send_coap_request( + UdpSock, + post, + sprintf("coap://127.0.0.1:~b/rd?ep=~ts<=600&lwm2m=1", [?PORT, Epn]), + #coap_content{content_format = <<"text/plain">>, + payload = <<";rt=\"oma.lwm2m\";ct=11543," + ",,">>}, + [], + MsgId1), #coap_message{method = Method1} = test_recv_coap_response(UdpSock), ?assertEqual({ok,created}, Method1),