def test__filter_notified(self):
        num_previous = 2
        # Instantiate so can use its dao for setup
        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)
        self.create_preexisting_review_pairings(self.activity_id,
                                                self.students, obj.dao.session)

        self.make_feedback_received_records(num_previous,
                                            session=obj.dao.session)

        self.workRepo = MagicMock()
        obj.work_repo = self.workRepo

        reviewers_with_notified_authors = [
            r.assessor_id for r in self.pairings
            if r.assessee_id in self.previously_sent
        ]

        # print(reviewers_with_authors_sent_feedback)
        # ra = obj.dao.session.query(ReviewAssociation).all()
        # fb = obj.dao.session.query(FeedbackReceivedRecord).all()

        # call
        obj._filter_notified()

        # check
        self.assertIsInstance(obj.statusRepos[0], FeedbackStatusRepository,
                              "Correct status repo used")

        self.workRepo.remove_student_records.assert_called()

        call_args = [
            c[0][0]
            for c in self.workRepo.remove_student_records.call_args_list
        ]

        print(call_args)

        expected = [
            r for r in self.student_ids if r in reviewers_with_notified_authors
        ]
        self.assertEqual(
            expected, call_args[0],
            "Submitters whose authors have already been sent feedback were removed"
        )
    def test_instantiates_w_correct_values(self):
        """Dummy checking in case some of the main variables used change"""
        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)

        self.assertIsInstance(obj.statusRepos[0], FeedbackStatusRepository,
                              "Correct status repo instantiated")
        self.assertEqual(obj.statusRepos[0].activity, self.activity,
                         "Status repo instantiated with correct activity")

        self.assertIsInstance(obj.activity_notifying_about, DiscussionReview,
                              "Notifying about expected type of activity")
        self.assertEqual(obj.activity_notifying_about,
                         self.unit.discussion_review, "Expected activity")

        self.assertIsInstance(
            obj.activity_for_review_pairings, DiscussionReview,
            "Review pairings based on expected activity type: Discussion review"
        )
        self.assertEqual(obj.activity_for_review_pairings,
                         self.unit.discussion_review, "Expected activity")

        self.assertIsInstance(
            obj.activity, DiscussionReview,
            "Working on results from expected  activity type")
        self.assertEqual(obj.activity, self.unit.discussion_review,
                         "Expected activity")
    def test__load_step(self, workLoaderMock, displayManagerMock):
        self.workRepo.remove_student_records = MagicMock()
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)
        # obj.display_manager = create_autospec(DisplayManager)

        # obj.statusRepos = create_autospec(FeedbackStatusRepository,  previously_sent_students=self.preexisting_student_ids)
        # call
        obj._load_step()

        # check
        workLoaderMock.make.assert_called()
        displayManagerMock.assert_called()

        call_args = [c[0][0] for c in workLoaderMock.call_args_list]
        print(call_args)
    def test_instantiates_correct_status_repos(self):
        """The sending of metareview results requires a
        special status repository"""
        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)

        self.assertIsInstance(obj.statusRepos, list, "status repos is a list")
        self.assertTrue(len(obj.statusRepos) == 1)
        self.assertIsInstance(obj.feedback_status_repo,
                              FeedbackStatusRepository,
                              "Invite repo instantiated")
    def test__assign_step(self, displayManagerMock):
        # self.workRepo.remove_student_records = MagicMock()
        # workLoaderMock.make = MagicMock( return_value=self.workRepo )

        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)
        obj.work_repo = MagicMock(submitter_ids=self.preexisting_student_ids)
        obj._filter_notified = MagicMock()
        self.preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.students, obj.dao.session)

        # call
        obj._assign_step()

        # check
        obj._filter_notified.assert_called()
        self.assertEqual(len(self.preexisting_student_ids),
                         len(obj.associations))
    def test__message_step(self, workLoaderMock, studentRepoMock,
                           messengerMock, statusRepoMock):
        students = {s.student_id: s for s in self.students}

        def se(sid):
            return students.get(sid)

        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)

        # setup work repository (use all students since no filtering occurs here)
        self.workRepo.submitter_ids = self.student_ids
        obj.work_repo = self.workRepo
        # setup students
        obj.studentRepo.get_student = MagicMock(side_effect=se)
        obj.studentRepo.download = MagicMock(return_value=self.students)
        # setup review pairings
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.students, obj.dao.session)
        obj.associations = preexisting_pairings

        # call
        obj._message_step()

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual(messengerMock.call_count, len(self.student_ids),
                         "Send method called expected number of times")
        messenger_args = [(c[1]['student_id'], c[1]['subject'], c[1]['body'])
                          for c in messengerMock.call_args_list]
        # print(args)

        # Check that all messages have the correct subject
        for sid, subj, body in messenger_args:
            expect_subj = FeedbackFromDiscussionReviewMessenger.email_subject_templ.format(
                self.unit.unit_number)
            self.assertEqual(expect_subj, subj, "Correct subject line")

        # Status repo calls on messenger
        obj.messenger.status_repositories[0].record.assert_called()
        call_list = obj.messenger.status_repositories[0].record.call_args_list
        status_args = [c[0][0] for c in call_list]
        self.assertEqual(len(self.students), len(call_list),
                         "Status repo record called expected number of times")
        for sid in self.student_ids:
            self.assertIn(sid, status_args,
                          "StatusRepo.record called on all students")

        # student repo calls on messenger
        for sid in self.student_ids:
            obj.messenger.student_repository.get_student.assert_any_call(sid)

        # Check the content sent
        for record in obj.associations:
            # This is the review which the assessor has submitted
            author_text = self.workRepo.get_formatted_work_by(
                record.assessor_id)
            # which we are sending to the person who created the posts
            sent_text = [
                t[2] for t in messenger_args if t[0] == record.assessee_id
            ][0]
            rx = r'{}'.format(author_text)
            self.assertRegex(sent_text, rx,
                             "Author's work in message sent to reviewer")
    def test_run_previously_sent(self, workLoaderMock, studentRepoMock,
                                 messengerMock):
        authors_who_have_not_been_notified = self.new_students_ids
        authors_who_have_been_previously_notified = self.preexisting_student_ids

        students = {s.student_id: s for s in self.students}

        def se(sid):
            return students.get(sid)

        obj = SendDiscussionReviewToPoster(course=self.course,
                                           unit=self.unit,
                                           is_test=True,
                                           send=True)

        # setup students
        obj.studentRepo.get_student = MagicMock(side_effect=se)
        obj.studentRepo.download = MagicMock(return_value=self.students)
        # setup review pairings
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.students, obj.dao.session)
        reviewers_with_notified_authors = [
            r.assessor_id for r in preexisting_pairings
            if r.assessee_id in authors_who_have_been_previously_notified
        ]
        reviewers_without_notified_authors = [
            s for s in self.student_ids
            if s not in reviewers_with_notified_authors
        ]
        obj.statusRepos = [
            create_autospec(
                FeedbackStatusRepository,
                reviewers_with_notified_authors=reviewers_with_notified_authors
            )
        ]

        # This will be handled by the _filter_notified step. But since
        # we are using a dummy work repo, calling remove_student_records won't do anything
        # Thus we need to pretend that it did its job. (We've tested it elsewhere)
        self.workRepo.submitter_ids = reviewers_without_notified_authors
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        # call
        obj.run()

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual(messengerMock.call_count,
                         len(authors_who_have_not_been_notified),
                         "Send method called expected number of times")
        messenger_args = [(c[1]['student_id'], c[1]['subject'], c[1]['body'])
                          for c in messengerMock.call_args_list]

        # Check that all messages have the correct subject
        for sid, subj, body in messenger_args:
            expect_subj = FeedbackFromDiscussionReviewMessenger.email_subject_templ.format(
                self.unit.unit_number)
            self.assertEqual(expect_subj, subj, "Correct subject line")

        # Status repo calls on messenger which
        # record the message having been sent to authors
        obj.messenger.status_repositories[0].record.assert_called()
        call_list = obj.messenger.status_repositories[0].record.call_args_list
        status_args = [c[0][0] for c in call_list]
        self.assertEqual(len(authors_who_have_not_been_notified),
                         len(call_list),
                         "Status repo record called expected number of times")
        for sid in authors_who_have_not_been_notified:
            self.assertIn(
                sid, status_args,
                "StatusRepo.record called on authors who have now received their feedback (i.e., from newly submitted reviewers)"
            )

        # student repo calls on messenger
        for sid in authors_who_have_not_been_notified:
            obj.messenger.student_repository.get_student.assert_any_call(sid)

        # Check the content sent
        for record in obj.associations:
            # This is the review which the assessor has submitted
            author_text = self.workRepo.get_formatted_work_by(
                record.assessor_id)
            # which we are sending to the person who created the posts
            sent_text = [
                t[2] for t in messenger_args if t[0] == record.assessee_id
            ][0]
            rx = r'{}'.format(author_text)
            self.assertRegex(sent_text, rx,
                             "Author's work in message sent to reviewer")