def test_multiple_courses(self):
        user = self.make_test_user(self.STUDENT_EMAIL)

        COURSE_TWO = 'course_two'
        COURSE_TWO_NS = 'ns_' + COURSE_TWO

        actions.simple_add_course(
            COURSE_TWO, self.ADMIN_EMAIL, 'Data Removal Test Two')

        actions.login(user.email())
        actions.register(self, user.email(), course=self.COURSE)
        actions.register(self, user.email(), course=COURSE_TWO)
        actions.unregister(self, self.COURSE, do_data_removal=True)

        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(
            data_removal.DataRemovalCronHandler.URL,
            headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        with common_utils.Namespace(self.NAMESPACE):
            self.assertIsNone(models.Student.get_by_user(user))
        with common_utils.Namespace(COURSE_TWO_NS):
            self.assertIsNotNone(
                models.Student.get_by_user(user))
示例#2
0
    def test_notifications_succeed(self):
        actions.login(self.STUDENT_EMAIL)
        user_id = None

        actions.register(self, self.STUDENT_EMAIL)
        self.assertIsNone(self._user_id)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertIsNotNone(self._user_id)
        user_id = self._user_id
        self.assertEquals(1, self._num_add_calls)
        self.assertEquals(0, self._num_unenroll_calls)
        self.assertEquals(0, self._num_reenroll_calls)

        actions.unregister(self)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, self._num_add_calls)
        self.assertEquals(1, self._num_unenroll_calls)
        self.assertEquals(0, self._num_reenroll_calls)


        with common_utils.Namespace(self.NAMESPACE):
            models.StudentProfileDAO.update(
                user_id, self.STUDENT_EMAIL, is_enrolled=True)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, self._num_add_calls)
        self.assertEquals(1, self._num_unenroll_calls)
        self.assertEquals(1, self._num_reenroll_calls)
示例#3
0
    def test_notifications_succeed(self):
        actions.login(self.STUDENT_EMAIL)
        user_id = None

        actions.register(self, self.STUDENT_EMAIL)
        self.assertIsNone(self._user_id)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertIsNotNone(self._user_id)
        user_id = self._user_id
        self.assertEquals(1, self._num_add_calls)
        self.assertEquals(0, self._num_unenroll_calls)
        self.assertEquals(0, self._num_reenroll_calls)

        actions.unregister(self)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, self._num_add_calls)
        self.assertEquals(1, self._num_unenroll_calls)
        self.assertEquals(0, self._num_reenroll_calls)

        with common_utils.Namespace(self.NAMESPACE):
            models.StudentProfileDAO.update(user_id,
                                            self.STUDENT_EMAIL,
                                            is_enrolled=True)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, self._num_add_calls)
        self.assertEquals(1, self._num_unenroll_calls)
        self.assertEquals(1, self._num_reenroll_calls)
