def test_not_enough_assignments_to_allocate(self): """Test for the case when there are too few assignments in the pool.""" email = '*****@*****.**' name = 'Student 1' submission = transforms.dumps([ {'index': 0, 'type': 'regex', 'value': 'S1-1', 'correct': True}, {'index': 1, 'type': 'choices', 'value': 3, 'correct': False}, {'index': 2, 'type': 'regex', 'value': 'is-S1', 'correct': True}, ]) payload = { 'answers': submission, 'assessment_type': LEGACY_REVIEW_UNIT_ID} actions.login(email) actions.register(self, name) response = actions.submit_assessment( self, LEGACY_REVIEW_UNIT_ID, payload) # The student goes to the review dashboard and requests an assignment # to review -- but there is nothing to review. response = actions.request_new_review( self, LEGACY_REVIEW_UNIT_ID, expected_status_code=200) actions.assert_does_not_contain('Assignment to review', response.body) actions.assert_contains( 'Sorry, there are no new submissions ', response.body) actions.assert_contains('disabled="true"', response.body) actions.logout()
def test_student_cannot_see_reviews_prematurely(self): """Test that students cannot see others' reviews prematurely.""" email = '*****@*****.**' name = 'Student 1' submission = transforms.dumps([ {'index': 0, 'type': 'regex', 'value': 'S1-1', 'correct': True}, {'index': 1, 'type': 'choices', 'value': 3, 'correct': False}, {'index': 2, 'type': 'regex', 'value': 'is-S1', 'correct': True}, ]) payload = { 'answers': submission, 'assessment_type': LEGACY_REVIEW_UNIT_ID} actions.login(email) actions.register(self, name) response = actions.submit_assessment( self, LEGACY_REVIEW_UNIT_ID, payload) # Student 1 cannot see the reviews for his assignment yet, because he # has not submitted the two required reviews. response = self.get('assessment?name=%s' % LEGACY_REVIEW_UNIT_ID) actions.assert_equals(response.status_int, 200) actions.assert_contains('Due date for this assignment', response.body) actions.assert_contains( 'After you have completed the required number of peer reviews', response.body) actions.logout()
def setUp(self): super(StudentRedirectTestBase, self).setUp() context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) course = courses.Course(None, context) self.unit = course.add_unit() self.unit.title = 'The Unit' self.unit.availability = courses.AVAILABILITY_AVAILABLE self.lesson_one = course.add_lesson(self.unit) self.lesson_one.title = 'Lesson One' self.lesson_one.availability = courses.AVAILABILITY_AVAILABLE self.lesson_two = course.add_lesson(self.unit) self.lesson_two.title = 'Lesson Two' self.lesson_two.availability = courses.AVAILABILITY_AVAILABLE self.assessment = course.add_assessment() self.assessment.title = 'The Assessment' self.assessment.availability = courses.AVAILABILITY_AVAILABLE course.save() actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) # Actions.register views the student's profile page; clear this out. with common_utils.Namespace(NAMESPACE): prefs = models.StudentPreferencesDAO.load_or_default() prefs.last_location = None models.StudentPreferencesDAO.save(prefs)
def setUp(self): super(ManualProgressTest, self).setUp() # Add a course that will show up. context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) # Register a student for that course. actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) # Add content to course self._course = courses.Course(None, context) self._unit_one = self._course.add_unit() self._unit_one.title = 'Unit Labels: Foo' self._unit_one.availability = courses.AVAILABILITY_AVAILABLE self._lesson_1_1 = self._course.add_lesson(self._unit_one) self._lesson_1_1.title = 'Unit One, Lesson One' self._lesson_1_1.availability = courses.AVAILABILITY_AVAILABLE self._lesson_1_1.manual_progress = True self._lesson_1_2 = self._course.add_lesson(self._unit_one) self._lesson_1_2.title = 'Unit One, Lesson Two' self._lesson_1_2.availability = courses.AVAILABILITY_AVAILABLE self._lesson_1_2.manual_progress = True self._unit_two = self._course.add_unit() self._unit_two.title = 'Unit Labels: Foo' self._unit_two.availability = courses.AVAILABILITY_AVAILABLE self._unit_two.manual_progress = True self._lesson_2_1 = self._course.add_lesson(self._unit_two) self._lesson_2_1.title = 'Unit Two, Lesson One' self._lesson_2_1.availability = courses.AVAILABILITY_AVAILABLE self._lesson_2_2 = self._course.add_lesson(self._unit_two) self._lesson_2_2.title = 'Unit Two, Lesson Two' self._lesson_2_2.availability = courses.AVAILABILITY_AVAILABLE self._sub_assessment = self._course.add_assessment() self._sub_assessment.availability = courses.AVAILABILITY_AVAILABLE self._toplevel_assessment = self._course.add_assessment() self._sub_assessment.availability = courses.AVAILABILITY_AVAILABLE self._unit_three = self._course.add_unit() self._unit_three.pre_assessment = self._sub_assessment.unit_id self._course.save() with common_utils.Namespace(NAMESPACE): self.foo_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Foo', 'descripton': 'foo', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.bar_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Bar', 'descripton': 'bar', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.overridden_environment = actions.OverriddenEnvironment( {'course': {analytics.CAN_RECORD_STUDENT_EVENTS: 'true'}}) self.overridden_environment.__enter__()
def setUp(self): super(CertificateCriteriaTestCase, self).setUp() self.base = '/' + self.COURSE_NAME context = actions.simple_add_course( self.COURSE_NAME, self.ADMIN_EMAIL, 'Certificate Criteria') self.old_namespace = namespace_manager.get_namespace() namespace_manager.set_namespace('ns_%s' % self.COURSE_NAME) self.course = courses.Course(None, context) self.course.save() self.TEST_USER = actions.login('*****@*****.**') actions.register(self, self.TEST_USER.email()) self.student = ( models.StudentProfileDAO.get_enrolled_student_by_user_for( self.TEST_USER, context)) # Override course.yaml settings by patching app_context. self.get_environ_old = sites.ApplicationContext.get_environ self.certificate_criteria = [] def get_environ_new(app_context): environ = self.get_environ_old(app_context) environ['certificate_criteria'] = self.certificate_criteria return environ sites.ApplicationContext.get_environ = get_environ_new
def test_unenroll_commanded_only_unenrolls_student(self): # Register user with profile enabled, so as to trigger call to # sites.get_course_for_current_request() when profile is updated # from lifecycle queue callback handler. user = actions.login(self.STUDENT_EMAIL) actions.register(self, self.STUDENT_EMAIL) # Verify user is really there. with common_utils.Namespace(self.NAMESPACE): self.assertIsNotNone(models.Student.get_by_user_id(user.user_id())) # Add taskqueue task so that queue callback happens w/o 'self.base' # being added to the URL and implicitly getting the course context # set. task = taskqueue.Task( params={ 'event': models.StudentLifecycleObserver.EVENT_UNENROLL_COMMANDED, 'user_id': user.user_id(), 'timestamp': '2015-05-14T10:02:09.758704Z', 'callbacks': appengine_config.CORE_MODULE_NAME }, target=taskqueue.DEFAULT_APP_VERSION) task.add('user-lifecycle') # Taskqueue add should not have updated student. student = models.Student.get_by_user_id(user.user_id()) self.assertTrue(student.is_enrolled) self.execute_all_deferred_tasks( models.StudentLifecycleObserver.QUEUE_NAME) # User should still be there, but now marked unenrolled. student = models.Student.get_by_user_id(user.user_id()) self.assertFalse(student.is_enrolled)
def test_unenroll_commanded_with_delete_requested(self): user = actions.login(self.STUDENT_EMAIL) actions.register(self, self.STUDENT_EMAIL, course=self.COURSE) # Verify user is really there. with common_utils.Namespace(self.NAMESPACE): self.assertIsNotNone(models.Student.get_by_user_id(user.user_id())) # Mark user for data deletion upon unenroll removal_models.ImmediateRemovalState.set_deletion_pending( user.user_id()) response = self.post( models.StudentLifecycleObserver.URL, {'user_id': user.user_id(), 'event': models.StudentLifecycleObserver.EVENT_UNENROLL_COMMANDED, 'timestamp': '2015-05-14T10:02:09.758704Z', 'callbacks': appengine_config.CORE_MODULE_NAME}, headers={'X-AppEngine-QueueName': models.StudentLifecycleObserver.QUEUE_NAME}) self.assertEquals(response.status_int, 200) self.assertEquals('', self.get_log()) # User should still be there, but now marked unenrolled. student = models.Student.get_by_user_id(user.user_id()) self.assertFalse(student.is_enrolled) # Running lifecycle queue should cause data removal to delete user. self.execute_all_deferred_tasks( models.StudentLifecycleObserver.QUEUE_NAME) # User should now be gone. self.assertIsNone(models.Student.get_by_user_id(user.user_id()))
def test_announcement_i18n_title(self): locale = 'de' announcement = self._add_announcement_and_translation(locale) actions.login('*****@*****.**') actions.register(self, 'John Doe') # Verify that one-off title translation also works. try: sites.set_path_info('/' + self.COURSE) ctx = sites.get_course_for_current_request() save_locale = ctx.get_current_locale() key = announcements.TranslatableResourceAnnouncement.key_for_entity( announcement) # Untranslated ctx.set_current_locale(None) i18n_title = str( announcements.TranslatableResourceAnnouncement.get_i18n_title( key)) self.assertEquals('Test Announcement', i18n_title) # Translated ctx.set_current_locale(locale) i18n_title = str( announcements.TranslatableResourceAnnouncement.get_i18n_title( key)) self.assertEquals('TEST ANNOUNCEMENT', i18n_title) finally: ctx.set_current_locale(save_locale) sites.unset_path_info()
def test_multiple_students(self): # Register two students user = actions.login(self.STUDENT_EMAIL) actions.register(self, user.email(), course=self.COURSE) other_user = actions.login('*****@*****.**') 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) self._unregister_and_request_data_removal(self.COURSE) self._complete_removal() # 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): COURSE_TWO = 'course_two' COURSE_TWO_NS = 'ns_' + COURSE_TWO # Slight cheat: Register gitkit data remover manually, rather than # enabling the entire module, which disrupts normal functional test # user login handling gitkit.EmailMapping.register_for_data_removal() actions.simple_add_course( COURSE_TWO, self.ADMIN_EMAIL, 'Data Removal Test Two') user = actions.login(self.STUDENT_EMAIL) actions.register(self, user.email(), course=self.COURSE) actions.register(self, user.email(), course=COURSE_TWO) # Slight cheat: Rather than enabling gitkit module, just call # the method that will insert the EmailMapping row. gitkit.EmailUpdatePolicy.apply(user) # Global profile object(s) should now exist. profile = models.StudentProfileDAO.get_profile_by_user_id( user.user_id()) self.assertIsNotNone(profile) email_policy = gitkit.EmailMapping.get_by_user_id(user.user_id()) self.assertIsNotNone(email_policy) # Unregister from 'data_removal_test' course. self._unregister_and_request_data_removal(self.COURSE) self._complete_removal() # Student object should be gone from data_removal_test course, but # not from course_two. 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)) # Global profile object(s) should still exist. profile = models.StudentProfileDAO.get_profile_by_user_id( user.user_id()) self.assertIsNotNone(profile) email_policy = gitkit.EmailMapping.get_by_user_id(user.user_id()) self.assertIsNotNone(email_policy) # Unregister from other course. self._unregister_and_request_data_removal(COURSE_TWO) self._complete_removal() # Both Student objects should now be gone. with common_utils.Namespace(self.NAMESPACE): self.assertIsNone(models.Student.get_by_user(user)) with common_utils.Namespace(COURSE_TWO_NS): self.assertIsNone(models.Student.get_by_user(user)) # Global profile object(s) should also be gone. profile = models.StudentProfileDAO.get_profile_by_user_id( user.user_id()) self.assertIsNone(profile) email_policy = gitkit.EmailMapping.get_by_user_id(user.user_id()) self.assertIsNone(email_policy)
def setUp(self): super(ManualProgressTest, self).setUp() # Add a course that will show up. context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) # Register a student for that course. actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) # Add content to course self._course = courses.Course(None, context) self._unit_one = self._course.add_unit() self._unit_one.title = "Unit Labels: Foo" self._unit_one.now_available = True self._lesson_1_1 = self._course.add_lesson(self._unit_one) self._lesson_1_1.title = "Unit One, Lesson One" self._lesson_1_1.now_available = True self._lesson_1_1.manual_progress = True self._lesson_1_2 = self._course.add_lesson(self._unit_one) self._lesson_1_2.title = "Unit One, Lesson Two" self._lesson_1_2.now_available = True self._lesson_1_2.manual_progress = True self._unit_two = self._course.add_unit() self._unit_two.title = "Unit Labels: Foo" self._unit_two.now_available = True self._unit_two.manual_progress = True self._lesson_2_1 = self._course.add_lesson(self._unit_two) self._lesson_2_1.title = "Unit Two, Lesson One" self._lesson_2_1.now_available = True self._lesson_2_2 = self._course.add_lesson(self._unit_two) self._lesson_2_2.title = "Unit Two, Lesson Two" self._lesson_2_2.now_available = True self._sub_assessment = self._course.add_assessment() self._sub_assessment.now_available = True self._toplevel_assessment = self._course.add_assessment() self._sub_assessment.now_available = True self._unit_three = self._course.add_unit() self._unit_three.pre_assessment = self._sub_assessment.unit_id self._course.save() with common_utils.Namespace(NAMESPACE): self.foo_id = models.LabelDAO.save( models.LabelDTO( None, {"title": "Foo", "descripton": "foo", "type": models.LabelDTO.LABEL_TYPE_COURSE_TRACK} ) ) self.bar_id = models.LabelDAO.save( models.LabelDTO( None, {"title": "Bar", "descripton": "bar", "type": models.LabelDTO.LABEL_TYPE_COURSE_TRACK} ) ) config.Registry.test_overrides[utils.CAN_PERSIST_ACTIVITY_EVENTS.name] = True
def test_enrollment(self): actions.logout() response = self.get_response( '{course(id: "%s") {enrollment {email enrolled}}}' % ( self.course_id)) enrollment = response['data']['course']['enrollment'] self.assertEquals({'enrolled': False, 'email': None}, enrollment) actions.login(STUDENT_EMAIL) response = self.get_response( '{course(id: "%s") {enrollment {email enrolled}}}' % ( self.course_id)) enrollment = response['data']['course']['enrollment'] self.assertEquals({'enrolled': False, 'email': None}, enrollment) actions.register(self, STUDENT_NAME) response = self.get_response( '{course (id: "%s") { enrollment { email enrolled}}}' % ( self.course_id)) enrollment = response['data']['course']['enrollment'] self.assertEquals( {'enrolled': True, 'email': STUDENT_EMAIL}, enrollment)
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)
def setUp(self): super(PeerReviewDashboardStudentTest, self).setUp() self.base = '/' + self.COURSE_NAME context = actions.simple_add_course( self.COURSE_NAME, '*****@*****.**', 'Peer Back Button Child') self.course = courses.Course(None, context) self.assessment = self.course.add_assessment() self.assessment.title = 'Assessment' self.assessment.html_content = 'assessment content' self.assessment.workflow_yaml = ( '{grader: human,' 'matcher: peer,' 'review_due_date: \'2034-07-01 12:00\',' 'review_min_count: 1,' 'review_window_mins: 20,' 'submission_due_date: \'2034-07-01 12:00\'}') self.assessment.availability = courses.AVAILABILITY_AVAILABLE self.course.save() actions.login(self.STUDENT_EMAIL) actions.register(self, self.STUDENT_EMAIL) actions.submit_assessment( self, self.assessment.unit_id, {'answers': '', 'score': 0, 'assessment_type': self.assessment.unit_id}, presubmit_checks=False )
def test_delete_link_when_registered_then_cancel_deletion(self): actions.login(self.STUDENT_EMAIL) actions.register(self, self.STUDENT_EMAIL) response = self.get('course') response = self.click(response, 'Delete My Data') self._unregister_flow(response, with_deletion_checked=True, cancel_on_deletion=True)
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)
def test_multiple_course(self): """Tests when multiple courses are available.""" sites.setup_courses('course:/test::ns_test, course:/:/') name = 'Test completed course' email = 'Student' # Make the course available. get_environ_old = sites.ApplicationContext.get_environ def get_environ_new(self): environ = get_environ_old(self) environ['course']['now_available'] = True return environ sites.ApplicationContext.get_environ = get_environ_new actions.login(email) actions.register(self, name) response = self.get('/explorer/courses') # Assert if 'View course list' text is shown on my course page. actions.assert_contains('View course list', response.body) # Clean up app_context. sites.ApplicationContext.get_environ = get_environ_old sites.reset_courses()
def test_jobs_run(self): COURSE = 'test' app_context = actions.simple_add_course(COURSE, ADMIN_EMAIL, 'Test') actions.register(self, 'Joe Admin', COURSE) config.set_report_allowed(True) response = self.get(usage_reporting.StartReportingJobs.URL, headers={'X-AppEngine-Cron': 'True'}) self.assertEquals(200, response.status_int) self.assertEquals('OK.', response.body) now = int(time.time()) self.execute_all_deferred_tasks( models.StudentLifecycleObserver.QUEUE_NAME) self.execute_all_deferred_tasks() expected = [{ messaging.Message._INSTALLATION: FAKE_INSTALLATION_ID, messaging.Message._COURSE: FAKE_COURSE_ID, messaging.Message._TIMESTAMP: FAKE_TIMESTAMP, messaging.Message._VERSION: os.environ['GCB_PRODUCT_VERSION'], messaging.Message._METRIC: messaging.Message.METRIC_STUDENT_COUNT, messaging.Message._VALUE: 1, }, { messaging.Message._INSTALLATION: FAKE_INSTALLATION_ID, messaging.Message._COURSE: FAKE_COURSE_ID, messaging.Message._TIMESTAMP: now - (now % 3600), messaging.Message._VERSION: os.environ['GCB_PRODUCT_VERSION'], messaging.Message._METRIC: messaging.Message.METRIC_ENROLLED, messaging.Message._VALUE: 1, }] actual = MockSender.get_sent() actual.sort(key=lambda x: x['timestamp']) self.assertEquals(expected, actual) sites.reset_courses()
def test_get_news_some_old_some_new(self): user = actions.login(self.STUDENT_EMAIL) actions.register(self, 'John Smith') # Newsworthy thing happened beyond newsworthy time limit, then_ts = utc.now_as_timestamp() - news.NEWSWORTHINESS_SECONDS - 1 then = utc.timestamp_to_datetime(then_ts) self._set_student_enroll_date(user, then) news_item = news.NewsItem('test:one', 'url_one', then) news.CourseNewsDao.add_news_item(news_item) news_item = news.NewsItem('test:two', 'url_two', then) news.CourseNewsDao.add_news_item(news_item) # But student has seen the thing, so it's marked as non-new. news.StudentNewsDao.mark_item_seen('test:one') response = self.get('course') soup = self.parse_html_string_to_soup(response.body) self.assertEquals(['has_new_news'], self._get_news_title_styles(soup)) self.assertEquals( [ news_tests_lib.NewsItem('Test Item two', 'url_two', True), news_tests_lib.NewsItem('Test Item one', 'url_one', False), ], news_tests_lib.extract_news_items_from_soup(soup))
def setUp(self): super(StudentRedirectTestBase, self).setUp() context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) course = courses.Course(None, context) self.unit = course.add_unit() self.unit.title = 'The Unit' self.unit.now_available = True self.lesson_one = course.add_lesson(self.unit) self.lesson_one.title = 'Lesson One' self.lesson_one.now_available = True self.lesson_two = course.add_lesson(self.unit) self.lesson_two.title = 'Lesson Two' self.lesson_two.now_available = True self.assessment = course.add_assessment() self.assessment.title = 'The Assessment' self.assessment.now_available = True course.save() actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) # Actions.register views the student's profile page; clear this out. with common_utils.Namespace(NAMESPACE): prefs = models.StudentPreferencesDAO.load_or_default() prefs.last_location = None models.StudentPreferencesDAO.save(prefs)
def test_remove_by_email(self): user = actions.login(self.STUDENT_EMAIL) actions.register(self, user.email(), course=self.COURSE) with common_utils.Namespace(self.NAMESPACE): sse = unsubscribe.SubscriptionStateEntity( key_name=user.email()) sse.is_subscribed = True sse.save() notifications.Manager.send_async( user.email(), self.ADMIN_EMAIL, 'testemail', 'Mary had a little lamb. She fed it beans and buns.', 'Pets for Mary', '{"audit_trail": "yes"}', retention_policy=notifications.RetainAll) # Finish deferred tasks so notifications subsystem would have # deleted items if it were going to. It shouldn't based on our # use of RetainAll above, but belt-and-suspenders. self.execute_all_deferred_tasks() l = list(notifications.Notification.all().run()) self.assertEquals(1, len(l)) l = list(notifications.Payload.all().run()) self.assertEquals(1, len(l)) self._unregister_and_request_data_removal(self.COURSE) self._complete_removal() with common_utils.Namespace(self.NAMESPACE): l = list(unsubscribe.SubscriptionStateEntity.all().run()) self.assertEquals(0, len(l)) l = list(notifications.Notification.all().run()) self.assertEquals(0, len(l)) l = list(notifications.Payload.all().run()) self.assertEquals(0, len(l))
def setUp(self): super(StudentLabelsTest, self).setUp() actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) with common_utils.Namespace(NAMESPACE): self.foo_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Foo', 'descripton': 'foo', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.bar_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Bar', 'descripton': 'bar', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.baz_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Baz', 'descripton': 'baz', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.quux_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Quux', 'descripton': 'quux', 'type': models.LabelDTO.LABEL_TYPE_GENERAL})) actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) actions.logout()
def test_single_completed_course(self): """Tests when a single completed course is present.""" name = 'Test Assessments' # Register. user = actions.login('*****@*****.**') actions.register(self, name) response = self.get('/explorer') # Before a course is not completed, # explorer page should not show 'view score' button. actions.assert_does_not_contain('View score', response.body) # Assign a grade to the course enrolled to mark it complete. profile = PersonalProfile.get_by_key_name(user.user_id()) info = {'final_grade': 'A'} course_info_dict = {'': info} profile.course_info = transforms.dumps(course_info_dict) profile.put() # Check if 'View score' text is visible on profile page. response = self.get('/explorer/profile') actions.assert_contains('View score', response.body) # Check if 'Go to course' button is not visible on explorer page. response = self.get('/explorer') actions.assert_does_not_contain('Go to course', response.body) # Check if 'View score' button is visible on explorer page. response = self.get('/explorer') actions.assert_contains('View score', response.body)
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))
def setUp(self): super(PeerReviewDashboardStudentTest, self).setUp() self.base = '/' + self.COURSE_NAME context = actions.simple_add_course(self.COURSE_NAME, '*****@*****.**', 'Peer Back Button Child') self.course = courses.Course(None, context) self.assessment = self.course.add_assessment() self.assessment.title = 'Assessment' self.assessment.html_content = 'assessment content' self.assessment.workflow_yaml = ( '{grader: human,' 'matcher: peer,' 'review_due_date: \'2034-07-01 12:00\',' 'review_min_count: 1,' 'review_window_mins: 20,' 'submission_due_date: \'2034-07-01 12:00\'}') self.assessment.availability = courses.AVAILABILITY_AVAILABLE self.course.save() actions.login(self.STUDENT_EMAIL) actions.register(self, self.STUDENT_EMAIL) actions.submit_assessment( self, self.assessment.unit_id, { 'answers': '', 'score': 0, 'assessment_type': self.assessment.unit_id }, presubmit_checks=False)
def setUp(self): super(ExtraTabsTests, self).setUp() self.base = '/' + COURSE_NAME app_context = actions.simple_add_course( COURSE_NAME, ADMIN_EMAIL, 'Extra Tabs Course') self.old_namespace = namespace_manager.get_namespace() namespace_manager.set_namespace('ns_%s' % COURSE_NAME) self.course = courses.Course(None, app_context) courses.Course.ENVIRON_TEST_OVERRIDES = { 'course': { 'extra_tabs': [ { 'label': 'FAQ', 'position': 'left', 'visibility': 'all', 'url': '', 'content': 'Frequently asked questions'}, { 'label': 'Resources', 'position': 'right', 'visibility': 'student', 'url': 'http://www.example.com', 'content': 'Links to resources'}] } } self.faq_url = 'modules/extra_tabs/render?index=0' actions.login(STUDENT_EMAIL, is_admin=False) actions.register(self, STUDENT_NAME)
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_id = None user = actions.login(self.STUDENT_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 self._unregister_and_request_data_removal(self.COURSE) # On submitting the unregister form, the user's ImmediateRemovalState # will have been marked as deltion-in-progress, and so user cannot # re-register yet. assert_cannot_register() # Run the queue to do the cleanup of indexed items, and add the # work-to-do items for batched cleanup. self.execute_all_deferred_tasks( models.StudentLifecycleObserver.QUEUE_NAME) assert_cannot_register() # Run the cron job that launches the map/reduce jobs to clean up # bulk items. Still not able to re-register. self.get(data_removal.DataRemovalCronHandler.URL, headers={'X-AppEngine-Cron': 'True'}) assert_cannot_register() # Run the map/reduce jobs. Bulk items should now be 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.assertIsNotNone(removal_state) assert_cannot_register() # Run the cron job one more time. When no bulk to-do items remain, # we then clean up the ImmediateRemovalState. Re-registration should # now be possible. self.get(data_removal.DataRemovalCronHandler.URL, headers={'X-AppEngine-Cron': 'True'}) 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_tracked_lessons(self): context = actions.simple_add_course('test', '*****@*****.**', 'Test Course') course = courses.Course(None, context) actions.login('*****@*****.**') actions.register(self, 'Some Admin', 'test') with common_utils.Namespace('ns_test'): foo_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Foo', 'descripton': 'foo', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) bar_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Bar', 'descripton': 'bar', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) unit1 = course.add_unit() unit1.availability = courses.AVAILABILITY_AVAILABLE unit1.labels = str(foo_id) lesson11 = course.add_lesson(unit1) lesson11.objectives = 'common plugh <gcb-youtube videoid="glados">' lesson11.availability = courses.AVAILABILITY_AVAILABLE lesson11.notes = search_unit_tests.VALID_PAGE_URL lesson11.video = 'portal' course.update_unit(unit1) unit2 = course.add_unit() unit2.availability = courses.AVAILABILITY_AVAILABLE unit1.labels = str(bar_id) lesson21 = course.add_lesson(unit2) lesson21.objectives = 'common plover' lesson21.availability = courses.AVAILABILITY_AVAILABLE course.update_unit(unit2) course.save() self.index_test_course() # Registered, un-tracked student sees all. response = self.get('/test/search?query=common') self.assertIn('common', response.body) self.assertIn('plugh', response.body) self.assertIn('plover', response.body) response = self.get('/test/search?query=link') # Do see followed links self.assertIn('Partial', response.body) self.assertIn('Absolute', response.body) response = self.get('/test/search?query=lemon') # Do see video refs self.assertIn('v=glados', response.body) # Student with tracks sees filtered view. with common_utils.Namespace('ns_test'): models.Student.set_labels_for_current(str(foo_id)) response = self.get('/test/search?query=common') self.assertIn('common', response.body) self.assertNotIn('plugh', response.body) self.assertIn('plover', response.body) response = self.get('/test/search?query=link') # Links are filtered self.assertNotIn('Partial', response.body) self.assertNotIn('Absolute', response.body) response = self.get('/test/search?query=lemon') # Don't see video refs self.assertNotIn('v=glados', response.body)
def test_announcement_news(self): actions.login('*****@*****.**') actions.register(self, 'John Doe') time.sleep(1) locale = 'de' announcement = self._add_announcement_and_translation( locale, is_draft=True) sent_data = { 'key': str(announcement.key()), 'title': 'Test Announcement', 'date': utc.to_text(seconds=utc.now_as_timestamp()), 'is_draft': False, } actions.login(self.ADMIN_EMAIL) response = self._put_announcement(sent_data) actions.login('*****@*****.**') # Verify announcement news item using news API directly news_items = news.CourseNewsDao.get_news_items() self.assertEquals(1, len(news_items)) item = news_items[0] now_timestamp = utc.now_as_timestamp() self.assertEquals( announcements.AnnouncementsStudentHandler.URL.lstrip('/'), item.url) self.assertEquals( str(announcements.TranslatableResourceAnnouncement.key_for_entity( announcement)), item.resource_key) self.assertAlmostEqual( now_timestamp, utc.datetime_to_timestamp(item.when), delta=10) # Verify announcement news item looking at HTTP response to /course response = self.get('course') soup = self.parse_html_string_to_soup(response.body) self.assertEquals( [news_tests_lib.NewsItem( 'Test Announcement', announcements.AnnouncementsStudentHandler.URL.lstrip('/'), True)], news_tests_lib.extract_news_items_from_soup(soup)) # Verify announcement news item translated title. self._set_prefs_locale(locale) response = self.get('course') soup = self.parse_html_string_to_soup(response.body) self.assertEquals( [news_tests_lib.NewsItem( 'TEST ANNOUNCEMENT', announcements.AnnouncementsStudentHandler.URL.lstrip('/'), True)], news_tests_lib.extract_news_items_from_soup(soup)) # Delete the announcement; news item should also go away. actions.login(self.ADMIN_EMAIL) self._delete_announcement(str(announcement.key())) actions.login('*****@*****.**') response = self.get('course') soup = self.parse_html_string_to_soup(response.body) self.assertEquals([], news_tests_lib.extract_news_items_from_soup(soup))
def setUp(self): super(StudentTracksTest, self).setUp() # Add a course that will show up. actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) # Add labels with common_utils.Namespace(NAMESPACE): self.foo_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Foo', 'descripton': 'foo', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.bar_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Bar', 'descripton': 'bar', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.baz_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Baz', 'descripton': 'baz', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.quux_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Quux', 'descripton': 'quux', 'type': models.LabelDTO.LABEL_TYPE_GENERAL})) # Register a student for that course. actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) actions.logout() # Add some units to the course. self._course = courses.Course( None, app_context=sites.get_all_courses()[0]) self._unit_no_labels = self._course.add_unit() self._unit_no_labels.title = 'Unit No Labels' self._unit_no_labels.availability = courses.AVAILABILITY_AVAILABLE self._course.add_lesson(self._unit_no_labels) self._unit_labels_foo = self._course.add_unit() self._unit_labels_foo.title = 'Unit Labels: Foo' self._unit_labels_foo.availability = courses.AVAILABILITY_AVAILABLE self._unit_labels_foo.labels = str(self.foo_id) self._course.add_lesson(self._unit_labels_foo) self._unit_labels_foo_bar = self._course.add_unit() self._unit_labels_foo_bar.title = 'Unit Labels: Bar, Foo' self._unit_labels_foo_bar.availability = courses.AVAILABILITY_AVAILABLE self._unit_labels_foo_bar.labels = '%s %s' % (self.bar_id, self.foo_id) self._course.add_lesson(self._unit_labels_foo_bar) self._unit_labels_quux = self._course.add_unit() self._unit_labels_quux.title = 'Unit Labels: Quux' self._unit_labels_quux.availability = courses.AVAILABILITY_AVAILABLE self._unit_labels_quux.labels = str(self.quux_id) self._course.add_lesson(self._unit_labels_quux) self._unit_labels_foo_quux = self._course.add_unit() self._unit_labels_foo_quux.title = 'Unit Labels: Foo Quux' self._unit_labels_foo_quux.availability = courses.AVAILABILITY_AVAILABLE self._unit_labels_foo_quux.labels = '%s %s' % (str(self.foo_id), str(self.quux_id)) self._course.add_lesson(self._unit_labels_foo_quux) self._course.save()
def test_get_news_no_news(self): actions.login(self.STUDENT_EMAIL) actions.register(self, 'John Smith') response = self.get('course') soup = self.parse_html_string_to_soup(response.body) self.assertEquals(['has_only_old_news'], self._get_news_title_styles(soup)) self.assertEquals([], news_tests_lib.extract_news_items_from_soup(soup))
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()
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_unregister_hides_deletion_option_when_no_deletion_policy(self): actions.login(self.STUDENT_EMAIL) actions.register(self, self.STUDENT_EMAIL) with actions.OverriddenEnvironment({ data_removal.DATA_REMOVAL_SETTINGS_SECTION: { data_removal.REMOVAL_POLICY: data_removal.IndefiniteRetentionPolicy.get_name()}}): response = self.get('student/unenroll') self.assertNotIn('Remove all my data from the course', 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))
def test_rest_handler_discretely_does_not_mail_registered_users(self): # To reduce spam the service should NOT email registered users, but for # privacy reasons should report to the requestor that it did. registered_student = '*****@*****.**' actions.login(registered_student) actions.register(self, 'Test User') response = self._do_valid_email_list_post([registered_student]) self.assertEquals(200, response['status']) self.assertEquals('OK, 1 messages sent', response['message']) self.assertEqual(0, self.send_async_count)
def setUp(self): super(StudentTracksTest, self).setUp() # Add a course that will show up. actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) # Add labels with common_utils.Namespace(NAMESPACE): self.foo_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Foo', 'descripton': 'foo', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.bar_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Bar', 'descripton': 'bar', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.baz_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Baz', 'descripton': 'baz', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK})) self.quux_id = models.LabelDAO.save(models.LabelDTO( None, {'title': 'Quux', 'descripton': 'quux', 'type': models.LabelDTO.LABEL_TYPE_GENERAL})) # Register a student for that course. actions.login(REGISTERED_STUDENT_EMAIL) actions.register(self, REGISTERED_STUDENT_NAME, COURSE_NAME) actions.logout() # Add some units to the course. self._course = courses.Course( None, app_context=sites.get_all_courses()[0]) self._unit_no_labels = self._course.add_unit() self._unit_no_labels.title = 'Unit No Labels' self._unit_no_labels.now_available = True self._unit_labels_foo = self._course.add_unit() self._unit_labels_foo.title = 'Unit Labels: Foo' self._unit_labels_foo.now_available = True self._unit_labels_foo.labels = str(self.foo_id) self._unit_labels_foo_bar = self._course.add_unit() self._unit_labels_foo_bar.title = 'Unit Labels: Bar, Foo' self._unit_labels_foo_bar.now_available = True self._unit_labels_foo_bar.labels = '%s %s' % (self.bar_id, self.foo_id) self._unit_labels_quux = self._course.add_unit() self._unit_labels_quux.title = 'Unit Labels: Quux' self._unit_labels_quux.now_available = True self._unit_labels_quux.labels = str(self.quux_id) self._unit_labels_foo_quux = self._course.add_unit() self._unit_labels_foo_quux.title = 'Unit Labels: Foo Quux' self._unit_labels_foo_quux.now_available = True self._unit_labels_foo_quux.labels = '%s %s' % (str(self.foo_id), str(self.quux_id)) self._course.save()
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 add_course_and_register_student(admin_email): google_app_context = actions.simple_add_course( course_name, admin_email, course_title) actions.update_course_config( course_name, {'course': {'now_available': True, 'browsable': True,},}) actions.register(self, 'John Smith', course_name) 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()
def setUp(self): super(UnitPrePostAssessmentTest, self).setUp() context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) self.course = courses.Course(None, context) self.unit_no_lessons = self.course.add_unit() self.unit_no_lessons.title = 'No Lessons' self.unit_no_lessons.now_available = True self.unit_one_lesson = self.course.add_unit() self.unit_one_lesson.title = 'One Lesson' self.unit_one_lesson.now_available = True self.lesson = self.course.add_lesson(self.unit_one_lesson) self.lesson.title = 'Lesson One' self.lesson.objectives = 'body of lesson' self.lesson.now_available = True self.assessment_one = self.course.add_assessment() self.assessment_one.title = 'Assessment One' self.assessment_one.html_content = 'assessment one content' self.assessment_one.now_available = True self.assessment_two = self.course.add_assessment() self.assessment_two.title = 'Assessment Two' self.assessment_two.html_content = 'assessment two content' self.assessment_two.now_available = True self.course.save() actions.login(STUDENT_EMAIL) actions.register(self, STUDENT_EMAIL, COURSE_NAME) config.Registry.test_overrides[ utils.CAN_PERSIST_ACTIVITY_EVENTS.name] = True with common_utils.Namespace(NAMESPACE): self.track_one_id = models.LabelDAO.save( models.LabelDTO( None, { 'title': 'Track One', 'descripton': 'track_one', 'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK })) self.general_one_id = models.LabelDAO.save( models.LabelDTO( None, { 'title': 'Track One', 'descripton': 'track_one', 'type': models.LabelDTO.LABEL_TYPE_GENERAL }))
def test_remove_by_email(self): user = actions.login(self.STUDENT_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() self._unregister_and_request_data_removal(self.COURSE) self._complete_removal() with common_utils.Namespace(self.NAMESPACE): l = list(unsubscribe.SubscriptionStateEntity.all().run()) self.assertEquals(0, len(l))