1212
1313import debug # pyflakes:ignore
1414
15- from ietf .review .models import ReviewRequest , ReviewTeamResult , ReviewerSettings , ReviewWish , UnavailablePeriod
15+ from ietf .review .models import (ReviewRequest , ReviewTeamResult , ReviewerSettings ,
16+ ReviewWish , UnavailablePeriod , NextReviewerInTeam )
17+ from ietf .review .utils import reviewer_rotation_list , possibly_advance_next_reviewer_for_team
1618import ietf .review .mailarch
1719from ietf .person .models import Email , Person
1820from ietf .name .models import ReviewResultName , ReviewRequestStateName , ReviewTypeName , DocRelationshipName
21+ from ietf .group .models import Group
1922from ietf .doc .models import DocumentAuthor , Document , DocAlias , RelatedDocument , DocEvent
2023from ietf .utils .test_utils import TestCase
21- from ietf .utils .test_data import make_test_data , make_review_data
24+ from ietf .utils .test_data import make_test_data , make_review_data , create_person
2225from ietf .utils .test_utils import login_testing_unauthorized , unicontent , reload_db_objects
2326from ietf .utils .mail import outbox , empty_outbox
2427
@@ -133,6 +136,94 @@ def test_close_request(self):
133136 self .assertEqual (len (outbox ), 1 )
134137 self .assertTrue ("closed" in unicode (outbox [0 ]).lower ())
135138
139+ def make_data_for_rotation_tests (self , doc ):
140+ team = Group .objects .create (state_id = "active" , acronym = "rotationteam" , name = "Review Team" , type_id = "dir" ,
141+ list_email = "rotationteam@ietf.org" , parent = Group .objects .get (acronym = "farfut" ))
142+
143+ # make a bunch of reviewers
144+ reviewers = [
145+ create_person (team , "reviewer" , name = "Test Reviewer{}" .format (i ), username = "testreviewer{}" .format (i ))
146+ for i in range (5 )
147+ ]
148+
149+ self .assertEqual (reviewers , reviewer_rotation_list (team ))
150+
151+ return team , reviewers
152+
153+ def test_possibly_advance_next_reviewer_for_team (self ):
154+ doc = make_test_data ()
155+
156+ team , reviewers = self .make_data_for_rotation_tests (doc )
157+
158+ def get_skip_next (person ):
159+ settings = (ReviewerSettings .objects .filter (team = team , person = person ).first ()
160+ or ReviewerSettings (team = team ))
161+ return settings .skip_next
162+
163+ possibly_advance_next_reviewer_for_team (team , reviewers [0 ].pk )
164+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [1 ])
165+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
166+ self .assertEqual (get_skip_next (reviewers [1 ]), 0 )
167+
168+ possibly_advance_next_reviewer_for_team (team , reviewers [1 ].pk )
169+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [2 ])
170+
171+ # skip reviewer 2
172+ possibly_advance_next_reviewer_for_team (team , reviewers [3 ].pk )
173+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [2 ])
174+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
175+ self .assertEqual (get_skip_next (reviewers [1 ]), 0 )
176+ self .assertEqual (get_skip_next (reviewers [2 ]), 0 )
177+ self .assertEqual (get_skip_next (reviewers [3 ]), 1 )
178+
179+ # pick reviewer 2, use up reviewer 3's skip_next
180+ possibly_advance_next_reviewer_for_team (team , reviewers [2 ].pk )
181+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [4 ])
182+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
183+ self .assertEqual (get_skip_next (reviewers [1 ]), 0 )
184+ self .assertEqual (get_skip_next (reviewers [2 ]), 0 )
185+ self .assertEqual (get_skip_next (reviewers [3 ]), 0 )
186+ self .assertEqual (get_skip_next (reviewers [4 ]), 0 )
187+
188+ # check wrap-around
189+ possibly_advance_next_reviewer_for_team (team , reviewers [4 ].pk )
190+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [0 ])
191+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
192+ self .assertEqual (get_skip_next (reviewers [1 ]), 0 )
193+ self .assertEqual (get_skip_next (reviewers [2 ]), 0 )
194+ self .assertEqual (get_skip_next (reviewers [3 ]), 0 )
195+ self .assertEqual (get_skip_next (reviewers [4 ]), 0 )
196+
197+ # unavailable
198+ today = datetime .date .today ()
199+ UnavailablePeriod .objects .create (team = team , person = reviewers [1 ], start_date = today , end_date = today , availability = "unavailable" )
200+ possibly_advance_next_reviewer_for_team (team , reviewers [0 ].pk )
201+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [2 ])
202+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
203+ self .assertEqual (get_skip_next (reviewers [1 ]), 0 )
204+ self .assertEqual (get_skip_next (reviewers [2 ]), 0 )
205+ self .assertEqual (get_skip_next (reviewers [3 ]), 0 )
206+ self .assertEqual (get_skip_next (reviewers [4 ]), 0 )
207+
208+ # pick unavailable anyway
209+ possibly_advance_next_reviewer_for_team (team , reviewers [1 ].pk )
210+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [2 ])
211+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
212+ self .assertEqual (get_skip_next (reviewers [1 ]), 1 )
213+ self .assertEqual (get_skip_next (reviewers [2 ]), 0 )
214+ self .assertEqual (get_skip_next (reviewers [3 ]), 0 )
215+ self .assertEqual (get_skip_next (reviewers [4 ]), 0 )
216+
217+ # not through min_interval
218+ ReviewRequest .objects .create (team = team , doc = doc , type_id = "early" , state_id = "accepted" , deadline = today , requested_by = reviewers [0 ], reviewer = reviewers [2 ].email_set .first ())
219+ possibly_advance_next_reviewer_for_team (team , reviewers [3 ].pk )
220+ self .assertEqual (NextReviewerInTeam .objects .get (team = team ).next_reviewer , reviewers [4 ])
221+ self .assertEqual (get_skip_next (reviewers [0 ]), 0 )
222+ self .assertEqual (get_skip_next (reviewers [1 ]), 1 )
223+ self .assertEqual (get_skip_next (reviewers [2 ]), 0 )
224+ self .assertEqual (get_skip_next (reviewers [3 ]), 0 )
225+ self .assertEqual (get_skip_next (reviewers [4 ]), 0 )
226+
136227 def test_assign_reviewer (self ):
137228 doc = make_test_data ()
138229
@@ -166,6 +257,7 @@ def test_assign_reviewer(self):
166257
167258 reviewer_settings = ReviewerSettings .objects .get (person__email = plain_email )
168259 reviewer_settings .filter_re = doc .name
260+ reviewer_settings .skip_next = 1
169261 reviewer_settings .save ()
170262
171263 UnavailablePeriod .objects .create (
@@ -177,6 +269,14 @@ def test_assign_reviewer(self):
177269
178270 ReviewWish .objects .create (person = plain_email .person , team = review_req .team , doc = doc )
179271
272+ # pick a non-existing reviewer as next to see that we can
273+ # handle reviewers who have left
274+ NextReviewerInTeam .objects .filter (team = review_req .team ).delete ()
275+ NextReviewerInTeam .objects .create (
276+ team = review_req .team ,
277+ next_reviewer = Person .objects .exclude (pk = plain_email .person_id ).first (),
278+ )
279+
180280 assign_url = urlreverse ('ietf.doc.views_review.assign_reviewer' , kwargs = { "name" : doc .name , "request_id" : review_req .pk })
181281
182282
@@ -194,16 +294,18 @@ def test_assign_reviewer(self):
194294 self .assertEqual (r .status_code , 200 )
195295 q = PyQuery (r .content )
196296 plain_label = q ("option[value=\" {}\" ]" .format (plain_email .address )).text ().lower ()
197- self .assertIn ("ready for" , plain_label )
198297 self .assertIn ("reviewed document before" , plain_label )
199298 self .assertIn ("wishes to review" , plain_label )
200299 self .assertIn ("is author" , plain_label )
201300 self .assertIn ("regexp matches" , plain_label )
202- self .assertIn ("unavailable" , plain_label )
301+ self .assertIn ("unavailable indefinitely" , plain_label )
302+ self .assertIn ("skip next 1" , plain_label )
303+ self .assertIn ("#1" , plain_label )
203304
204305 # assign
205306 empty_outbox ()
206- reviewer = Email .objects .filter (role__name = "reviewer" , role__group = review_req .team ).first ()
307+ rotation_list = reviewer_rotation_list (review_req .team )
308+ reviewer = Email .objects .filter (role__name = "reviewer" , role__group = review_req .team , person = rotation_list [0 ]).first ()
207309 r = self .client .post (assign_url , { "action" : "assign" , "reviewer" : reviewer .pk })
208310 self .assertEqual (r .status_code , 302 )
209311
@@ -212,12 +314,13 @@ def test_assign_reviewer(self):
212314 self .assertEqual (review_req .reviewer , reviewer )
213315 self .assertEqual (len (outbox ), 1 )
214316 self .assertTrue ("assigned" in unicode (outbox [0 ]))
317+ self .assertEqual (NextReviewerInTeam .objects .get (team = review_req .team ).next_reviewer , rotation_list [1 ])
215318
216319 # re-assign
217320 empty_outbox ()
218321 review_req .state = ReviewRequestStateName .objects .get (slug = "accepted" )
219322 review_req .save ()
220- reviewer = Email .objects .filter (role__name = "reviewer" , role__group = review_req .team ). exclude ( pk = reviewer . pk ).first ()
323+ reviewer = Email .objects .filter (role__name = "reviewer" , role__group = review_req .team , person = rotation_list [ 1 ] ).first ()
221324 r = self .client .post (assign_url , { "action" : "assign" , "reviewer" : reviewer .pk })
222325 self .assertEqual (r .status_code , 302 )
223326
0 commit comments