示例#4
0
    def test_end_to_end(self):
        """Actually enroll and unenroll students; verify reporting counts."""

        COURSE_NAME_BASE = 'test'
        NUM_COURSES = 2
        NUM_STUDENTS = 3
        THE_TIMESTAMP = 1427245200

        for course_num in range(NUM_COURSES):
            course_name = '%s_%d' % (COURSE_NAME_BASE, course_num)
            actions.simple_add_course(course_name, ADMIN_EMAIL, course_name)
            actions.update_course_config(course_name, {
                'course': {
                    'now_available': True,
                    'browsable': True,
                },
            })
            for student_num in range(NUM_STUDENTS):
                name = '%s_%d_%d' % (COURSE_NAME_BASE, course_num, student_num)
                actions.login(name + '@foo.com')
                actions.register(self, name, course_name)
                if student_num == 0:
                    actions.unregister(self, course_name)
                actions.logout()

        # Expect no messages yet; haven't run job.
        self.assertEquals([], MockSender.get_sent())

        # Run all counting jobs.
        usage_reporting.StartReportingJobs._submit_jobs()
        self.execute_all_deferred_tasks()

        # Verify counts.  (Ignore dates, these are fickle and subject to
        # weirdness on hour boundaries.  Also ignore course/instance IDs;
        # they are non-random and thus all the same.)
        num_enrolled_msgs = 0
        num_unenrolled_msgs = 0
        num_student_count_msgs = 0
        for message in MockSender.get_sent():
            if (message[messaging.Message._METRIC] ==
                    messaging.Message.METRIC_STUDENT_COUNT):
                num_student_count_msgs += 1
                self.assertEquals(NUM_STUDENTS,
                                  message[messaging.Message._VALUE])
            elif (message[messaging.Message._METRIC] ==
                  messaging.Message.METRIC_ENROLLED):
                num_enrolled_msgs += 1
                self.assertEquals(NUM_STUDENTS,
                                  message[messaging.Message._VALUE])
            elif (message[messaging.Message._METRIC] ==
                  messaging.Message.METRIC_UNENROLLED):
                num_unenrolled_msgs += 1
                self.assertEquals(1, message[messaging.Message._VALUE])

        self.assertEquals(NUM_COURSES, num_enrolled_msgs)
        self.assertEquals(NUM_COURSES, num_unenrolled_msgs)
        self.assertEquals(NUM_COURSES, num_student_count_msgs)
        sites.reset_courses()
