eceb6c9b43
* Add self-service account deletion * Disable access to cancelled accounts & implement Stripe interactions * Add tests * Fix failing tests * Remove cancelled accounts from lists * Fix incorrect redirect * Use _path instead of _url for consistency * Don't track how far the inicieration job got We still want the step tracking so that the job can be interrupted. But, since the scope is idempotent, we don't need to track how far it got. * Specify the exact time when the data will be deleted * Fix crash due to unadvancable cursor * Rename up_for_incineration to due_for_incineration * Regenrate the schema * Fix incorrect path check * Migrate the SQLite schema * Only show the cancel button on cancellable accounts * Check that a subscirption method exists before calling it * Ignore job failures due to missing records when an account gets deleted * Skip sending notifications on cancelled accounts * Use collbacks to integrate * Add a blank line between queue_as and discard_on * Break checks into methods * Inline methods * Rename Account::IncinerateJob * Run migrations * Migrate SQLite
181 lines
5.8 KiB
Ruby
181 lines
5.8 KiB
Ruby
require "test_helper"
|
|
|
|
class Notification::BundleTest < ActiveSupport::TestCase
|
|
include ActionMailer::TestHelper
|
|
|
|
setup do
|
|
@user = users(:david)
|
|
@user.settings.bundle_email_every_few_hours!
|
|
end
|
|
|
|
test "new notifications are bundled" do
|
|
notification = assert_difference -> { @user.notification_bundles.pending.count }, 1 do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
end
|
|
|
|
bundle = @user.notification_bundles.pending.last
|
|
assert_includes bundle.notifications, notification
|
|
end
|
|
|
|
test "don't bundle new notifications if bundling is disabled" do
|
|
@user.settings.bundle_email_never!
|
|
|
|
assert_no_difference -> { @user.notification_bundles.count } do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
end
|
|
end
|
|
|
|
test "notifications are bundled withing the aggregation period" do
|
|
@user.notification_bundles.destroy_all
|
|
|
|
notification_1 = assert_difference -> { @user.notification_bundles.pending.count }, 1 do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
end
|
|
travel_to 3.hours.from_now
|
|
|
|
notification_2 = assert_no_difference -> { @user.notification_bundles.count } do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
end
|
|
travel_to 3.days.from_now
|
|
|
|
notification_3 = assert_difference -> { @user.notification_bundles.pending.count }, 1 do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
end
|
|
|
|
assert_equal 2, @user.notification_bundles.count
|
|
bundle_1, bundle_2 = @user.notification_bundles.all.to_a
|
|
assert_includes bundle_1.notifications, notification_1
|
|
assert_includes bundle_1.notifications, notification_2
|
|
assert_includes bundle_2.notifications, notification_3
|
|
end
|
|
|
|
test "overlapping bundles are invalid" do
|
|
bundle_1 = @user.notification_bundles.create!(
|
|
starts_at: Time.current,
|
|
ends_at: 4.hours.from_now,
|
|
status: :pending
|
|
)
|
|
|
|
bundle_2 = @user.notification_bundles.build(
|
|
starts_at: 2.hours.from_now,
|
|
ends_at: 6.hours.from_now,
|
|
status: :pending
|
|
)
|
|
assert_not bundle_2.valid?
|
|
|
|
# Bundle with overlapping end time should be invalid
|
|
bundle_3 = @user.notification_bundles.build(
|
|
starts_at: 2.hours.ago,
|
|
ends_at: 2.hours.from_now,
|
|
status: :pending
|
|
)
|
|
assert_not bundle_3.valid?
|
|
|
|
# Bundle completely within another bundle should be invalid
|
|
bundle_4 = @user.notification_bundles.build(
|
|
starts_at: 1.hour.from_now,
|
|
ends_at: 3.hours.from_now,
|
|
status: :pending
|
|
)
|
|
assert_not bundle_4.valid?
|
|
|
|
# Non-overlapping bundle should be valid
|
|
bundle_5 = @user.notification_bundles.build(
|
|
starts_at: 5.hours.from_now,
|
|
ends_at: 9.hours.from_now,
|
|
status: :pending
|
|
)
|
|
assert bundle_5.valid?
|
|
end
|
|
|
|
test "overlapping bundles that are created relying on set_default_window are not created" do
|
|
@user.notification_bundles.destroy_all
|
|
|
|
bundle = @user.notification_bundles.create!(starts_at: Time.current)
|
|
|
|
assert_raises ActiveRecord::RecordInvalid do
|
|
@user.notification_bundles.create!(starts_at: bundle.starts_at - 1.second)
|
|
end
|
|
end
|
|
|
|
test "deliver_all delivers due bundles" do
|
|
@user.notification_bundles.destroy_all
|
|
|
|
notification = @user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
|
|
bundle = @user.notification_bundles.pending.last
|
|
|
|
assert bundle.pending?
|
|
assert_includes bundle.notifications, notification
|
|
|
|
bundle.update!(ends_at: 1.minute.ago)
|
|
|
|
perform_enqueued_jobs only: Notification::Bundle::DeliverJob do
|
|
Notification::Bundle.deliver_all
|
|
end
|
|
|
|
bundle.reload
|
|
assert bundle.delivered?
|
|
end
|
|
|
|
test "deliver_all don't deliver bundles that are not due" do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
bundle = @user.notification_bundles.pending.last
|
|
|
|
bundle.update!(ends_at: 1.minute.from_now)
|
|
|
|
perform_enqueued_jobs only: Notification::Bundle::DeliverJob do
|
|
Notification::Bundle.deliver_all
|
|
end
|
|
|
|
bundle.reload
|
|
assert bundle.pending?
|
|
end
|
|
|
|
test "deliver sends email with time in user's time zone" do
|
|
@user.settings.update!(timezone_name: "Madrid")
|
|
|
|
freeze_time Time.utc(2025, 1, 15, 14, 30, 0) do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
bundle = @user.notification_bundles.pending.last
|
|
bundle.deliver
|
|
|
|
email = ActionMailer::Base.deliveries.last
|
|
assert_not_nil email
|
|
|
|
# Time in Madrid should be 15:30 (UTC+1 in winter)
|
|
assert_match /notifications since 3pm/i, email.text_part&.body&.to_s
|
|
end
|
|
end
|
|
|
|
test "out-of-order notification bundling should still work" do
|
|
first_notification = @user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
second_notification = @user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
@user.notification_bundles.destroy_all
|
|
|
|
assert first_notification.created_at < second_notification.created_at
|
|
@user.bundle(second_notification)
|
|
@user.bundle(first_notification)
|
|
|
|
assert_equal 1, @user.notification_bundles.pending.count
|
|
assert_equal 2, @user.notification_bundles.last.notifications.count
|
|
assert_includes @user.notification_bundles.last.notifications, first_notification
|
|
assert_includes @user.notification_bundles.last.notifications, second_notification
|
|
end
|
|
|
|
test "deliver does not send email for cancelled accounts" do
|
|
@user.notifications.create!(source: events(:logo_published), creator: @user)
|
|
bundle = @user.notification_bundles.pending.last
|
|
|
|
@user.account.cancel(initiated_by: @user)
|
|
|
|
assert_no_emails do
|
|
deliver_enqueued_emails do
|
|
bundle.deliver
|
|
end
|
|
end
|
|
|
|
assert bundle.delivered?, "Bundle should be marked as delivered even if not sent"
|
|
end
|
|
end
|