From 9f088bcb7fa50e1c9ba768e03726ef34007c4484 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Wed, 14 Apr 2021 19:35:08 +0800 Subject: [PATCH] test(proper): test message hooks --- .../emqx_exhook/test/emqx_exhook_demo_svr.erl | 54 ++- .../test/props/prop_exhook_hooks.erl | 402 +++++++++--------- 2 files changed, 244 insertions(+), 212 deletions(-) diff --git a/apps/emqx_exhook/test/emqx_exhook_demo_svr.erl b/apps/emqx_exhook/test/emqx_exhook_demo_svr.erl index 05fa07465..971295d61 100644 --- a/apps/emqx_exhook/test/emqx_exhook_demo_svr.erl +++ b/apps/emqx_exhook/test/emqx_exhook_demo_svr.erl @@ -179,18 +179,44 @@ on_client_disconnected(Req, Md) -> -spec on_client_authenticate(emqx_exhook_pb:client_authenticate_request(), grpc:metadata()) -> {ok, emqx_exhook_pb:valued_response(), grpc:metadata()} | {error, grpc_cowboy_h:error_response()}. -on_client_authenticate(Req, Md) -> +on_client_authenticate(#{clientinfo := #{username := Username}} = Req, Md) -> ?MODULE:in({?FUNCTION_NAME, Req}), %io:format("fun: ~p, req: ~0p~n", [?FUNCTION_NAME, Req]), - {ok, #{type => 'IGNORE'}, Md}. + %% some cases for testing + case Username of + <<"baduser">> -> + {ok, #{type => 'STOP_AND_RETURN', + value => {bool_result, false}}, Md}; + <<"gooduser">> -> + {ok, #{type => 'STOP_AND_RETURN', + value => {bool_result, true}}, Md}; + <<"normaluser">> -> + {ok, #{type => 'CONTINUE', + value => {bool_result, true}}, Md}; + _ -> + {ok, #{type => 'IGNORE'}, Md} + end. -spec on_client_check_acl(emqx_exhook_pb:client_check_acl_request(), grpc:metadata()) -> {ok, emqx_exhook_pb:valued_response(), grpc:metadata()} | {error, grpc_cowboy_h:error_response()}. -on_client_check_acl(Req, Md) -> +on_client_check_acl(#{clientinfo := #{username := Username}} = Req, Md) -> ?MODULE:in({?FUNCTION_NAME, Req}), %io:format("fun: ~p, req: ~0p~n", [?FUNCTION_NAME, Req]), - {ok, #{type => 'STOP_AND_RETURN', value => {bool_result, true}}, Md}. + %% some cases for testing + case Username of + <<"baduser">> -> + {ok, #{type => 'STOP_AND_RETURN', + value => {bool_result, false}}, Md}; + <<"gooduser">> -> + {ok, #{type => 'STOP_AND_RETURN', + value => {bool_result, true}}, Md}; + <<"normaluser">> -> + {ok, #{type => 'CONTINUE', + value => {bool_result, true}}, Md}; + _ -> + {ok, #{type => 'IGNORE'}, Md} + end. -spec on_client_subscribe(emqx_exhook_pb:client_subscribe_request(), grpc:metadata()) -> {ok, emqx_exhook_pb:empty_success(), grpc:metadata()} @@ -267,10 +293,26 @@ on_session_terminated(Req, Md) -> -spec on_message_publish(emqx_exhook_pb:message_publish_request(), grpc:metadata()) -> {ok, emqx_exhook_pb:valued_response(), grpc:metadata()} | {error, grpc_cowboy_h:error_response()}. -on_message_publish(Req, Md) -> +on_message_publish(#{message := #{from := From} = Msg} = Req, Md) -> ?MODULE:in({?FUNCTION_NAME, Req}), %io:format("fun: ~p, req: ~0p~n", [?FUNCTION_NAME, Req]), - {ok, #{}, Md}. + %% some cases for testing + case From of + <<"baduser">> -> + NMsg = Msg#{qos => 0, + topic => <<"">>, + payload => <<"">> + }, + {ok, #{type => 'STOP_AND_RETURN', + value => {message, NMsg}}, Md}; + <<"gooduser">> -> + NMsg = Msg#{topic => From, + payload => From}, + {ok, #{type => 'STOP_AND_RETURN', + value => {message, NMsg}}, Md}; + _ -> + {ok, #{type => 'IGNORE'}, Md} + end. -spec on_message_delivered(emqx_exhook_pb:message_delivered_request(), grpc:metadata()) -> {ok, emqx_exhook_pb:empty_success(), grpc:metadata()} diff --git a/apps/emqx_exhook/test/props/prop_exhook_hooks.erl b/apps/emqx_exhook/test/props/prop_exhook_hooks.erl index 9fcd66402..3e59cf5c6 100644 --- a/apps/emqx_exhook/test/props/prop_exhook_hooks.erl +++ b/apps/emqx_exhook/test/props/prop_exhook_hooks.erl @@ -44,20 +44,11 @@ prop_client_connect() -> ?ALL({ConnInfo, ConnProps}, {conninfo(), conn_properties()}, begin - _OutConnProps = emqx_hooks:run_fold('client.connect', [ConnInfo], ConnProps), + ok = emqx_hooks:run('client.connect', [ConnInfo, ConnProps]), {'on_client_connect', Resp} = emqx_exhook_demo_svr:take(), Expected = #{props => properties(ConnProps), - conninfo => - #{node => nodestr(), - clientid => maps:get(clientid, ConnInfo), - username => maybe(maps:get(username, ConnInfo, <<>>)), - peerhost => peerhost(ConnInfo), - sockport => sockport(ConnInfo), - proto_name => maps:get(proto_name, ConnInfo), - proto_ver => stringfy(maps:get(proto_ver, ConnInfo)), - keepalive => maps:get(keepalive, ConnInfo) - } + conninfo => from_conninfo(ConnInfo) }, ?assertEqual(Expected, Resp), true @@ -67,78 +58,86 @@ prop_client_connack() -> ?ALL({ConnInfo, Rc, AckProps}, {conninfo(), connack_return_code(), ack_properties()}, begin - _OutAckProps = emqx_hooks:run_fold('client.connack', [ConnInfo, Rc], AckProps), + ok = emqx_hooks:run('client.connack', [ConnInfo, Rc, AckProps]), {'on_client_connack', Resp} = emqx_exhook_demo_svr:take(), Expected = #{props => properties(AckProps), result_code => atom_to_binary(Rc, utf8), - conninfo => - #{node => nodestr(), - clientid => maps:get(clientid, ConnInfo), - username => maybe(maps:get(username, ConnInfo, <<>>)), - peerhost => peerhost(ConnInfo), - sockport => sockport(ConnInfo), - proto_name => maps:get(proto_name, ConnInfo), - proto_ver => stringfy(maps:get(proto_ver, ConnInfo)), - keepalive => maps:get(keepalive, ConnInfo) - } + conninfo => from_conninfo(ConnInfo) }, ?assertEqual(Expected, Resp), true end). prop_client_authenticate() -> - ?ALL({ClientInfo, AuthResult}, {clientinfo(), authresult()}, + ?ALL({ClientInfo0, AuthResult}, + {clientinfo(), authresult()}, begin - _OutAuthResult = emqx_hooks:run_fold('client.authenticate', [ClientInfo], AuthResult), + ClientInfo = inject_magic_into(username, ClientInfo0), + OutAuthResult = emqx_hooks:run_fold('client.authenticate', [ClientInfo], AuthResult), + ExpectedAuthResult = case maps:get(username, ClientInfo) of + <<"baduser">> -> + AuthResult#{ + auth_result => not_authorized, + anonymous => false}; + <<"gooduser">> -> + AuthResult#{ + auth_result => success, + anonymous => false}; + <<"normaluser">> -> + AuthResult#{ + auth_result => success, + anonymous => false}; + _ -> + case maps:get(auth_result, AuthResult) of + success -> + #{auth_result => success, + anonymous => false}; + _ -> + #{auth_result => not_authorized, + anonymous => false} + end + end, + ?assertEqual(ExpectedAuthResult, OutAuthResult), + {'on_client_authenticate', Resp} = emqx_exhook_demo_svr:take(), Expected = #{result => authresult_to_bool(AuthResult), - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true end). prop_client_check_acl() -> - ?ALL({ClientInfo, PubSub, Topic, Result}, - {clientinfo(), oneof([publish, subscribe]), topic(), oneof([allow, deny])}, + ?ALL({ClientInfo0, PubSub, Topic, Result}, + {clientinfo(), oneof([publish, subscribe]), + topic(), oneof([allow, deny])}, begin - _OutResult = emqx_hooks:run_fold('client.check_acl', [ClientInfo, PubSub, Topic], Result), + ClientInfo = inject_magic_into(username, ClientInfo0), + OutResult = emqx_hooks:run_fold( + 'client.check_acl', + [ClientInfo, PubSub, Topic], + Result), + ExpectedOutResult = case maps:get(username, ClientInfo) of + <<"baduser">> -> deny; + <<"gooduser">> -> allow; + <<"normaluser">> -> allow; + _ -> Result + end, + ?assertEqual(ExpectedOutResult, OutResult), + {'on_client_check_acl', Resp} = emqx_exhook_demo_svr:take(), Expected = #{result => aclresult_to_bool(Result), type => pubsub_to_enum(PubSub), topic => Topic, - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true end). - prop_client_connected() -> ?ALL({ClientInfo, ConnInfo}, {clientinfo(), conninfo()}, @@ -146,18 +145,7 @@ prop_client_connected() -> ok = emqx_hooks:run('client.connected', [ClientInfo, ConnInfo]), {'on_client_connected', Resp} = emqx_exhook_demo_svr:take(), Expected = - #{clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + #{clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -171,18 +159,7 @@ prop_client_disconnected() -> {'on_client_disconnected', Resp} = emqx_exhook_demo_svr:take(), Expected = #{reason => stringfy(Reason), - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -192,23 +169,12 @@ prop_client_subscribe() -> ?ALL({ClientInfo, SubProps, TopicTab}, {clientinfo(), sub_properties(), topictab()}, begin - _OutTopicTab = emqx_hooks:run_fold('client.subscribe', [ClientInfo, SubProps], TopicTab), + ok = emqx_hooks:run('client.subscribe', [ClientInfo, SubProps, TopicTab]), {'on_client_subscribe', Resp} = emqx_exhook_demo_svr:take(), Expected = #{props => properties(SubProps), topic_filters => topicfilters(TopicTab), - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -218,23 +184,12 @@ prop_client_unsubscribe() -> ?ALL({ClientInfo, UnSubProps, TopicTab}, {clientinfo(), unsub_properties(), topictab()}, begin - _OutTopicTab = emqx_hooks:run_fold('client.unsubscribe', [ClientInfo, UnSubProps], TopicTab), + ok = emqx_hooks:run('client.unsubscribe', [ClientInfo, UnSubProps, TopicTab]), {'on_client_unsubscribe', Resp} = emqx_exhook_demo_svr:take(), Expected = #{props => properties(UnSubProps), topic_filters => topicfilters(TopicTab), - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -246,18 +201,7 @@ prop_session_created() -> ok = emqx_hooks:run('session.created', [ClientInfo, SessInfo]), {'on_session_created', Resp} = emqx_exhook_demo_svr:take(), Expected = - #{clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + #{clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -272,18 +216,7 @@ prop_session_subscribed() -> Expected = #{topic => Topic, subopts => subopts(SubOpts), - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -297,18 +230,7 @@ prop_session_unsubscribed() -> {'on_session_unsubscribed', Resp} = emqx_exhook_demo_svr:take(), Expected = #{topic => Topic, - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -320,18 +242,7 @@ prop_session_resumed() -> ok = emqx_hooks:run('session.resumed', [ClientInfo, SessInfo]), {'on_session_resumed', Resp} = emqx_exhook_demo_svr:take(), Expected = - #{clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + #{clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -343,18 +254,7 @@ prop_session_discared() -> ok = emqx_hooks:run('session.discarded', [ClientInfo, SessInfo]), {'on_session_discarded', Resp} = emqx_exhook_demo_svr:take(), Expected = - #{clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + #{clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -366,18 +266,7 @@ prop_session_takeovered() -> ok = emqx_hooks:run('session.takeovered', [ClientInfo, SessInfo]), {'on_session_takeovered', Resp} = emqx_exhook_demo_svr:take(), Expected = - #{clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + #{clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), true @@ -391,21 +280,98 @@ prop_session_terminated() -> {'on_session_terminated', Resp} = emqx_exhook_demo_svr:take(), Expected = #{reason => stringfy(Reason), - clientinfo => - #{node => nodestr(), - clientid => maps:get(clientid, ClientInfo), - username => maybe(maps:get(username, ClientInfo, <<>>)), - password => maybe(maps:get(password, ClientInfo, <<>>)), - peerhost => ntoa(maps:get(peerhost, ClientInfo)), - sockport => maps:get(sockport, ClientInfo), - protocol => stringfy(maps:get(protocol, ClientInfo)), - mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), - is_superuser => maps:get(is_superuser, ClientInfo, false), - anonymous => maps:get(anonymous, ClientInfo, true) - } + clientinfo => from_clientinfo(ClientInfo) }, ?assertEqual(Expected, Resp), + true + end). +prop_message_publish() -> + ?ALL(Msg0, message(), + begin + Msg = emqx_message:from_map( + inject_magic_into(from, emqx_message:to_map(Msg0))), + OutMsg= emqx_hooks:run_fold('message.publish', [], Msg), + case emqx_topic:match(emqx_message:topic(Msg), <<"$SYS/#">>) of + true -> + ?assertEqual(Msg, OutMsg), + skip; + _ -> + ExpectedOutMsg = case emqx_message:from(Msg) of + <<"baduser">> -> + MsgMap = emqx_message:to_map(Msg), + emqx_message:from_map( + MsgMap#{qos => 0, + topic => <<"">>, + payload => <<"">> + }); + <<"gooduser">> = From -> + MsgMap = emqx_message:to_map(Msg), + emqx_message:from_map( + MsgMap#{topic => From, + payload => From + }); + _ -> Msg + end, + ?assertEqual(ExpectedOutMsg, OutMsg), + + {'on_message_publish', Resp} = emqx_exhook_demo_svr:take(), + Expected = + #{message => from_message(Msg) + }, + ?assertEqual(Expected, Resp) + end, + true + end). + +prop_message_dropped() -> + ?ALL({Msg, By, Reason}, {message(), hardcoded, shutdown_reason()}, + begin + ok = emqx_hooks:run('message.dropped', [Msg, By, Reason]), + case emqx_topic:match(emqx_message:topic(Msg), <<"$SYS/#">>) of + true -> skip; + _ -> + {'on_message_dropped', Resp} = emqx_exhook_demo_svr:take(), + Expected = + #{reason => stringfy(Reason), + message => from_message(Msg) + }, + ?assertEqual(Expected, Resp) + end, + true + end). + +prop_message_delivered() -> + ?ALL({ClientInfo, Msg}, {clientinfo(), message()}, + begin + ok = emqx_hooks:run('message.delivered', [ClientInfo, Msg]), + case emqx_topic:match(emqx_message:topic(Msg), <<"$SYS/#">>) of + true -> skip; + _ -> + {'on_message_delivered', Resp} = emqx_exhook_demo_svr:take(), + Expected = + #{clientinfo => from_clientinfo(ClientInfo), + message => from_message(Msg) + }, + ?assertEqual(Expected, Resp) + end, + true + end). + +prop_message_acked() -> + ?ALL({ClientInfo, Msg}, {clientinfo(), message()}, + begin + ok = emqx_hooks:run('message.acked', [ClientInfo, Msg]), + case emqx_topic:match(emqx_message:topic(Msg), <<"$SYS/#">>) of + true -> skip; + _ -> + {'on_message_acked', Resp} = emqx_exhook_demo_svr:take(), + Expected = + #{clientinfo => from_clientinfo(ClientInfo), + message => from_message(Msg) + }, + ?assertEqual(Expected, Resp) + end, true end). @@ -465,23 +431,39 @@ aclresult_to_bool(Result) -> pubsub_to_enum(publish) -> 'PUBLISH'; pubsub_to_enum(subscribe) -> 'SUBSCRIBE'. -%prop_message_publish() -> -% ?ALL({Msg, Env, Encode}, {message(), topic_filter_env()}, -% begin -% true -% end). -% -%prop_message_delivered() -> -% ?ALL({ClientInfo, Msg, Env, Encode}, {clientinfo(), message(), topic_filter_env()}, -% begin -% true -% end). -% -%prop_message_acked() -> -% ?ALL({ClientInfo, Msg, Env, Encode}, {clientinfo(), message()}, -% begin -% true -% end). +from_conninfo(ConnInfo) -> + #{node => nodestr(), + clientid => maps:get(clientid, ConnInfo), + username => maybe(maps:get(username, ConnInfo, <<>>)), + peerhost => peerhost(ConnInfo), + sockport => sockport(ConnInfo), + proto_name => maps:get(proto_name, ConnInfo), + proto_ver => stringfy(maps:get(proto_ver, ConnInfo)), + keepalive => maps:get(keepalive, ConnInfo) + }. + +from_clientinfo(ClientInfo) -> + #{node => nodestr(), + clientid => maps:get(clientid, ClientInfo), + username => maybe(maps:get(username, ClientInfo, <<>>)), + password => maybe(maps:get(password, ClientInfo, <<>>)), + peerhost => ntoa(maps:get(peerhost, ClientInfo)), + sockport => maps:get(sockport, ClientInfo), + protocol => stringfy(maps:get(protocol, ClientInfo)), + mountpoint => maybe(maps:get(mountpoint, ClientInfo, <<>>)), + is_superuser => maps:get(is_superuser, ClientInfo, false), + anonymous => maps:get(anonymous, ClientInfo, true) + }. + +from_message(Msg) -> + #{node => nodestr(), + id => emqx_guid:to_hexstr(emqx_message:id(Msg)), + qos => emqx_message:qos(Msg), + from => stringfy(emqx_message:from(Msg)), + topic => emqx_message:topic(Msg), + payload => emqx_message:payload(Msg), + timestamp => emqx_message:timestamp(Msg) + }. %%-------------------------------------------------------------------- %% Helper @@ -533,7 +515,15 @@ shutdown_reason() -> oneof([utf8(), {shutdown, emqx_ct_proper_types:limited_atom()}]). authresult() -> - #{auth_result => connack_return_code()}. + ?LET(RC, connack_return_code(), #{auth_result => RC}). -%topic_filter_env() -> -% oneof([{<<"#">>}, {undefined}, {topic()}]). +inject_magic_into(Key, Object) -> + case castspell() of + muggles -> Object; + Spell -> + Object#{Key => Spell} + end. + +castspell() -> + L = [<<"baduser">>, <<"gooduser">>, <<"normaluser">>, muggles], + lists:nth(rand:uniform(length(L)), L).