Skip to content

Commit

Permalink
Merge pull request #4225 from esl/fetch-specific-msgs-mam
Browse files Browse the repository at this point in the history
Update version of XEP-0313: Message Archive Management pt. 2
  • Loading branch information
chrzaszcz authored Feb 27, 2024
2 parents b7ce0f9 + db4ed10 commit 0478cfb
Show file tree
Hide file tree
Showing 16 changed files with 359 additions and 51 deletions.
168 changes: 165 additions & 3 deletions big_tests/tests/mam_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
server_returns_item_not_found_for_before_filter_with_nonexistent_id/1,
server_returns_item_not_found_for_after_filter_with_nonexistent_id/1,
server_returns_item_not_found_for_after_filter_with_invalid_id/1,
server_returns_item_not_found_for_ids_filter_with_nonexistent_id/1,
muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id/1,
%% complete_flag_cases tests
before_complete_false_last5/1,
before_complete_false_before10/1,
Expand All @@ -120,6 +122,10 @@
offline_message/1,
nostore_hint/1,
querying_for_all_messages_with_jid/1,
query_messages_by_ids/1,
simple_query_messages_by_ids/1,
muc_query_messages_by_ids/1,
muc_simple_query_messages_by_ids/1,
muc_querying_for_all_messages/1,
muc_querying_for_all_messages_with_jid/1,
muc_light_service_discovery_stored_in_pm/1,
Expand Down Expand Up @@ -181,6 +187,8 @@
stanza_archive_request/2,
stanza_text_search_archive_request/3,
stanza_include_groupchat_request/3,
stanza_fetch_by_id_request/3,
stanza_fetch_by_id_request/4,
stanza_date_range_archive_request_not_empty/3,
wait_archive_respond/1,
wait_for_complete_archive_response/3,
Expand Down Expand Up @@ -209,17 +217,21 @@
wait_message_range/3,
wait_message_range/5,
message_id/2,
get_pre_generated_msgs_ids/2,
get_received_msgs_ids/1,
stanza_prefs_set_request/4,
stanza_prefs_get_request/1,
stanza_query_get_request/1,
parse_prefs_result_iq/1,
mam_ns_binary/0,
mam_ns_binary_v04/0,
mam_ns_binary_v06/0,
mam_ns_binary_extended/0,
retract_ns/0,
retract_tombstone_ns/0,
groupchat_field_ns/0,
groupchat_available_ns/0,
data_validate_ns/0,
make_alice_and_bob_friends/2,
run_prefs_case/6,
prefs_cases2/0,
Expand Down Expand Up @@ -353,7 +365,8 @@ basic_groups() ->
[{mam_metrics, [], mam_metrics_cases()},
{mam04, [parallel], mam_cases() ++ [retrieve_form_fields] ++ text_search_cases()},
{mam06, [parallel], mam_cases() ++ [retrieve_form_fields_extra_features]
++ stanzaid_cases() ++ retract_cases() ++ metadata_cases()},
++ stanzaid_cases() ++ retract_cases()
++ metadata_cases() ++ fetch_specific_msgs_cases()},
{nostore, [parallel], nostore_cases()},
{archived, [parallel], archived_cases()},
{configurable_archiveid, [], configurable_archiveid_cases()},
Expand All @@ -373,7 +386,7 @@ basic_groups() ->
{muc_all, [parallel],
[{muc04, [parallel], muc_cases() ++ muc_text_search_cases()},
{muc06, [parallel], muc_cases() ++ muc_stanzaid_cases() ++ muc_retract_cases()
++ muc_metadata_cases()},
++ muc_metadata_cases() ++ muc_fetch_specific_msgs_cases()},
{muc_configurable_archiveid, [], muc_configurable_archiveid_cases()},
{muc_rsm_all, [parallel],
[{muc_rsm04, [parallel], muc_rsm_cases()}]}]},
Expand Down Expand Up @@ -444,6 +457,13 @@ metadata_cases() ->
metadata_archive_request_one_message
].

fetch_specific_msgs_cases() ->
[
query_messages_by_ids,
simple_query_messages_by_ids,
server_returns_item_not_found_for_ids_filter_with_nonexistent_id
].

muc_text_search_cases() ->
[
muc_text_search_request
Expand Down Expand Up @@ -510,6 +530,13 @@ muc_metadata_cases() ->
muc_metadata_archive_request_one_message
].

