Files
Lotty/src/backend/apps/reviews/tests/test_reviews_approver_groups.py
T
2026-02-12 20:48:29 +03:00

378 lines
14 KiB
Python

import uuid
from typing import Any
from django.core.exceptions import ValidationError
from django.db.models import QuerySet
from django.test import TestCase
from apps.reviews.models import ApproverGroup
from apps.reviews.selectors import (
approver_group_get_by_experimenter,
approver_group_get_by_experimenter_id,
approver_group_get_by_id,
approver_group_list,
approver_group_list_for_approver,
)
from apps.reviews.services import (
approver_group_add_approver,
approver_group_create,
approver_group_delete,
approver_group_remove_approver,
approver_group_update,
)
from apps.users.models import User
from ._helpers import (
_make_admin,
_make_approver,
_make_experimenter,
_make_viewer,
)
class ApproverGroupModelTest(TestCase):
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_model")
self.approver: User = _make_approver("_model")
def test_create_group(self) -> None:
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver.pk)],
min_approvals=1,
)
self.assertIsNotNone(group.pk)
self.assertEqual(group.experimenter, self.experimenter)
self.assertEqual(group.min_approvals, 1)
self.assertEqual(group.approvers.count(), 1)
def test_str_representation(self) -> None:
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
min_approvals=2,
)
result = str(group)
self.assertIn("ApproverGroup", result)
self.assertIn("min_approvals=2", result)
def test_can_approve_true(self) -> None:
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver.pk)],
)
self.assertTrue(group.can_approve(self.approver))
def test_can_approve_false_not_in_group(self) -> None:
other_approver: User = _make_approver("_other")
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver.pk)],
)
self.assertFalse(group.can_approve(other_approver))
def test_one_to_one_constraint(self) -> None:
approver_group_create(experimenter=self.experimenter)
with self.assertRaises(ValidationError):
approver_group_create(
experimenter=self.experimenter,
min_approvals=1,
)
class ApproverGroupCreateServiceTest(TestCase):
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_create")
self.approver1: User = _make_approver("_create1")
self.approver2: User = _make_approver("_create2")
def test_create_with_approvers(self) -> None:
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver1.pk), str(self.approver2.pk)],
min_approvals=2,
)
self.assertEqual(group.approvers.count(), 2)
self.assertEqual(group.min_approvals, 2)
def test_create_without_approvers(self) -> None:
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
min_approvals=1,
)
self.assertEqual(group.approvers.count(), 0)
self.assertEqual(group.min_approvals, 1)
def test_create_default_min_approvals(self) -> None:
group: ApproverGroup = approver_group_create(
experimenter=self.experimenter
)
self.assertEqual(group.min_approvals, 1)
def test_create_rejects_non_experimenter_user(self) -> None:
admin: User = _make_admin("_cre_admin")
with self.assertRaises(ValidationError):
approver_group_create(experimenter=admin)
def test_create_rejects_viewer_as_experimenter(self) -> None:
viewer: User = _make_viewer("_cre_viewer")
with self.assertRaises(ValidationError):
approver_group_create(experimenter=viewer)
def test_create_rejects_approver_as_experimenter(self) -> None:
approver: User = _make_approver("_cre_as_exp")
with self.assertRaises(ValidationError):
approver_group_create(experimenter=approver)
def test_create_rejects_inactive_experimenter(self) -> None:
self.experimenter.is_active = False
self.experimenter.save()
with self.assertRaises(ValidationError):
approver_group_create(experimenter=self.experimenter)
def test_create_rejects_non_approver_in_approver_list(self) -> None:
viewer: User = _make_viewer("_cre_bad_appr")
with self.assertRaises(ValidationError):
approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(viewer.pk)],
)
def test_create_rejects_missing_approver_ids(self) -> None:
with self.assertRaises(ValidationError):
approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(uuid.uuid4())],
)
def test_create_rejects_duplicate_group(self) -> None:
approver_group_create(experimenter=self.experimenter)
with self.assertRaises(ValidationError):
approver_group_create(experimenter=self.experimenter)
def test_create_min_approvals_zero_raises(self) -> None:
with self.assertRaises(ValidationError):
approver_group_create(
experimenter=self.experimenter,
min_approvals=0,
)
def test_create_min_approvals_exceeds_approvers_raises(self) -> None:
with self.assertRaises(ValidationError):
approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver1.pk)],
min_approvals=3,
)
class ApproverGroupUpdateServiceTest(TestCase):
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_upd")
self.approver1: User = _make_approver("_upd1")
self.approver2: User = _make_approver("_upd2")
self.approver3: User = _make_approver("_upd3")
self.group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver1.pk), str(self.approver2.pk)],
min_approvals=1,
)
def test_update_min_approvals(self) -> None:
updated: ApproverGroup = approver_group_update(
group=self.group, min_approvals=2
)
self.assertEqual(updated.min_approvals, 2)
def test_update_approver_ids_replaces_set(self) -> None:
updated: ApproverGroup = approver_group_update(
group=self.group,
approver_ids=[str(self.approver3.pk)],
)
approver_pks: set[Any] = set(
updated.approvers.values_list("pk", flat=True)
)
self.assertEqual(approver_pks, {self.approver3.pk})
def test_update_both_fields(self) -> None:
updated: ApproverGroup = approver_group_update(
group=self.group,
approver_ids=[
str(self.approver1.pk),
str(self.approver2.pk),
str(self.approver3.pk),
],
min_approvals=3,
)
self.assertEqual(updated.approvers.count(), 3)
self.assertEqual(updated.min_approvals, 3)
def test_update_no_op(self) -> None:
updated: ApproverGroup = approver_group_update(group=self.group)
self.assertEqual(updated.min_approvals, self.group.min_approvals)
def test_update_min_approvals_exceeds_new_approver_count_raises(
self,
) -> None:
with self.assertRaises(ValidationError):
approver_group_update(
group=self.group,
approver_ids=[str(self.approver1.pk)],
min_approvals=5,
)
def test_update_min_approvals_exceeds_existing_count_raises(self) -> None:
with self.assertRaises(ValidationError):
approver_group_update(group=self.group, min_approvals=10)
def test_update_rejects_non_approver_role(self) -> None:
viewer: User = _make_viewer("_upd_bad")
with self.assertRaises(ValidationError):
approver_group_update(
group=self.group,
approver_ids=[str(viewer.pk)],
)
def test_update_rejects_missing_user(self) -> None:
with self.assertRaises(ValidationError):
approver_group_update(
group=self.group,
approver_ids=[str(uuid.uuid4())],
)
class ApproverGroupDeleteServiceTest(TestCase):
def test_delete_removes_group(self) -> None:
exp: User = _make_experimenter("_del")
group: ApproverGroup = approver_group_create(experimenter=exp)
pk = group.pk
approver_group_delete(group=group)
self.assertFalse(ApproverGroup.objects.filter(pk=pk).exists())
def test_delete_allows_recreating_group(self) -> None:
exp: User = _make_experimenter("_del2")
group: ApproverGroup = approver_group_create(experimenter=exp)
approver_group_delete(group=group)
new_group: ApproverGroup = approver_group_create(experimenter=exp)
self.assertIsNotNone(new_group.pk)
class ApproverGroupAddRemoveServiceTest(TestCase):
def setUp(self) -> None:
self.experimenter: User = _make_experimenter("_ar")
self.approver1: User = _make_approver("_ar1")
self.approver2: User = _make_approver("_ar2")
self.group: ApproverGroup = approver_group_create(
experimenter=self.experimenter,
approver_ids=[str(self.approver1.pk)],
min_approvals=1,
)
def test_add_approver(self) -> None:
approver_group_add_approver(group=self.group, approver=self.approver2)
self.assertEqual(self.group.approvers.count(), 2)
self.assertTrue(
self.group.approvers.filter(pk=self.approver2.pk).exists()
)
def test_add_approver_rejects_non_approver_role(self) -> None:
viewer: User = _make_viewer("_ar_bad")
with self.assertRaises(ValidationError):
approver_group_add_approver(group=self.group, approver=viewer)
def test_add_approver_rejects_duplicate(self) -> None:
with self.assertRaises(ValidationError):
approver_group_add_approver(
group=self.group, approver=self.approver1
)
def test_remove_approver(self) -> None:
approver_group_add_approver(group=self.group, approver=self.approver2)
approver_group_remove_approver(
group=self.group, approver=self.approver1
)
self.assertEqual(self.group.approvers.count(), 1)
self.assertFalse(
self.group.approvers.filter(pk=self.approver1.pk).exists()
)
def test_remove_approver_not_in_group_raises(self) -> None:
with self.assertRaises(ValidationError):
approver_group_remove_approver(
group=self.group, approver=self.approver2
)
def test_remove_approver_below_min_raises(self) -> None:
with self.assertRaises(ValidationError):
approver_group_remove_approver(
group=self.group, approver=self.approver1
)
class ApproverGroupSelectorsTest(TestCase):
def setUp(self) -> None:
self.exp1: User = _make_experimenter("_sel1")
self.exp2: User = _make_experimenter("_sel2")
self.appr1: User = _make_approver("_sel1")
self.appr2: User = _make_approver("_sel2")
self.group1: ApproverGroup = approver_group_create(
experimenter=self.exp1,
approver_ids=[str(self.appr1.pk)],
min_approvals=1,
)
self.group2: ApproverGroup = approver_group_create(
experimenter=self.exp2,
approver_ids=[str(self.appr1.pk), str(self.appr2.pk)],
min_approvals=2,
)
def test_get_by_id(self) -> None:
found: ApproverGroup | None = approver_group_get_by_id(
str(self.group1.pk)
)
self.assertEqual(found, self.group1)
def test_get_by_id_invalid_uuid(self) -> None:
self.assertIsNone(approver_group_get_by_id("not-a-uuid"))
def test_get_by_id_nonexistent(self) -> None:
self.assertIsNone(approver_group_get_by_id(str(uuid.uuid4())))
def test_get_by_experimenter(self) -> None:
found: ApproverGroup | None = approver_group_get_by_experimenter(
self.exp1
)
self.assertEqual(found, self.group1)
def test_get_by_experimenter_no_group(self) -> None:
exp3: User = _make_experimenter("_sel3")
self.assertIsNone(approver_group_get_by_experimenter(exp3))
def test_get_by_experimenter_id(self) -> None:
found: ApproverGroup | None = approver_group_get_by_experimenter_id(
str(self.exp2.pk)
)
self.assertEqual(found, self.group2)
def test_get_by_experimenter_id_invalid(self) -> None:
self.assertIsNone(approver_group_get_by_experimenter_id("bad"))
def test_get_by_experimenter_id_nonexistent(self) -> None:
self.assertIsNone(
approver_group_get_by_experimenter_id(str(uuid.uuid4()))
)
def test_list_all(self) -> None:
qs: QuerySet[ApproverGroup] = approver_group_list()
self.assertEqual(qs.count(), 2)
def test_list_for_approver(self) -> None:
qs: QuerySet[ApproverGroup] = approver_group_list_for_approver(
self.appr1
)
self.assertEqual(qs.count(), 2)
qs2: QuerySet[ApproverGroup] = approver_group_list_for_approver(
self.appr2
)
self.assertEqual(qs2.count(), 1)