mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
226 lines
7.5 KiB
Erlang
226 lines
7.5 KiB
Erlang
%% SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
-module(guild_connect_async_tests).
|
|
-typing([eqwalizer]).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
finalize_pending_session_tracks_connected_user_test() ->
|
|
SessionId = <<"s1">>,
|
|
UserId = 10,
|
|
Attempt = 3,
|
|
State0 = finalize_state(SessionId, UserId, Attempt, true, #{}, sets:new(), #{UserId => 1}),
|
|
State1 = finalize_session(SessionId, UserId, Attempt, State0),
|
|
?assertEqual(#{UserId => 1}, maps:get(user_session_counts, State1)),
|
|
?assertEqual(true, sets:is_element(UserId, maps:get(connected_user_ids, State1))),
|
|
?assertEqual(2, maps:get(UserId, maps:get(presence_subscriptions, State1))),
|
|
flush_connect_result().
|
|
|
|
finalize_connected_session_does_not_double_count_test() ->
|
|
SessionId = <<"s1">>,
|
|
UserId = 10,
|
|
Attempt = 4,
|
|
State0 = finalize_state(
|
|
SessionId,
|
|
UserId,
|
|
Attempt,
|
|
false,
|
|
#{UserId => 1},
|
|
sets:from_list([UserId]),
|
|
#{UserId => 1}
|
|
),
|
|
State1 = finalize_session(SessionId, UserId, Attempt, State0),
|
|
?assertEqual(#{UserId => 1}, maps:get(user_session_counts, State1)),
|
|
?assertEqual(true, sets:is_element(UserId, maps:get(connected_user_ids, State1))),
|
|
?assertEqual(1, maps:get(UserId, maps:get(presence_subscriptions, State1))),
|
|
flush_connect_result().
|
|
|
|
finalize_not_member_discards_pending_session_test() ->
|
|
SessionId = <<"s-nm">>,
|
|
UserId = 777,
|
|
Attempt = 1,
|
|
Pending = #{
|
|
session_id => SessionId,
|
|
user_id => UserId,
|
|
pid => self(),
|
|
mref => make_ref(),
|
|
pending_connect => true,
|
|
active_guilds => sets:new()
|
|
},
|
|
State0 = #{
|
|
id => 42,
|
|
sessions => #{SessionId => Pending},
|
|
session_connect_pending => #{SessionId => Attempt},
|
|
session_connect_inflight => 1,
|
|
session_connect_queue => queue:new(),
|
|
user_session_counts => #{},
|
|
connected_user_ids => sets:new(),
|
|
presence_subscriptions => #{}
|
|
},
|
|
State1 = guild_connect_async:finalize_session_connect_async(
|
|
SessionId,
|
|
Attempt,
|
|
{error, not_member},
|
|
finalize_computed(SessionId, UserId),
|
|
State0
|
|
),
|
|
?assertEqual(#{}, maps:get(sessions, State1)),
|
|
?assertEqual(0, maps:get(UserId, maps:get(user_session_counts, State1), 0)),
|
|
?assertNot(sets:is_element(UserId, maps:get(connected_user_ids, State1))),
|
|
receive
|
|
{guild_connect_result, 42, Attempt, {error, not_member}} -> ok
|
|
after 0 ->
|
|
?assert(false, not_member_result_not_relayed)
|
|
end.
|
|
|
|
enqueue_session_connect_async_drops_oldest_waiter_when_queue_full_test() ->
|
|
OldSessionId = <<"s-old">>,
|
|
NewSessionId = <<"s-new">>,
|
|
GuildId = 42,
|
|
OldAttempt = 1,
|
|
NewAttempt = 2,
|
|
State0 = saturated_connect_state(GuildId, OldSessionId, OldAttempt, 1),
|
|
Request = connect_request(NewSessionId, 20),
|
|
State1 = guild_connect_async:enqueue_session_connect_async(
|
|
GuildId, NewAttempt, Request, #{}, State0
|
|
),
|
|
Pending = maps:get(session_connect_pending, State1),
|
|
?assertEqual(false, maps:is_key(OldSessionId, Pending)),
|
|
?assertEqual(NewAttempt, maps:get(NewSessionId, Pending)),
|
|
?assertEqual(false, maps:is_key(OldSessionId, maps:get(sessions, State1))),
|
|
?assertEqual(true, maps:is_key(NewSessionId, maps:get(sessions, State1))),
|
|
QueueItems = queue:to_list(maps:get(session_connect_queue, State1)),
|
|
?assertEqual([NewSessionId], queued_session_ids(QueueItems)),
|
|
receive
|
|
{guild_connect_result, GuildId, OldAttempt, {error, overloaded}} -> ok
|
|
after 0 ->
|
|
?assert(false, overflow_drop_was_not_reported)
|
|
end.
|
|
|
|
enqueue_session_connect_async_allows_immediate_start_when_wait_queue_disabled_test() ->
|
|
SessionId = <<"s-start">>,
|
|
GuildId = 42,
|
|
Attempt = 1,
|
|
State0 = #{
|
|
id => GuildId,
|
|
sessions => #{},
|
|
session_connect_queue => queue:new(),
|
|
session_connect_pending => #{},
|
|
session_connect_inflight => 0,
|
|
session_connect_max_queue => 0,
|
|
data => #{},
|
|
member_count => 0,
|
|
voice_states => #{},
|
|
member_list_engine => undefined,
|
|
virtual_channel_access => #{}
|
|
},
|
|
State1 = guild_connect_async:enqueue_session_connect_async(
|
|
GuildId, Attempt, connect_request(SessionId, 30), #{}, State0
|
|
),
|
|
?assertEqual(1, maps:get(session_connect_inflight, State1)),
|
|
?assertEqual([], queue:to_list(maps:get(session_connect_queue, State1))),
|
|
?assertEqual(Attempt, maps:get(SessionId, maps:get(session_connect_pending, State1))),
|
|
WorkerRefs = maps:get(session_connect_worker_refs, State1, #{}),
|
|
cleanup_worker_refs(WorkerRefs).
|
|
|
|
finalize_state(SessionId, UserId, Attempt, PendingConnect, Counts, Connected, PresenceSubs) ->
|
|
Existing = #{
|
|
session_id => SessionId,
|
|
user_id => UserId,
|
|
pid => self(),
|
|
mref => make_ref(),
|
|
pending_connect => PendingConnect,
|
|
active_guilds => sets:new()
|
|
},
|
|
#{
|
|
id => 42,
|
|
sessions => #{SessionId => Existing},
|
|
session_connect_pending => #{SessionId => Attempt},
|
|
session_connect_inflight => 1,
|
|
session_connect_queue => queue:new(),
|
|
user_session_counts => Counts,
|
|
connected_user_ids => Connected,
|
|
presence_subscriptions => PresenceSubs,
|
|
member_presence => #{}
|
|
}.
|
|
|
|
saturated_connect_state(GuildId, SessionId, Attempt, MaxQueue) ->
|
|
PendingSession = #{
|
|
session_id => SessionId,
|
|
user_id => 10,
|
|
pid => self(),
|
|
mref => make_ref(),
|
|
pending_connect => true,
|
|
active_guilds => sets:new()
|
|
},
|
|
#{
|
|
id => GuildId,
|
|
sessions => #{SessionId => PendingSession},
|
|
session_connect_pending => #{SessionId => Attempt},
|
|
session_connect_queue => queue:from_list([
|
|
#{
|
|
guild_id => GuildId,
|
|
attempt => Attempt,
|
|
request => connect_request(SessionId, 10),
|
|
reply_via_pid => undefined
|
|
}
|
|
]),
|
|
session_connect_inflight => 8,
|
|
session_connect_max_queue => MaxQueue,
|
|
user_session_counts => #{},
|
|
connected_user_ids => sets:new(),
|
|
presence_subscriptions => #{},
|
|
member_presence => #{}
|
|
}.
|
|
|
|
connect_request(SessionId, UserId) ->
|
|
#{
|
|
session_id => SessionId,
|
|
user_id => UserId,
|
|
session_pid => self(),
|
|
bot => false,
|
|
is_staff => false,
|
|
active_guilds => sets:new()
|
|
}.
|
|
|
|
queued_session_ids(Items) ->
|
|
[maps:get(session_id, maps:get(request, Item, #{}), undefined) || Item <- Items].
|
|
|
|
cleanup_worker_refs(WorkerRefs) ->
|
|
maps:foreach(
|
|
fun(Ref, _Value) ->
|
|
receive
|
|
{'DOWN', Ref, process, _Pid, _Reason} -> ok
|
|
after 1000 ->
|
|
?assert(false, async_connect_worker_did_not_exit)
|
|
end
|
|
end,
|
|
WorkerRefs
|
|
).
|
|
|
|
finalize_computed(SessionId, UserId) ->
|
|
#{
|
|
request => #{session_id => SessionId, user_id => UserId, session_pid => self()},
|
|
user_roles => [],
|
|
viewable_channels => #{},
|
|
should_mark_guild_synced => false,
|
|
initial_last_message_ids => #{},
|
|
initial_channel_versions => #{}
|
|
}.
|
|
|
|
finalize_session(SessionId, UserId, Attempt, State) ->
|
|
guild_connect_async:finalize_session_connect_async(
|
|
SessionId,
|
|
Attempt,
|
|
{ok, #{}},
|
|
finalize_computed(SessionId, UserId),
|
|
State
|
|
).
|
|
|
|
flush_connect_result() ->
|
|
receive
|
|
{guild_connect_result, _GuildId, _Attempt, _Reply} -> ok
|
|
after 0 ->
|
|
ok
|
|
end.
|