613c99dce2
also provided tests
378 lines
14 KiB
Python
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)
|