test(notify): prefs gate email/push on reminder and waitlist.
CI / test (push) Successful in 7m47s
CI / deploy-ift (push) Successful in 3m5s
CI / e2e-ift (push) Successful in 1m26s
CI / deploy-stage (push) Successful in 2m13s
CI / e2e-stage (push) Failing after 3m23s

Assert email=false skips SMTP; push=true hits web_push_deliver.
Refs EventHub/EventHubBack#75
This commit is contained in:
2026-08-15 21:50:08 +03:00
parent 12274f9ed0
commit 00bf72e4d1
3 changed files with 124 additions and 3 deletions
+3
View File
@@ -96,6 +96,7 @@ ensure_indexes(Tables) when is_list(Tables) ->
{verification, [user_id]}, {verification, [user_id]},
{password_reset, [user_id]}, {password_reset, [user_id]},
{notification, [user_id, is_read]}, {notification, [user_id, is_read]},
{push_subscription, [user_id, endpoint]},
{auth_session, [family_id, subject_id]}, {auth_session, [family_id, subject_id]},
{report, [resolved_by]}, {report, [resolved_by]},
{ticket, [assigned_to]} {ticket, [assigned_to]}
@@ -179,6 +180,8 @@ table_opts(admin_audit) ->
[{ram_copies, [node()]}, {attributes, record_info(fields, admin_audit)}]; [{ram_copies, [node()]}, {attributes, record_info(fields, admin_audit)}];
table_opts(notification) -> table_opts(notification) ->
[{ram_copies, [node()]}, {attributes, record_info(fields, notification)}]; [{ram_copies, [node()]}, {attributes, record_info(fields, notification)}];
table_opts(push_subscription) ->
[{ram_copies, [node()]}, {attributes, record_info(fields, push_subscription)}];
table_opts(stats_counter) -> table_opts(stats_counter) ->
[{ram_copies, [node()]}, {attributes, record_info(fields, stats_counter)}]; [{ram_copies, [node()]}, {attributes, record_info(fields, stats_counter)}];
table_opts(stats_daily) -> table_opts(stats_daily) ->
+75 -2
View File
@@ -3,7 +3,7 @@
-include("records.hrl"). -include("records.hrl").
-define(TABLES, [user, calendar, event, booking, admin, subscription, calendar_specialist, -define(TABLES, [user, calendar, event, booking, admin, subscription, calendar_specialist,
recurrence_exception, notification]). recurrence_exception, notification, push_subscription]).
setup() -> setup() ->
eh_test_support:start_mnesia(), eh_test_support:start_mnesia(),
@@ -57,7 +57,9 @@ logic_booking_test_() ->
{"Process timeout expires past pending", fun test_process_timeout_expires_past/0}, {"Process timeout expires past pending", fun test_process_timeout_expires_past/0},
{"Reminder sends once within lead window", fun test_reminder_within_window/0}, {"Reminder sends once within lead window", fun test_reminder_within_window/0},
{"Reminder skipped outside lead window", fun test_reminder_outside_window/0}, {"Reminder skipped outside lead window", fun test_reminder_outside_window/0},
{"Reminder skipped for pending", fun test_reminder_skips_pending/0} {"Reminder skipped for pending", fun test_reminder_skips_pending/0},
{"Reminder skips email when prefs email=false", fun test_reminder_email_pref_off/0},
{"Reminder calls web_push when prefs push=true", fun test_reminder_web_push/0}
]}. ]}.
%% Вспомогательные функции %% Вспомогательные функции
@@ -598,3 +600,74 @@ test_reminder_skips_pending() ->
{ok, Stored} = core_booking:get_by_id(Booking#booking.id), {ok, Stored} = core_booking:get_by_id(Booking#booking.id),
?assertEqual(false, Stored#booking.reminder_sent), ?assertEqual(false, Stored#booking.reminder_sent),
application:unset_env(eventhub, reminder_lead_hours). application:unset_env(eventhub, reminder_lead_hours).
test_reminder_email_pref_off() ->
application:set_env(eventhub, reminder_lead_hours, 24),
Self = self(),
application:set_env(eventhub, smtp_host, "smtp.test"),
application:set_env(eventhub, smtp_deliver,
fun(_From, To, Raw, _Opts) ->
Self ! {smtp, To, Raw},
{ok, mock}
end),
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
{ok, _} = logic_notification_prefs:put_prefs(ParticipantId, #{email => false, push => true}),
CalendarId = create_test_calendar(OwnerId, auto),
EventId = create_test_event_at(CalendarId, hours_from_now(2)),
{ok, Booking} = logic_booking:create_booking(ParticipantId, EventId),
ok = logic_booking:process_reminders(),
receive
{smtp, _, _} -> error(unexpected_email_when_pref_off)
after 300 ->
ok
end,
{ok, Stored} = core_booking:get_by_id(Booking#booking.id),
?assertEqual(true, Stored#booking.reminder_sent),
Notifs = core_notification:list_by_user(ParticipantId),
?assert(lists:any(fun(#notification{type = event_reminder}) -> true; (_) -> false end,
Notifs)),
application:unset_env(eventhub, smtp_host),
application:unset_env(eventhub, smtp_deliver),
application:unset_env(eventhub, reminder_lead_hours).
test_reminder_web_push() ->
application:set_env(eventhub, reminder_lead_hours, 24),
application:set_env(eventhub, vapid_public_key, <<"BKtestpublickey0123456789abcdef">>),
application:set_env(eventhub, vapid_private_key, <<"testprivatekey0123456789abcdef">>),
Self = self(),
application:set_env(eventhub, web_push_deliver,
fun(Ep, _P256, _Auth, Payload, _Pub, _Priv) ->
Self ! {push, Ep, Payload},
ok
end),
OwnerId = create_test_user(user),
ParticipantId = create_test_user(user),
{ok, _} = logic_notification_prefs:put_prefs(ParticipantId, #{email => false, push => true}),
{ok, _} = core_push_subscription:upsert(
ParticipantId,
<<"https://push.example/endpoint-reminder">>,
<<"p256dh-test">>,
<<"auth-test">>),
CalendarId = create_test_calendar(OwnerId, auto),
EventId = create_test_event_at(CalendarId, hours_from_now(2)),
{ok, _} = logic_booking:create_booking(ParticipantId, EventId),
ok = logic_booking:process_reminders(),
receive
{push, Ep, Payload} ->
?assertEqual(<<"https://push.example/endpoint-reminder">>, Ep),
?assert(binary:match(Payload, <<"Напоминание"/utf8>>) =/= nomatch)
after 1000 ->
error(timeout_web_push)
end,
{ok, _} = logic_notification_prefs:put_prefs(ParticipantId, #{email => false, push => false}),
ok = logic_web_push:send(ParticipantId, <<"t">>, <<"b">>, <<"/x">>),
receive
{push, _, _} -> error(push_should_be_skipped)
after 300 ->
ok
end,
application:unset_env(eventhub, web_push_deliver),
application:unset_env(eventhub, vapid_public_key),
application:unset_env(eventhub, vapid_private_key),
application:unset_env(eventhub, reminder_lead_hours).
+46 -1
View File
@@ -3,7 +3,7 @@
-include("records.hrl"). -include("records.hrl").
-define(TABLES, [user, calendar, event, booking, waitlist_entry, subscription, -define(TABLES, [user, calendar, event, booking, waitlist_entry, subscription,
notification, calendar_specialist]). notification, calendar_specialist, push_subscription]).
setup() -> setup() ->
eh_test_support:start_mnesia(), eh_test_support:start_mnesia(),
@@ -21,6 +21,7 @@ logic_waitlist_test_() ->
{"join when full and enabled", fun test_join_full/0}, {"join when full and enabled", fun test_join_full/0},
{"join rejected when not full", fun test_not_full/0}, {"join rejected when not full", fun test_not_full/0},
{"promote on cancel", fun test_promote_on_cancel/0}, {"promote on cancel", fun test_promote_on_cancel/0},
{"promote respects email=false and sends push", fun test_promote_prefs_push/0},
{"leave waitlist", fun test_leave/0} {"leave waitlist", fun test_leave/0}
]}. ]}.
@@ -94,6 +95,50 @@ test_promote_on_cancel() ->
?assertEqual(1, length(Active)), ?assertEqual(1, length(Active)),
?assertEqual({error, not_found}, core_waitlist:get_waiting(EventId, Waiter)). ?assertEqual({error, not_found}, core_waitlist:get_waiting(EventId, Waiter)).
test_promote_prefs_push() ->
Self = self(),
application:set_env(eventhub, smtp_host, "smtp.test"),
application:set_env(eventhub, smtp_deliver,
fun(_From, To, Raw, _Opts) ->
Self ! {smtp, To, Raw},
{ok, mock}
end),
application:set_env(eventhub, vapid_public_key, <<"BKtestpublic">>),
application:set_env(eventhub, vapid_private_key, <<"testprivate">>),
application:set_env(eventhub, web_push_deliver,
fun(Ep, _P, _A, Payload, _Pub, _Priv) ->
Self ! {push, Ep, Payload},
ok
end),
Owner = create_user(),
Guest = create_user(),
Waiter = create_user(),
{ok, _} = logic_notification_prefs:put_prefs(Waiter, #{email => false, push => true}),
{ok, _} = core_push_subscription:upsert(
Waiter, <<"https://push.example/waitlist">>, <<"p256">>, <<"auth">>),
Cal = create_cal(Owner, true),
EventId = create_event(Cal#calendar.id, 1),
{ok, Booking} = logic_booking:create_booking(Guest, EventId),
{ok, _} = logic_waitlist:join(Waiter, EventId),
{ok, _} = logic_booking:cancel_booking(Booking#booking.id, Guest),
receive
{smtp, _, _} -> error(unexpected_waitlist_email)
after 300 ->
ok
end,
receive
{push, Ep, Payload} ->
?assertEqual(<<"https://push.example/waitlist">>, Ep),
?assert(binary:match(Payload, <<"листа ожидания"/utf8>>) =/= nomatch)
after 1000 ->
error(timeout_waitlist_push)
end,
application:unset_env(eventhub, smtp_host),
application:unset_env(eventhub, smtp_deliver),
application:unset_env(eventhub, web_push_deliver),
application:unset_env(eventhub, vapid_public_key),
application:unset_env(eventhub, vapid_private_key).
test_leave() -> test_leave() ->
Owner = create_user(), Owner = create_user(),
Guest = create_user(), Guest = create_user(),