Skip to content

Commit 6b85d5a

Browse files
author
Sasha Romijn
committed
- Remove consideration of unavailability from ranking for recommended
assignment order, as it is obsolete - Add test for recommended assignment order - Legacy-Id: 16989
1 parent ce812a3 commit 6b85d5a

2 files changed

Lines changed: 67 additions & 27 deletions

File tree

ietf/review/policies.py

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ def setup_reviewer_field(self, field, review_req):
5656
if one_assignment:
5757
field.initial = one_assignment.reviewer_id
5858

59-
choices = self._recommended_assignment_order(field.queryset, review_req)
59+
choices = self.recommended_assignment_order(field.queryset, review_req)
6060
if not field.required:
6161
choices = [("", field.empty_label)] + choices
6262

6363
field.choices = choices
6464

65-
def _recommended_assignment_order(self, email_queryset, review_req):
65+
def recommended_assignment_order(self, email_queryset, review_req):
6666
"""
6767
Determine the recommended assignment order for a review request,
6868
choosing from the reviewers in email_queryset, which should be a queryset
@@ -71,7 +71,7 @@ def _recommended_assignment_order(self, email_queryset, review_req):
7171
if review_req.team != self.team:
7272
raise ValueError('Reviewer queue policy was passed review request belonging to different team.')
7373
resolver = AssignmentOrderResolver(email_queryset, review_req, self.default_reviewer_rotation_list())
74-
return resolver.determine_ranking()
74+
return [(r['email'].pk, r['label']) for r in resolver.determine_ranking()]
7575

7676
def _unavailable_reviewers(self, dont_skip):
7777
# prune reviewers not in the rotation (but not the assigned
@@ -127,11 +127,12 @@ def determine_ranking(self):
127127
"""
128128
ranking = []
129129
for e in self.possible_emails:
130-
ranking.append(self._ranking_for_email(e))
130+
ranking_for_email = self._ranking_for_email(e)
131+
if ranking_for_email:
132+
ranking.append(ranking_for_email)
131133

132134
ranking.sort(key=lambda r: r["scores"], reverse=True)
133-
134-
return [(r["email"].pk, r["label"]) for r in ranking]
135+
return ranking
135136