示例#5
0
 def test_delete_link_when_unregistered_then_proceed(self):
     user = actions.login(self.STUDENT_EMAIL)
     actions.register(self, self.STUDENT_EMAIL)
     actions.unregister(self)
     response = self.get('course')
     response = self.click(response, 'Delete My Data')
     self._deletion_flow_for_unregistered_student(response, cancel=False)
     response = self.get('course')
     self.assertNotIn('Delete My Data', response.body)
 def test_delete_link_when_unregistered_then_proceed(self):
     user = actions.login(self.STUDENT_EMAIL)
     actions.register(self, self.STUDENT_EMAIL)
     actions.unregister(self)
     response = self.get('course')
     response = self.click(response, 'Delete My Data')
     self._deletion_flow_for_unregistered_student(response, cancel=False)
     response = self.get('course')
     self.assertNotIn('Delete My Data', response.body)
    def test_student_property_removed(self):
        """Test a sampling of types whose index contains user ID.

        Here, indices start with the user ID, but are suffixed with the name
        of a specific property sub-type.  Verify that these are removed.
        """
        user = self.make_test_user(self.STUDENT_EMAIL)


        user_id = None
        actions.login(user.email())
        actions.register(self, self.STUDENT_EMAIL, course=self.COURSE)

        # Get IDs of those students; make an event for each.
        with common_utils.Namespace(self.NAMESPACE):
            student = models.Student.get_by_user(user)
            user_id = student.user_id
            p = models.StudentPropertyEntity.create(student, 'foo')
            p.value = 'foo'
            p.put()
            invitation.InvitationStudentProperty.load_or_create(student)
            questionnaire.StudentFormEntity.load_or_create(student, 'a_form')
            cm = competency.BaseCompetencyMeasure(user_id)
            cm.load(123)
            cm.save()

        # Assure ourselves that we have exactly one of the items we just added.
        with common_utils.Namespace(self.NAMESPACE):
            l = list(models.StudentPropertyEntity.all().run())
            self.assertEquals(2, len(l))  # 'foo', 'linear-course-completion'
            l = list(invitation.InvitationStudentProperty.all().run())
            self.assertEquals(1, len(l))
            l = list(questionnaire.StudentFormEntity.all().run())
            self.assertEquals(1, len(l))
            l = list(competency.CompetencyMeasureEntity.all().run())
            self.assertEquals(1, len(l))


        actions.unregister(self, self.COURSE, do_data_removal=True)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(
            data_removal.DataRemovalCronHandler.URL,
            headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        # Assure ourselves that all added items are now gone.
        with common_utils.Namespace(self.NAMESPACE):
            l = list(models.StudentPropertyEntity.all().run())
            self.assertEquals(0, len(l))
            l = list(invitation.InvitationStudentProperty.all().run())
            self.assertEquals(0, len(l))
            l = list(questionnaire.StudentFormEntity.all().run())
            self.assertEquals(0, len(l))
            l = list(competency.CompetencyMeasureEntity.all().run())
            self.assertEquals(0, len(l))
示例#8
0
    def test_student_property_removed(self):
        """Test a sampling of types whose index contains user ID.

        Here, indices start with the user ID, but are suffixed with the name
        of a specific property sub-type.  Verify that these are removed.
        """
        user = self.make_test_user(self.STUDENT_EMAIL)

        user_id = None
        actions.login(user.email())
        actions.register(self, self.STUDENT_EMAIL, course=self.COURSE)

        # Get IDs of those students; make an event for each.
        with common_utils.Namespace(self.NAMESPACE):
            student = models.Student.get_by_user(user)
            user_id = student.user_id
            p = models.StudentPropertyEntity.create(student, 'foo')
            p.value = 'foo'
            p.put()
            invitation.InvitationStudentProperty.load_or_create(student)
            questionnaire.StudentFormEntity.load_or_create(student, 'a_form')
            cm = competency.BaseCompetencyMeasure(user_id)
            cm.load(123)
            cm.save()

        # Assure ourselves that we have exactly one of the items we just added.
        with common_utils.Namespace(self.NAMESPACE):
            l = list(models.StudentPropertyEntity.all().run())
            self.assertEquals(2, len(l))  # 'foo', 'linear-course-completion'
            l = list(invitation.InvitationStudentProperty.all().run())
            self.assertEquals(1, len(l))
            l = list(questionnaire.StudentFormEntity.all().run())
            self.assertEquals(1, len(l))
            l = list(competency.CompetencyMeasureEntity.all().run())
            self.assertEquals(1, len(l))

        actions.unregister(self, self.COURSE, do_data_removal=True)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(data_removal.DataRemovalCronHandler.URL,
                 headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        # Assure ourselves that all added items are now gone.
        with common_utils.Namespace(self.NAMESPACE):
            l = list(models.StudentPropertyEntity.all().run())
            self.assertEquals(0, len(l))
            l = list(invitation.InvitationStudentProperty.all().run())
            self.assertEquals(0, len(l))
            l = list(questionnaire.StudentFormEntity.all().run())
            self.assertEquals(0, len(l))
            l = list(competency.CompetencyMeasureEntity.all().run())
            self.assertEquals(0, len(l))
    def test_non_removal_policy(self):
        with actions.OverriddenEnvironment({
                data_removal.DATA_REMOVAL_SETTINGS_SECTION: {
                    data_removal.REMOVAL_POLICY:
                    data_removal.IndefiniteRetentionPolicy.get_name()
                }
        }):

            user = actions.login(self.STUDENT_EMAIL)
            actions.register(self, self.STUDENT_EMAIL, course=self.COURSE)
            self.execute_all_deferred_tasks(
                models.StudentLifecycleObserver.QUEUE_NAME)

            with common_utils.Namespace(self.NAMESPACE):
                # After registration, we should have a student object, and no
                # ImmediateRemovalState instance due to the don't-care policy.
                student = models.Student.get_by_user(user)
                self.assertIsNotNone(student)
                self.assertIsNone(
                    removal_models.ImmediateRemovalState.get_by_user_id(
                        student.user_id))
                r = removal_models.BatchRemovalState.get_by_user_ids(
                    [student.user_id])
                self.assertEqual([None], r)

            actions.unregister(self, course=self.COURSE)

            # Expect to see unregister event on queue -- register event handled
            # as part of actions.register.
            task_count = self.execute_all_deferred_tasks(
                models.StudentLifecycleObserver.QUEUE_NAME)
            self.assertEquals(1, task_count)

            # Running deletion cycle should have no effect.  Verify that.
            self._complete_removal()

            with common_utils.Namespace(self.NAMESPACE):
                # After unregister, we should still have a student object.
                student = models.Student.get_by_user(user)
                self.assertIsNotNone(student)
                self.assertIsNone(
                    removal_models.ImmediateRemovalState.get_by_user_id(
                        student.user_id))
                r = removal_models.BatchRemovalState.get_by_user_ids(
                    [student.user_id])
                self.assertEqual([None], r)
    def test_non_removal_policy(self):
        with actions.OverriddenEnvironment({
            data_removal.DATA_REMOVAL_SETTINGS_SECTION: {
                data_removal.REMOVAL_POLICY:
                data_removal.IndefiniteRetentionPolicy.get_name()}}):

            user = actions.login(self.STUDENT_EMAIL)
            actions.register(self, self.STUDENT_EMAIL, course=self.COURSE)
            self.execute_all_deferred_tasks(
                models.StudentLifecycleObserver.QUEUE_NAME)

            with common_utils.Namespace(self.NAMESPACE):
                # After registration, we should have a student object, and no
                # ImmediateRemovalState instance due to the don't-care policy.
                student = models.Student.get_by_user(user)
                self.assertIsNotNone(student)
                self.assertIsNone(
                    removal_models.ImmediateRemovalState.get_by_user_id(
                        student.user_id))
                r = removal_models.BatchRemovalState.get_by_user_ids(
                    [student.user_id])
                self.assertEqual([None], r)

            actions.unregister(self, course=self.COURSE)

            # Expect to see unregister event on queue -- register event handled
            # as part of actions.register.
            task_count = self.execute_all_deferred_tasks(
                models.StudentLifecycleObserver.QUEUE_NAME)
            self.assertEquals(1, task_count)

            # Running deletion cycle should have no effect.  Verify that.
            self._complete_removal()

            with common_utils.Namespace(self.NAMESPACE):
                # After unregister, we should still have a student object.
                student = models.Student.get_by_user(user)
                self.assertIsNotNone(student)
                self.assertIsNone(
                    removal_models.ImmediateRemovalState.get_by_user_id(
                        student.user_id))
                r = removal_models.BatchRemovalState.get_by_user_ids(
                    [student.user_id])
                self.assertEqual([None], r)
    def test_reregistration_blocked_during_deletion(self):

        def assert_cannot_register():
            response = self.get('register')
            self.assertIn('You cannot re-register for this course',
                          response.body)
            self.assertNotIn('What is your name?', response.body)

        user = self.make_test_user(self.STUDENT_EMAIL)

        user_id = None
        actions.login(user.email())
        actions.register(self, user.email())
        with common_utils.Namespace(self.NAMESPACE):
            # After registration, we should have a student object, and
            # a ImmediateRemovalState instance.
            student = models.Student.get_by_user(user)
            self.assertIsNotNone(student)
            user_id = student.user_id

        actions.unregister(self, do_data_removal=True)
        assert_cannot_register()

        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        assert_cannot_register()

        self.get(
            data_removal.DataRemovalCronHandler.URL,
            headers={'X-AppEngine-Cron': 'True'})
        assert_cannot_register()

        # Can re-register after all items are cleaned.
        self.execute_all_deferred_tasks()
        with common_utils.Namespace(self.NAMESPACE):
            student = models.Student.get_by_user(user)
            self.assertIsNone(student)
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNone(removal_state)

        actions.register(self, self.STUDENT_EMAIL)
    def test_remove_by_email(self):
        user = self.make_test_user(self.STUDENT_EMAIL)

        actions.login(user.email())
        actions.register(self, user.email(), course=self.COURSE)

        # Get IDs of those students; make an event for each.
        with common_utils.Namespace(self.NAMESPACE):
            sse = unsubscribe.SubscriptionStateEntity(key_name=user.email())
            sse.save()

        actions.unregister(self, self.COURSE, do_data_removal=True)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(data_removal.DataRemovalCronHandler.URL,
                 headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        with common_utils.Namespace(self.NAMESPACE):
            l = list(unsubscribe.SubscriptionStateEntity.all().run())
            self.assertEquals(0, len(l))
    def test_reregistration_blocked_during_deletion(self):
        def assert_cannot_register():
            response = self.get('register')
            self.assertIn('You cannot re-register for this course',
                          response.body)
            self.assertNotIn('What is your name?', response.body)

        user = self.make_test_user(self.STUDENT_EMAIL)

        user_id = None
        actions.login(user.email())
        actions.register(self, user.email())
        with common_utils.Namespace(self.NAMESPACE):
            # After registration, we should have a student object, and
            # a ImmediateRemovalState instance.
            student = models.Student.get_by_user(user)
            self.assertIsNotNone(student)
            user_id = student.user_id

        actions.unregister(self, do_data_removal=True)
        assert_cannot_register()

        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        assert_cannot_register()

        self.get(data_removal.DataRemovalCronHandler.URL,
                 headers={'X-AppEngine-Cron': 'True'})
        assert_cannot_register()

        # Can re-register after all items are cleaned.
        self.execute_all_deferred_tasks()
        with common_utils.Namespace(self.NAMESPACE):
            student = models.Student.get_by_user(user)
            self.assertIsNone(student)
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNone(removal_state)

        actions.register(self, self.STUDENT_EMAIL)
    def test_multiple_students(self):
        user = self.make_test_user(self.STUDENT_EMAIL)
        other_user = self.make_test_user('*****@*****.**')

        # Register two students
        actions.login(user.email())
        actions.register(self, user.email(), course=self.COURSE)

        actions.login(other_user.email())
        actions.register(self, other_user.email(), course=self.COURSE)

        # Get IDs of those students; make an event for each.
        with common_utils.Namespace(self.NAMESPACE):
            student1_id = (
                models.Student.get_by_user(user).user_id)
            student2_id = (
                models.Student.get_by_user(other_user).user_id)
            models.EventEntity(user_id=student1_id, source='test').put()
            models.EventEntity(user_id=student2_id, source='test').put()

        # Unregister one of them.
        actions.login(self.STUDENT_EMAIL)
        actions.unregister(self, self.COURSE, do_data_removal=True)

        # Complete all data removal tasks.
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(
            data_removal.DataRemovalCronHandler.URL,
            headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        # Unregistered student and his data are gone; still-registered
        # student's data is still present.
        with common_utils.Namespace(self.NAMESPACE):
            self.assertIsNone(models.Student.get_by_user(user))
            self.assertIsNotNone(models.Student.get_by_user(other_user))
            entities = list(models.EventEntity.all().run())
            self.assertEquals(1, len(entities))
            self.assertEquals(student2_id, entities[0].user_id)
    def test_remove_by_email(self):
        user = self.make_test_user(self.STUDENT_EMAIL)

        actions.login(user.email())
        actions.register(self, user.email(), course=self.COURSE)

        # Get IDs of those students; make an event for each.
        with common_utils.Namespace(self.NAMESPACE):
            sse = unsubscribe.SubscriptionStateEntity(
                key_name=user.email())
            sse.save()

        actions.unregister(self, self.COURSE, do_data_removal=True)
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(
            data_removal.DataRemovalCronHandler.URL,
            headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        with common_utils.Namespace(self.NAMESPACE):
            l = list(unsubscribe.SubscriptionStateEntity.all().run())
            self.assertEquals(0, len(l))
    def test_multiple_students(self):
        user = self.make_test_user(self.STUDENT_EMAIL)
        other_user = self.make_test_user('*****@*****.**')

        # Register two students
        actions.login(user.email())
        actions.register(self, user.email(), course=self.COURSE)

        actions.login(other_user.email())
        actions.register(self, other_user.email(), course=self.COURSE)

        # Get IDs of those students; make an event for each.
        with common_utils.Namespace(self.NAMESPACE):
            student1_id = (models.Student.get_by_user(user).user_id)
            student2_id = (models.Student.get_by_user(other_user).user_id)
            models.EventEntity(user_id=student1_id, source='test').put()
            models.EventEntity(user_id=student2_id, source='test').put()

        # Unregister one of them.
        actions.login(self.STUDENT_EMAIL)
        actions.unregister(self, self.COURSE, do_data_removal=True)

        # Complete all data removal tasks.
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(data_removal.DataRemovalCronHandler.URL,
                 headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        # Unregistered student and his data are gone; still-registered
        # student's data is still present.
        with common_utils.Namespace(self.NAMESPACE):
            self.assertIsNone(models.Student.get_by_user(user))
            self.assertIsNotNone(models.Student.get_by_user(other_user))
            entities = list(models.EventEntity.all().run())
            self.assertEquals(1, len(entities))
            self.assertEquals(student2_id, entities[0].user_id)
    def test_multiple_courses(self):
        user = self.make_test_user(self.STUDENT_EMAIL)

        COURSE_TWO = 'course_two'
        COURSE_TWO_NS = 'ns_' + COURSE_TWO

        actions.simple_add_course(COURSE_TWO, self.ADMIN_EMAIL,
                                  'Data Removal Test Two')

        actions.login(user.email())
        actions.register(self, user.email(), course=self.COURSE)
        actions.register(self, user.email(), course=COURSE_TWO)
        actions.unregister(self, self.COURSE, do_data_removal=True)

        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.get(data_removal.DataRemovalCronHandler.URL,
                 headers={'X-AppEngine-Cron': 'True'})
        self.execute_all_deferred_tasks()

        with common_utils.Namespace(self.NAMESPACE):
            self.assertIsNone(models.Student.get_by_user(user))
        with common_utils.Namespace(COURSE_TWO_NS):
            self.assertIsNotNone(models.Student.get_by_user(user))
示例#18
0
 def unregister(self):
     self.base = '/test'
     actions.unregister(self)
     self.base = ''
    def test_end_to_end(self):
        """Actually enroll and unenroll students; verify reporting counts."""

        COURSE_NAME_BASE = 'test'
        NUM_COURSES = 2
        NUM_STUDENTS = 3
        THE_TIMESTAMP = 1427245200

        for course_num in range(NUM_COURSES):
            course_name = '%s_%d' % (COURSE_NAME_BASE, course_num)
            actions.simple_add_course(course_name, ADMIN_EMAIL, course_name)
            actions.update_course_config(
                course_name,
                {
                    'course': {
                        'now_available': True,
                        'browsable': True,
                    },
                })
            for student_num in range(NUM_STUDENTS):
                name = '%s_%d_%d' % (COURSE_NAME_BASE, course_num, student_num)
                actions.login(name + '@foo.com')
                actions.register(self, name, course_name)
                if student_num == 0:
                    actions.unregister(self, course_name)
                actions.logout()

        # Expect no messages yet; haven't run job.
        self.assertEquals([], MockSender.get_sent())

        # Run all counting jobs.
        with actions.OverriddenConfig(config.REPORT_ALLOWED.name, True):
            usage_reporting.StartReportingJobs._for_testing_only_get()
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.execute_all_deferred_tasks()

        # Verify counts.  (Ignore dates, these are fickle and subject to
        # weirdness on hour boundaries.  Also ignore course/instance IDs;
        # they are non-random and thus all the same.)
        num_enrolled_msgs = 0
        num_unenrolled_msgs = 0
        num_student_count_msgs = 0
        for message in MockSender.get_sent():
            if (message[messaging.Message._METRIC] ==
                messaging.Message.METRIC_STUDENT_COUNT):
                num_student_count_msgs += 1
                self.assertEquals(
                    NUM_STUDENTS, message[messaging.Message._VALUE])
            elif (message[messaging.Message._METRIC] ==
                  messaging.Message.METRIC_ENROLLED):
                num_enrolled_msgs += 1
                self.assertEquals(
                    NUM_STUDENTS, message[messaging.Message._VALUE])
            elif (message[messaging.Message._METRIC] ==
                  messaging.Message.METRIC_UNENROLLED):
                num_unenrolled_msgs += 1
                self.assertEquals(
                    1, message[messaging.Message._VALUE])

        self.assertEquals(NUM_COURSES, num_enrolled_msgs)
        self.assertEquals(NUM_COURSES, num_unenrolled_msgs)
        self.assertEquals(NUM_COURSES, num_student_count_msgs)
        sites.reset_courses()
    def test_immediate_removal_policy(self):
        user = self.make_test_user(self.STUDENT_EMAIL)

        actions.login(user.email())
        actions.register(self, self.STUDENT_EMAIL, course=self.COURSE)
        task_count = self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, task_count)  # registration.
        user_id = None

        with common_utils.Namespace(self.NAMESPACE):
            # After registration, we should have a student object, and
            # a ImmediateRemovalState instance.
            student = models.Student.get_by_user(user)
            self.assertIsNotNone(student)
            user_id = student.user_id
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNotNone(removal_state)
            self.assertEquals(
                removal_models.ImmediateRemovalState.STATE_REGISTERED,
                removal_state.state)
            r = removal_models.BatchRemovalState.get_by_user_ids([user_id])
            self.assertEqual([None], r)

            # Add an EventEntity record so we can see it being removed.
            event = models.EventEntity(user_id=user_id, source='test')
            event.put()

        actions.unregister(self, self.COURSE, do_data_removal=True)

        with common_utils.Namespace(self.NAMESPACE):
            # Immediately upon unregistration, we should still have the student
            # record, and removal state should be pending deletion.
            student = models.Student.get_by_user(user)
            self.assertIsNotNone(student)
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNotNone(removal_state)
            self.assertEquals(
                removal_models.ImmediateRemovalState.STATE_DELETION_PENDING,
                removal_state.state)
            r = removal_models.BatchRemovalState.get_by_user_ids([user_id])
            self.assertEqual([None], r)
            events = list(models.EventEntity.all().run())
            self.assertEquals(1, len(events))

        # We should have gotten a to-do item on the task queue for student
        # removal.
        task_count = self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, task_count)  # unregistration.

        with common_utils.Namespace(self.NAMESPACE):
            # Having processed the queue item, the student record should now
            # be gone.
            students = list(models.Student.all().run())
            student = models.Student.get_by_user(user)
            self.assertIsNone(student)
            # But the record tracking removal should not yet be gone.
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNotNone(removal_state)
            self.assertEquals(
                removal_models.ImmediateRemovalState.STATE_DELETION_PENDING,
                removal_state.state)
            # And we should have a to-do item for the cron batch cleanup.
            r = removal_models.BatchRemovalState.get_by_user_ids([user_id])
            self.assertEquals(1, len(r))
            removal_record = r[0]
            self.assertEquals(
                models_data_removal.Registry.get_unindexed_class_names(),
                removal_record.resource_types)
            # Events won't have been cleaned up yet; need cron batch to run.
            events = list(models.EventEntity.all().run())
            self.assertEquals(1, len(events))

        # Call the cron handler to schedule batch removal tasks.  This, in
        # turn, will schedule map/reduce jobs to remove records for that
        # student.
        response = self.get(data_removal.DataRemovalCronHandler.URL,
                            headers={'X-AppEngine-Cron': 'True'})
        self.assertEquals(200, response.status_int)
        self.assertEquals('OK.', response.body)

        # Run the map/reduce jobs to completion.
        self.execute_all_deferred_tasks()

        # We should now be completely clean; the M/R job that finishes last
        # should also clean up the to-do tracking item.
        with common_utils.Namespace(self.NAMESPACE):
            student = models.Student.get_by_user(user)
            self.assertIsNone(student)
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNone(removal_state)
            # Events should now be gone.
            events = list(models.EventEntity.all().run())
            self.assertEquals(0, len(events))
 def test_unregister_without_deletion_permits_reregistration(self):
     actions.login(self.STUDENT_EMAIL)
     actions.register(self, self.STUDENT_EMAIL)
     actions.unregister(self)
     actions.register(self, self.STUDENT_EMAIL)
    def test_immediate_removal_policy(self):
        user = self.make_test_user(self.STUDENT_EMAIL)

        actions.login(user.email())
        actions.register(self, self.STUDENT_EMAIL, course=self.COURSE)
        task_count = self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, task_count)  # registration.
        user_id = None

        with common_utils.Namespace(self.NAMESPACE):
            # After registration, we should have a student object, and
            # a ImmediateRemovalState instance.
            student = models.Student.get_by_user(user)
            self.assertIsNotNone(student)
            user_id = student.user_id
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNotNone(removal_state)
            self.assertEquals(
                removal_models.ImmediateRemovalState.STATE_REGISTERED,
                removal_state.state)
            r = removal_models.BatchRemovalState.get_by_user_ids([user_id])
            self.assertEqual([None], r)

            # Add an EventEntity record so we can see it being removed.
            event = models.EventEntity(user_id=user_id, source='test')
            event.put()

        actions.unregister(self, self.COURSE, do_data_removal=True)

        with common_utils.Namespace(self.NAMESPACE):
            # Immediately upon unregistration, we should still have the student
            # record, and removal state should be pending deletion.
            student = models.Student.get_by_user(user)
            self.assertIsNotNone(student)
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNotNone(removal_state)
            self.assertEquals(
                removal_models.ImmediateRemovalState.STATE_DELETION_PENDING,
                removal_state.state)
            r = removal_models.BatchRemovalState.get_by_user_ids([user_id])
            self.assertEqual([None], r)
            events = list(models.EventEntity.all().run())
            self.assertEquals(1, len(events))

        # We should have gotten a to-do item on the task queue for student
        # removal.
        task_count = self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.assertEquals(1, task_count)  # unregistration.

        with common_utils.Namespace(self.NAMESPACE):
            # Having processed the queue item, the student record should now
            # be gone.
            students = list(models.Student.all().run())
            student = models.Student.get_by_user(user)
            self.assertIsNone(student)
            # But the record tracking removal should not yet be gone.
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNotNone(removal_state)
            self.assertEquals(
                removal_models.ImmediateRemovalState.STATE_DELETION_PENDING,
                removal_state.state)
            # And we should have a to-do item for the cron batch cleanup.
            r = removal_models.BatchRemovalState.get_by_user_ids([user_id])
            self.assertEquals(1, len(r))
            removal_record = r[0]
            self.assertEquals(
                models_data_removal.Registry.get_unindexed_class_names(),
                removal_record.resource_types)
            # Events won't have been cleaned up yet; need cron batch to run.
            events = list(models.EventEntity.all().run())
            self.assertEquals(1, len(events))

        # Call the cron handler to schedule batch removal tasks.  This, in
        # turn, will schedule map/reduce jobs to remove records for that
        # student.
        response = self.get(
            data_removal.DataRemovalCronHandler.URL,
            headers={'X-AppEngine-Cron': 'True'})
        self.assertEquals(200, response.status_int)
        self.assertEquals('OK.', response.body)

        # Run the map/reduce jobs to completion.
        self.execute_all_deferred_tasks()

        # We should now be completely clean; the M/R job that finishes last
        # should also clean up the to-do tracking item.
        with common_utils.Namespace(self.NAMESPACE):
            student = models.Student.get_by_user(user)
            self.assertIsNone(student)
            removal_state = removal_models.ImmediateRemovalState.get_by_user_id(
                user_id)
            self.assertIsNone(removal_state)
            # Events should now be gone.
            events = list(models.EventEntity.all().run())
            self.assertEquals(0, len(events))
示例#23
0
 def unregister(self):
     self.base = '/test'
     actions.unregister(self)
     self.base = ''
 def test_unregister_without_deletion_permits_reregistration(self):
     actions.login(self.STUDENT_EMAIL)
     actions.register(self, self.STUDENT_EMAIL)
     actions.unregister(self)
     actions.register(self, self.STUDENT_EMAIL)