def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.activity = self.unit.discussion_forum
        self.course = MagicMock()

        # student recieiving the message
        self.author = student_factory()
        self.reviewer = student_factory()

        # This would be the content unit
        self.work = fake.text()
        # Set to none so that loader thinks not a quiz
        self.activity_id = self.unit.discussion_forum.id
        self.dao = SqliteDAO()
        self.session = self.dao.session
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects

        # self.studentRepo = StudentRepository()
        # self.studentRepo.get_student = MagicMock( return_value=self.reviewer )
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock(
            return_value=self.work)
        self.review_assign = MagicMock(assessor_id=self.reviewer.id,
                                       assessee_id=self.author.id)
        self.statusRepo = MagicMock()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content(self.student_ids)
        self.workRepo.add_students_to_data(self.student_ids,
                                           make_dataframe=True)
 def setUp( self ):
     self.config_for_test()
     env.CONFIG.semester_name = "T30"
     self.unit = unit_factory()
     self.course = MagicMock()
     self.activity_id = self.unit.review.id
     # self.dao = SqliteDAO()
     self.create_new_and_preexisting_students()
     # Prepare fake work repo to give values to calling  objects
     self.workRepo = ContentRepositoryMock()
     self.workRepo.create_test_content( self.student_ids )
     self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True)
예제 #3
0
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.course = MagicMock()

        # Set to none so that loader thinks not a quiz
        self.unit.initial_work.quiz_id = None
        self.activity_id = self.unit.initial_work.id
        self.dao = SqliteDAO()
        self.session = self.dao.session
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content(self.student_ids)
        self.workRepo.add_students_to_data(self.student_ids,
                                           make_dataframe=True)
    def test_run_some_already_notified( self, workLoaderMock, studentRepoMock, messengerMock ):
        # Set up status repo with some students already notified
        num_previously_sent = fake.random.randint( 1, len( self.students ) - 1 )
        previously_sent = self.student_ids[ : num_previously_sent ]
        # previously_sent = fake.random.choices(self.student_ids, k=num_previously_sent)
        to_notify = [ s for s in self.student_ids if s not in previously_sent ]
        num_to_notify = len( to_notify )

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content( self.student_ids )

        # prepare student repo
        students = { s.student_id: s for s in self.students }

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

        # set up mocks on instantiated object
        obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True )
        obj.studentRepo.get_student = MagicMock( side_effect=se )
        obj.studentRepo.download = MagicMock( return_value=self.students )

        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        # Sets up data for the association repo to use
        self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students )

        reviewers_without_prev_notified_authors = [s.assessor_id for s in self.preexisting_pairings if s.assessee_id not in previously_sent]

        # setting this since filter step doesn't happen on dummy
        workRepo.submitter_ids = reviewers_without_prev_notified_authors
        # workRepo.remove_student_records = MagicMock()
        workLoaderMock.make = MagicMock( return_value=workRepo )

        # Set up previous notifications
        for sid in previously_sent:
            obj.feedback_status_repo.record( sid )

        # call
        obj.run()

        # check
        self.assertEqual( num_to_notify, len( obj.associations ), "Correct number of students notified" )

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual( messengerMock.call_count, num_to_notify, "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 the content sent
        for record in obj.associations:
            # print(record.assessee_id)
            reviewer_text = workRepo.get_formatted_work_by( record.assessor_id )
            # see if sent to assessee
            sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ]
            rx = r'{}'.format( reviewer_text )
            self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )
예제 #5
0
    def test_raises_when_only_one_submission(self, workLoaderMock,
                                             studentRepoMock):

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content(self.new_students_ids)
        workRepo.add_students_to_data(self.student_ids, make_dataframe=True)

        # Setting to return all the previously assigned students.
        # this should cause all the students to be filtered out
        # and the errror raised
        self.workRepo.submitter_ids = [self.new_students[0]]
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        studentRepoMock.download = MagicMock(return_value=self.students)

        # call
        obj = SendInitialWorkToReviewer(course=self.course,
                                        unit=self.unit,
                                        is_test=True,
                                        send=True)
        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.preexisting_students)

        with self.assertRaises(NoAvailablePartner):
            obj.run()
