Skip to content

Commit

Permalink
Merge pull request #4083 from esl/update-xep-0280
Browse files Browse the repository at this point in the history
Update xep 0280
  • Loading branch information
chrzaszcz authored Aug 10, 2023
2 parents 5854ea9 + 24b86c8 commit 23aa906
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 26 deletions.
122 changes: 106 additions & 16 deletions big_tests/tests/carboncopy_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,32 @@
-import(domain_helper, [domain/0]).

all() ->
[{group, all}].
[{group, one2one},
{group, muc}].

groups() ->
[{all, [parallel],
[discovering_support,
enabling_carbons,
disabling_carbons,
avoiding_carbons,
non_enabled_clients_dont_get_sent_carbons,
non_enabled_clients_dont_get_received_carbons,
enabled_single_resource_doesnt_get_carbons,
unavailable_resources_dont_get_carbons,
dropped_client_doesnt_create_duplicate_carbons,
prop_forward_received_chat_messages,
prop_forward_sent_chat_messages,
prop_normal_routing_to_bare_jid
]}].
[{one2one, [parallel],
[discovering_support,
enabling_carbons,
disabling_carbons,
avoiding_carbons,
non_enabled_clients_dont_get_sent_carbons,
non_enabled_clients_dont_get_received_carbons,
enabled_single_resource_doesnt_get_carbons,
unavailable_resources_dont_get_carbons,
dropped_client_doesnt_create_duplicate_carbons,
prop_forward_received_chat_messages,
prop_forward_sent_chat_messages,
prop_normal_routing_to_bare_jid,
chat_message_is_carbon_copied,
normal_message_with_body_is_carbon_copied,
normal_message_with_receipt_is_carbon_copied,
normal_message_with_csn_is_carbon_copied,
normal_message_with_chat_marker_is_carbon_copied]},
{muc, [parallel],
[group_chat_is_not_carbon_copied,
local_user_to_muc_participant_is_carbon_copied,
muc_participant_to_local_user_is_not_carbon_copied]}].

%%%===================================================================
%%% Overall setup/teardown
Expand All @@ -40,6 +49,18 @@ end_per_suite(C) ->
escalus_fresh:clean(),
escalus:end_per_suite(C).

init_per_group(muc, Config) ->
muc_helper:load_muc(Config),
Config;
init_per_group(_GroupName, Config) ->
Config.

end_per_group(muc, Config) ->
muc_helper:unload_muc(),
Config;
end_per_group(_GroupName, Config) ->
Config.

%%%===================================================================
%%% Testcase specific setup/teardown
%%%===================================================================
Expand Down Expand Up @@ -150,7 +171,7 @@ unavailable_resources_dont_get_carbons(Config) ->
Body2 = <<"carbonated">>,
escalus_client:send(Bob, escalus_stanza:chat_to(Alice2, Body2)),
wait_for_message_with_body(Alice2, Body2),
carboncopy_helper:wait_for_carbon_with_body(Alice1, Body2, #{from => Bob, to => Alice2})
carboncopy_helper:wait_for_carbon_chat_with_body(Alice1, Body2, #{from => Bob, to => Alice2})
end).

dropped_client_doesnt_create_duplicate_carbons(Config) ->
Expand Down Expand Up @@ -201,6 +222,75 @@ prop_normal_routing_to_bare_jid(Config) ->
Msg)
end))).

chat_message_is_carbon_copied(Config) ->
message_is_carbon_copied(Config, fun carboncopy_helper:chat_message_with_body/1).

normal_message_with_body_is_carbon_copied(Config) ->
message_is_carbon_copied(Config, fun carboncopy_helper:normal_message_with_body/1).

normal_message_with_receipt_is_carbon_copied(Config) ->
message_is_carbon_copied(Config, fun carboncopy_helper:normal_message_with_receipt/1).

normal_message_with_csn_is_carbon_copied(Config) ->
message_is_carbon_copied(Config, fun carboncopy_helper:normal_message_with_csn/1).

normal_message_with_chat_marker_is_carbon_copied(Config) ->
message_is_carbon_copied(Config, fun carboncopy_helper:normal_message_with_chat_marker/1).

