def test_caching(self): course = self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment( self.enabled(md_enabled=True, jinja_enabled=True)): for url in [ '/test/foo/main.css', '/test/foo/index.html', '/test/foo/markdown.md' ]: self.assert_no_cache(self.get(url)) with actions.OverriddenEnvironment( self.enabled(md_enabled=True, jinja_enabled=True, caching=webserv.CACHING_5_MIN)): response = self.get('/test/foo/main.css') self.assert_cached(response, 5) for url in ['/test/foo/index.html', '/test/foo/markdown.md']: self.assert_no_cache(self.get(url)) with actions.OverriddenEnvironment( self.enabled(md_enabled=True, jinja_enabled=False, caching=webserv.CACHING_1_HOUR)): for url in [ '/test/foo/main.css', '/test/foo/index.html', '/test/foo/markdown.md' ]: self.assert_cached(self.get(url), 60)
def test_html_with_and_without_markdown(self): self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.enabled(md_enabled=False)): response = self.get('/test/foo/index.md') self.assertIn('gcb-md-header: /md_header.html', response.body) self.assertNotIn('<title>Course Builder Markdown Page</title>', response.body) self.assertIn('gcb-md-footer: /md_footer.html', response.body) self.assertNotIn('<p>Powered by Course Builder!</p>', response.body) response = self.get('/test/foo/markdown.md') self.assertNotIn('<h1>A First Level Header</h1>', response.body) self.assertNotIn('<h2 id="my-second-level-header">', response.body) self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body) with actions.OverriddenEnvironment(self.enabled(md_enabled=True)): response = self.get('/test/foo/index.md') self.assertNotIn('gcb-md-header: /md_header.html', response.body) self.assertIn('<title>Course Builder Markdown Page</title>', response.body) self.assertNotIn('gcb-md-footer: /md_footer.html', response.body) self.assertIn('<p>Powered by Course Builder!</p>', response.body) response = self.get('/test/foo/markdown.md') self.assertIn('<h1>A First Level Header</h1>', response.body) self.assertIn('<h2 id="my-second-level-header">', response.body) self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body)
def test_markdown_jinja_permutations(self): self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment( self.enabled(md_enabled=False, jinja_enabled=False)): response = self.get('/test/foo/markdown.md') self.assertNotIn('<h1>A First Level Header</h1>', response.body) self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body) with actions.OverriddenEnvironment( self.enabled(md_enabled=True, jinja_enabled=False)): response = self.get('/test/foo/markdown.md') self.assertIn('<h1>A First Level Header</h1>', response.body) self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body) with actions.OverriddenEnvironment( self.enabled(md_enabled=False, jinja_enabled=True)): response = self.get('/test/foo/markdown.md') self.assertNotIn('<h1>A First Level Header</h1>', response.body) self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body) with actions.OverriddenEnvironment( self.enabled(md_enabled=True, jinja_enabled=True)): response = self.get('/test/foo/markdown.md') self.assertIn('<h1>A First Level Header</h1>', response.body) self.assertNotIn('{{ course_info.course.title }}', response.body) self.assertIn('Power Searching with Google', response.body)
def test_course_list_text(self): course = courses.Course.get(self.app_context) # show_in_explorer setting not explicitly set - do we default to True? self._verify_course_list_state('Yes') # Explicitly set show_in_explorer to True. with actions.OverriddenEnvironment( {'course': {constants.SHOW_IN_EXPLORER: True}}): self._verify_course_list_state('Yes') # Explicitly set show_in_explorer to False with actions.OverriddenEnvironment( {'course': {constants.SHOW_IN_EXPLORER: False}}): self._verify_course_list_state('No')
def test_get_client_id_returns_expected_value_when_set(self): with actions.OverriddenEnvironment( self.get_env(client_id=self.client_id)): # Treat as module-protected. pylint: disable=protected-access self.assertEqual( self.client_id, core_tags._Runtime(self.app_context).get_client_id())
def test_invitation_row_supressed_if_invitations_disabled(self): email_env = {'course': {'invitation_email': {'enabled': False}}} with actions.OverriddenEnvironment(email_env): self.register() dom = self.parse_html_string(self.get(self.URL).body) self.assertIsNone(self._find_row(dom, 'Invite Friends')) self.assertIsNotNone(self._find_row(dom, 'Subscribe/Unsubscribe'))
def test_configured_true_when_enabled_and_api_key_and_client_id_set(self): self.enable_courses_can_use_google_apis() with actions.OverriddenEnvironment( self.get_env(api_key=self.api_key, client_id=self.client_id)): # Treat as module-protected. pylint: disable=protected-access self.assertTrue(core_tags._Runtime(self.app_context).configured())
def test_guide_enabled_private(self): with actions.OverriddenEnvironment(self.GUIDE_ENABLED_PRIVATE): for name in ['Alpha', 'Bravo', 'Charlie', 'Delta']: actions.logout() self.assert_guide_not_accesssible(name) actions.login('*****@*****.**') self.assert_guide_not_accesssible(name) if name == 'Bravo' or name == 'Charlie': self.register(name) self.assert_guide_not_accesssible(name) actions.login('*****@*****.**', is_admin=True) self.assert_guide_accesssible(name) # check course labels as admin sees them response = self.get('/modules/guides') self.assertEquals(200, response.status_int) self.assertIn( 'category="Power Searching with Google [Alpha] ' '(Private)', response.body) self.assertIn( 'category="Power Searching with Google [Bravo] ' '(Private)', response.body) self.assertIn( 'category="Power Searching with Google [Charlie] ' '(Private)', response.body) self.assertIn( 'category="Power Searching with Google [Delta] ' '(Private)', response.body)
def test_can_enroll_true_when_in_whitelist_and_course_available(self): complex_whitelist = ( ' [email protected], %s \n [email protected]' % self.email) with actions.OverriddenEnvironment(self.get_env( now_available=True, whitelist=complex_whitelist)): self.assertTrue( courses.Course.get(self.app_context).can_enroll_current_user())
def test_invitation_link_supressed_if_email_not_configured(self): email_env = {'course': {'invitation_email': {'enabled': True}}} with actions.OverriddenEnvironment(email_env): self.register() dom = self.parse_html_string(self.get(self.URL).body) invite_friends_row = self._find_row(dom, 'Invite Friends') td = invite_friends_row.find('td') self.assertEquals('Invitations not currently available', td.text)
def test_news_disabled_ui(self): with actions.OverriddenEnvironment({ news.NEWS_SETTINGS_SECTION: { news.IS_NEWS_ENABLED_SETTING: False, }}): response = self.get('course') soup = self.parse_html_string_to_soup(response.body) title = soup.find(id='gcb_news_titlebar_text') self.assertIsNone(title)
def test_invitation_link_shown(self): self.register() with actions.OverriddenEnvironment(self.EMAIL_ENV): dom = self.parse_html_string(self.get(self.URL).body) invite_friends_row = self._find_row(dom, 'Invite Friends') link = invite_friends_row.find('td/a') self.assertEquals( 'Click to send invitations to family and friends', link.text) self.assertEquals(InvitationHandlerTests.URL, link.attrib['href'])
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_course_slug_webserver_no_slug(self): self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.enabled(slug='')): self.assertRedirectPage('/', '/test/') self.assertRedirectPage('/test', '/test/') self.assertPage('/test/', 'Web Server') self.assertPage('/test/course', 'Power Searching') self.assertPage('/test/index.html', 'Web Server') self.assertNoPage('/test/badPage.html')
def test_get_returns_500_when_child_courses_malformed(self): self.assert_user_not_enrolled_in_any_course() with actions.OverriddenEnvironment(self.get_env('bad')): response = self.testapp.get( '/parent/modules/embed/v1/resource/example/1', expect_errors=True) self.assert_child_course_namespaces_malformed(response) self.assert_user_not_enrolled_in_any_course()
def test_no_course_no_webserver(self): actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.disabled()): self.assertRedirectPage('/', '/admin/welcome') self.assertNoPage('/test') self.assertNoPage('/test/course') self.assertNoPage('/test/anything-here/anything.html') self.assertNoPage('/foo/index.html') self.assertNoPage('/foo/') self.assertNoPage('/foo')
def test_course_no_slug_webserver_no_slug(self): self._init_course('') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.enabled(slug='')): self.assertPage('/', 'Web Server') self.assertPage('/course', 'Power Searching') self.assertNoPage('/anything-here/anything.html') self.assertPage('/index.html', 'Web Server') self.assertNoPage('/foo/index.html') self.assertNoPage('/foo/') self.assertNoPage('/foo')
def test_course_no_webserver(self): self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.disabled()): self.assertRedirectPage('/', '/test/course?use_last_location=true') self.assertPage('/test', 'Searching') self.assertPage('/test/', 'Searching') self.assertPage('/test/course', 'Searching') self.assertNoPage('/test/foo/index.html') self.assertNoPage('/test/foo/') self.assertNoPage('/test/anything-here/anything.html')
def test_markdown_alternative_names(self): # when an author creates markdown document foo.md and wants to add # a link to a document bar.md he may specify either bar.html or # bar.md as link target; here we tests that markdown.html is # accessible; it does not really exist in the filesystem; a system # will pretend it exists when markdown is enabled and that it does # not exist when markdown is disabled self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.enabled(md_enabled=True)): response = self.get('/test/foo/markdown.html') self.assertIn('<h1>A First Level Header</h1>', response.body) self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body) self.assertNoPage('/test/foo/main.html') with actions.OverriddenEnvironment(self.enabled(md_enabled=False)): self.assertNoPage('/test/foo/markdown.html') self.assertNoPage('/test/foo/main.html')
def test_html_with_and_without_jinja(self): self._init_course('test') actions.login('*****@*****.**', is_admin=True) with actions.OverriddenEnvironment(self.enabled(jinja_enabled=False)): response = self.get('/test/foo/index.html') self.assertIn('{{ course_info.course.title }}', response.body) self.assertNotIn('Power Searching with Google', response.body) response = self.get('/test/foo/main.css') self.assertIn('{{ course_info.course.title }}', response.body) with actions.OverriddenEnvironment(self.enabled(jinja_enabled=True)): response = self.get('/test/foo/index.html') self.assertNotIn('{{ course_info.course.title }}', response.body) self.assertIn('Power Searching with Google', response.body) self.assertIn('<script>gcbTagYoutubeEnqueueVideo("1ppwmxidyIE", ', response.body) response = self.get('/test/foo/main.css') self.assertIn('{{ course_info.course.title }}', response.body) response = self.get('/test/foo/jinja.html') self.assertNotIn('gcb_webserv_metadata', response.body) self.assertIn('<li><b>is_super_admin</b>: True</li>', response.body) self.assertIn('Pre-course assessment', response.body) self.assertIn('*****@*****.**', response.body) actions.login('*****@*****.**') with actions.OverriddenEnvironment(self.enabled(jinja_enabled=True)): response = self.get('/test/foo/jinja.html') self.assertNotIn('gcb_webserv_metadata', response.body) self.assertNotIn('<li><b>is_super_admin</b>: True</li>', response.body) self.assertNotIn('Pre-course assessment', response.body) self.assertNotIn('*****@*****.**', response.body) self.assertIn('can only be seen by the by admin', response.body)
def test_guide_disabled(self): with actions.OverriddenEnvironment(self.GUIDE_DISABLED): for name in ['Alpha', 'Bravo', 'Charlie', 'Delta']: actions.logout() self.assert_guide_not_accesssible(name) actions.login('*****@*****.**') self.assert_guide_not_accesssible(name) if name == 'Bravo' or name == 'Charlie': self.register(name) self.assert_guide_not_accesssible(name) actions.login('*****@*****.**', is_admin=True) self.assert_guide_not_accesssible(name)
def test_invitation_page_content(self): self.register() with actions.OverriddenEnvironment(self.EMAIL_ENV): response = self.get(self.URL) self.assertEquals(200, response.status_code) dom = self.parse_html_string(response.body) # A sample email is displayed self.assertIn( 'Email from A. Student', ''.join(dom.find('.//div[@class="subject-line"]').itertext())) self.assertIn( 'From A. Student. Unsubscribe: ' 'http://localhost/invitation_course/modules/unsubscribe', dom.find('.//div[@class="email-body"]').text)
def setUp(self): super(ProgressPercent, self).setUp() context = actions.simple_add_course(COURSE_NAME, ADMIN_EMAIL, COURSE_TITLE) self.course = courses.Course(None, context) self.unit = self.course.add_unit() self.unit.title = 'No Lessons' self.unit.availability = courses.AVAILABILITY_AVAILABLE self.lesson_one = self.course.add_lesson(self.unit) self.lesson_one.title = 'Lesson One' self.lesson_one.objectives = 'body of lesson' self.lesson_one.availability = courses.AVAILABILITY_AVAILABLE self.lesson_two = self.course.add_lesson(self.unit) self.lesson_two.title = 'Lesson Two' self.lesson_two.objectives = 'body of lesson' self.lesson_two.availability = courses.AVAILABILITY_AVAILABLE self.lesson_three = self.course.add_lesson(self.unit) self.lesson_three.title = 'Lesson Three' self.lesson_three.objectives = 'body of lesson' self.lesson_three.availability = courses.AVAILABILITY_AVAILABLE self.assessment_one = self.course.add_assessment() self.assessment_one.title = 'Assessment One' self.assessment_one.html_content = 'assessment one content' self.assessment_one.availability = courses.AVAILABILITY_AVAILABLE self.assessment_two = self.course.add_assessment() self.assessment_two.title = 'Assessment Two' self.assessment_two.html_content = 'assessment two content' self.assessment_two.availability = courses.AVAILABILITY_AVAILABLE self.course.save() actions.login(STUDENT_EMAIL) actions.register(self, STUDENT_EMAIL, COURSE_NAME) self.overridden_environment = actions.OverriddenEnvironment( {'course': { analytics.CAN_RECORD_STUDENT_EVENTS: 'true' }}) self.overridden_environment.__enter__() self.tracker = self.course.get_progress_tracker() with Namespace(NAMESPACE): self.student = models.Student.get_by_user(users.get_current_user())
def test_announcement_translation_caching(self): LOCALE = 'de' with actions.OverriddenConfig(models.CAN_USE_MEMCACHE.name, True): with actions.OverriddenEnvironment({ 'i18n': { 'course:locale': 'en_US', 'extra_locales': [{ 'locale': LOCALE, 'availability': 'true' }] } }): key = self._add_announcement() data = { 'key': key, 'date': utc.to_text(seconds=0), 'html': 'Unsafe for operation', 'title': 'Attention', 'is_draft': False, } self._put_announcement(data) self._put_translation(data, LOCALE, 'Achtung', 'Gefahrlich!') actions.login('*****@*****.**') actions.register(self, 'John Doe') self._set_prefs_locale(None) self._verify_announcements([data['title']], [data['html']]) self._set_prefs_locale(LOCALE) self._verify_announcements(['Achtung'], ['Gefahrlich!']) # Verify that we have data added to the cache. cached = models.MemcacheManager.get( announcements.AnnouncementEntity._cache_key(LOCALE)) self.assertIsNotNone(cached) # Modify the translated version. actions.login(self.ADMIN_EMAIL) self._put_translation(data, LOCALE, 'Foo', 'Bar') # Verify that the cache has been purged cached = models.MemcacheManager.get( announcements.AnnouncementEntity._cache_key(LOCALE)) self.assertIsNone(cached) # And that the changed translations show up on the page. actions.login('*****@*****.**') self._verify_announcements(['Foo'], ['Bar'])
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_invitation_panel_available_only_for_registered_student(self): with actions.OverriddenEnvironment(self.EMAIL_ENV): response = self.get(self.URL) self.assertEquals(302, response.status_code) self.assertEquals('http://localhost/invitation_course/course', response.headers['Location']) actions.login(self.STUDENT_EMAIL, is_admin=False) response = self.get(self.URL) self.assertEquals(302, response.status_code) self.assertEquals('http://localhost/invitation_course/course', response.headers['Location']) actions.register(self, self.STUDENT_NAME) response = self.get(self.URL) self.assertEquals(200, response.status_code)
def test_guide_shows_all_unit_lessons(self): with actions.OverriddenEnvironment(self.GUIDE_ENABLED_PRIVATE): actions.login('*****@*****.**', is_admin=True) # check guides page response = self.get('/modules/guides') self.assertIn('<gcb-guide-container>', response.body) self.assertIn('category="Power Searching with Google [Alpha]', response.body) self.assertIn('<gcb-guide-card', response.body) self.assertIn( # note that we intentionally don't show "Unit 1 - " 'label="Introduction"', response.body) # check unit and lesson pages app_ctx = sites.get_all_courses()[0] course = courses.Course(None, app_context=app_ctx) for unit in course.get_units(): if unit.type != verify.UNIT_TYPE_UNIT: continue response = self.get('/Alpha/guide?unit_id=%s' % unit.unit_id) # check unit details self.assertIn(unit.title, response.body.decode('utf-8')) self.assertIn('unit_id="%s"' % unit.unit_id, response.body.decode('utf-8')) # check polymer components self.assertIn('<gcb-step-container', response.body) self.assertIn('<gcb-step-container-data', response.body) self.assertIn('<gcb-step-card', response.body) self.assertIn('<gcb-step-card-data', response.body) # check all lesson titles for lesson in course.get_lessons(unit.unit_id): self.assertIn('lesson_id="%s"' % lesson.lesson_id, response.body.decode('utf-8')) self.assertIn(lesson.title, response.body.decode('utf-8')) # check for specific lesson content and custom tags self.assertIn('Check Answer', response.body) self.assertIn('<script>gcbTagYoutubeEnqueueVideo("', response.body) self.assertIn( '<script src="/modules/' 'assessment_tags/resources/grading.js">', response.body)
def test_change_base_announcment_updates_i18n_progress(self): LOCALE = 'de' with actions.OverriddenConfig(models.CAN_USE_MEMCACHE.name, True): with actions.OverriddenEnvironment({ 'course': { 'locale': 'en_US', }, 'extra_locales': [{ 'locale': LOCALE, 'availability': 'true' }] }): key = self._add_announcement() data = { 'key': key, 'date': utc.to_text(seconds=0), 'html': 'Unsafe for operation', 'title': 'Attention', 'is_draft': False, } self._put_announcement(data) self._put_translation(data, LOCALE, 'Achtung', 'Gefahrlich!') # Verify that having saved the translation, we are in progress # state DONE. resource_key = str( resource.Key( announcements.ResourceHandlerAnnouncement.TYPE, db.Key(encoded=data['key']).id())) progress = i18n_dashboard.I18nProgressDAO.load(resource_key) self.assertEquals(progress.get_progress(LOCALE), i18n_dashboard.I18nProgressDTO.DONE) # Modify the announcement in the base language. data['title'] = 'Informational' data['html'] = 'Now safe for operation again' self._put_announcement(data) self.execute_all_deferred_tasks() # Verify that saving the base version of the announcement # moves the progress state back. progress = i18n_dashboard.I18nProgressDAO.load(resource_key) self.assertEquals(progress.get_progress(LOCALE), i18n_dashboard.I18nProgressDTO.IN_PROGRESS)
def test_markup_in_instructor_details(self): with actions.OverriddenEnvironment({ 'course': { 'instructor_details': '<gcb-markdown instanceid="j7UKhedk1arY">\n' 'foo\n' '# bar\n' '### baz\n' '</gcb-markdown>' } }): response = self.get_response( '{course (id: "%s") { instructorDetails } }' % self.course_id) self.assertEquals( response['data']['course']['instructorDetails'], '<div><link href="/modules/core_tags/_static/css/markdown.css" ' 'rel="stylesheet"/></div><div><div class="gcb-markdown">' '<p>foo</p>\n<h1>bar</h1>\n<h3>baz</h3></div></div><div></div>' )
def test_invitation_panel_unavailable_when_email_is_not_fully_set_up(self): self.register() for sender_email in ['', '*****@*****.**']: for subject_template in ['', 'the subject']: for body_template in ['', 'the body']: email_env = { 'course': { 'invitation_email': { 'sender_email': sender_email, 'subject_template': subject_template, 'body_template': body_template}}} with actions.OverriddenEnvironment(email_env): response = self.get(self.URL) if sender_email and subject_template and body_template: self.assertEquals(200, response.status_code) else: self.assertEquals(302, response.status_code) self.assertEquals( 'http://localhost/invitation_course/course', response.headers['Location'])