def test_reviewer_collection(self): c = ReviewerCollection() c[201] = null_tuple(Reviewer)._replace(id=201, person_id=2001, role=BaseReviewerRole.TECH) c[202] = null_tuple(Reviewer)._replace(id=202, person_id=2002, role=BaseReviewerRole.EXTERNAL) self.assertFalse(c.has_person(9999)) self.assertTrue(c.has_person(2001)) self.assertFalse(c.has_person(2001, roles=[BaseReviewerRole.EXTERNAL])) self.assertTrue(c.has_person(2001, roles=[BaseReviewerRole.TECH])) self.assertEqual(c.person_id_by_role(BaseReviewerRole.EXTERNAL), [2002]) self.assertFalse(c.has_role(BaseReviewerRole.FEEDBACK)) self.assertTrue(c.has_role(BaseReviewerRole.EXTERNAL)) self.assertEqual(c.role_by_person_id(2001), [BaseReviewerRole.TECH]) self.assertEqual(c.role_by_person_id(2002), [BaseReviewerRole.EXTERNAL]) reviewers = c.values_by_role(BaseReviewerRole.EXTERNAL) self.assertIsInstance(reviewers, list) self.assertEqual(len(reviewers), 1) self.assertIsInstance(reviewers[0], Reviewer) self.assertEqual(reviewers[0].id, 202)
def test_call_collection(self): c = CallCollection() c[1] = null_tuple(Call)._replace(id=1, queue_id=11, state=CallState.OPEN) c[2] = null_tuple(Call)._replace(id=2, queue_id=12, state=CallState.OPEN) c[3] = null_tuple(Call)._replace(id=3, queue_id=13, state=CallState.UNOPENED) c[4] = null_tuple(Call)._replace(id=4, queue_id=13, state=CallState.CLOSED) self.assertEqual( [x.id for x in c.values_matching(state=CallState.OPEN)], [1, 2]) self.assertEqual( [x.id for x in c.values_matching(state=CallState.UNOPENED)], [3]) self.assertEqual( [x.id for x in c.values_matching(state=CallState.CLOSED)], [4]) self.assertEqual([x.id for x in c.values_matching(queue_id=11)], [1]) self.assertEqual([x.id for x in c.values_matching(queue_id=12)], [2]) self.assertEqual([x.id for x in c.values_matching(queue_id=13)], [3, 4]) self.assertEqual([x.id for x in c.values_matching(queue_id=(11, 12))], [1, 2])
def _test_affiliation_assignment(self, title, affiliations, pi, cois, ref_assignment): view = JCMT(1) # Prepare member collection. members = MemberCollection() i = 0 if pi is not None: i += 1 members[i] = null_tuple(Member)._replace(id=i, affiliation_id=pi, pi=True) for coi in cois: i += 1 members[i] = null_tuple(Member)._replace(id=i, affiliation_id=coi, pi=False) # Compute assignment, make set of affiliations and check total. assignment = view.calculate_affiliation_assignment( db=None, members=members, affiliations=affiliations) assigned_affiliations = set(assignment.keys()) assigned_total = sum(assignment.values()) self.assertAlmostEqual( assigned_total, 1.0, msg='{}: total assignment not equal to 1'.format(title)) # Check that the assignmenets match those specified. for (aff_id, aff_frac) in ref_assignment.items(): self.assertIn(aff_id, assignment, msg='{}: affiliation {} missing'.format( title, aff_id)) self.assertAlmostEqual( assignment[aff_id], aff_frac, msg='{}: affiliation {}: {} (should be {})'.format( title, aff_id, assignment[aff_id], aff_frac), places=5) assigned_affiliations.remove(aff_id) # There should be no other un-matched assignments. self.assertFalse(assigned_affiliations, msg='{}: extra affiliations present: {!r}'.format( title, list(assigned_affiliations)))
def test_feedback_extra(self): # Set up test proposal with a JCMT allocation. types = self.view.get_call_types() proposal_id = self._create_test_proposal('20A', 'P', types.STANDARD) proposal = self.db.get_proposal( facility_id=None, proposal_id=proposal_id) rc = JCMTRequestCollection() rc[1] = null_tuple(JCMTRequest)._replace( instrument=JCMTInstrument.HARP, ancillary=JCMTAncillary.NONE, weather=JCMTWeather.BAND5, time=4.5) self.db.sync_jcmt_proposal_allocation(proposal_id, rc) # Test the get_feedback_extra method. extra = self.view.get_feedback_extra(self.db, proposal) self.assertIsInstance(extra, dict) self.assertEqual(set(extra.keys()), set(('jcmt_allocation',))) alloc = extra['jcmt_allocation'] self.assertIsInstance(alloc, list) self.assertEqual(len(alloc), 1) a = alloc[0] self.assertEqual(a.instrument, 'HARP') self.assertEqual(a.weather, 'Band 5') self.assertEqual(a.time, 4.5) self.assertIsNone(a.ancillary)
def test_proposal_figure_collection(self): fc = ProposalFigureCollection() fc[1001] = null_tuple(ProposalFigureInfo)._replace( id=1001, role=BaseTextRole.TECHNICAL_CASE) fc[1002] = null_tuple(ProposalFigureInfo)._replace( id=1002, role=BaseTextRole.TECHNICAL_CASE) fc[1003] = null_tuple(ProposalFigureInfo)._replace( id=1003, role=BaseTextRole.SCIENCE_CASE) fc[1004] = null_tuple(ProposalFigureInfo)._replace( id=1004, role=BaseTextRole.SCIENCE_CASE) tech = set( (x.id for x in fc.values_by_role(BaseTextRole.TECHNICAL_CASE))) sci = set((x.id for x in fc.values_by_role(BaseTextRole.SCIENCE_CASE))) self.assertEqual(tech, set((1001, 1002))) self.assertEqual(sci, set((1003, 1004)))
def test_group_member_collection(self): c = GroupMemberCollection() c[101] = null_tuple(GroupMember)._replace(id=101, group_type=GroupType.CTTEE, facility_id=1) c[102] = null_tuple(GroupMember)._replace(id=102, group_type=GroupType.TECH, facility_id=1) c[103] = null_tuple(GroupMember)._replace(id=103, group_type=GroupType.TECH, facility_id=1) c[104] = null_tuple(GroupMember)._replace(id=104, group_type=GroupType.COORD, facility_id=2) self.assertEqual( sorted([x.id for x in c.values_by_group_type(GroupType.CTTEE)]), [101]) self.assertEqual( sorted([x.id for x in c.values_by_group_type(GroupType.TECH)]), [102, 103]) self.assertEqual( sorted([x.id for x in c.values_by_group_type(GroupType.COORD)]), [104]) self.assertTrue(c.has_entry(group_type=GroupType.CTTEE)) self.assertTrue( c.has_entry(group_type=(GroupType.TECH, GroupType.COORD))) self.assertFalse(c.has_entry(group_type=999)) self.assertTrue(c.has_entry(facility_id=1)) self.assertTrue(c.has_entry(facility_id=2)) self.assertFalse(c.has_entry(facility_id=3)) self.assertTrue(c.has_entry(group_type=GroupType.CTTEE, facility_id=1)) self.assertFalse(c.has_entry(group_type=GroupType.CTTEE, facility_id=2)) self.assertTrue(c.has_entry(group_type=GroupType.COORD, facility_id=2)) self.assertFalse(c.has_entry(group_type=GroupType.COORD, facility_id=1))
def test_call_preamble_collection(self): c = CallPreambleCollection() c[101] = null_tuple(CallPreamble)._replace(id=101, type=1) c[102] = null_tuple(CallPreamble)._replace(id=102, type=2) v = c.get_type(1) self.assertIsInstance(v, CallPreamble) self.assertEqual(v.id, 101) with self.assertRaises(NoSuchValue): c.get_type(999) v = c.get_type(2, default=None) self.assertIsInstance(v, CallPreamble) self.assertEqual(v.id, 102) v = c.get_type(999, default=None) self.assertIsNone(v)
def test_email_collection(self): c = EmailCollection() c[1] = null_tuple(Email)._replace(address='a@b', primary=False) with self.assertRaisesRegexp(UserError, 'There is no primary'): c.validate() c[2] = null_tuple(Email)._replace(address='c@d', primary=True) c.validate() c[3] = null_tuple(Email)._replace(address='e@f', primary=True) with self.assertRaisesRegexp(UserError, 'more than one primary'): c.validate() c[3] = null_tuple(Email)._replace(address='a@b', primary=False) with self.assertRaisesRegexp(UserError, 'appears more than once'): c.validate()
def test_member_collection(self): c = MemberCollection() c[101] = null_tuple(Member)._replace(id=101, person_id=9001, pi=False, person_name='Person One') with self.assertRaises(KeyError): c.get_pi() self.assertIsNone(c.get_pi(default=None)) c[102] = null_tuple(Member)._replace(id=102, person_id=9002, pi=True, person_name='Person Two') c[103] = null_tuple(Member)._replace(id=103, person_id=9003, pi=False, person_name='Person Three') result = c.get_pi() self.assertEqual(result.person_id, 9002) result = c.get_person(9003) self.assertEqual(result.id, 103) # hedwig.view.auth.for_proposal relies on this exception being # raised when the current user isn't a member of the proposal. with self.assertRaises(KeyError): c.get_person(999999) self.assertTrue(c.has_person(9001)) self.assertFalse(c.has_person(999999))
def test_proposal_collection(self): c = ProposalCollection() c[101] = null_tuple(Proposal)._replace(id=101, facility_id=1) c[102] = null_tuple(Proposal)._replace(id=102, facility_id=1) c[103] = null_tuple(Proposal)._replace(id=103, facility_id=1) c[201] = null_tuple(Proposal)._replace(id=201, facility_id=2) c[202] = null_tuple(Proposal)._replace(id=202, facility_id=2) c[203] = null_tuple(Proposal)._replace(id=203, facility_id=2) fl = list(c.values_by_facility(facility_id=1)) self.assertEqual([x.id for x in fl], [101, 102, 103]) fl = list(c.values_by_facility(facility_id=2)) self.assertEqual([x.id for x in fl], [201, 202, 203]) fl = list(c.values_by_facility(facility_id=3)) self.assertEqual(fl, [])
def test_jcmt_review(self): """ Test methods associated with the "jcmt_review" table. """ role_class = JCMTReviewerRole proposal_id = self._create_test_proposal() person_id = self.db.add_person('Test Reviewer') reviewer_id = self.db.add_reviewer( role_class, proposal_id, person_id, role_class.CTTEE_PRIMARY) self.assertIsInstance(reviewer_id, int) with self.assertRaises(NoSuchRecord): self.db.get_jcmt_review(reviewer_id) with self.assertRaisesRegexp( ConsistencyError, 'JCMT review does not exist'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=True) with self.assertRaisesRegexp( UserError, 'expertise level not recognised'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace(expertise=999), is_update=False) with self.assertRaisesRegexp( Error, 'expertise should be specified'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace(expertise=None), is_update=False) self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) jcmt_review = self.db.get_jcmt_review(reviewer_id) self.assertIsInstance(jcmt_review, JCMTReview) self.assertEqual(jcmt_review.expertise, JCMTReviewerExpertise.INTERMEDIATE) with self.assertRaisesRegexp( ConsistencyError, 'JCMT review already exist'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.EXPERT), is_update=True) jcmt_review = self.db.get_jcmt_review(reviewer_id) self.assertIsNotNone(jcmt_review) self.assertIsInstance(jcmt_review, JCMTReview) self.assertEqual(jcmt_review.expertise, JCMTReviewerExpertise.EXPERT) # Add a second review and try a multiple-reviewer search. reviewer_id_2 = self.db.add_reviewer( role_class, proposal_id, person_id, role_class.CTTEE_SECONDARY) self.assertIsInstance(reviewer_id_2, int) self.db.set_jcmt_review( role_class, reviewer_id_2, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) result = self.db.search_jcmt_review( reviewer_id=[reviewer_id, reviewer_id_2]) self.assertIsInstance(result, ResultCollection) self.assertEqual(set(result.keys()), set((reviewer_id, reviewer_id_2)))
def make_review(id, role, rating, weight): return null_tuple(Reviewer)._replace( id=101, role=role, review_rating=rating, review_weight=weight, review_state=ReviewState.DONE)
def test_reviewer_collection_rating(self): c = ReviewerCollection() rr = BaseReviewerRole def rwf_inc_unweighted(reviewer): if reviewer.review_weight is None: if rr.get_info(reviewer.role).weight: return (None, None) return (reviewer.review_rating, 1.0) return (reviewer.review_rating, reviewer.review_weight / 100.0) def rwf_exc_unweighted(reviewer): if reviewer.review_weight is None: return (None, None) return (reviewer.review_rating, reviewer.review_weight / 100.0) rating = c.get_overall_rating(rwf_inc_unweighted, with_std_dev=False) self.assertIsNone(rating) rating = c.get_overall_rating(rwf_inc_unweighted, with_std_dev=True) self.assertIsInstance(rating, tuple) self.assertEqual(len(rating), 2) self.assertIsNone(rating[0]) self.assertIsNone(rating[1]) # Add some simple review ratings. rs = [ dict(role=rr.TECH), dict(role=rr.EXTERNAL), dict(role=rr.EXTERNAL, review_rating=20), dict(role=rr.CTTEE_PRIMARY), dict(role=rr.CTTEE_PRIMARY, review_rating=10), dict(role=rr.CTTEE_PRIMARY, review_rating=80, review_weight=100), ] for (r, n) in zip(rs, itertools.count(100)): c[n] = null_tuple(Reviewer)._replace(review_state=ReviewState.DONE, **r) self.assertEqual( c.get_overall_rating(rwf_inc_unweighted, with_std_dev=False), 50) self.assertEqual( c.get_overall_rating(rwf_exc_unweighted, with_std_dev=False), 80) # Repeat test above, including calculation of standard deviation. rating = c.get_overall_rating(rwf_exc_unweighted, with_std_dev=True) self.assertIsInstance(rating, tuple) self.assertEqual(len(rating), 2) self.assertEqual(rating[0], 80.0) self.assertEqual(rating[1], 0.0) (rating, std_dev) = c.get_overall_rating(rwf_inc_unweighted, with_std_dev=True) self.assertEqual(rating, 50.0) self.assertEqual(std_dev, 30.0) # Add some more reviews with non-100% weights. rs = [ dict(role=rr.CTTEE_SECONDARY, review_rating=20, review_weight=50), dict(role=rr.CTTEE_SECONDARY, review_rating=40, review_weight=50), ] for (r, n) in zip(rs, itertools.count(200)): c[n] = null_tuple(Reviewer)._replace(review_state=ReviewState.DONE, **r) self.assertEqual( c.get_overall_rating(rwf_exc_unweighted, with_std_dev=False), 55) (rating, std_dev) = c.get_overall_rating(rwf_exc_unweighted, with_std_dev=True) self.assertEqual(rating, 55.0) self.assertAlmostEqual(std_dev, 25.981, places=3)
def make_review(id, role, rating, expertise): return null_tuple(Reviewer)._replace( id=101, role=role, review_rating=rating, review_state=ReviewState.DONE, review_extra=null_tuple(JCMTReview)._replace( expertise=expertise))
def test_jcmt_review(self): """ Test methods associated with the "jcmt_review" table. """ role_class = JCMTReviewerRole proposal_id = self._create_test_proposal() person_id = self.db.add_person('Test Reviewer') reviewer_id = self.db.add_reviewer(role_class, proposal_id, person_id, role_class.CTTEE_PRIMARY) self.assertIsInstance(reviewer_id, int) with self.assertRaises(NoSuchRecord): self.db.get_jcmt_review(reviewer_id) with self.assertRaisesRegexp(ConsistencyError, 'JCMT review does not exist'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=True) with self.assertRaisesRegexp(UserError, 'expertise level not recognised'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace(expertise=999), is_update=False) with self.assertRaisesRegexp(Error, 'expertise should be specified'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace(expertise=None), is_update=False) self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) jcmt_review = self.db.get_jcmt_review(reviewer_id) self.assertIsInstance(jcmt_review, JCMTReview) self.assertEqual(jcmt_review.expertise, JCMTReviewerExpertise.INTERMEDIATE) with self.assertRaisesRegexp(ConsistencyError, 'JCMT review already exist'): self.db.set_jcmt_review( role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) self.db.set_jcmt_review(role_class, reviewer_id, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.EXPERT), is_update=True) jcmt_review = self.db.get_jcmt_review(reviewer_id) self.assertIsNotNone(jcmt_review) self.assertIsInstance(jcmt_review, JCMTReview) self.assertEqual(jcmt_review.expertise, JCMTReviewerExpertise.EXPERT) # Add a second review and try a multiple-reviewer search. reviewer_id_2 = self.db.add_reviewer(role_class, proposal_id, person_id, role_class.CTTEE_SECONDARY) self.assertIsInstance(reviewer_id_2, int) self.db.set_jcmt_review( role_class, reviewer_id_2, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) result = self.db.search_jcmt_review( reviewer_id=[reviewer_id, reviewer_id_2]) self.assertIsInstance(result, ResultCollection) self.assertEqual(set(result.keys()), set((reviewer_id, reviewer_id_2)))
def make_review(id, role, rating, weight): return null_tuple(Reviewer)._replace(id=101, role=role, review_rating=rating, review_weight=weight, review_state=ReviewState.DONE)
def test_attach_review(self): types = self.view.get_call_types() roles = self.view.get_reviewer_roles() # Create test proposals and reviews. proposal_1 = self._create_test_proposal('20A', 'P', types.STANDARD) proposal_2 = self._create_test_proposal('20A', 'P', types.STANDARD) person_id = self.db.add_person('Test Reviewer') review_1a = self.db.add_reviewer( roles, proposal_1, person_id, roles.CTTEE_PRIMARY) self.db.set_review( roles, review_1a, text='test', format_=FormatType.PLAIN, assessment=None, rating=30, weight=None, note='', note_format=FormatType.PLAIN, note_public=False, is_update=False) self.db.set_jcmt_review( roles, review_1a, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.EXPERT), is_update=False) review_1b = self.db.add_reviewer( roles, proposal_1, person_id, roles.CTTEE_SECONDARY) self.db.set_review( roles, review_1b, text='test', format_=FormatType.PLAIN, assessment=None, rating=40, weight=None, note='', note_format=FormatType.PLAIN, note_public=False, is_update=False) self.db.set_jcmt_review( roles, review_1b, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.INTERMEDIATE), is_update=False) review_2a = self.db.add_reviewer( roles, proposal_2, person_id, roles.CTTEE_PRIMARY) self.db.set_review( roles, review_2a, text='test', format_=FormatType.PLAIN, assessment=None, rating=50, weight=None, note='', note_format=FormatType.PLAIN, note_public=False, is_update=False) self.db.set_jcmt_review( roles, review_2a, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.NON_EXPERT), is_update=False) review_2b = self.db.add_reviewer( roles, proposal_2, person_id, roles.CTTEE_SECONDARY) self.db.set_review( roles, review_2b, text='test', format_=FormatType.PLAIN, assessment=None, rating=60, weight=None, note='', note_format=FormatType.PLAIN, note_public=False, is_update=False) self.db.set_jcmt_review( roles, review_2b, review=null_tuple(JCMTReview)._replace( expertise=JCMTReviewerExpertise.NON_EXPERT), is_update=False) # Expected data for tests. expect = { proposal_1: { review_1a: {'r': 30, 'e': JCMTReviewerExpertise.EXPERT}, review_1b: {'r': 40, 'e': JCMTReviewerExpertise.INTERMEDIATE}, }, proposal_2: { review_2a: {'r': 50, 'e': JCMTReviewerExpertise.NON_EXPERT}, review_2b: {'r': 60, 'e': JCMTReviewerExpertise.NON_EXPERT}, } } # Original proposal collection should not have JCMT review info. c = self.db.search_proposal(with_reviewers=True, with_review_info=True) self.assertIsInstance(c, ProposalCollection) self.assertEqual(set(c.keys()), set(expect.keys())) for proposal in c.values(): proposal_expect = expect[proposal.id] rc = proposal.reviewers self.assertIsInstance(rc, ReviewerCollection) self.assertEqual(set(rc.keys()), set(proposal_expect.keys())) for reviewer in rc.values(): reviewer_expect = proposal_expect[reviewer.id] self.assertEqual(reviewer.review_rating, reviewer_expect['r']) self.assertIsNone(reviewer.review_extra) # Attach the JCMT information. self.view.attach_review_extra(self.db, c) # Check that the collection has been updated correctly. self.assertEqual(set(c.keys()), set(expect.keys())) for proposal in c.values(): proposal_expect = expect[proposal.id] rc = proposal.reviewers self.assertIsInstance(rc, ReviewerCollection) self.assertEqual(set(rc.keys()), set(proposal_expect.keys())) for reviewer in rc.values(): reviewer_expect = proposal_expect[reviewer.id] self.assertEqual(reviewer.review_rating, reviewer_expect['r']) self.assertIsInstance(reviewer.review_extra, JCMTReview) self.assertEqual(reviewer.review_extra.expertise, reviewer_expect['e'])