Files
fluxer/fluxer_gateway/test/guild_voice_permissions_tests.erl
T

224 lines
8.8 KiB
Erlang

%% SPDX-License-Identifier: AGPL-3.0-or-later
-module(guild_voice_permissions_tests).
-typing([eqwalizer]).
-include_lib("eunit/include/eunit.hrl").
voice_permissions_missing_view_test() ->
State = permission_test_state(0, fun(_) -> constants:view_channel_permission() end),
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 0}, #{}, State, false
),
?assertMatch({error, permission_denied, voice_permission_denied}, Result).
voice_permissions_full_channel_test() ->
State = permission_test_state(2, fun(_) -> required_voice_perms() end),
VoiceStates = #{
<<"conn1">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn2">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"2">>}
},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
3, 10, #{<<"user_limit">> => 2}, VoiceStates, State, false
),
?assertMatch({error, permission_denied, voice_channel_full}, Result).
voice_permissions_existing_user_update_test() ->
State = permission_test_state(2, fun(_) -> required_voice_perms() end),
VoiceStates = #{
<<"conn1">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn2">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"2">>}
},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 2}, VoiceStates, State, true
),
?assertEqual({ok, allowed}, Result).
voice_permissions_unlimited_channel_camera_caps_at_25_test() ->
State = permission_test_state(2, fun(_) -> required_voice_perms() end),
VoiceStates = camera_limited_voice_states(25, 10),
Result = guild_voice_permissions:check_voice_permissions_and_limits(
26, 10, #{<<"user_limit">> => 0}, VoiceStates, State, false
),
?assertMatch({error, permission_denied, voice_channel_full}, Result).
voice_permissions_connection_limit_reached_test() ->
State = permission_test_state(2, fun(_) -> required_voice_perms() end),
VoiceStates = #{
<<"conn1">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn2">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>}
},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1,
10,
#{<<"user_limit">> => 0, <<"voice_connection_limit">> => 2},
VoiceStates,
State,
false
),
?assertMatch({error, permission_denied, voice_connection_limit_reached}, Result),
OtherUserResult = guild_voice_permissions:check_voice_permissions_and_limits(
2,
10,
#{<<"user_limit">> => 0, <<"voice_connection_limit">> => 2},
VoiceStates,
State,
false
),
?assertEqual({ok, allowed}, OtherUserResult).
voice_permissions_connection_limit_counts_pending_test() ->
Future = erlang:system_time(millisecond) + 1000,
State0 = permission_test_state(2, fun(_) -> required_voice_perms() end),
State = maps:put(
pending_voice_connections,
#{
<<"pending">> => #{
user_id => 1,
channel_id => 10,
expires_at => Future
}
},
State0
),
VoiceStates = #{
<<"conn1">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn2">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn3">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn4">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>}
},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 0}, VoiceStates, State, false
),
?assertMatch({error, permission_denied, voice_connection_limit_reached}, Result).
voice_permissions_virtual_access_bypass_test() ->
Base = permission_test_state(7, fun(_) -> 0 end),
State = Base#{virtual_channel_access => #{1 => sets:from_list([10])}},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 0}, #{}, State, false
),
?assertEqual({ok, allowed}, Result).
voice_permissions_move_pending_bypass_test() ->
Base = permission_test_state(7, fun(_) -> 0 end),
State = Base#{virtual_channel_access_move_pending => #{1 => sets:from_list([10])}},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 0}, #{}, State, false
),
?assertEqual({ok, allowed}, Result).
voice_permissions_without_lease_denied_test() ->
State = permission_test_state(7, fun(_) -> 0 end),
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 0}, #{}, State, false
),
?assertMatch({error, permission_denied, voice_permission_denied}, Result).
voice_permissions_virtual_access_other_channel_denied_test() ->
Base = permission_test_state(7, fun(_) -> 0 end),
State = Base#{virtual_channel_access => #{1 => sets:from_list([99])}},
Result = guild_voice_permissions:check_voice_permissions_and_limits(
1, 10, #{<<"user_limit">> => 0}, #{}, State, false
),
?assertMatch({error, permission_denied, voice_permission_denied}, Result).
users_in_channel_test() ->
VoiceStates = #{
<<"conn1">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"1">>},
<<"conn2">> => #{<<"channel_id">> => <<"10">>, <<"user_id">> => <<"2">>},
<<"conn3">> => #{<<"channel_id">> => <<"20">>, <<"user_id">> => <<"3">>}
},
Result = guild_voice_permissions:users_in_channel(10, VoiceStates),
?assertEqual(2, sets:size(Result)),
?assert(sets:is_element(1, Result)),
?assert(sets:is_element(2, Result)),
?assertNot(sets:is_element(3, Result)).
permission_sync_disconnects_when_view_channel_lost_test() ->
ConnectOnly = constants:connect_permission(),
{State, UserId, ChannelId, GuildId} = build_perm_sync_state(ConnectOnly),
ok = guild_voice_permission_sync:sync_user_voice_permissions(UserId, State),
receive
{synced, GuildId, ChannelId, UserId, <<"test-conn">>, Perms} ->
?assertEqual(true, maps:get(disconnected, Perms, false))
after 200 ->
?assert(false)
end.
permission_sync_does_not_disconnect_with_full_perms_test() ->
FullPerms =
constants:view_channel_permission() bor
constants:connect_permission() bor
constants:speak_permission(),
{State, UserId, ChannelId, GuildId} = build_perm_sync_state(FullPerms),
ok = guild_voice_permission_sync:sync_user_voice_permissions(UserId, State),
receive
{synced, GuildId, ChannelId, UserId, <<"test-conn">>, Perms} ->
?assertEqual(true, maps:get(can_speak, Perms, false)),
?assertNot(maps:is_key(disconnected, Perms))
after 200 ->
?assert(false)
end.
build_perm_sync_state(Permissions) ->
Self = self(),
TestFun = fun(GId, ChId, UId, ConnId, Perms) ->
Self ! {synced, GId, ChId, UId, ConnId, Perms}
end,
UserId = 10,
ChannelId = 500,
GuildId = 42,
RoleId = 999,
RoleIdBin = integer_to_binary(RoleId),
GuildIdBin = integer_to_binary(GuildId),
UserIdBin = integer_to_binary(UserId),
ChIdBin = integer_to_binary(ChannelId),
PermsBin = integer_to_binary(Permissions),
VoiceState = #{
<<"user_id">> => UserIdBin,
<<"channel_id">> => ChIdBin,
<<"connection_id">> => <<"test-conn">>,
<<"deaf">> => false
},
State = #{
id => GuildId,
voice_states => #{<<"conn">> => VoiceState},
test_permission_sync_fun => TestFun,
data => #{
<<"guild">> => #{<<"owner_id">> => <<"1">>},
<<"roles">> => [
#{<<"id">> => RoleIdBin, <<"permissions">> => PermsBin},
#{<<"id">> => GuildIdBin, <<"permissions">> => <<"0">>}
],
<<"members">> => [
#{<<"user">> => #{<<"id">> => UserIdBin}, <<"roles">> => [RoleIdBin]}
],
<<"channels">> => [
#{<<"id">> => ChIdBin, <<"permission_overwrites">> => []}
]
}
},
{State, UserId, ChannelId, GuildId}.
required_voice_perms() ->
constants:view_channel_permission() bor constants:connect_permission().
permission_test_state(GuildId, PermFun) ->
#{id => GuildId, test_perm_fun => PermFun}.
camera_limited_voice_states(Count, ChannelId) ->
lists:foldl(
fun(UserId, Acc) ->
ConnId = <<"conn", (integer_to_binary(UserId))/binary>>,
Acc#{
ConnId => #{
<<"channel_id">> => integer_to_binary(ChannelId),
<<"user_id">> => integer_to_binary(UserId),
<<"self_video">> => UserId =:= 1
}
}
end,
#{},
lists:seq(1, Count)
).