def setUp(self): super(AutoregisterTests, self).setUp() self.context = actions.simple_add_course( self.COURSE_NAME, self.ADMIN_EMAIL, 'Autoregister Course') course = courses.Course(None, app_context=self.context) self.unit = course.add_unit() self.unit.now_available = True self.lesson = course.add_lesson(self.unit) self.lesson.now_available = True course.save() actions.login(self.ADMIN_EMAIL) actions.update_course_config( self.COURSE_NAME, { 'course': { 'now_available': True, 'browsable': False, }, autoregister.AUTOREGISTER_SETTINGS_SCHEMA_SECTION: { autoregister.REDIRECT_URL: self.REDIRECT_URL, autoregister.AUTOREGISTER_ENABLED: True, } }) actions.login(self.STUDENT_EMAIL)
def test_no_redirect_when_course_is_browsable(self): actions.update_course_config(self.COURSE_NAME, {'course': { 'browsable': True }}) response = self.get(self.COURSE_URL) self.assertEqual(200, response.status_int)
def setUp(self): super(AutoregisterTests, self).setUp() self.context = actions.simple_add_course(self.COURSE_NAME, self.ADMIN_EMAIL, 'Autoregister Course') course = courses.Course(None, app_context=self.context) self.unit = course.add_unit() self.unit.now_available = True self.lesson = course.add_lesson(self.unit) self.lesson.now_available = True course.save() actions.login(self.ADMIN_EMAIL) actions.update_course_config( self.COURSE_NAME, { 'course': { 'now_available': True, 'browsable': False, }, autoregister.AUTOREGISTER_SETTINGS_SCHEMA_SECTION: { autoregister.REDIRECT_URL: self.REDIRECT_URL, autoregister.AUTOREGISTER_ENABLED: True, } }) actions.login(self.STUDENT_EMAIL)
def test_hook_content_new_location_overrides_old_location(self): actions.update_course_config(COURSE_NAME, {'html_hooks': {'foo': {'bar': 'zab'}}}) actions.update_course_config(COURSE_NAME, {'foo': {'bar': 'baz'}}) self.assertEquals( 'zab', utils.HtmlHooks.get_content(self.course, 'foo.bar'))
def test_page_unavailable_when_course_not_public(self): actions.update_course_config(self.COURSE_NAME, {'course': { 'now_available': False }}) response = self.get(self.COURSE_URL, expect_errors=True) self.assertEqual(404, response.status_int)
def setUp(self): super(AssetsRestTest, self).setUp() actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) actions.login(ADMIN_EMAIL, is_admin=True) actions.update_course_config(COURSE_NAME, { 'extra_locales': [ {'locale': 'de_DE', 'availability': 'available'}]}) self.COURSE_NAME = COURSE_NAME
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_no_redirect_when_autoregister_disabled(self): actions.update_course_config( self.COURSE_NAME, { autoregister.AUTOREGISTER_SETTINGS_SCHEMA_SECTION: { autoregister.AUTOREGISTER_ENABLED: False, } }) response = self.get(self.PREVIEW_URL) self.assertEqual(200, response.status_int)
def test_hook_rest_delete_removes_from_old_and_new_location(self): actions.update_course_config(COURSE_NAME, {"html_hooks": {"foo": {"bar": "zab"}}}) actions.update_course_config(COURSE_NAME, {"foo": {"bar": "baz"}}) url = "%s?key=%s&xsrf_token=%s" % (ADMIN_SETTINGS_URL, cgi.escape("foo.bar"), cgi.escape(self.xsrf_token)) self.delete(url) env = self.course.get_environ(self.app_context) self.assertNotIn("bar", env["foo"]) self.assertNotIn("bar", env["html_hooks"]["foo"])
def test_hook_i18n(self): actions.update_course_config( COURSE_NAME, { 'html_hooks': {'base': {'after_body_tag_begins': 'foozle'}}, 'extra_locales': [ {'locale': 'de', 'availability': 'available'}, ] }) hook_bundle = { 'content': { 'type': 'html', 'source_value': '', 'data': [{ 'source_value': 'foozle', 'target_value': 'FUZEL', }], } } hook_key = i18n_dashboard.ResourceBundleKey( utils.ResourceHtmlHook.TYPE, 'base.after_body_tag_begins', 'de') with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.save( i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) # Verify non-translated version. response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('foozle', html_hook.text) # Set preference to translated language, and check that that's there. with common_utils.Namespace(NAMESPACE): prefs = models.StudentPreferencesDAO.load_or_default() prefs.locale = 'de' models.StudentPreferencesDAO.save(prefs) response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('FUZEL', html_hook.text) # With no translation present, but preference set to foreign language, # verify that we fall back to the original language. # Remove translation bundle, and clear cache. with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.delete( i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) model_caching.CacheFactory.get_cache_instance( i18n_dashboard.RESOURCE_BUNDLE_CACHE_NAME).clear() response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('foozle', html_hook.text)
def test_hook_i18n(self): actions.update_course_config( COURSE_NAME, { 'html_hooks': {'base': {'after_body_tag_begins': 'foozle'}}, 'extra_locales': [ {'locale': 'de', 'availability': 'available'}, ] }) hook_bundle = { 'content': { 'type': 'html', 'source_value': '', 'data': [{ 'source_value': 'foozle', 'target_value': 'FUZEL', }], } } hook_key = i18n_dashboard.ResourceBundleKey( utils.ResourceHtmlHook.TYPE, 'base.after_body_tag_begins', 'de') with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.save( i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) # Verify non-translated version. response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('foozle', html_hook.text) # Set preference to translated language, and check that that's there. with common_utils.Namespace(NAMESPACE): prefs = models.StudentPreferencesDAO.load_or_default() prefs.locale = 'de' models.StudentPreferencesDAO.save(prefs) response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('FUZEL', html_hook.text) # With no translation present, but preference set to foreign language, # verify that we fall back to the original language. # Remove translation bundle, and clear cache. with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.delete( i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) i18n_dashboard.ProcessScopedResourceBundleCache.instance().clear() response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('foozle', html_hook.text)
def setUp(self): super(AssetsRestTest, self).setUp() actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) actions.login(ADMIN_EMAIL, is_admin=True) actions.update_course_config(COURSE_NAME, { 'extra_locales': [{ 'locale': 'de_DE', 'availability': 'available' }] }) self.COURSE_NAME = COURSE_NAME
def test_hook_rest_edit_removes_from_old_location(self): actions.update_course_config(COURSE_NAME, {'html_hooks': {'foo': {'bar': 'zab'}}}) actions.update_course_config(COURSE_NAME, {'foo': {'bar': 'baz'}}) response = self.put(ADMIN_SETTINGS_URL, {'request': transforms.dumps({ 'xsrf_token': cgi.escape(self.xsrf_token), 'key': 'foo.bar', 'payload': transforms.dumps({'hook_content': 'BAZ'})})}) env = self.course.get_environ(self.app_context) self.assertNotIn('bar', env['foo']) self.assertEquals('BAZ', env['html_hooks']['foo']['bar'])
def test_hook_rest_delete_removes_from_old_and_new_location(self): actions.update_course_config(COURSE_NAME, {'html_hooks': {'foo': {'bar': 'zab'}}}) actions.update_course_config(COURSE_NAME, {'foo': {'bar': 'baz'}}) url = '%s?key=%s&xsrf_token=%s' % ( ADMIN_SETTINGS_URL, cgi.escape('foo.bar'), cgi.escape(self.xsrf_token)) self.delete(url) env = self.course.get_environ(self.app_context) self.assertNotIn('bar', env['foo']) self.assertNotIn('bar', env['html_hooks']['foo'])
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 test_hook_i18n(self): actions.update_course_config( COURSE_NAME, { "html_hooks": {"base": {"after_body_tag_begins": "foozle"}}, "extra_locales": [{"locale": "de", "availability": "available"}], }, ) hook_bundle = { "content": { "type": "html", "source_value": "", "data": [{"source_value": "foozle", "target_value": "FUZEL"}], } } hook_key = i18n_dashboard.ResourceBundleKey(utils.ResourceHtmlHook.TYPE, "base.after_body_tag_begins", "de") with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.save(i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) # Verify non-translated version. response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals("foozle", html_hook.text) # Set preference to translated language, and check that that's there. with common_utils.Namespace(NAMESPACE): prefs = models.StudentPreferencesDAO.load_or_default() prefs.locale = "de" models.StudentPreferencesDAO.save(prefs) response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals("FUZEL", html_hook.text) # With no translation present, but preference set to foreign language, # verify that we fall back to the original language. # Remove translation bundle, and clear cache. with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.delete(i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) i18n_dashboard.ProcessScopedResourceBundleCache.instance().clear() response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals("foozle", html_hook.text)
def test_hook_rest_edit_removes_from_old_location(self): actions.update_course_config(COURSE_NAME, {"html_hooks": {"foo": {"bar": "zab"}}}) actions.update_course_config(COURSE_NAME, {"foo": {"bar": "baz"}}) response = self.put( ADMIN_SETTINGS_URL, { "request": transforms.dumps( { "xsrf_token": cgi.escape(self.xsrf_token), "key": "foo.bar", "payload": transforms.dumps({"hook_content": "BAZ"}), } ) }, ) env = self.course.get_environ(self.app_context) self.assertNotIn("bar", env["foo"]) self.assertEquals("BAZ", env["html_hooks"]["foo"]["bar"])
def test_suppress_next_prev_buttons(self): # Set up one-lesson unit w/ pre, post assessment. Set course # settings to suppress prev/next buttons only on assessments. actions.login(ADMIN_EMAIL) actions.update_course_config( COURSE_NAME, {'unit': { 'hide_assessment_navigation_buttons': True }}) actions.login(STUDENT_EMAIL) self.unit_one_lesson.pre_assessment = self.assessment_one.unit_id self.unit_one_lesson.post_assessment = self.assessment_two.unit_id self.course.save() # Verify we have suppressed prev/next/end buttons on pre-assessment. response = self._get_unit_page(self.unit_one_lesson) self.assertNotIn('Previous Page', response.body) self.assertNotIn('Next Page', response.body) self.assertNotIn(' End ', response.body) # Submit assessment. Verify confirmation page _does_ have prev/next. response = self._post_assessment(self.assessment_one.unit_id).follow() self.assertIn('Previous Page', response.body) self.assertIn('Next Page', response.body) # Click to lesson. Verify have prev/next. response = self._click_next_button(response) self.assertIn('Previous Page', response.body) self.assertIn('Next Page', response.body) # Verify we have suppressed prev/next/end buttons on post-assessment. response = self._click_next_button(response) self.assertNotIn('Previous Page', response.body) self.assertNotIn('Next Page', response.body) self.assertNotIn(' End ', response.body) # Submit post-assessment; verify we have prev/end buttons response = self._post_assessment(self.assessment_two.unit_id).follow() self.assertIn('Previous Page', response.body) self.assertNotIn('Next Page', response.body) self.assertIn(' End ', response.body)
def test_suppress_next_prev_buttons(self): # Set up one-lesson unit w/ pre, post assessment. Set course # settings to suppress prev/next buttons only on assessments. actions.login(ADMIN_EMAIL) actions.update_course_config(COURSE_NAME, { 'unit': {'hide_assessment_navigation_buttons': True}}) actions.login(STUDENT_EMAIL) self.unit_one_lesson.pre_assessment = self.assessment_one.unit_id self.unit_one_lesson.post_assessment = self.assessment_two.unit_id self.course.save() # Verify we have suppressed prev/next/end buttons on pre-assessment. response = self._get_unit_page(self.unit_one_lesson) self.assertNotIn('Previous Page', response.body) self.assertNotIn('Next Page', response.body) self.assertNotIn(' End ', response.body) # Submit assessment. Verify confirmation page _does_ have prev/next. response = self._post_assessment(self.assessment_one.unit_id).follow() self.assertIn('Previous Page', response.body) self.assertIn('Next Page', response.body) # Click to lesson. Verify have prev/next. response = self._click_next_button(response) self.assertIn('Previous Page', response.body) self.assertIn('Next Page', response.body) # Verify we have suppressed prev/next/end buttons on post-assessment. response = self._click_next_button(response) self.assertNotIn('Previous Page', response.body) self.assertNotIn('Next Page', response.body) self.assertNotIn(' End ', response.body) # Submit post-assessment; verify we have prev/end buttons response = self._post_assessment(self.assessment_two.unit_id).follow() self.assertIn('Previous Page', response.body) self.assertNotIn('Next Page', response.body) self.assertIn(' End ', response.body)
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_hook_content_found_in_old_location(self): actions.update_course_config(COURSE_NAME, {"foo": {"bar": "baz"}}) self.assertEquals("baz", utils.HtmlHooks.get_content(self.course, "foo.bar"))
def test_hook_content_new_location_overrides_old_location(self): actions.update_course_config(COURSE_NAME, {"html_hooks": {"foo": {"bar": "zab"}}}) actions.update_course_config(COURSE_NAME, {"foo": {"bar": "baz"}}) self.assertEquals("zab", utils.HtmlHooks.get_content(self.course, "foo.bar"))
def test_page_unavailable_when_course_not_public(self): actions.update_course_config(self.COURSE_NAME, {'course': {'now_available': False}}) response = self.get(self.COURSE_URL, expect_errors=True) self.assertEqual(404, response.status_int)
def test_no_redirect_when_course_is_browsable(self): actions.update_course_config(self.COURSE_NAME, {'course': {'browsable': True}}) response = self.get(self.COURSE_URL) self.assertEqual(200, response.status_int)
def test_hook_content_found_in_old_location(self): actions.update_course_config(COURSE_NAME, {'foo': {'bar': 'baz'}}) self.assertEquals('baz', utils.HtmlHooks.get_content(self.course, 'foo.bar'))
def test_hook_content_found_in_old_location(self): actions.update_course_config(COURSE_NAME, {'foo': {'bar': 'baz'}}) self.assertEquals( 'baz', utils.HtmlHooks.get_content(self.course, 'foo.bar'))