136137
def _ranking_for_email(self, email):
137138
"""
@@ -149,23 +150,9 @@ def add_boolean_score(direction, expr, explanation=None):
149150
if expr and explanation:
150151
explanations.append(explanation)
151152

152-
# unavailable for review periods
153-
periods = self.unavailable_periods.get(email.person_id, [])
154-
unavailable_at_the_moment = periods and not (
155-
email.person_id in self.has_reviewed_previous and all(
156-
p.availability == "canfinish" for p in periods))
157-
add_boolean_score(-1, unavailable_at_the_moment)
158-
159-
def format_period(p):
160-
if p.end_date:
161-
res = "unavailable until {}".format(p.end_date.isoformat())
162-
else:
163-
res = "unavailable indefinitely"
164-
return "{} ({})".format(res, p.get_availability_display())
165-
166-
if periods:
167-
explanations.append(", ".join(format_period(p) for p in periods))
168-
153+
if email.person_id not in self.rotation_index:
154+
return
155+
169156
# misc
170157
add_boolean_score(+1, email.person_id in self.has_reviewed_previous, "reviewed document before")
171158
add_boolean_score(+1, email.person_id in self.wish_to_review, "wishes to review document")

ietf/review/test_policies.py

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
from ietf.doc.factories import WgDraftFactory
66
from ietf.group.factories import ReviewTeamFactory
77
from ietf.group.models import Group, Role
8-
from ietf.review.factories import ReviewAssignmentFactory
8+
from ietf.person.models import Email
9+
from ietf.review.factories import ReviewAssignmentFactory, ReviewRequestFactory
910
from ietf.review.models import ReviewerSettings, NextReviewerInTeam, UnavailablePeriod, \
10-
ReviewRequest
11-
from ietf.review.policies import get_reviewer_queue_policy
11+
ReviewRequest, ReviewWish
12+
from ietf.review.policies import get_reviewer_queue_policy, AssignmentOrderResolver
1213
from ietf.utils.test_data import create_person
1314
from ietf.utils.test_utils import TestCase
1415

@@ -49,6 +50,14 @@ def test_default_reviewer_rotation_list(self):
4950
rotation = policy.default_reviewer_rotation_list()
5051
self.assertNotIn(unavailable_reviewer, rotation)
5152
self.assertEqual(rotation, reviewers[2:] + reviewers[:1])
53+
54+
def test_recommended_assignment_order(self):
55+
team = ReviewTeamFactory(acronym="rotationteam", name="Review Team", list_email="rotationteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
56+
policy = get_reviewer_queue_policy(team)
57+
58+
reviewer_high = create_person(team, "reviewer", name="Test Reviewer-high", username="testreviewerhigh")
59+
reviewer_low = create_person(team, "reviewer", name="Test Reviewer-low", username="testreviewerlow")
60+
5261

5362
def test_update_policy_state_for_assignment(self):
5463

@@ -137,4 +146,48 @@ def get_skip_next(person):
137146
self.assertEqual(get_skip_next(reviewers[1]), 1)
138147
self.assertEqual(get_skip_next(reviewers[2]), 0)
139148
self.assertEqual(get_skip_next(reviewers[3]), 0)
140-
self.assertEqual(get_skip_next(reviewers[4]), 0)
149+
self.assertEqual(get_skip_next(reviewers[4]), 0)
150+
151+
152+
class AssignmentOrderResolverTests(TestCase):
153+
def test_determine_ranking(self):
154+
# reviewer_high is second in the default rotation, reviewer_low is first
155+
# however, reviewer_high hits every score increase, reviewer_low hits every score decrease
156+
team = ReviewTeamFactory(acronym="rotationteam", name="Review Team", list_email="rotationteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
157+
reviewer_high = create_person(team, "reviewer", name="Test Reviewer-high", username="testreviewerhigh")
158+
reviewer_low = create_person(team, "reviewer", name="Test Reviewer-low", username="testreviewerlow")
159+
160+
# Trigger author check, AD check and group check
161+
doc = WgDraftFactory(group__acronym='mars', rev='01', authors=[reviewer_low], ad_id=reviewer_low.pk, shepherd=reviewer_low)
162+
Role.objects.create(group=doc.group, person=reviewer_low, email=reviewer_low.email(), name_id='advisor')
163+
164+
review_req = ReviewRequestFactory(doc=doc, team=team, type_id='early', state_id='assigned')
165+
rotation_list = [reviewer_low, reviewer_high]
166+
167+
# Trigger previous review check and completed review stats - TODO: something something related documents
168+
ReviewAssignmentFactory(review_request__team=team, review_request__doc=doc, reviewer=reviewer_high.email(), state_id='completed')
169+
# Trigger other review stats
170+
ReviewAssignmentFactory(review_request__team=team, review_request__doc=doc, reviewer=reviewer_high.email(), state_id='no-response')
171+
ReviewAssignmentFactory(review_request__team=team, review_request__doc=doc, reviewer=reviewer_high.email(), state_id='part-completed')
172+
# Trigger review wish check
173+
ReviewWish.objects.create(team=team, doc=doc, person=reviewer_high)
174+
175+
# Trigger max frequency and open review stats
176+
ReviewAssignmentFactory(review_request__team=team, reviewer=reviewer_low.email(), state_id='assigned', review_request__doc__pages=10)
177+
# Trigger skip_next, max frequency and filter_re
178+
ReviewerSettings.objects.create(
179+
team=team,
180+
person=reviewer_low,
181+
filter_re='.*draft.*',
182+
skip_next=2,
183+
min_interval=91,
184+
)
185+
186+
order = AssignmentOrderResolver(Email.objects.all(), review_req, rotation_list)
187+
ranking = order.determine_ranking()
188+
self.assertEqual(ranking[0]['email'], reviewer_high.email())
189+
self.assertEqual(ranking[1]['email'], reviewer_low.email())
190+
self.assertEqual(ranking[0]['scores'], [ 1, 1, 1, 1, 0, 0, -1])
191+
self.assertEqual(ranking[1]['scores'], [-1, -1, -1, -1, -91, -2, 0])
192+
self.assertEqual(ranking[0]['label'], 'Test Reviewer-high: reviewed document before; wishes to review document; #2; 1 no response, 1 partially complete, 1 fully completed')
193+
self.assertEqual(ranking[1]['label'], 'Test Reviewer-low: is author of document; filter regexp matches; max frequency exceeded, ready in 91 days; skip next 2; #1; currently 1 open, 10 pages')

0 commit comments

Comments
 (0)