mirror of
https://github.com/zulip/zulip.git
synced 2025-11-13 18:36:36 +00:00
This is designed to help PostgreSQL have better specificity and locality in its indexes. Subsequent commits will adjust the code to make sure that we use these indexes rather than the `realm_id`-less versions. We do not add a `realm_id` variation to the full-text index, since it is a GIN index; multi-column GIN indexes are not terribly performant, require the `btree_gin` extension for `int` types (which requires superuser privileges on PostgreSQL 12 and earlier), and cannot be consistently added concurrently on running instances. After all indexes have been made, we also run `CREATE STATISTICS` in order to give PostgreSQL the opportunity to realize that recipient and sender are highly correlated with message realm, allowing it to estimate that `(realm_id, recipient_id)` is likely as specific as matching a given `recipient_id`, instead of as likely as matching `realm_id` times matching a `recipient_id`. Finally, those statistics must be filled by `ANALYZE zerver_message`, which is run last.
105 lines
4.1 KiB
Python
105 lines
4.1 KiB
Python
# These are tests for Zulip's database migrations. System documented at:
|
|
# https://zulip.readthedocs.io/en/latest/subsystems/schema-migrations.html
|
|
#
|
|
# You can also read
|
|
# https://www.caktusgroup.com/blog/2016/02/02/writing-unit-tests-django-migrations/
|
|
# to get a tutorial on the framework that inspired this feature.
|
|
from datetime import datetime, timezone
|
|
from unittest import skip
|
|
|
|
import orjson
|
|
from django.db.migrations.state import StateApps
|
|
|
|
from zerver.lib.test_classes import MigrationsTestCase
|
|
from zerver.lib.test_helpers import use_db_models
|
|
|
|
# Important note: These tests are very expensive, and details of
|
|
# Django's database transaction model mean it does not super work to
|
|
# have a lot of migrations tested in this file at once; so we usually
|
|
# delete the old migration tests when adding a new one, so this file
|
|
# always has a single migration test in it as an example.
|
|
#
|
|
# The error you get with multiple similar tests doing migrations on
|
|
# the same table is this (table name may vary):
|
|
#
|
|
# django.db.utils.OperationalError: cannot ALTER TABLE
|
|
# "zerver_subscription" because it has pending trigger events
|
|
#
|
|
# As a result, we generally mark these tests as skipped once they have
|
|
# been tested for a migration being merged.
|
|
|
|
|
|
@skip("Cannot be run because there is a non-atomic migration that has been merged after it")
|
|
class ScheduledEmailData(MigrationsTestCase):
|
|
migrate_from = "0467_rename_extradata_realmauditlog_extra_data_json"
|
|
migrate_to = "0468_rename_followup_day_email_templates"
|
|
|
|
@use_db_models
|
|
def setUpBeforeMigration(self, apps: StateApps) -> None:
|
|
iago = self.example_user("iago")
|
|
ScheduledEmail = apps.get_model("zerver", "ScheduledEmail")
|
|
send_date = datetime(2025, 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
|
|
|
|
templates = [
|
|
["zerver/emails/followup_day1", "a", True, 10],
|
|
["zerver/emails/followup_day2", "b", False, 20],
|
|
["zerver/emails/onboarding_zulip_guide", "c", True, 30],
|
|
]
|
|
|
|
for template in templates:
|
|
email_fields = {
|
|
"template_prefix": template[0],
|
|
"string_context": template[1],
|
|
"boolean_context": template[2],
|
|
"integer_context": template[3],
|
|
}
|
|
|
|
email = ScheduledEmail.objects.create(
|
|
type=1,
|
|
realm=iago.realm,
|
|
scheduled_timestamp=send_date,
|
|
data=orjson.dumps(email_fields).decode(),
|
|
)
|
|
email.users.add(iago.id)
|
|
|
|
def test_updated_email_templates(self) -> None:
|
|
ScheduledEmail = self.apps.get_model("zerver", "ScheduledEmail")
|
|
send_date = datetime(2025, 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
|
|
|
|
old_templates = [
|
|
"zerver/emails/followup_day1",
|
|
"zerver/emails/followup_day2",
|
|
]
|
|
|
|
current_templates = [
|
|
"zerver/emails/account_registered",
|
|
"zerver/emails/onboarding_zulip_guide",
|
|
"zerver/emails/onboarding_zulip_topics",
|
|
]
|
|
|
|
email_data = [
|
|
["zerver/emails/account_registered", "a", True, 10],
|
|
["zerver/emails/onboarding_zulip_topics", "b", False, 20],
|
|
["zerver/emails/onboarding_zulip_guide", "c", True, 30],
|
|
]
|
|
|
|
scheduled_emails = ScheduledEmail.objects.all()
|
|
self.assert_length(scheduled_emails, 3)
|
|
|
|
checked_emails = []
|
|
for email in scheduled_emails:
|
|
self.assertEqual(email.type, 1)
|
|
self.assertEqual(email.scheduled_timestamp, send_date)
|
|
|
|
updated_data = orjson.loads(email.data)
|
|
template_prefix = updated_data["template_prefix"]
|
|
self.assertFalse(template_prefix in old_templates)
|
|
for data in email_data:
|
|
if template_prefix == data[0]:
|
|
self.assertEqual(updated_data["string_context"], data[1])
|
|
self.assertEqual(updated_data["boolean_context"], data[2])
|
|
self.assertEqual(updated_data["integer_context"], data[3])
|
|
checked_emails.append(template_prefix)
|
|
|
|
self.assertEqual(current_templates, sorted(checked_emails))
|