예제 #6
0
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.activity_data = activity_data_factory()
        self.activity = Activity(**self.activity_data)
        # student recieiving the message
        self.receiving_student = student_factory()
        self.reviewed_student_work = fake.text()

        self.studentRepo = StudentRepository()
        self.studentRepo.get_student = MagicMock(
            return_value=self.receiving_student)
        self.contentRepo = ContentRepositoryMock()
        self.statusRepo = create_autospec(StatusRepository)
class TestUnitTests(TestingBase):
    """Unit tests with all dependencies mocked"""
    def setUp( self ):
        self.config_for_test()
        env.CONFIG.semester_name = "T30"
        self.unit = unit_factory()
        self.course = MagicMock()
        self.activity_id = self.unit.review.id
        # self.dao = SqliteDAO()
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content( self.student_ids )
        self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True)

    def test_instantiates_correct_status_repos( self ):
        """The sending of metareview results requires a
        special status repository"""
        obj = SendReviewToReviewee( 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) == 2)
        self.assertIsInstance(obj.invite_status_repo, InvitationStatusRepository, "Invite repo instantiated")
        self.assertIsInstance( obj.feedback_status_repo, FeedbackStatusRepository, "Correct status repo instantiated" )
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        # self.activity_data = activity_data_factory()
        self.activity = self.unit.review  #InitialWork( **self.activity_data )

        # student recieiving the message
        self.author = student_factory()
        self.reviewer = student_factory()

        # This would be the content unit
        self.work = fake.text()

        self.studentRepo = StudentRepository()
        self.studentRepo.get_student = MagicMock(return_value=self.reviewer)
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock(
            return_value=self.work)
        self.review_assign = MagicMock(assessor_id=self.reviewer.id,
                                       assessee_id=self.author.id)
        self.statusRepo = MagicMock()  #create_autospec(StatusRepository)
예제 #9
0
    def setUp( self ):
        self.config_for_test()
        self.unit = unit_factory()
        self.activity = self.unit.metareview

        # student receiving the message
        self.author = student_factory()
        self.reviewer = student_factory()

        # This would be the results of the peer review
        self.work = fake.text()

        self.studentRepo = StudentRepository()
        # self.studentRepo.data = {self.author.id : self.author,
        #                          self.reviewer.id: self.reviewer
        #                          }
        self.studentRepo.get_student = MagicMock( return_value=self.author )
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock( return_value=self.work )
        self.statusRepo = create_autospec(InvitationStatusRepository)

        self.review_assign = MagicMock( assessor_id=self.reviewer.id, assessee_id=self.author.id )
예제 #10
0
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        # self.activity_data = activity_data_factory()
        self.activity = self.unit.metareview  #InitialWork( **self.activity_data )

        self.author = student_factory()
        # student receiving the message (we are sending the feedback
        # created by the author of the content assignment)
        self.reviewer = student_factory()

        # This would be metareview feedback on the review
        self.work = fake.text()

        self.studentRepo = StudentRepository()
        self.studentRepo.get_student = MagicMock(return_value=self.reviewer)
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock(
            return_value=self.work)

        self.review_assign = MagicMock(assessor_id=self.reviewer.id,
                                       assessee_id=self.author.id)
        self.statusRepo = create_autospec(FeedbackStatusRepository)
    def test_run( self, workLoaderMock, studentRepoMock, messengerMock, statusRepoMock, inviteStatusRepoMock ):

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content( self.student_ids )
        workRepo.submitter_ids = self.student_ids
        workRepo.remove_student_records = MagicMock()
        workLoaderMock.make = MagicMock( return_value=workRepo )

        # prepare student repo
        students = { s.student_id: s for s in self.students }

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

        # call
        obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True )
        obj.studentRepo.get_student = MagicMock( side_effect=se )
        obj.studentRepo.download = MagicMock( return_value=self.students )

        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        # Sets up data for the association repo to use
        self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students )

        obj.run()

        # check
        self.assertEqual( len( obj.associations ), len( self.students ), "Correct number of students notified" )

        # Check that filtered previously notified
        workRepo.remove_student_records.assert_called()

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual( messengerMock.call_count, len( self.students ),
                          "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:
            self.assertEqual(self.unit.metareview.email_subject, subj, "Correct subject line")

        # Status repo calls on messenger
        for repo in obj.messenger.status_repositories:
            repo.record.assert_called()
            # obj.messenger.status_repositories.record_invited.assert_called()
            call_list = repo.record.call_args_list
            # call_list = obj.messenger.status_repositories.record_invited.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, "Record called on both repos for 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:
            # print(record.assessee_id)
            reviewer_text = workRepo.get_formatted_work_by( record.assessor_id )
            # see if sent to assessee
            sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ]
            rx = r'{}'.format( reviewer_text )
            self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )
