fix(profiling): assign realistic document ownership so seed data exercises the guardian permission path

This commit is contained in:
stumpylog
2026-07-27 17:25:48 -07:00
parent e0902c63d6
commit e80ede4cb0
+32 -17
View File
@@ -10,6 +10,7 @@ from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from guardian.shortcuts import assign_perm
from documents.models import Document
from documents.tests.factories import CorrespondentFactory
from documents.tests.factories import DocumentFactory
from documents.tests.factories import DocumentTypeFactory
@@ -18,13 +19,17 @@ from documents.tests.factories import TagFactory
if TYPE_CHECKING:
from documents.models import Correspondent
from documents.models import Document
from documents.models import DocumentType
from documents.models import StoragePath
from documents.models import Tag
ScaleProfile = Literal["medium", "large"]
# Fraction of seeded documents given a real owner; the remainder stays
# owner=None, mirroring a real install's mix of owned and legacy/imported
# unowned documents.
_OWNED_FRACTION = 0.9
class _ScaleCounts:
__slots__ = (
@@ -140,7 +145,20 @@ def seed_permission_dataset(
for user in users:
user.groups.add(rng.choice(groups))
documents = tuple(DocumentFactory.create_batch(counts.documents))
documents = list(DocumentFactory.create_batch(counts.documents))
# Assign realistic ownership -- without this, every document stays
# owner=None and the "owned or unowned" visibility clause is trivially
# true for every row, so no guardian permission check ever needs to run
# (see the amendment note above this code block).
owned_documents = []
for document in documents:
if rng.random() < _OWNED_FRACTION:
document.owner = rng.choice(users)
owned_documents.append(document)
Document.objects.bulk_update(owned_documents, ["owner"], batch_size=2_000)
documents = tuple(documents)
tags = tuple(TagFactory.create_batch(counts.tags))
correspondents = tuple(CorrespondentFactory.create_batch(counts.correspondents))
document_types = tuple(DocumentTypeFactory.create_batch(counts.document_types))
@@ -149,29 +167,26 @@ def seed_permission_dataset(
n_user_perms = round(counts.documents * _USER_PERM_ROWS_PER_DOC)
n_group_perms = round(counts.documents * _GROUP_PERM_ROWS_PER_DOC)
# guardian's assign_perm is a get_or_create on the (subject, object,
# permission) triple, so drawing (subject, document) pairs *with*
# replacement -- rng.choice/rng.choice in a loop -- collides far more
# than the raw draw count suggests once the subject pool is small
# relative to the number of draws (a birthday-paradox effect): e.g. at
# medium scale, 45,387 draws over only 5 groups x 20,000 documents =
# 100,000 slots yields ~36,500 *distinct* pairs, not ~45,387. Sampling
# distinct pairs up front guarantees the seeded row counts actually
# land on the real-install ratios the scale profiles are derived from.
for user_idx, doc_idx in _sample_distinct_pairs(
# Grant permissions only on OWNED documents -- a grant on an already-
# unowned document is a no-op for visibility (unowned documents are
# visible to everyone regardless), so restricting the pool here is what
# makes each assign_perm() call actually matter for someone, and is
# what exercises the guardian-permission-join code path this profiling
# effort exists to measure.
for user_idx, owned_idx in _sample_distinct_pairs(
rng,
len(users),
len(documents),
len(owned_documents),
n_user_perms,
):
assign_perm("view_document", users[user_idx], documents[doc_idx])
for group_idx, doc_idx in _sample_distinct_pairs(
assign_perm("view_document", users[user_idx], owned_documents[owned_idx])
for group_idx, owned_idx in _sample_distinct_pairs(
rng,
len(groups),
len(documents),
len(owned_documents),
n_group_perms,
):
assign_perm("view_document", groups[group_idx], documents[doc_idx])
assign_perm("view_document", groups[group_idx], owned_documents[owned_idx])
return SeededData(
users=users,