muc_fetch_specific_msgs_cases() ->
[
muc_query_messages_by_ids,
muc_simple_query_messages_by_ids,
muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id
].

configurable_archiveid_cases() ->
[no_elements,
only_stanzaid,
Expand Down Expand Up @@ -828,6 +855,11 @@ init_per_testcase(C=filter_forwarded, Config) ->
init_per_testcase(C=querying_for_all_messages_with_jid, Config) ->
Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]),
escalus:init_per_testcase(C, bootstrap_archive(Config1));
init_per_testcase(C, Config) when C =:= query_messages_by_ids;
C =:= simple_query_messages_by_ids;
C =:= server_returns_item_not_found_for_ids_filter_with_nonexistent_id ->
Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]),
escalus:init_per_testcase(C, bootstrap_archive(Config1));
init_per_testcase(C=archived, Config) ->
Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]),
escalus:init_per_testcase(C, Config1);
Expand All @@ -846,6 +878,11 @@ init_per_testcase(C=offline_message, Config) ->
escalus:init_per_testcase(C, Config1);
init_per_testcase(C=nostore_hint, Config) ->
escalus:init_per_testcase(C, Config);
init_per_testcase(C, Config) when C =:= muc_query_messages_by_ids;
C =:= muc_simple_query_messages_by_ids;
C =:= muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id ->
Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]),
escalus:init_per_testcase(C, muc_bootstrap_archive(start_alice_room(Config1)));
init_per_testcase(C=muc_querying_for_all_messages, Config) ->
Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]),
escalus:init_per_testcase(C,
Expand Down Expand Up @@ -1056,6 +1093,11 @@ end_per_testcase(C=muc_show_x_user_to_moderators_in_anon_rooms, Config) ->
end_per_testcase(C=muc_show_x_user_for_your_own_messages_in_anon_rooms, Config) ->
destroy_room(Config),
escalus:end_per_testcase(C, Config);
end_per_testcase(C, Config) when C =:= muc_query_messages_by_ids;
C =:= muc_simple_query_messages_by_ids;
C =:= muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id ->
destroy_room(Config),
escalus:end_per_testcase(C, Config);
end_per_testcase(C=muc_querying_for_all_messages, Config) ->
destroy_room(Config),
escalus:end_per_testcase(C, Config);
Expand Down Expand Up @@ -1648,6 +1690,121 @@ querying_for_all_messages_with_jid(Config) ->
end,
escalus:story(Config, [{alice, 1}], F).

query_messages_by_ids(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Msgs = ?config(pre_generated_msgs, Config),
IDs = get_pre_generated_msgs_ids(Msgs, [5, 10]),

Stanza = stanza_fetch_by_id_request(P, <<"fetch-msgs-by-ids">>, IDs),
escalus:send(Alice, Stanza),

Result = wait_archive_respond(Alice),
ResultIDs = get_received_msgs_ids(Result),

assert_respond_size(2, Result),
?assert_equal(lists:sort(ResultIDs), lists:sort(IDs)),
ok
end,
escalus:story(Config, [{alice, 1}], F).

simple_query_messages_by_ids(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Msgs = ?config(pre_generated_msgs, Config),
[ID1, ID2, ID5] = get_pre_generated_msgs_ids(Msgs, [1, 2, 5]),

RSM = #rsm_in{max = 10, direction = 'after', id = ID1, simple = true},
Stanza = stanza_fetch_by_id_request(P, <<"simple-fetch-msgs-by-ids">>, [ID2, ID5], RSM),
escalus:send(Alice, Stanza),

Result = wait_archive_respond(Alice),
ParsedIQ = parse_result_iq(Result),
ResultIDs = get_received_msgs_ids(Result),

?assert_equal(lists:sort(ResultIDs), lists:sort([ID2, ID5])),
?assert_equal(undefined, ParsedIQ#result_iq.count),
?assert_equal(undefined, ParsedIQ#result_iq.first_index),
ok
end,
escalus:story(Config, [{alice, 1}], F).

server_returns_item_not_found_for_ids_filter_with_nonexistent_id(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Msgs = ?config(pre_generated_msgs, Config),
IDs = get_pre_generated_msgs_ids(Msgs, [3, 12]),
NonexistentID = <<"AV25E9SCO50K">>,

Stanza = stanza_fetch_by_id_request(P, <<"ids-not-found">>, IDs ++ [NonexistentID]),
escalus:send(Alice, Stanza),
Result = escalus:wait_for_stanza(Alice),

escalus:assert(is_iq_error, [Stanza], Result),
escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], Result),
ok
end,
escalus:story(Config, [{alice, 1}], F).

muc_query_messages_by_ids(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Room = ?config(room, Config),
Msgs = ?config(pre_generated_muc_msgs, Config),
IDs = get_pre_generated_msgs_ids(Msgs, [5, 10]),

Stanza = stanza_fetch_by_id_request(P, <<"fetch-muc-msgs-by-ids">>, IDs),
escalus:send(Alice, stanza_to_room(Stanza, Room)),

Result = wait_archive_respond(Alice),
ResultIDs = get_received_msgs_ids(Result),

assert_respond_size(2, Result),
?assert_equal(lists:sort(ResultIDs), lists:sort(IDs)),
ok
end,
escalus:story(Config, [{alice, 1}], F).

muc_simple_query_messages_by_ids(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Room = ?config(room, Config),
Msgs = ?config(pre_generated_muc_msgs, Config),
[ID1, ID2, ID5] = get_pre_generated_msgs_ids(Msgs, [1, 2, 5]),

RSM = #rsm_in{max = 10, direction = 'after', id = ID1, simple = true},
Stanza = stanza_fetch_by_id_request(P, <<"muc-simple-fetch-msgs-by-ids">>, [ID2, ID5], RSM),
escalus:send(Alice, stanza_to_room(Stanza, Room)),

Result = wait_archive_respond(Alice),
ParsedIQ = parse_result_iq(Result),
ResultIDs = get_received_msgs_ids(Result),

?assert_equal(lists:sort(ResultIDs), lists:sort([ID2, ID5])),
?assert_equal(undefined, ParsedIQ#result_iq.count),
?assert_equal(undefined, ParsedIQ#result_iq.first_index),
ok
end,
escalus:story(Config, [{alice, 1}], F).

muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Room = ?config(room, Config),
Msgs = ?config(pre_generated_muc_msgs, Config),
IDs = get_pre_generated_msgs_ids(Msgs, [3, 12]),
NonexistentID = <<"AV25E9SCO50K">>,

Stanza = stanza_fetch_by_id_request(P, <<"muc-ids-not-found">>, IDs ++ [NonexistentID]),
escalus:send(Alice, stanza_to_room(Stanza, Room)),
Result = escalus:wait_for_stanza(Alice),

escalus:assert(is_iq_error, [Stanza], Result),
escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], Result),
ok
end,
escalus:story(Config, [{alice, 1}], F).

muc_querying_for_all_messages(Config) ->
P = ?config(props, Config),
F = fun(Alice) ->
Expand Down Expand Up @@ -1943,9 +2100,13 @@ retrieve_form_fields_extra_features(ConfigIn) ->
escalus:assert(is_iq_with_ns, [Namespace], Res),
QueryEl = exml_query:subelement(Res, <<"query">>),
XEl = exml_query:subelement(QueryEl, <<"x">>),
IDsEl = exml_query:subelement_with_attr(XEl, <<"var">>, <<"ids">>),
ValidateEl = exml_query:path(IDsEl, [{element_with_ns, <<"validate">>, data_validate_ns()},
{element, <<"open">>}]),
escalus:assert(has_field_with_type, [<<"before-id">>, <<"text-single">>], XEl),
escalus:assert(has_field_with_type, [<<"after-id">>, <<"text-single">>], XEl),
escalus:assert(has_field_with_type, [<<"include-groupchat">>, <<"boolean">>], XEl)
escalus:assert(has_field_with_type, [<<"include-groupchat">>, <<"boolean">>], XEl),
?assertNotEqual(ValidateEl, undefined)
end).

archived(Config) ->
Expand Down Expand Up @@ -3406,6 +3567,7 @@ discover_features(Config, Client, Service) ->
escalus:assert(is_iq_result, Stanza),
escalus:assert(has_feature, [mam_ns_binary_v04()], Stanza),
escalus:assert(has_feature, [mam_ns_binary_v06()], Stanza),
escalus:assert(has_feature, [mam_ns_binary_extended()], Stanza),
escalus:assert(has_feature, [retract_ns()], Stanza),
check_include_groupchat_features(Stanza,
?config(configuration, Config),
Expand Down
Loading

0 comments on commit 0478cfb

Please sign in to comment.