class TestFunctionalTests( TestingBase ):
    """Checks that works properly on first run after
    deadline on work that has been submitted
    """

    def setUp( self ):
        self.config_for_test()
        env.CONFIG.semester_name = "T30"
        self.unit = unit_factory()
        self.course = MagicMock()
        self.activity_id = self.unit.review.id
        # self.dao = SqliteDAO()
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content( self.student_ids )
        self.workRepo.add_students_to_data(self.student_ids, make_dataframe=True)

    @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.InvitationStatusRepository' )
    @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.FeedbackStatusRepository' )
    @patch( 'CanvasHacks.Messaging.base.ConversationMessageSender.send' )
    @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository' )
    @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.WorkRepositoryLoaderFactory' )
    def test_run( self, workLoaderMock, studentRepoMock, messengerMock, statusRepoMock, inviteStatusRepoMock ):

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content( self.student_ids )
        workRepo.submitter_ids = self.student_ids
        workRepo.remove_student_records = MagicMock()
        workLoaderMock.make = MagicMock( return_value=workRepo )

        # prepare student repo
        students = { s.student_id: s for s in self.students }

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

        # call
        obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True )
        obj.studentRepo.get_student = MagicMock( side_effect=se )
        obj.studentRepo.download = MagicMock( return_value=self.students )

        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        # Sets up data for the association repo to use
        self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students )

        obj.run()

        # check
        self.assertEqual( len( obj.associations ), len( self.students ), "Correct number of students notified" )

        # Check that filtered previously notified
        workRepo.remove_student_records.assert_called()

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual( messengerMock.call_count, len( self.students ),
                          "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:
            self.assertEqual(self.unit.metareview.email_subject, subj, "Correct subject line")

        # Status repo calls on messenger
        for repo in obj.messenger.status_repositories:
            repo.record.assert_called()
            # obj.messenger.status_repositories.record_invited.assert_called()
            call_list = repo.record.call_args_list
            # call_list = obj.messenger.status_repositories.record_invited.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, "Record called on both repos for 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:
            # print(record.assessee_id)
            reviewer_text = workRepo.get_formatted_work_by( record.assessor_id )
            # see if sent to assessee
            sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ]
            rx = r'{}'.format( reviewer_text )
            self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )

    @patch( 'CanvasHacks.Messaging.base.ConversationMessageSender.send' )
    @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository' )
    @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.WorkRepositoryLoaderFactory' )
    def test_run_some_already_notified( self, workLoaderMock, studentRepoMock, messengerMock ):
        # Set up status repo with some students already notified
        num_previously_sent = fake.random.randint( 1, len( self.students ) - 1 )
        previously_sent = self.student_ids[ : num_previously_sent ]
        # previously_sent = fake.random.choices(self.student_ids, k=num_previously_sent)
        to_notify = [ s for s in self.student_ids if s not in previously_sent ]
        num_to_notify = len( to_notify )

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content( self.student_ids )

        # prepare student repo
        students = { s.student_id: s for s in self.students }

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

        # set up mocks on instantiated object
        obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True )
        obj.studentRepo.get_student = MagicMock( side_effect=se )
        obj.studentRepo.download = MagicMock( return_value=self.students )

        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        # Sets up data for the association repo to use
        self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students )

        reviewers_without_prev_notified_authors = [s.assessor_id for s in self.preexisting_pairings if s.assessee_id not in previously_sent]

        # setting this since filter step doesn't happen on dummy
        workRepo.submitter_ids = reviewers_without_prev_notified_authors
        # workRepo.remove_student_records = MagicMock()
        workLoaderMock.make = MagicMock( return_value=workRepo )

        # Set up previous notifications
        for sid in previously_sent:
            obj.feedback_status_repo.record( sid )

        # call
        obj.run()

        # check
        self.assertEqual( num_to_notify, len( obj.associations ), "Correct number of students notified" )

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual( messengerMock.call_count, num_to_notify, "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 the content sent
        for record in obj.associations:
            # print(record.assessee_id)
            reviewer_text = workRepo.get_formatted_work_by( record.assessor_id )
            # see if sent to assessee
            sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ]
            rx = r'{}'.format( reviewer_text )
            self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )

    @patch( 'CanvasHacks.Messaging.base.ConversationMessageSender.send' )
    @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository' )
    @patch( 'CanvasHacks.SkaaSteps.SendReviewToReviewee.WorkRepositoryLoaderFactory' )
    def test_run_some_not_turned_in( self, workLoaderMock, studentRepoMock, messengerMock ):
        # Set up status repo with some students already notified
        num_unsubmitted = fake.random.randint( 1, len( self.students ) - 1 )
        submitted = self.student_ids[ : num_unsubmitted ]
        # previously_sent = fake.random.choices(self.student_ids, k=num_previously_sent)
        to_notify = [ s for s in self.student_ids if s in submitted ]
        num_to_notify = len( to_notify )
        # feedbackStatusRepoMock.previously_sent_result = MagicMock( return_value=previously_sent )

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content( self.student_ids )
        workRepo.submitter_ids = to_notify
        workLoaderMock.make = MagicMock( return_value=workRepo )

        # prepare student repo
        students = { s.student_id: s for s in self.students }

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

        # set up mocks on instantiated object
        obj = SendReviewToReviewee( course=self.course, unit=self.unit, is_test=True, send=True )
        obj.studentRepo.get_student = MagicMock( side_effect=se )
        obj.studentRepo.download = MagicMock( return_value=self.students )

        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        # Sets up data for the association repo to use
        self.preexisting_pairings = self.create_preexisting_review_pairings( self.unit.initial_work.id, self.students )

        # call
        obj.run()

        # check
        self.assertEqual( num_to_notify, len( obj.associations ), "Correct number of students notified" )

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual( messengerMock.call_count, num_to_notify, "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 the content sent
        for record in obj.associations:
            # print(record.assessee_id)
            reviewer_text = workRepo.get_formatted_work_by( record.assessor_id )
            # see if sent to assessee
            sent_text = [ t[ 2 ] for t in messenger_args if t[ 0 ] == record.assessee_id ][ 0 ]
            rx = r'{}'.format( reviewer_text )
            self.assertRegex( sent_text, rx, "Reviewer's work in message sent to author" )
class TestUnitTests(TestingBase):
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.activity = self.unit.discussion_forum
        self.course = MagicMock()

        # student recieiving the message
        self.author = student_factory()
        self.reviewer = student_factory()

        # This would be the content unit
        self.work = fake.text()
        # Set to none so that loader thinks not a quiz
        self.activity_id = self.unit.discussion_forum.id
        self.dao = SqliteDAO()
        self.session = self.dao.session
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects

        # self.studentRepo = StudentRepository()
        # self.studentRepo.get_student = MagicMock( return_value=self.reviewer )
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock(
            return_value=self.work)
        self.review_assign = MagicMock(assessor_id=self.reviewer.id,
                                       assessee_id=self.author.id)
        self.statusRepo = MagicMock()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content(self.student_ids)
        self.workRepo.add_students_to_data(self.student_ids,
                                           make_dataframe=True)

    def test_instantiates_correct_status_repo(self):
        """The sending of metareview results requires a
        special status repository"""
        obj = SendForumPostsToReviewer(course=self.course,
                                       unit=self.unit,
                                       is_test=True,
                                       send=True)
        self.assertEqual(len(obj.statusRepos), 1,
                         "expected number of status repos")
        self.assertIsInstance(obj.statusRepos[0], InvitationStatusRepository,
                              "Correct status repo instantiated")

    def test__message_step(self):
        self.skipTest("todo")

    def test__assign_step(self):
        self.skipTest("todo")

    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.DisplayManager')
    @patch(
        'CanvasHacks.SkaaSteps.SendForumPostsToReviewer.WorkRepositoryLoaderFactory'
    )
    def test__load_step(self, workLoaderMock, displayManagerMock):
        self.workRepo.remove_student_records = MagicMock()
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

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

        # call
        obj._load_step()

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

        call_args = [c[0][0] for c in workLoaderMock.call_args_list]
class TestFunctionalTests(TestingBase):
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.activity = self.unit.discussion_forum
        self.course = MagicMock()

        # student recieiving the message
        self.author = student_factory()
        self.reviewer = student_factory()

        # This would be the content unit
        self.work = fake.text()
        # Set to none so that loader thinks not a quiz
        self.activity_id = self.unit.discussion_forum.id
        self.dao = SqliteDAO()
        self.session = self.dao.session
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects

        # self.studentRepo = StudentRepository()
        # self.studentRepo.get_student = MagicMock( return_value=self.reviewer )
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock(
            return_value=self.work)
        self.review_assign = MagicMock(assessor_id=self.reviewer.id,
                                       assessee_id=self.author.id)
        self.statusRepo = MagicMock()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content(self.student_ids)
        self.workRepo.add_students_to_data(self.student_ids,
                                           make_dataframe=True)

    @patch(
        'CanvasHacks.SkaaSteps.SendForumPostsToReviewer.InvitationStatusRepository'
    )
    @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send')
    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository')
    @patch(
        'CanvasHacks.SkaaSteps.SendForumPostsToReviewer.WorkRepositoryLoaderFactory'
    )
    def test_run(self, workLoaderMock, studentRepoMock, messengerMock,
                 statusRepoMock):
        self.workRepo.submitter_ids = self.new_students_ids

        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        # prepare student repo
        students = {s.student_id: s for s in self.students}

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

        # studentRepoMock.get_student = MagicMock(side_effect=se)
        # studentRepoMock.download = MagicMock( return_value=self.students )

        # call
        obj = SendForumPostsToReviewer(course=self.course,
                                       unit=self.unit,
                                       is_test=True,
                                       send=True)
        # obj.studentRepo = MagicMock()
        obj.studentRepo.get_student = MagicMock(side_effect=se)
        obj.studentRepo.download = MagicMock(return_value=self.students)
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.preexisting_students, obj.dao.session)

        obj.run()

        # check
        self.assertEqual(len(obj.associations), len(self.new_students_ids),
                         "Correct number of students assigned")

        # Check that new assignments don't involve previously assigned sudents
        for rec in obj.associations:
            self.assertNotIn(
                rec.assessor_id, self.preexisting_student_ids,
                "Newly assigned assessor not among previously assigned students"
            )
            self.assertNotIn(
                rec.assessee_id, self.preexisting_student_ids,
                "Newly assigned assessee not among previously assigned students"
            )

        # Check whether each new student has been assigned
        new_assessor_ids = [r.assessor_id for r in obj.associations]
        new_assessee_ids = [r.assessee_id for r in obj.associations]
        self.assertEqual(len(set(new_assessor_ids)),
                         len(self.new_students_ids),
                         "No duplicate assessor assignments")
        self.assertEqual(len(set(new_assessee_ids)),
                         len(self.new_students_ids),
                         "No duplicate assessee assignments")
        for sid in self.new_students_ids:
            self.assertIn(sid, new_assessee_ids, "Student is an assessee")
            self.assertIn(sid, new_assessor_ids, "Student is an assessor")

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual(messengerMock.call_count, len(self.new_students_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:
            self.assertEqual(self.unit.discussion_review.email_subject, 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

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

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

        # Check the content sent
        for record in obj.associations:
            # print(record.assessee_id)
            author_text = self.workRepo.get_formatted_work_by(
                record.assessee_id)
            # see if sent to assessor
            sent_text = [
                t[2] for t in messenger_args if t[0] == record.assessor_id
            ][0]
            rx = r'{}'.format(author_text)
            self.assertRegex(sent_text, rx,
                             "Author's work in message sent to reviewer")

    def test_audit_frame(self):
        self.skipTest("todo")
class TestFunctionalTests(TestingBase):
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.activity = self.unit.discussion_review
        self.course = MagicMock()

        # student recieiving the message
        self.author = student_factory()
        self.reviewer = student_factory()

        # This would be the content unit
        self.work = fake.text()
        # Set to none so that loader thinks not a quiz
        self.activity_id = self.unit.discussion_review.id
        self.dao = SqliteDAO()
        self.session = self.dao.session
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects

        # self.studentRepo = StudentRepository()
        # self.studentRepo.get_student = MagicMock( return_value=self.reviewer )
        self.contentRepo = ContentRepositoryMock()
        self.contentRepo.get_formatted_work_by = MagicMock(
            return_value=self.work)
        self.review_assign = MagicMock(assessor_id=self.reviewer.id,
                                       assessee_id=self.author.id)
        self.statusRepo = MagicMock()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content(self.student_ids)
        self.workRepo.add_students_to_data(self.student_ids,
                                           make_dataframe=True)

    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")

    @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send')
    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository')
    @patch(
        'CanvasHacks.SkaaSteps.SendDiscussionReviewToPoster.WorkRepositoryLoaderFactory'
    )
    def test_run_first_time_for_activity(self, workLoaderMock, studentRepoMock,
                                         messengerMock):
        # even though this will be the result of the filtering
        # we need to limit here since the mock doesn't have the property
        self.workRepo.submitter_ids = self.student_ids
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        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)
        obj.statusRepos = [
            create_autospec(FeedbackStatusRepository,
                            previously_sent_students=[])
        ]

        # call
        obj.run()

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        # Every student should've been messaged
        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]

        # 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.student_ids), 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")

    # @patch( 'CanvasHacks.SkaaSteps.ISkaaSteps.FeedbackStatusRepository' )
    @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send')
    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository')
    @patch(
        'CanvasHacks.SkaaSteps.SendDiscussionReviewToPoster.WorkRepositoryLoaderFactory'
    )
    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")
예제 #16
0
class TestFunctionalTestWhenNonQuizType(TestingBase):
    """
    Tests the entire process in various use cases using
    local data when the unit is NOT some flavor of quiz (and thus
    does not use a quiz report)

    For tests of whole process which hit server, see tests.EndToEnd
    """
    def setUp(self):
        self.config_for_test()
        self.unit = unit_factory()
        self.course = MagicMock()

        # Set to none so that loader thinks not a quiz
        self.unit.initial_work.quiz_id = None
        self.activity_id = self.unit.initial_work.id
        self.dao = SqliteDAO()
        self.session = self.dao.session
        self.create_new_and_preexisting_students()
        # Prepare fake work repo to give values to calling  objects
        self.workRepo = ContentRepositoryMock()
        self.workRepo.create_test_content(self.student_ids)
        self.workRepo.add_students_to_data(self.student_ids,
                                           make_dataframe=True)

        # workRepo = create_autospec( QuizRepository )
        # workRepo.get_formatted_work_by = MagicMock( return_value=testText )

    @patch(
        'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.InvitationStatusRepository'
    )
    @patch('CanvasHacks.Messaging.base.ConversationMessageSender.send')
    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository')
    @patch(
        'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.WorkRepositoryLoaderFactory'
    )
    def test_does_not_send_to_people_already_assigned(self, workLoaderMock,
                                                      studentRepoMock,
                                                      messengerMock,
                                                      statusRepoMock):
        """
        Simulates a run where some students have already been assigned
        peer reviewers and a new group is being processed.

        Focus in testing is on making sure that the two groups don't get mixed up

        :param workLoaderMock:
        :param studentRepoMock:
        :param messengerMock:
        :return:
        """
        self.workRepo.submitter_ids = self.new_students_ids

        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        # prepare student repo
        students = {s.student_id: s for s in self.students}

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

        # studentRepoMock.get_student = MagicMock(side_effect=se)
        # studentRepoMock.download = MagicMock( return_value=self.students )

        # call
        obj = SendInitialWorkToReviewer(course=self.course,
                                        unit=self.unit,
                                        is_test=True,
                                        send=True)
        # obj.studentRepo = MagicMock()
        obj.studentRepo.get_student = MagicMock(side_effect=se)
        obj.studentRepo.download = MagicMock(return_value=self.students)
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.preexisting_students, obj.dao.session)

        obj.run()

        # check
        self.assertEqual(len(obj.associations), len(self.new_students_ids),
                         "Correct number of students assigned")

        # Check that new assignments don't involve previously assigned sudents
        for rec in obj.associations:
            self.assertNotIn(
                rec.assessor_id, self.preexisting_student_ids,
                "Newly assigned assessor not among previously assigned students"
            )
            self.assertNotIn(
                rec.assessee_id, self.preexisting_student_ids,
                "Newly assigned assessee not among previously assigned students"
            )

        # Check whether each new student has been assigned
        new_assessor_ids = [r.assessor_id for r in obj.associations]
        new_assessee_ids = [r.assessee_id for r in obj.associations]
        self.assertEqual(len(set(new_assessor_ids)),
                         len(self.new_students_ids),
                         "No duplicate assessor assignments")
        self.assertEqual(len(set(new_assessee_ids)),
                         len(self.new_students_ids),
                         "No duplicate assessee assignments")
        for sid in self.new_students_ids:
            self.assertIn(sid, new_assessee_ids, "Student is an assessee")
            self.assertIn(sid, new_assessor_ids, "Student is an assessor")

        # ================== Events on Messenger
        # Check that mocked objects were called with expected data
        messengerMock.assert_called()
        self.assertEqual(messengerMock.call_count, len(self.new_students_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:
            self.assertEqual(self.unit.review.email_subject, subj,
                             "Correct subject line")

        # Status repo calls on messenger (only 1 repo)
        obj.messenger.status_repositories[0].record.assert_called()
        call_list = obj.messenger.status_repositories[0].record.call_args_list

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

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

        # Check the content sent
        for record in obj.associations:
            # print(record.assessee_id)
            author_text = self.workRepo.get_formatted_work_by(
                record.assessee_id)
            # see if sent to assessor
            sent_text = [
                t[2] for t in messenger_args if t[0] == record.assessor_id
            ][0]
            rx = r'{}'.format(author_text)
            self.assertRegex(sent_text, rx,
                             "Author's work in message sent to reviewer")

    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository')
    @patch(
        'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.WorkRepositoryLoaderFactory'
    )
    def test_raises_when_all_submitters_already_assigned(
            self, workLoaderMock, studentRepoMock):
        # Prepare fake work repo to give values to calling  objects
        # workRepo = ContentRepositoryMock()
        # workRepo.create_test_content( self.preexisting_student_ids )
        # workRepo.add_students_to_data(self.student_ids, make_dataframe=True)

        # Setting to return all the previously assigned students.
        # this should cause all the students to be filtered out
        # and the errror raised
        self.workRepo.submitter_ids = self.preexisting_student_ids
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        studentRepoMock.download = MagicMock(return_value=self.students)

        # call
        obj = SendInitialWorkToReviewer(course=self.course,
                                        unit=self.unit,
                                        is_test=True,
                                        send=True)
        self.session = obj.dao.session
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.preexisting_students)

        with self.assertRaises(AllAssigned):
            obj.run()

    @patch('CanvasHacks.SkaaSteps.ISkaaSteps.StudentRepository')
    @patch(
        'CanvasHacks.SkaaSteps.SendInitialWorkToReviewer.WorkRepositoryLoaderFactory'
    )
    def test_raises_when_only_one_submission(self, workLoaderMock,
                                             studentRepoMock):

        # Prepare fake work repo to give values to calling  objects
        workRepo = ContentRepositoryMock()
        workRepo.create_test_content(self.new_students_ids)
        workRepo.add_students_to_data(self.student_ids, make_dataframe=True)

        # Setting to return all the previously assigned students.
        # this should cause all the students to be filtered out
        # and the errror raised
        self.workRepo.submitter_ids = [self.new_students[0]]
        workLoaderMock.make = MagicMock(return_value=self.workRepo)

        studentRepoMock.download = MagicMock(return_value=self.students)

        # call
        obj = SendInitialWorkToReviewer(course=self.course,
                                        unit=self.unit,
                                        is_test=True,
                                        send=True)
        # Have to do this after object creation so that we can use the
        # same in-memory db
        self.session = obj.dao.session
        preexisting_pairings = self.create_preexisting_review_pairings(
            self.activity_id, self.preexisting_students)

        with self.assertRaises(NoAvailablePartner):
            obj.run()