message_is_carbon_copied(Config, StanzaFun) ->
escalus:fresh_story(
Config, [{alice, 2}, {bob, 1}],
fun(Alice1, Alice2, Bob) ->
enable_carbons([Alice1, Alice2]),
Body = <<"carbonated">>,
escalus_client:send(Bob, StanzaFun(#{to => Alice2, body => Body})),
AliceReceived = escalus_client:wait_for_stanza(Alice2),
escalus:assert(is_message, AliceReceived),
carboncopy_helper:wait_for_carbon_message(Alice1, #{from => Bob, to => Alice2})
end).

group_chat_is_not_carbon_copied(Config) ->
escalus:fresh_story(Config, [{alice, 2}, {bob, 1}],
fun(Alice1, Alice2, Bob) ->
enable_carbons([Alice1, Alice2]),
RoomCfg = muc_helper:start_fresh_room(Config, inbox_helper:extract_user_specs(Bob), <<"some_friendly_name">>, default),
muc_helper:enter_room(RoomCfg, [{Alice1, <<"cool_alice">>}, {Bob, <<"cool_bob">>}]),

Msg = <<"Hi Room!">>,
muc_helper:send_to_room(RoomCfg, Bob, Msg),
muc_helper:verify_message_received(RoomCfg, [Alice1, Bob], <<"cool_bob">>, Msg),
?assertEqual([], escalus_client:peek_stanzas(Alice2))
end).

local_user_to_muc_participant_is_carbon_copied(Config) ->
escalus:fresh_story(Config, [{alice, 2}, {bob, 1}],
fun(Alice1, Alice2, Bob) ->
enable_carbons([Alice1, Alice2]),
RoomCfg = muc_helper:start_fresh_room(Config, inbox_helper:extract_user_specs(Bob), <<"some_friendly_name">>, default),
muc_helper:enter_room(RoomCfg, [{Alice1, <<"cool_alice">>}, {Bob, <<"cool_bob">>}]),
RoomJid = proplists:get_value(room_jid, RoomCfg),
Body = <<"Hello!">>,
Stanza = escalus_stanza:chat_to(<<RoomJid/binary, "/cool_alice">>, Body),

escalus:send(Bob, Stanza),
escalus:wait_for_stanza(Alice1),
carboncopy_helper:wait_for_carbon_chat_with_body(Alice2, Body, #{from => <<RoomJid/binary, "/cool_bob">>, to => Alice1})
end).

muc_participant_to_local_user_is_not_carbon_copied(Config) ->
escalus:fresh_story(Config, [{alice, 2}, {bob, 1}],
fun(Alice1, Alice2, Bob) ->
enable_carbons([Alice1, Alice2]),
RoomCfg = muc_helper:start_fresh_room(Config, inbox_helper:extract_user_specs(Bob), <<"some_friendly_name">>, default),
muc_helper:enter_room(RoomCfg, [{Alice1, <<"cool_alice">>}, {Bob, <<"cool_bob">>}]),
RoomJid = proplists:get_value(room_jid, RoomCfg),
Body = <<"Hello!">>,
Stanza = escalus_stanza:chat(<<RoomJid/binary, "/cool_bob">>, Alice1, Body),

escalus:send(Bob, Stanza),
escalus:wait_for_stanza(Alice1),
?assertEqual([], escalus_client:peek_stanzas(Alice2))
end).

%%
%% Test scenarios w/assertions
Expand Down
78 changes: 73 additions & 5 deletions big_tests/tests/carboncopy_helper.erl
Original file line number Diff line number Diff line change
@@ -1,8 +1,76 @@
-module(carboncopy_helper).
-export([wait_for_carbon_with_body/3]).
-compile([export_all, nowarn_export_all]).

wait_for_carbon_with_body(Client, Body, #{from := From, to := To}) ->
-include_lib("exml/include/exml.hrl").
-include_lib("escalus/include/escalus_xmlns.hrl").

wait_for_carbon_chat_with_body(Client, Body, #{from := From, to := To}) when is_binary(From) ->
escalus:assert(
is_forwarded_received_message,
[From, escalus_client:full_jid(To), Body],
escalus_client:wait_for_stanza(Client)
);

wait_for_carbon_chat_with_body(Client, Body, #{from := From, to := To}) ->
escalus:assert(
is_forwarded_received_message,
[escalus_client:full_jid(From), escalus_client:full_jid(To), Body],
escalus_client:wait_for_stanza(Client)).
is_forwarded_received_message,
[escalus_client:full_jid(From), escalus_client:full_jid(To), Body],
escalus_client:wait_for_stanza(Client)
).

wait_for_carbon_message(Client, #{from := From, to := To}) ->
escalus:assert(
fun is_forwarded_received_message/3,
[escalus_client:full_jid(From), escalus_client:full_jid(To)],
escalus_client:wait_for_stanza(Client)
).

is_forwarded_received_message(From, To, Stanza) ->
Carbon = exml_query:subelement(Stanza, <<"received">>),
escalus_pred:has_ns(?NS_CARBONS_2, Carbon) andalso
is_forwarded_message(From, To, exml_query:subelement(Carbon, <<"forwarded">>)).

is_forwarded_message(From, To, Stanza) ->
escalus_pred:has_ns(?NS_FORWARD_0, Stanza) andalso
is_message_from_to(From, To, exml_query:subelement(Stanza, <<"message">>)).

is_message_from_to(From, To, #xmlel{attrs = Attrs} = Stanza) ->
escalus_pred:is_message(Stanza) andalso
escalus_compat:bin(From) == proplists:get_value(<<"from">>, Attrs) andalso
escalus_compat:bin(To) == proplists:get_value(<<"to">>, Attrs).

chat_message_with_body(#{to := User, body := Body}) ->
escalus_stanza:chat_to(User, Body).

normal_message_with_body(#{to := User, body := Body}) ->
escalus_stanza:message(Body, #{type => <<"normal">>, to => User}).

normal_message_with_receipt(#{to := User}) ->
Msg = #xmlel{
name = <<"message">>,
attrs = [
{<<"type">>, <<"normal">>},
{<<"from">>, escalus_utils:get_jid(User)},
{<<"id">>, escalus_stanza:id()}
]
},
escalus_stanza:receipt_conf(Msg).

normal_message_with_csn(#{to := User}) ->
#xmlel{
name = <<"message">>,
attrs = [
{<<"type">>, <<"normal">>},
{<<"to">>, escalus_utils:get_jid(User)}
],
children = [
#xmlel{
name = <<"stateName">>,
attrs = [{<<"xmlns">>, ?NS_CHATSTATES}]
}
]
}.

normal_message_with_chat_marker(#{to := User}) ->
Msg = escalus_stanza:chat_marker(User, <<"received">>, escalus_stanza:id()),
escalus_stanza:setattr(Msg, <<"type">>, <<"normal">>).
6 changes: 3 additions & 3 deletions big_tests/tests/sm_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ carboncopy_works(Config) ->
mongoose_helper:enable_carbons([Alice1, Alice]),
escalus_connection:send(Bob, escalus_stanza:chat_to(Alice1, <<"msg-4">>)),
sm_helper:wait_for_messages(Alice1, [<<"msg-4">>]),
carboncopy_helper:wait_for_carbon_with_body(Alice, <<"msg-4">>, #{from => Bob, to => Alice1})
carboncopy_helper:wait_for_carbon_chat_with_body(Alice, <<"msg-4">>, #{from => Bob, to => Alice1})
end).

carboncopy_works_after_resume(Config) ->
Expand All @@ -977,12 +977,12 @@ carboncopy_works_after_resume(Config) ->
%% Direct send
escalus_connection:send(Bob, escalus_stanza:chat_to(Alice1, <<"msg-4">>)),
sm_helper:wait_for_messages(Alice1, [<<"msg-4">>]),
carboncopy_helper:wait_for_carbon_with_body(Alice, <<"msg-4">>, #{from => Bob, to => Alice1}),
carboncopy_helper:wait_for_carbon_chat_with_body(Alice, <<"msg-4">>, #{from => Bob, to => Alice1}),
escalus_connection:stop(Alice)
end).

wait_for_carbon_with_bodies(Client, Texts, Params) ->
[carboncopy_helper:wait_for_carbon_with_body(Client, Text, Params) || Text <- Texts].
[carboncopy_helper:wait_for_carbon_chat_with_body(Client, Text, Params) || Text <- Texts].

buffer_unacked_messages_and_die(Config, AliceSpec, Bob, Texts) ->
F = fun(_Client) -> ok end,
Expand Down
9 changes: 7 additions & 2 deletions src/mod_carboncopy.erl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
%%%----------------------------------------------------------------------
-module (mod_carboncopy).
-author ('ecestari@process-one.net').
-xep([{xep, 280}, {version, "0.13.3"}, {legacy_versions, ["0.6"]}]).
-xep([{xep, 280}, {version, "1.0.1"}, {legacy_versions, ["0.6"]}]).
-behaviour(gen_mod).
-behaviour(mongoose_module_metrics).

Expand Down Expand Up @@ -180,7 +180,8 @@ is_chat(Packet) ->
case exml_query:attr(Packet, <<"type">>, <<"normal">>) of
<<"normal">> -> contains_body(Packet) orelse
contains_receipts(Packet) orelse
contains_csn(Packet);
contains_csn(Packet) orelse
contains_chat_markers(Packet);
<<"chat">> -> true;
_ -> false
end.
Expand Down Expand Up @@ -226,6 +227,10 @@ contains_receipts(Packet) ->
contains_csn(Packet) ->
undefined =/= exml_query:subelement_with_ns(Packet, ?NS_CHATSTATES).

-spec contains_chat_markers(exml:element()) -> boolean().
contains_chat_markers(Packet) ->
undefined =/= exml_query:subelement_with_ns(Packet, ?NS_CHAT_MARKERS).

-spec is_carbon_private(exml:element()) -> boolean().
is_carbon_private(Packet) ->
[] =/= subelements_with_nss(Packet, <<"private">>, carbon_namespaces()).
Expand Down

0 comments on commit 23aa906

Please sign in to comment.