class GetAudienceTests(TestCase): def setUp(self): self.factory = RequestFactory() def test_setting_missing(self): # If BROWSERID_AUDIENCES isn't defined, raise # ImproperlyConfigured. request = self.factory.get('/') # Simulate missing attribute with a mock property that raises # AttributeError. with patch('django_browserid.base.settings') as settings: mock_browserid_audiences = PropertyMock(side_effect=AttributeError) type(settings).BROWSERID_AUDIENCES = mock_browserid_audiences with self.assertRaises(ImproperlyConfigured): base.get_audience(request) def test_same_origin_found(self): # If an audience is found in BROWSERID_AUDIENCES with the same # origin as the request URI, return it. request = self.factory.get('http://testserver') audiences = ['https://example.com', 'http://testserver'] with self.settings(BROWSERID_AUDIENCES=audiences): eq_(base.get_audience(request), 'http://testserver') def test_no_audience(self): # If no matching audiences is found in BROWSERID_AUDIENCES, # raise ImproperlyConfigured. request = self.factory.get('http://testserver') with self.settings(BROWSERID_AUDIENCES=['https://example.com']): with self.assertRaises(ImproperlyConfigured): base.get_audience(request)
class InValidStockRSRTestCase(TestCase): """Testing request to stock RSR. invalid hosts : - "invalid_host" - "" """ def setUp(self): """Setup.""" self.factory = RequestFactory() self.req_not_found_host = self.factory.get('/', {}, HTTP_HOST='not-found.akvo.org') self.req_not_found_host2 = self.factory.get('/', {}, HTTP_HOST='not-found.test.akvo.org') self.req_invalid_host = self.factory.get('/', {}, HTTP_HOST='invalid_host') self.req_empty_host = self.factory.get('/', {}, HTTP_HOST='') def test_is_rsr_host(self): """Test request to normal RSR host.""" self.assertFalse(_is_rsr_host(self.req_not_found_host.get_host())) self.assertFalse(_is_rsr_host(self.req_not_found_host2.get_host())) with self.assertRaises(DisallowedHost): _is_rsr_host(self.req_invalid_host.get_host()) with self.assertRaises(DisallowedHost): _is_rsr_host(self.req_empty_host.get_host())
class GetNetTest(TestCase): def setUp(self): self.factory = RequestFactory() self.url = reverse('calendar:list') def test_valid_next(self): url = self.url + '?cal_next=1' req = self.factory.get(url) net = get_net(req) self.assertEqual(net, 1) def test_valid_prev(self): url = self.url + '?cal_prev=1' req = self.factory.get(url) net = get_net(req) self.assertEqual(net, -1) def test_invalid(self): url = self.url + '?cal_next=nann' req = self.factory.get(url) net = get_net(req) self.assertEqual(net, 0) def test_valid_next_and_prev(self): url = self.url + '?cal_next=1&cal_prev=2' req = self.factory.get(url) net = get_net(req) self.assertEqual(net, -1)
class HelperTester(django.test.TestCase): def setUp(self): # Every test needs access to the request factory. self.factory = RequestFactory() self.helper = helper.Helper() pass def tearDown(self): assert settings.CACHE_BACKEND == "locmem:///" [cache.delete(key) for key in cache._cache.keys()] def test_uniqueList(self): a = [1, 1, 2, 3, 4, 7, 7, 6, 6, 8] b = helper.uniqueList(a) expected = [1, 2, 3, 4, 7, 6, 8] for (i, j) in zip(b, expected): self.assertTrue(i == j) def test_jsonp(self): request = self.factory.get("/home") response = self.helper.jsonp(request, {"random_data": "random"}) self.assertTrue(response.content, '{"random_data": "random"}') request = self.factory.get("/home?callback=123") response = self.helper.jsonp(request, {"random_data": "random"}) self.assertTrue(response.content, '123({"random_data": "random"});')
class CsrfTokenTests(TestCase): def setUp(self): self.factory = RequestFactory() self.view = views.CsrfToken() def test_lazy_token_called(self): """ If the csrf_token variable in the RequestContext is a lazy callable, make sure it is called during the view. """ global _lazy_csrf_token_called _lazy_csrf_token_called = False # I'd love to use a Mock here instead, but lazy doesn't behave # well with Mocks for some reason. def _lazy_csrf_token(): global _lazy_csrf_token_called _lazy_csrf_token_called = True return 'asdf' csrf_token = lazy(_lazy_csrf_token, six.text_type)() request = self.factory.get('/browserid/csrf/') with patch('django_browserid.views.RequestContext') as RequestContext: RequestContext.return_value = {'csrf_token': csrf_token} response = self.view.get(request) eq_(response.status_code, 200) eq_(response.content, b'asdf') ok_(_lazy_csrf_token_called) def test_never_cache(self): request = self.factory.get('/browserid/csrf/') response = self.view.get(request) eq_(response['Cache-Control'], 'max-age=0')
class CsrfTokenTests(TestCase): def setUp(self): self.factory = RequestFactory() self.view = views.CsrfToken() def test_session_csrf(self): request = self.factory.get('/browserid/csrf/') request.csrf_token = 'asdf' response = self.view.get(request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, b'asdf') def test_django_csrf(self): request = self.factory.get('/browserid/csrf/') rotate_token(request) token = get_token(request) response = self.view.get(request) self.assertEqual(response.status_code, 200) self.assertEqual(response.content, six.b(token)) def test_never_cache(self): request = self.factory.get('/browserid/csrf/') response = self.view.get(request) self.assertTrue('max-age=0' in response['Cache-Control'])
class LoginViewTestCase(unittest.TestCase): def setUp(self): self.factory = RequestFactory() def test_get(self): request = self.factory.get(reverse("account_login")) request.user = AnonymousUser() response = LoginView.as_view()(request) self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, ["account/login.html"]) def test_get_disabled(self): request = self.factory.get(reverse("account_login")) request.user = AnonymousUser() response = LoginDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) def test_post_disabled(self): request = self.factory.post(reverse("account_login")) request.user = AnonymousUser() response = LoginDisabledView.as_view()(request) self.assertEqual(response.status_code, 403) def test_custom_redirect_field(self): request = self.factory.request() request.GET = {"next_page": "/profile/"} form = LoginUsernameForm({"username": "******", "password": "******"}) view = LoginRedirectView(request=request, redirect_field_name="next_page") self.assertEqual("/profile/", view.form_valid(form)["Location"])
class BaseClientTestCase(object): "Common client test functionality." oauth_client = None def setUp(self): super(BaseClientTestCase, self).setUp() self.consumer_key = self.get_random_string() self.consumer_secret = self.get_random_string() self.provider = self.create_provider( consumer_key=self.consumer_key, consumer_secret=self.consumer_secret) self.oauth = self.oauth_client(self.provider) self.factory = RequestFactory() def test_redirect_url(self, *args, **kwargs): "Redirect url is build from provider authorization_url." with patch.object(self.oauth, 'get_redirect_args') as args: args.return_value = {'foo': 'bar'} request = self.factory.get('/login/') url = self.oauth.get_redirect_url(request, callback='/callback/') scheme, netloc, path, params, query, fragment = urlparse(url) query = parse_qs(query) self.assertEqual('%s://%s%s' % (scheme, netloc, path), self.provider.authorization_url) self.assertEqual(query, {'foo': ['bar']}) def test_additional_redirect_args(self, *args, **kwargs): "Additional redirect arguments." with patch.object(self.oauth, 'get_redirect_args') as args: args.return_value = {'foo': 'bar'} request = self.factory.get('/login/') additional = {'scope': 'email'} url = self.oauth.get_redirect_url(request, callback='/callback/', parameters=additional) scheme, netloc, path, params, query, fragment = urlparse(url) query = parse_qs(query) self.assertEqual(query, {'foo': ['bar'], 'scope': ['email']})
class TestTourView(TestCase): def setUp(self): self.view = fx_views.TourView.as_view() self.rf = RequestFactory(HTTP_USER_AGENT='Firefox') @override_settings(DEV=True) def test_fx_old_tour_template(self, render_mock): """Should use old firstrun template""" req = self.rf.get('/en-US/firefox/tour/') self.view(req, version='29.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/australis/firstrun.html']) @override_settings(DEV=True) def test_fx_dev_browser_35_0_a2(self, render_mock): """Should use dev browser firstrun template""" req = self.rf.get('/en-US/firefox/tour/') self.view(req, version='35.0a2') template = render_mock.call_args[0][1] eq_(template, ['firefox/dev-firstrun.html']) @override_settings(DEV=True) def test_fx_firstrun_tour_36_0(self, render_mock): """Should use fx36 tour template for 36.0""" req = self.rf.get('/en-US/firefox/tour/') self.view(req, version='36.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/australis/fx36/tour.html'])
class GetPageNumberFromRequestTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_no_querystring_key(self): # Ensure the first page is returned if page info cannot be # retrieved from the querystring. request = self.factory.get('/') self.assertEqual(1, utils.get_page_number_from_request(request)) def test_default_querystring_key(self): # Ensure the default page label is used if ``querystring_key`` # is not provided. request = self.factory.get('?{0}=2'.format(PAGE_LABEL)) self.assertEqual(2, utils.get_page_number_from_request(request)) def test_default(self): # Ensure the default page number is returned if page info cannot be # retrieved from the querystring. request = self.factory.get('/') page_number = utils.get_page_number_from_request(request, default=3) self.assertEqual(3, page_number) def test_custom_querystring_key(self): # Ensure the page returned correctly reflects the ``querystring_key``. request = self.factory.get('?mypage=4'.format(PAGE_LABEL)) page_number = utils.get_page_number_from_request( request, querystring_key='mypage') self.assertEqual(4, page_number) def test_post_data(self): # The page number can also be present in POST data. request = self.factory.post('/', {PAGE_LABEL: 5}) self.assertEqual(5, utils.get_page_number_from_request(request))
class UtilModuleTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_get_credentials_no_cloud(self): request = self.factory.get('url') request.META['HTTP_AUTHORIZATION'] = 'Basic ' + base64.b64encode('user:pass') user, password, cloud = util.get_credentials(request) self.assertEqual(user, 'user') self.assertEqual(password, 'pass') self.assertEqual(cloud, settings.LIB_DIGI_DEVICECLOUD['DEFAULT_CLOUD_SERVER']) def test_get_credentials_with_cloud(self): request = self.factory.get('url') usercloud= settings.LIB_DIGI_DEVICECLOUD['USERNAME_CLOUD_DELIMETER'].join(['user', 'custom_cloud']) request.META['HTTP_AUTHORIZATION'] = 'Basic ' + base64.b64encode(':'.join([usercloud, 'pass'])) user, password, cloud = util.get_credentials(request) self.assertEqual(user, 'user') self.assertEqual(password, 'pass') self.assertEqual(cloud, 'custom_cloud') def test_key_search(self): d = {'a': {'deeply': {'nested': {'dict': {'key': 'value'}}}}} self.assertTrue(util.is_key_in_nested_dict(d, 'nested')) self.assertFalse(util.is_key_in_nested_dict(d, 'nope'))
class TestTourView(TestCase): def setUp(self): self.view = fx_views.TourView.as_view() self.rf = RequestFactory(HTTP_USER_AGENT='Firefox') @override_settings(DEV=False) def test_fx_australis_secure_redirect(self, render_mock): """Should redirect to https""" url = '/en-US/firefox/tour/' req = self.rf.get(url) with patch.object(req, 'is_secure', return_value=False): resp = self.view(req, fx_version='29.0a2') eq_(resp['location'], 'https://testserver' + url) @override_settings(DEV=True) def test_fx_australis_secure_redirect_not_dev(self, render_mock): """Should not redirect to https: in DEV mode.""" url = '/en-US/firefox/tour/' req = self.rf.get(url) with patch.object(req, 'is_secure', return_value=False): resp = self.view(req, fx_version='29.0a2') eq_(resp.status_code, 200) @override_settings(DEV=True) def test_fx_australis_secure_redirect_secure(self, render_mock): """Should not redirect to https: when already secure.""" url = '/en-US/firefox/tour/' req = self.rf.get(url) with patch.object(req, 'is_secure', return_value=True): resp = self.view(req, fx_version='29.0a2') eq_(resp.status_code, 200)
class GetQuerystringForPageTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_querystring(self): # Ensure the querystring is correctly generated from request. request = self.factory.get('/') querystring = utils.get_querystring_for_page(request, 2, 'mypage') self.assertEqual('?mypage=2', querystring) def test_default_page(self): # Ensure the querystring is empty for the default page. request = self.factory.get('/') querystring = utils.get_querystring_for_page( request, 3, 'mypage', default_number=3) self.assertEqual('', querystring) def test_composition(self): # Ensure existing querystring is correctly preserved. request = self.factory.get('/?mypage=1&foo=bar') querystring = utils.get_querystring_for_page(request, 4, 'mypage') self.assertIn('mypage=4', querystring) self.assertIn('foo=bar', querystring) def test_querystring_key(self): # The querystring key is deleted from the querystring if present. request = self.factory.get('/?querystring_key=mykey') querystring = utils.get_querystring_for_page(request, 5, 'mypage') self.assertEqual('?mypage=5', querystring)
def test_version_sidebar(self): request = RequestFactory() request.GET = {} request.APP = amo.FIREFOX request.get(reverse('search.search')) facets = { u'platforms': [{u'doc_count': 58, u'key': 1}], u'appversions': [{u'doc_count': 58, u'key': 5000000200100}], u'categories': [{u'doc_count': 55, u'key': 1}], u'tags': [], } versions = version_sidebar(request, {}, facets) assert versions[0].selected versions = version_sidebar(request, {'appver': '5.0'}, facets) assert versions[1].selected # We're not storing the version in the session anymore: no memories. versions = version_sidebar(request, {}, facets) assert versions[0].selected # We read the appver from the cleaned form data. request.GET['appver'] = '123.4' # No form data, fallback to default (first entry). versions = version_sidebar(request, {}, facets) assert versions[0].selected # Form data has the proper version, use it. versions = version_sidebar(request, {'appver': '5.0'}, facets) assert versions[1].selected # Form data has the proper version, which is new: add it. versions = version_sidebar(request, {'appver': '123.4'}, facets) assert versions[1].selected assert len(versions) == 3
class TestViews(TestCase): def setUp(self): self.rf = RequestFactory() def test_hacks_newsletter_frames_allow(self): """ Bedrock pages get the 'x-frame-options: DENY' header by default. The hacks newsletter page is framed, so needs to ALLOW. """ with self.activate('en-US'): resp = self.client.get(reverse('mozorg.hacks_newsletter')) ok_('x-frame-options' not in resp) @patch('bedrock.newsletter.views.l10n_utils.render') def test_updated_allows_good_tokens(self, mock_render): token = unicode(uuid.uuid4()) req = self.rf.get('/', {'token': token, 'unsub': 1}) updated(req) self.assertEqual(mock_render.call_args[0][2]['token'], token) @patch('bedrock.newsletter.views.l10n_utils.render') def test_updated_disallows_bad_tokens(self, mock_render): token = 'the-dude' req = self.rf.get('/', {'token': token, 'unsub': 1}) updated(req) eq_(mock_render.call_args[0][2]['token'], None) token = '\'>"><img src=x onerror=alert(1)>' req = self.rf.get('/', {'token': token, 'unsub': 1}) updated(req) eq_(mock_render.call_args[0][2]['token'], None)
def test_cached_view(self): calls = [0] @cached_view(timeout=100) def get_calls(request): calls[0] += 1 return calls[0] factory = RequestFactory() r1 = factory.get('/hi') r2 = factory.get('/hi') r2.META['REMOTE_ADDR'] = '10.10.10.10' r3 = factory.get('/bye') self.assertEqual(get_calls(r1), 1) # cache self.assertEqual(get_calls(r1), 1) # hit self.assertEqual(get_calls(r2), 1) # hit, since only url is considered self.assertEqual(get_calls(r3), 2) # miss get_calls.invalidate(r1) self.assertEqual(get_calls(r1), 3) # miss # Can pass uri to invalidate get_calls.invalidate(r1.build_absolute_uri()) self.assertEqual(get_calls(r1), 4) # miss
class SSLifyMiddlwareTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_perma_redirects_http_to_https(self): request = self.factory.get('/woot/') self.assertTrue(request.build_absolute_uri().startswith('http://')) middleware = SSLifyMiddleware() request = middleware.process_request(request) self.assertIsInstance(request, HttpResponsePermanentRedirect) self.assertTrue(request['Location'].startswith('https://')) self.assertEqual(443, urlsplit(request['Location']).port) def test_custom_ssl_port(self): custom_port = 8443 with self.settings(SSLIFY_PORT=custom_port): request = self.factory.get('/woot/') middleware = SSLifyMiddleware() request = middleware.process_request(request) self.assertEqual(custom_port, urlsplit(request['Location']).port) def test_disable_for_tests(self): with self.settings(SSLIFY_DISABLE=True): request = self.client.get('/woot/') self.assertEqual(404, request.status_code) def tearDown(self): del self.factory
class TestPlatformRedirector(TestCase): def setUp(self): self.rf = RequestFactory() def test_desktop_redirects(self): callback = platform_redirector('/red/', '/green/', '/blue/') url = callback(self.rf.get('/take/comfort/', HTTP_USER_AGENT='Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; ' 'rv:53.0) Gecko/20100101 Firefox/53.0')) self.assertEqual(url, '/red/') def test_android_redirects(self): callback = platform_redirector('/red/', '/green/', '/blue/') url = callback(self.rf.get('/take/comfort/', HTTP_USER_AGENT='Mozilla/5.0 (Android 6.0.1; Mobile; rv:51.0) ' 'Gecko/51.0 Firefox/51.0')) self.assertEqual(url, '/green/') def test_ios_redirects(self): callback = platform_redirector('/red/', '/green/', '/blue/') url = callback(self.rf.get('/take/comfort/', HTTP_USER_AGENT='Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3 like ' 'Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, ' 'like Gecko) Mobile/8F190')) self.assertEqual(url, '/blue/')
class HomeTests(TestCase): def setUp(self): self.factory = RequestFactory() def test_not_authenticated(self): """ If the current user isn't authenticated, render the home page. """ request = self.factory.get('/') request.user = Mock() request.user.is_authenticated.return_value = False with patch('affiliates.base.views.render') as render: eq_(views.home(request), render.return_value) render.assert_called_with(request, 'base/home.html') def test_authenticated(self): """ If the current user is authenticated, redirect to the dashboard. """ request = self.factory.get('/') request.user = Mock() request.user.is_authenticated.return_value = True response = views.home(request) self.assertRedirectsNoFollow(response, reverse('base.dashboard'))
def test_review_queue(self): tracker, commit1 = make_commit(self.widgy_site, vt_class=ReviewedVersionTracker) p = Permission.objects.get(codename='change_versioncommit') user = User.objects.create() user.user_permissions.add(p) user.save() request_factory = RequestFactory() tracker = refetch(tracker) self.assertFalse(tracker.get_published_node(request_factory.get('/'))) commit1.approve(user) tracker = refetch(tracker) self.assertEqual(tracker.get_published_node(request_factory.get('/')), commit1.root_node) commit2 = tracker.commit(publish_at=timezone.now()) tracker = refetch(tracker) self.assertEqual(tracker.get_published_node(request_factory.get('/')), commit1.root_node) commit2.approve(user) tracker = refetch(tracker) self.assertEqual(tracker.get_published_node(request_factory.get('/')), commit2.root_node)
class MailPreviewMessageViewTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_dispatch_unknown_mail(self): request = self.factory.get( reverse('mail_factory_preview_message', kwargs={'mail_name': 'unknown', 'lang': 'fr'})) view = views.MailPreviewMessageView() with self.assertRaises(Http404): view.dispatch(request, 'unknown', 'fr') def test_dispatch(self): request = self.factory.get( reverse('mail_factory_preview_message', kwargs={'mail_name': 'no_custom', 'lang': 'fr'})) view = views.MailPreviewMessageView() view.request = request view.dispatch(request, 'no_custom', 'fr') self.assertEqual(view.mail_name, 'no_custom') self.assertEqual(view.lang, 'fr') self.assertEqual(view.mail_class, factory._registry['no_custom']) def test_get_context_data(self): view = views.MailPreviewMessageView() view.lang = 'fr' view.mail_name = 'no_custom' view.mail_class = factory._registry['no_custom'] data = view.get_context_data() self.assertIn('mail_name', data) self.assertEqual(data['mail_name'], 'no_custom') self.assertIn('message', data)
def request_config(): factory = RequestFactory() # test defaults request = factory.get("/") table = (Fake("Table") .has_attr(prefixed_page_field="page", prefixed_per_page_field="per_page", prefixed_order_by_field="sort", order_by=NOTSET) .expects("paginate")) RequestConfig(request).configure(table) assert table.order_by is NOTSET # basic test request = factory.get("/?page=1&per_page=5&sort=abc") table = (Fake("Table") .has_attr(prefixed_page_field="page", prefixed_per_page_field="per_page", prefixed_order_by_field="sort") .expects("paginate").with_args(page=1, per_page=5) .expects("order_by").with_args("abc")) RequestConfig(request).configure(table) # Test with some defaults. request = factory.get("/?page=1&sort=abc") table = (Fake("Table") .has_attr(prefixed_page_field="page", prefixed_per_page_field="per_page", prefixed_order_by_field="sort") .expects("paginate").with_args(page=1, per_page=5) .expects("order_by").with_args("abc")) RequestConfig(request, paginate={"per_page": 5}).configure(table)
class Test500View(BaseTest): def setUp(self): super(Test500View, self).setUp() self.factory = RequestFactory() def test_default_server_error(self): try: raise ValueError('test') except ValueError: request = self.factory.get('/index/{0}/'.format(self.resource.id), follow=True) view = server_error(request) self.assertEqual(view.content, '<h1>Server Error (500)</h1>') def test_custom_server_error(self): try: raise TemplateSyntaxError('test') except TemplateSyntaxError: request = self.factory.get('/index/{0}/'.format(self.resource.id), follow=True) request.user = self.user thread_locals.resource = self.resource view = server_error(request) self.failUnless('TemplateSyntaxError' in view.content)
class TrackMiddlewareTestCase(TestCase): def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() def test_normal_request(self, mock_server_track): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(mock_server_track.called) def test_default_filters_do_not_render_view(self, mock_server_track): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(mock_server_track.called) mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self, mock_server_track): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self, mock_server_track): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(mock_server_track.called) mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(mock_server_track.called)
class SiteMappingTests(TestCase, TestUtils): def setUp(self): self.factory = RequestFactory() def test_get_site_by_request(self): dummy_request = self.factory.get('/') dummy_request.META['HTTP_REFERER'] = 'http://dev.beamremit.com/' site = get_site_by_request(dummy_request) self.assertIsNotNone(site) self.assertEqual(site.id, 0) self.assertEqual(site.domain, 'dev.beamremit.com') dummy_request = self.factory.get('/') dummy_request.META['HTTP_REFERER'] = 'http://dev.bitcoinagainstebola.org/' site = get_site_by_request(dummy_request) self.assertIsNotNone(site) self.assertEqual(site.id, 1) self.assertEqual(site.domain, 'dev.bitcoinagainstebola.org') dummy_request = self.factory.get('/') dummy_request.META['HTTP_REFERER'] = 'http://dev.bitcoinagainstebola.org/#!/' site = get_site_by_request(dummy_request) self.assertIsNotNone(site) self.assertEqual(site.id, 1) self.assertEqual(site.domain, 'dev.bitcoinagainstebola.org') def test_get_site_by_request_fail(self): dummy_request = self.factory.get('/') dummy_request.META['HTTP_REFERER'] = 'foo' dummy_request.DATA = {'hello': 'error'} site = get_site_by_request(dummy_request) self.assertIsNotNone(site) self.assertEqual(site.id, 0)
class MiddlewareTests(TestCase): def setUp(self): self.factory = RequestFactory() self.middleware = SubdomainMiddleware() self.url = '/' self.old_cache_get = cache.get def tearDown(self): cache.get = self.old_cache_get @override_settings(PRODUCTION_DOMAIN='readthedocs.org') def test_no_cname_creation(self): self.assertEqual(Domain.objects.count(), 0) self.project = get(Project, slug='my_slug') cache.get = lambda x: 'my_slug' request = self.factory.get(self.url, HTTP_HOST='my.valid.hostname') self.middleware.process_request(request) self.assertEqual(Domain.objects.count(), 0) @override_settings(PRODUCTION_DOMAIN='readthedocs.org') def test_no_readthedocs_domain(self): self.assertEqual(Domain.objects.count(), 0) self.project = get(Project, slug='pip') cache.get = lambda x: 'my_slug' request = self.factory.get(self.url, HTTP_HOST='pip.readthedocs.org') self.middleware.process_request(request) self.assertEqual(Domain.objects.count(), 0)
class TemplateTagTestCase(TestCase): def setUp(self): self.HTTP_HOST = CUSTOM_HTTP_HOST self.factory = RequestFactory(HTTP_HOST=self.HTTP_HOST) def test_short_url(self): """ the short_url templatetag works with auto-generated links """ link = Link.objects.create(url='http://www.python.org/') request = self.factory.get(reverse('index')) out = Template( "{% load shortener_helpers %}" "{% short_url link %}" ).render(RequestContext(request, {'link': link})) self.assertEqual( out, 'http://%s/%s' % (self.HTTP_HOST, link.to_base62())) def test_short_url_with_custom(self): """ the short_url templatetag works with custom links """ custom = 'python' link = Link.objects.create( url='http://www.python.org/', id=base62.to_decimal(custom)) request = self.factory.get(reverse('index')) out = Template( "{% load shortener_helpers %}" "{% short_url link %}" ).render(RequestContext(request, {'link': link})) self.assertEqual( out, 'http://%s/%s' % (self.HTTP_HOST, link.to_base62()))
class TemplateFilterChoiceTestCase(TestCase): regular_url = "/simple/?param=1" pjax_url = "/simple/?param=1&_pjax=true" def setUp(self): self.rf = RequestFactory() def build_regular_request(self): return self.rf.get(self.regular_url) def build_pjax_request(self): return self.rf.get(self.pjax_url, HTTP_X_PJAX=True) def test_template_choice_filter_with_request(self): from easy_pjax.templatetags.pjax_tags import pjax assert pjax("base.html", self.build_pjax_request()) == "pjax_base.html" assert pjax("base.html", self.build_regular_request()) == "base.html" def test_template_choice_filter_with_template_params(self): from easy_pjax.templatetags.pjax_tags import pjax assert pjax("base.html,other_pjax.html", self.build_pjax_request()) == "other_pjax.html" assert pjax("base.html", self.build_regular_request()) == "base.html" def test_template_choice_filter_with_flag(self): from easy_pjax.templatetags.pjax_tags import pjax assert pjax("base.html", True) == "pjax_base.html" assert pjax("base.html", False) == "base.html"
class TestHome(TestCase): def setUp(self): self.view = views.HomeTestView.as_view() self.rf = RequestFactory() @override_settings(MOBILIZER_LOCALE_LINK={'es-ES': 'El Dudarino', 'de': 'Herr Dude'}) def test_gets_right_mobilizer_url(self, resp_mock): """Home page should get correct mobilizer link for locale.""" req = self.rf.get('/') req.locale = 'de' self.view(req) ctx = resp_mock.call_args[0][2] self.assertEqual(ctx['mobilizer_link'], 'Herr Dude') @override_settings(MOBILIZER_LOCALE_LINK={'en-US': 'His Dudeness', 'de': 'Herr Dude'}) def test_gets_default_mobilizer_url(self, resp_mock): """Home page should get default mobilizer link for other locale.""" req = self.rf.get('/') req.locale = 'xx' # does not exist self.view(req) ctx = resp_mock.call_args[0][2] self.assertEqual(ctx['mobilizer_link'], 'His Dudeness') def test_can_post(self, resp_mock): """Home page must accept post for newsletter signup.""" req = self.rf.post('/') self.view(req) # would return 405 before calling render otherwise resp_mock.assert_called_once_with(req, ['mozorg/home.html'], ANY)
class TestContributeSignupSwitcher(TestCase): def setUp(self): self.rf = RequestFactory() patcher = patch('bedrock.mozorg.views.lang_file_has_tag') self.lang_file_has_tag = patcher.start() self.addCleanup(patcher.stop) patcher = patch('bedrock.mozorg.views.ContributeSignup') self.ContributeSignup = patcher.start() self.addCleanup(patcher.stop) patcher = patch('bedrock.mozorg.views.ContributeSignupOldForm') self.ContributeSignupOldForm = patcher.start() self.addCleanup(patcher.stop) def test_uses_new_view(self): """Uses new view when lang file has the tag.""" req = self.rf.get('/') self.lang_file_has_tag.return_value = True views.contribute_signup(req) self.ContributeSignup.as_view.return_value.assert_called_with(req) self.assertFalse(self.ContributeSignupOldForm.as_view.return_value.called) def test_uses_old_view(self): """Uses old view when lang file does not have the tag.""" req = self.rf.get('/') self.lang_file_has_tag.return_value = False views.contribute_signup(req) self.ContributeSignupOldForm.as_view.return_value.assert_called_with(req) self.assertFalse(self.ContributeSignup.as_view.return_value.called)
class TestWhatsNew(TestCase): def setUp(self): self.view = fx_views.WhatsnewView.as_view() self.rf = RequestFactory(HTTP_USER_AGENT='Firefox') @override_settings(DEV=True) def test_fx_dev_browser_35_0_a2_whatsnew(self, render_mock): """Should show dev browser whatsnew template""" req = self.rf.get('/en-US/firefox/whatsnew/') self.view(req, version='35.0a2') template = render_mock.call_args[0][1] eq_(template, ['firefox/dev-whatsnew.html']) @override_settings(DEV=True) def test_rv_prefix(self, render_mock): """Prefixed oldversion shouldn't impact version sniffing.""" req = self.rf.get('/en-US/firefox/whatsnew/?oldversion=rv:10.0') self.view(req, version='54.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.html']) @override_settings(DEV=True) def test_fx_default_whatsnew(self, render_mock): """Should use standard template for 54.0""" req = self.rf.get('/en-US/firefox/whatsnew/') self.view(req, version='54.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.html']) # begin 57.0 whatsnew tests @override_settings(DEV=True) def test_fx_57_0_EN(self, render_mock): """Should use English CEO letter template for 57.0 in English""" req = self.rf.get('/firefox/whatsnew/') req.locale = 'en-US' self.view(req, version='57.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/fx57/whatsnew-57.en-US.html']) @override_settings(DEV=True) def test_fx_57_0_locale(self, render_mock): """Should use regular template for 57.0 in locales without the letter""" req = self.rf.get('/firefox/whatsnew/') req.locale = 'nl' self.view(req, version='57.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/fx57/whatsnew-57.html']) @override_settings(DEV=True) def test_fx_dev_57_0(self, render_mock): """Should use developer whatsnew page for 57.0 dev edition""" req = self.rf.get('/firefox/whatsnew/') req.locale = 'en-US' self.view(req, version='57.0a2') template = render_mock.call_args[0][1] eq_(template, ['firefox/developer/whatsnew.html']) @override_settings(DEV=True) def test_fx_57_0_old_version(self, render_mock): """Should use Quantum template when updating from older major version""" req = self.rf.get('/en-US/firefox/whatsnew/?oldversion=56.0') self.view(req, version='57.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/fx57/whatsnew-57.en-US.html']) @override_settings(DEV=True) def test_fx_57_0_old_minor_version(self, render_mock): """Should use mobile promo template when updating from older minor version""" req = self.rf.get('/en-US/firefox/whatsnew/?oldversion=57.0.1') self.view(req, version='57.0.2') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.html']) # end 57.0 whatsnew tests # begin 59.0 whatsnew tests @override_settings(DEV=True) def test_fx_59_0(self, render_mock): """Should use Firefox Accounts template for 59.0""" req = self.rf.get('/firefox/whatsnew/') req.locale = 'en-US' self.view(req, version='59.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/whatsnew-fxa.html']) @override_settings(DEV=True) def test_fx_59_0_old_major_version(self, render_mock): """Should use Firefox Accounts template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=58.0') req.locale = 'en-US' self.view(req, version='59.0.1') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/whatsnew-fxa.html']) @override_settings(DEV=True) def test_fx_59_0_old_minor_version(self, render_mock): """Should use regular whatsnew template when updating from older minor version""" req = self.rf.get('/firefox/whatsnew/?oldversion=59.0') req.locale = 'en-US' self.view(req, version='59.0.1') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.html']) @override_settings(DEV=True) def test_fx_59_0_id_locale_template(self, render_mock): """Should use id locale specific template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=58.0') req.locale = 'id' self.view(req, version='59.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.id.html']) @override_settings(DEV=True) def test_fx_59_0_zh_TW_locale_template(self, render_mock): """Should use zh-TW locale specific template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=58.0') req.locale = 'zh-TW' self.view(req, version='59.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.zh-TW.html']) # end 59.0 whatsnew tests # begin 60.0 whatsnew tests @override_settings(DEV=True) def test_fx_60_0(self, render_mock): """Should use FxA/Fx mobile/Focus template for 60.0""" req = self.rf.get('/firefox/whatsnew/') req.locale = 'en-US' self.view(req, version='60.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/whatsnew-fx60.html']) @override_settings(DEV=True) def test_fx_60_0_old_major_version(self, render_mock): """Should use FxA/Fx mobile/Focus template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=59.0') req.locale = 'en-US' self.view(req, version='60.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/whatsnew-fx60.html']) @override_settings(DEV=True) def test_fx_60_0_id_locale_template(self, render_mock): """Should use id locale specific template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=59.0') req.locale = 'id' self.view(req, version='60.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.id.html']) @override_settings(DEV=True) def test_fx_60_0_zh_TW_locale_template(self, render_mock): """Should use zh-TW locale specific template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=59.0') req.locale = 'zh-TW' self.view(req, version='60.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.zh-TW.html']) # end 60.0 whatsnew tests # begin 61.0 whatsnew tests @override_settings(DEV=True) def test_fx_61_0(self, render_mock): """Should use FxA/Fx mobile/Focus template for 61.0""" req = self.rf.get('/firefox/whatsnew/') req.locale = 'en-US' self.view(req, version='61.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/whatsnew-fx61.html']) @override_settings(DEV=True) def test_fx_61_0_old_major_version(self, render_mock): """Should use FxA/Fx mobile/Focus template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=60.0') req.locale = 'en-US' self.view(req, version='61.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/whatsnew-fx61.html']) @override_settings(DEV=True) def test_fx_61_0_id_locale_template(self, render_mock): """Should use id locale specific template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=60.0') req.locale = 'id' self.view(req, version='61.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.id.html']) @override_settings(DEV=True) def test_fx_61_0_zh_TW_locale_template(self, render_mock): """Should use zh-TW locale specific template when updating from older major version""" req = self.rf.get('/firefox/whatsnew/?oldversion=60.0') req.locale = 'zh-TW' self.view(req, version='61.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/whatsnew/index.zh-TW.html'])
class EditUserViews(TestCase): """view user and edit profile""" def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"): self.local_user = models.User.objects.create_user( "*****@*****.**", "*****@*****.**", "password", local=True, localname="mouse", ) self.rat = models.User.objects.create_user("*****@*****.**", "*****@*****.**", "password", local=True, localname="rat") self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work")) with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.delay"): models.ShelfBook.objects.create( book=self.book, user=self.local_user, shelf=self.local_user.shelf_set.first(), ) models.SiteSettings.objects.create() self.anonymous_user = AnonymousUser self.anonymous_user.is_authenticated = False def test_edit_user_page(self, _): """there are so many views, this just makes sure it LOADS""" view = views.EditUser.as_view() request = self.factory.get("") request.user = self.local_user result = view(request) self.assertIsInstance(result, TemplateResponse) result.render() self.assertEqual(result.status_code, 200) def test_edit_user(self, _): """use a form to update a user""" view = views.EditUser.as_view() form = forms.EditUserForm(instance=self.local_user) form.data["name"] = "New Name" form.data["email"] = "*****@*****.**" form.data["default_post_privacy"] = "public" form.data["preferred_timezone"] = "UTC" request = self.factory.post("", form.data) request.user = self.local_user self.assertIsNone(self.local_user.name) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) self.assertEqual(self.local_user.name, "New Name") self.assertEqual(self.local_user.email, "*****@*****.**") def test_edit_user_avatar(self, _): """use a form to update a user""" view = views.EditUser.as_view() form = forms.EditUserForm(instance=self.local_user) form.data["name"] = "New Name" form.data["email"] = "*****@*****.**" form.data["default_post_privacy"] = "public" form.data["preferred_timezone"] = "UTC" image_file = pathlib.Path(__file__).parent.joinpath( "../../static/images/no_cover.jpg") form.data["avatar"] = SimpleUploadedFile(image_file, open(image_file, "rb").read(), content_type="image/jpeg") request = self.factory.post("", form.data) request.user = self.local_user with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) self.assertEqual(self.local_user.name, "New Name") self.assertEqual(self.local_user.email, "*****@*****.**") self.assertIsNotNone(self.local_user.avatar) self.assertEqual(self.local_user.avatar.width, 120) self.assertEqual(self.local_user.avatar.height, 120) def test_crop_avatar(self, _): """reduce that image size""" image_file = pathlib.Path(__file__).parent.joinpath( "../../static/images/no_cover.jpg") image = Image.open(image_file) result = views.edit_user.crop_avatar(image) self.assertIsInstance(result, ContentFile) image_result = Image.open(result) self.assertEqual(image_result.size, (120, 120)) def test_delete_user_page(self, _): """there are so many views, this just makes sure it LOADS""" view = views.DeleteUser.as_view() request = self.factory.get("") request.user = self.local_user result = view(request) self.assertIsInstance(result, TemplateResponse) result.render() self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task") def test_delete_user(self, *_): """use a form to update a user""" view = views.DeleteUser.as_view() form = forms.DeleteUserForm() form.data["password"] = "******" request = self.factory.post("", form.data) request.user = self.local_user middleware = SessionMiddleware() middleware.process_request(request) request.session.save() self.assertIsNone(self.local_user.name) with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay" ) as delay_mock: view(request) self.assertEqual(delay_mock.call_count, 1) activity = json.loads(delay_mock.call_args[0][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["cc"][0], "https://www.w3.org/ns/activitystreams#Public") self.local_user.refresh_from_db() self.assertFalse(self.local_user.is_active) self.assertEqual(self.local_user.deactivation_reason, "self_deletion")
def setUp(self): factory = RequestFactory() request = factory.get(reverse('test_adminsite:index')) request.user = self.u1 self.ctx = site.each_context(request)
class DeckTest(TestCase): def setUp(self): self.request_factory = RequestFactory() def test_flow(self): request = self.request_factory.get("/", {}) response = new_deck(request) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) self.assertEqual(resp['shuffled'], False) deck_id = resp['deck_id'] request = self.request_factory.get("/", {}) response = draw(request, deck_id) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) ace = resp['cards'][0] self.assertEqual(ace['suit'], 'SPADES') self.assertEqual(ace['value'], 'ACE') self.assertEqual(ace['code'], 'AS') self.assertEqual(resp['remaining'], 51) request = self.request_factory.get("/", {}) response = shuffle(request, deck_id) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) self.assertEqual(resp['shuffled'], True) self.assertEqual(resp['remaining'], 52) request = self.request_factory.get("/", {"count": 10}) response = draw(request, deck_id) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) self.assertEqual(resp['remaining'], 42) self.assertEqual(len(resp['cards']), 10) cards = resp['cards'] card0 = cards[0] card1 = cards[1] request = self.request_factory.get( "/", {"cards": card0['code'] + ',' + card1['code']}) response = add_to_pile(request, deck_id, 'chase') self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) self.assertEqual(resp['remaining'], 42) piles = resp['piles'] self.assertEqual(piles['chase']['remaining'], 2) request = self.request_factory.get("/", {"cards": card0['code']}) response = draw_from_pile(request, deck_id, 'chase') self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) cards = resp['cards'] self.assertEqual(cards[0]['code'], card0['code']) piles = resp['piles'] self.assertEqual(piles['chase']['remaining'], 1) request = self.request_factory.get("/", {}) response = draw_from_pile(request, deck_id, 'chase') self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) cards = resp['cards'] self.assertEqual(cards[0]['code'], card1['code']) piles = resp['piles'] self.assertEqual(piles['chase']['remaining'], 0) def test_partial_deck(self): #test to make sure a new partial deck is returned when requested request = self.request_factory.get("/", {'cards': 'AC,AD,AH,AS'}) response = shuffle(request) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) self.assertEqual(resp['shuffled'], True) deck_id = resp['deck_id'] self.assertEqual(resp['remaining'], 4) #draw 4 cards and make sure they match the input data (and verify deck is empty) request = self.request_factory.get("/", {'count': 4}) response = draw(request, deck_id) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) one, two, three, four = False, False, False, False for card in resp['cards']: if card['code'] == 'AS': one = True elif card['code'] == 'AD': two = True elif card['code'] == 'AH': three = True elif card['code'] == 'AC': four = True self.assertEqual(resp['remaining'], 0) self.assertEqual(one, True) self.assertEqual(two, True) self.assertEqual(three, True) self.assertEqual(four, True) #verify that reshuffling a partial deck returns a partial deck request = self.request_factory.get("/", {'cards': 'KC,KD,KH,KS'}) response = shuffle(request) resp = json.loads(response.content.decode('utf-8')) deck_id = resp['deck_id'] reshuffleRequest = self.request_factory.get("/", {}) response = shuffle(reshuffleRequest, deck_id) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['remaining'], 4) def test_draw_new(self): request = self.request_factory.get("/", {'count': 5}) response = draw(request) self.assertEqual(response.status_code, 200) resp = json.loads(response.content.decode('utf-8')) self.assertEqual(resp['success'], True) self.assertEqual(resp['remaining'], 47)
class TestViews(ModuleStoreTestCase): """ Tests related to class_dashboard/views.py """ def setUp(self): super(TestViews, self).setUp() self.request_factory = RequestFactory() self.request = self.request_factory.get('') self.request.user = None self.simple_data = {'error': 'error'} @patch('class_dashboard.views.has_instructor_access_for_class') def test_all_problem_grade_distribution_has_access(self, has_access): """ Test returns proper value when have proper access """ has_access.return_value = True response = views.all_problem_grade_distribution( self.request, 'test/test/test') self.assertEqual(json.dumps(self.simple_data), response.content) @patch('class_dashboard.views.has_instructor_access_for_class') def test_all_problem_grade_distribution_no_access(self, has_access): """ Test for no access """ has_access.return_value = False response = views.all_problem_grade_distribution( self.request, 'test/test/test') self.assertEqual( "{\"error\": \"Access Denied: User does not have access to this course\'s data\"}", response.content) @patch('class_dashboard.views.has_instructor_access_for_class') def test_all_sequential_open_distribution_has_access(self, has_access): """ Test returns proper value when have proper access """ has_access.return_value = True response = views.all_sequential_open_distrib(self.request, 'test/test/test') self.assertEqual(json.dumps(self.simple_data), response.content) @patch('class_dashboard.views.has_instructor_access_for_class') def test_all_sequential_open_distribution_no_access(self, has_access): """ Test for no access """ has_access.return_value = False response = views.all_sequential_open_distrib(self.request, 'test/test/test') self.assertEqual( "{\"error\": \"Access Denied: User does not have access to this course\'s data\"}", response.content) @patch('class_dashboard.views.has_instructor_access_for_class') def test_section_problem_grade_distribution_has_access(self, has_access): """ Test returns proper value when have proper access """ has_access.return_value = True response = views.section_problem_grade_distrib(self.request, 'test/test/test', '1') self.assertEqual(json.dumps(self.simple_data), response.content) @patch('class_dashboard.views.has_instructor_access_for_class') def test_section_problem_grade_distribution_no_access(self, has_access): """ Test for no access """ has_access.return_value = False response = views.section_problem_grade_distrib(self.request, 'test/test/test', '1') self.assertEqual( "{\"error\": \"Access Denied: User does not have access to this course\'s data\"}", response.content) def test_sending_deprecated_id(self): course = CourseFactory.create() instructor = AdminFactory.create() self.request.user = instructor response = views.all_sequential_open_distrib(self.request, text_type(course.id)) self.assertEqual('[]', response.content) response = views.all_problem_grade_distribution( self.request, text_type(course.id)) self.assertEqual('[]', response.content) response = views.section_problem_grade_distrib(self.request, text_type(course.id), 'no section') self.assertEqual('{"error": "error"}', response.content)
def setUp(self): factory = RequestFactory() self.request = factory.get(self.url) self.ajax_request = factory.get(self.url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
class TestFirstRun(TestCase): def setUp(self): self.view = fx_views.FirstrunView.as_view() self.rf = RequestFactory() @override_settings(DEV=True) def test_fx_firstrun_40_0(self, render_mock): """Should use default firstrun template""" req = self.rf.get('/en-US/firefox/firstrun/') self.view(req, version='40.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/firstrun/index.html']) @override_settings(DEV=True) def test_fx_firstrun_56_0(self, render_mock): """Should use the default dev edition firstrun template""" req = self.rf.get('/en-US/firefox/firstrun/') self.view(req, version='56.0a2') template = render_mock.call_args[0][1] eq_(template, ['firefox/dev-firstrun.html']) @override_settings(DEV=True) def test_fxdev_firstrun_57_0(self, render_mock): """Should use 57 quantum dev edition firstrun template""" req = self.rf.get('/en-US/firefox/firstrun/') self.view(req, version='57.0a2') template = render_mock.call_args[0][1] eq_(template, ['firefox/developer/firstrun.html']) @override_settings(DEV=True) def test_fx_firstrun_57_0(self, render_mock): """Should use 57 quantum firstrun template""" req = self.rf.get('/en-US/firefox/firstrun/') self.view(req, version='57.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/firstrun/firstrun-quantum.html']) # facebook container funnelcake - bug 1450106 @override_settings(DEV=True) def test_fx_firstrun_fbcontainer(self, render_mock): """Should use facebook container template""" req = self.rf.get('/en-US/firefox/firstrun/?xv=facebook-container') self.view(req, version='59.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/firstrun/facebook-container.html']) @override_settings(DEV=True) def test_fx_firstrun_fbcontainer_non_enUS(self, render_mock): """Should use 57 quantum firstrun template for non en-US locales""" req = self.rf.get('/firefox/firstrun/?xv=facebook-container') req.locale = 'fr' self.view(req, version='59.0') template = render_mock.call_args[0][1] eq_(template, ['firefox/firstrun/firstrun-quantum.html']) # test redirect to /firefox/new/ for legacy /firstrun URLs - Bug 1343823 @override_settings(DEV=True) def test_fx_firstrun_legacy_redirect(self, render_mock): req = self.rf.get('/firefox/firstrun/') req.locale = 'en-US' resp = self.view(req, version='39.0') assert resp.status_code == 301 assert resp['location'].endswith('/firefox/new/') def test_fx_firstrun_dev_edition_legacy_redirect(self, render_mock): req = self.rf.get('/firefox/firstrun/') req.locale = 'en-US' resp = self.view(req, version='39.0a2') assert resp.status_code == 301 assert resp['location'].endswith('/firefox/new/')
def setUp(self): factory = RequestFactory() self.request = factory.get('/') self.metadata = metadata(self.request)
class TestFraudReport(TestCase): def setUp(self): self.factory = RequestFactory() with self.activate('en-US'): self.url = reverse('legal.fraud-report') self.data = { 'input_url': 'http://www.test.com', 'input_category': 'Charging for software', 'input_product': 'Firefox', 'input_specific_product': '', 'input_details': 'test details', 'input_attachment_desc': 'test attachment', 'input_email': '*****@*****.**', } def tearDown(self): mail.outbox = [] def test_view_post_valid_data(self): """ A valid POST should 302 redirect. """ request = self.factory.post(self.url, self.data) # make sure CSRF doesn't hold us up request._dont_enforce_csrf_checks = True response = legal_views.fraud_report(request) eq_(response.status_code, 302) eq_(response['Location'], '/en-US/about/legal/fraud-report/?submitted=True') def test_view_post_missing_data(self): """ POST with missing data should return 200 and contain form errors in the template. """ self.data.update(input_url='') # remove required url request = self.factory.post(self.url, self.data) # make sure CSRF doesn't hold us up request._dont_enforce_csrf_checks = True response = legal_views.fraud_report(request) eq_(response.status_code, 200) self.assertIn('Please enter a URL.', response.content) def test_view_post_honeypot(self): """ POST with honeypot text box filled should return 200 and contain general form error message. """ self.data['office_fax'] = 'spammer' request = self.factory.post(self.url, self.data) # make sure CSRF doesn't hold us up request._dont_enforce_csrf_checks = True response = legal_views.fraud_report(request) eq_(response.status_code, 200) self.assertIn('An error has occurred', response.content) def test_form_valid_data(self): """ Form should be valid. """ form = FraudReportForm(self.data) # make sure form is valid ok_(form.is_valid()) def test_form_invalid_data(self): """ With incorrect data (missing url), form should not be valid and should have url in the errors hash. """ self.data.update(input_url='') # remove required url form = FraudReportForm(self.data) # make sure form is invalid eq_(False, form.is_valid()) # make sure url errors are in form self.assertIn('input_url', form.errors) def test_form_honeypot(self): """ Form with honeypot text box filled should not be valid. """ self.data['office_fax'] = 'spammer!' form = FraudReportForm(self.data) eq_(False, form.is_valid()) def test_form_valid_attachement(self): """ Form should be valid when attachment under/at size limit. """ # attachment within size limit mock_attachment = Mock(_size=legal_forms.FRAUD_REPORT_FILE_SIZE_LIMIT) form = FraudReportForm(self.data, {'input_attachment': mock_attachment}) # make sure form is valid ok_(form.is_valid()) def test_form_invalid_attachement(self): """ Form should be invalid and contain attachment errors when attachment over size limit. """ # attachment within size limit mock_attachment = Mock( _size=(legal_forms.FRAUD_REPORT_FILE_SIZE_LIMIT + 1)) form = FraudReportForm(self.data, {'input_attachment': mock_attachment}) # make sure form is not valid eq_(False, form.is_valid()) # make sure attachment errors are in form self.assertIn('input_attachment', form.errors) @patch('bedrock.legal.views.jingo.render_to_string', return_value='jingo rendered') @patch('bedrock.legal.views.EmailMessage') def test_email(self, mock_email_message, mock_render_to_string): """ Make sure email is sent with expected values. """ mock_send = Mock() mock_email_message.return_value = Mock(send=mock_send) form = FraudReportForm(self.data) # submit form request = self.factory.get('/') submit_form(request, form) # make sure email was sent mock_send.assert_called_once_with() # make sure email values are correct mock_email_message.assert_called_once_with( legal_views.FRAUD_REPORT_EMAIL_SUBJECT, 'jingo rendered', legal_views.FRAUD_REPORT_EMAIL_FROM, legal_views.FRAUD_REPORT_EMAIL_TO) @patch('bedrock.legal.views.jingo.render_to_string', return_value='jingo rendered') @patch('bedrock.legal.views.EmailMessage') def test_email_with_attachement(self, mock_email_message, mock_render_to_string): """ Make sure email is sent with attachment. """ mock_attachment = Mock( content_type='text/plain', _size=(legal_forms.FRAUD_REPORT_FILE_SIZE_LIMIT)) # make sure name attribute is treated as string mock_attachment.name = 'img.jpg' form = FraudReportForm(self.data, {'input_attachment': mock_attachment}) # submit form request = self.factory.get('/') submit_form(request, form) # make sure attachment was attached mock_email_message.return_value.attach.assert_called_once_with( 'img.jpg', mock_attachment.read.return_value, 'text/plain') mock_attachment.read.assert_called_once_with() # make sure email was sent mock_email_message.return_value.send.assert_called_once_with() # make sure email values are correct mock_email_message.assert_called_once_with( legal_views.FRAUD_REPORT_EMAIL_SUBJECT, 'jingo rendered', legal_views.FRAUD_REPORT_EMAIL_FROM, legal_views.FRAUD_REPORT_EMAIL_TO) def test_emails_not_escaped(self): """ Strings in the fraud report form should not be HTML escaped when inserted into the email, which is just text. E.g. if they entered J'adore le ''Renard de feu'' the email should not contain J'adore le ''Renard de feu'' Tags are still stripped, though. """ STRING1 = u"<em>J'adore Citröns</em> & <Piñatas> so there" EXPECTED1 = u"J'adore Citröns & so there" STRING2 = u"<em>J'adore Piñatas</em> & <fromage> so here" EXPECTED2 = u"J'adore Piñatas & so here" STRING3 = u"J'adore <coffee>el café</coffee> también" EXPECTED3 = u"J'adore el café también" self.data.update(input_specific_product=STRING1, input_details=STRING2, input_attachment_desc=STRING3) request = self.factory.post(self.url, self.data) # make sure CSRF doesn't hold us up request._dont_enforce_csrf_checks = True legal_views.fraud_report(request) eq_(len(mail.outbox), 1) m = mail.outbox[0] self.assertIn(EXPECTED1, m.body) self.assertIn(EXPECTED2, m.body) self.assertIn(EXPECTED3, m.body)
class MailFormViewTest(TestCase): def setUp(self): self.factory = RequestFactory() def test_dispatch_unknown_mail(self): request = self.factory.get( reverse('mail_factory_form', kwargs={'mail_name': 'unknown'})) view = views.MailFormView() with self.assertRaises(Http404): view.dispatch(request, 'unknown') def test_dispatch(self): request = self.factory.post( reverse('mail_factory_form', kwargs={'mail_name': 'no_custom'}), { 'raw': 'foo', 'send': 'foo', 'email': 'email' }) view = views.MailFormView() view.request = request view.dispatch(request, 'no_custom') self.assertEqual(view.mail_name, 'no_custom') self.assertEqual(view.mail_class, factory._registry['no_custom']) self.assertTrue(view.raw) self.assertTrue(view.send) self.assertEqual(view.email, 'email') def test_get_form_kwargs(self): request = self.factory.get( reverse('mail_factory_form', kwargs={'mail_name': 'unknown'})) view = views.MailFormView() view.mail_name = 'no_custom' view.mail_class = factory._registry['no_custom'] view.request = request self.assertIn('mail_class', view.get_form_kwargs()) self.assertEqual(view.get_form_kwargs()['mail_class'].__name__, 'NoCustomMail') def test_get_form_class(self): view = views.MailFormView() view.mail_name = 'no_custom' self.assertEqual(view.get_form_class(), MailForm) def test_form_valid_raw(self): class MockForm(object): cleaned_data = {'title': 'title', 'content': 'content'} view = views.MailFormView() view.mail_name = 'no_custom' view.raw = True response = view.form_valid(MockForm()) self.assertEqual(response.status_code, 200) self.assertTrue(isinstance(response, HttpResponse)) self.assertTrue(response.content.startswith(b'<pre>')) def test_form_valid_send(self): class MockForm(object): cleaned_data = {'title': 'title', 'content': 'content'} request = self.factory.get( reverse('mail_factory_form', kwargs={'mail_name': 'unknown'})) view = views.MailFormView() view.request = request view.mail_name = 'no_custom' view.raw = False view.send = True view.email = '*****@*****.**' old_factory_mail = factory.mail # save current mail method # save current django.contrib.messages.success (imported in .views) old_messages_success = views.messages.success self.factory_send_called = False def mock_factory_mail(mail_name, to, context): self.factory_send_called = True # noqa factory.mail = mock_factory_mail # mock mail method views.messages.success = lambda x, y: True # mock messages.success response = view.form_valid(MockForm()) factory.mail = old_factory_mail # restore mail method views.messages.success = old_messages_success # restore messages self.assertTrue(self.factory_send_called) self.assertEqual(response.status_code, 302) self.assertEqual(response['location'], reverse('mail_factory_list')) def test_form_valid_html(self): class MockForm(object): cleaned_data = {'title': 'title', 'content': 'content'} def get_context_data(self): return self.cleaned_data view = views.MailFormView() view.mail_name = 'custom_form' # has templates for html alternative view.raw = False view.send = False response = view.form_valid(MockForm()) self.assertEqual(response.status_code, 200) self.assertTrue(isinstance(response, HttpResponse)) def test_get_context_data(self): request = self.factory.get( reverse('mail_factory_form', kwargs={'mail_name': 'unknown'})) view = views.MailFormView() view.mail_name = 'no_custom' view.mail_class = factory._registry['no_custom'] view.request = request # save the current old_get_mail_preview = views.MailPreviewMixin.get_mail_preview # mock views.MailPreviewMixin.get_mail_preview = lambda x, y, z: 'mocked' data = view.get_context_data() # restore after mock views.MailPreviewMixin.get_mail_preview = old_get_mail_preview self.assertIn('mail_name', data) self.assertEqual(data['mail_name'], 'no_custom') self.assertIn('preview_messages', data) self.assertDictEqual(data['preview_messages'], { 'fr': 'mocked', 'en': 'mocked' })
class TestRNAViews(TestCase): def setUp(self): self.factory = RequestFactory() self.request = self.factory.get('/') self.render_patch = patch( 'bedrock.releasenotes.views.l10n_utils.render') self.mock_render = self.render_patch.start() self.mock_render.return_value.has_header.return_value = False def tearDown(self): self.render_patch.stop() @property def last_ctx(self): """ Convenient way to access the context of the last rendered response. """ return self.mock_render.call_args[0][2] @patch('bedrock.releasenotes.views.get_object_or_404') @patch('bedrock.releasenotes.views.Q') def test_get_release_or_404(self, Q, get_object_or_404): eq_(views.get_release_or_404('version', 'product'), get_object_or_404.return_value) get_object_or_404.assert_called_with(Release, Q.return_value, version='version') Q.assert_called_once_with(product='product') @patch('bedrock.releasenotes.views.get_object_or_404') @patch('bedrock.releasenotes.views.Q') def test_get_release_or_404_esr(self, Q, get_object_or_404): eq_(views.get_release_or_404('24.5.0', 'Firefox'), get_object_or_404.return_value) Q.assert_any_call(product='Firefox') Q.assert_any_call(product='Firefox Extended Support Release') @patch('bedrock.releasenotes.views.get_object_or_404') @patch('bedrock.releasenotes.views.Q') def test_get_release_or_404_endswith_esr(self, Q, get_object_or_404): eq_(views.get_release_or_404('45.0esr', 'Firefox'), get_object_or_404.return_value) Q.assert_any_call(product='Firefox') Q.assert_any_call(product='Firefox Extended Support Release') @override_settings(DEV=False) @patch('bedrock.releasenotes.views.release_notes_template') @patch('bedrock.releasenotes.views.get_release_or_404') @patch('bedrock.releasenotes.views.equivalent_release_url') def test_release_notes(self, mock_equiv_rel_url, get_release_or_404, mock_release_notes_template): """ Should use release returned from get_release_or_404 with the correct params and pass the correct context variables and template to l10n_utils.render. """ mock_release = get_release_or_404.return_value mock_release.major_version.return_value = '34' mock_release.notes.return_value = ([Release(id=1), Release(id=2)], [Release(id=3), Release(id=4)]) views.release_notes(self.request, '27.0') get_release_or_404.assert_called_with('27.0', 'Firefox') mock_release.notes.assert_called_with(public_only=True) eq_(self.last_ctx['version'], '27.0') eq_(self.last_ctx['release'], mock_release) eq_(self.last_ctx['new_features'], [Release(id=1), Release(id=2)]) eq_(self.last_ctx['known_issues'], [Release(id=3), Release(id=4)]) eq_(self.mock_render.call_args[0][1], mock_release_notes_template.return_value) mock_equiv_rel_url.assert_called_with(mock_release) mock_release_notes_template.assert_called_with(mock_release.channel, 'Firefox', 34) @patch('bedrock.releasenotes.views.get_release_or_404') @patch('bedrock.releasenotes.views.releasenotes_url') def test_release_notes_beta_redirect(self, releasenotes_url, get_release_or_404): """ Should redirect to url for beta release """ get_release_or_404.side_effect = [Http404, 'mock release'] releasenotes_url.return_value = '/firefox/27.0beta/releasenotes/' response = views.release_notes(self.request, '27.0') eq_(response.status_code, 302) eq_(response['location'], '/firefox/27.0beta/releasenotes/') get_release_or_404.assert_called_with('27.0beta', 'Firefox') releasenotes_url.assert_called_with('mock release') @patch('bedrock.releasenotes.views.get_release_or_404') def test_system_requirements(self, get_release_or_404): """ Should use release returned from get_release_or_404, with a default channel of Release and default product of Firefox, and pass the version to l10n_utils.render """ views.system_requirements(self.request, '27.0.1') get_release_or_404.assert_called_with('27.0.1', 'Firefox') eq_(self.last_ctx['release'], get_release_or_404.return_value) eq_(self.last_ctx['version'], '27.0.1') eq_(self.mock_render.call_args[0][1], 'firefox/releases/system_requirements.html') def test_release_notes_template(self): """ Should return correct template name based on channel and product """ eq_(views.release_notes_template('Nightly', 'Firefox'), 'firefox/releases/nightly-notes.html') eq_(views.release_notes_template('Aurora', 'Firefox'), 'firefox/releases/aurora-notes.html') eq_(views.release_notes_template('Aurora', 'Firefox', 35), 'firefox/releases/dev-browser-notes.html') eq_(views.release_notes_template('Aurora', 'Firefox', 34), 'firefox/releases/aurora-notes.html') eq_(views.release_notes_template('Beta', 'Firefox'), 'firefox/releases/beta-notes.html') eq_(views.release_notes_template('Release', 'Firefox'), 'firefox/releases/release-notes.html') eq_(views.release_notes_template('ESR', 'Firefox'), 'firefox/releases/esr-notes.html') eq_(views.release_notes_template('Release', 'Thunderbird'), 'thunderbird/releases/release-notes.html') eq_(views.release_notes_template('Beta', 'Thunderbird'), 'thunderbird/releases/beta-notes.html') eq_(views.release_notes_template('', ''), 'firefox/releases/release-notes.html') @override_settings(DEV=False) @patch('bedrock.releasenotes.views.get_object_or_404') def test_non_public_release(self, get_object_or_404): """ Should raise 404 if not release.is_public and not settings.DEV """ get_object_or_404.return_value = Release(is_public=False) with self.assertRaises(Http404): views.get_release_or_404('42', 'Firefox') @patch('bedrock.releasenotes.views.releasenotes_url') def test_no_equivalent_release_url(self, mock_releasenotes_url): """ Should return None without calling releasenotes_url """ release = Mock() release.equivalent_android_release.return_value = None release.equivalent_desktop_release.return_value = None eq_(views.equivalent_release_url(release), None) eq_(mock_releasenotes_url.called, 0) @patch('bedrock.releasenotes.views.releasenotes_url') def test_android_equivalent_release_url(self, mock_releasenotes_url): """ Should return the url for the equivalent android release """ release = Mock() eq_(views.equivalent_release_url(release), mock_releasenotes_url.return_value) mock_releasenotes_url.assert_called_with( release.equivalent_android_release.return_value) @patch('bedrock.releasenotes.views.releasenotes_url') def test_desktop_equivalent_release_url(self, mock_releasenotes_url): """ Should return the url for the equivalent desktop release """ release = Mock() release.equivalent_android_release.return_value = None eq_(views.equivalent_release_url(release), mock_releasenotes_url.return_value) mock_releasenotes_url.assert_called_with( release.equivalent_desktop_release.return_value) @patch('bedrock.releasenotes.views.android_builds') def test_get_download_url_android(self, mock_android_builds): """ Shoud return the download link for the release.channel from android_builds """ mock_android_builds.return_value = [{'download_link': '/download'}] release = Mock(product='Firefox for Android') link = views.get_download_url(release) eq_(link, '/download') mock_android_builds.assert_called_with(release.channel) def test_get_download_url_thunderbird(self): release = Mock(product='Thunderbird') link = views.get_download_url(release) eq_(link, '/en-US/thunderbird/') def test_get_download_url_thunderbird_beta(self): release = Mock(product='Thunderbird', channel='Beta') link = views.get_download_url(release) eq_(link, '/en-US/thunderbird/channel/') def test_check_url(self): eq_( views.check_url('Firefox for Android', '45.0'), 'https://support.mozilla.org/kb/will-firefox-work-my-mobile-device' ) eq_(views.check_url('Firefox for Android', '46.0'), '/en-US/firefox/android/46.0/system-requirements/') eq_(views.check_url('Firefox for iOS', '1.4'), '/en-US/firefox/ios/1.4/system-requirements/') eq_(views.check_url('Firefox', '42.0'), '/en-US/firefox/42.0/system-requirements/')
class TestViews(TestCase): @override_settings(DEBUG=True) def test_login(self): """ Login and logout """ user = UserFactory() login_url = reverse('dashboard:login') response = self.client.post(login_url, data={ 'user': user.email, 'password': user.password }) self.assertEqual(response.status_code, 302) logout_url = reverse('dashboard:logout_start') response = self.client.get(logout_url) self.assertEqual(response.status_code, 302) def test_report(self): """ Though dashboard.views.report is a view for test_api, it should be tested because a change here it could affect another test module """ self.factory = RequestFactory() # site_id: 1 # event_source_all request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'event_source_all' }) response = views.reports(request) json_response = '[{"clicks": 1234, "shares": 3000, "label": "googlePlus"}, ' \ '{"clicks": 650, "shares": 12300, "label": "facebook"}, ' \ '{"clicks": 123, "shares": 1456, "label": "twitter"}, ' \ '{"clicks": 12, "shares": 102, "label": "pinterest"}, ' \ '{"clicks": 345, "shares": 2345, "label": "linkedin"}, ' \ '{"clicks": 5, "shares": 45, "label": "other"}]' self.assertEqual(response.content, json_response) # event_tool_all self.factory = RequestFactory() request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'event_tool_all' }) response = views.reports(request) json_response = '[{"clicks": 123, "shares": 2345, "label": "copy-paste"}, ' \ '{"clicks": 1234, "shares": 5432, "label": "sharing-buttons"}, ' \ '{"clicks": 12, "shares": 878, "label": "address-bar"}]' self.assertEqual(response.content, json_response) # event_month request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'event_month' }) response = views.reports(request) json_response = '[{"clicks": 234, "shares": 134, "month": 1401}, ' \ '{"clicks": 256, "shares": 178, "month": 1402}, ' \ '{"clicks": 345, "shares": 190, "month": 1403}, ' \ '{"clicks": 456, "shares": 185, "month": 1404}, ' \ '{"clicks": 256, "shares": 155, "month": 1405}, ' \ '{"clicks": 700, "shares": 256, "month": 1406}, ' \ '{"clicks": 987, "shares": 356, "month": 1407}, ' \ '{"clicks": 1056, "shares": 98, "month": 1408}, ' \ '{"clicks": 965, "shares": 15, "month": 1409}, ' \ '{"clicks": 865, "shares": 5, "month": 1410}, ' \ '{"clicks": 545, "shares": 1, "month": 1411}, ' \ '{"clicks": 325, "shares": 10, "month": 1412}, ' \ '{"clicks": 487, "shares": 0, "month": 1501}, ' \ '{"clicks": 65, "shares": 5, "month": 1502}]' self.assertEqual(response.content, json_response) # event_url_all request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'event_url_all' }) response = views.reports(request) json_response = '[{"url": "http://gravity4.com/contact/", ' \ '"clicks": 2343, "shares": 1343, "title": "Contact"}, ' \ '{"url": "http://gravity4.com/g4team/", "clicks": 234, ' \ '"shares": 345, "title": "Team"}, ' \ '{"url": "http://gravity4.com/labs/", "clicks": 334, ' \ '"shares": 675, "title": "Labs"}, ' \ '{"url": "http://gravity4.com/app-center/", ' \ '"clicks": 6334, "shares": 4675, ' \ '"title": "App Center"}, ' \ '{"url": "http://gravity4.com/product/", ' \ '"clicks": 12334, "shares": 8675, ' \ '"title": "Product"}, ' \ '{"url": "http://gravity4.com/vision/", ' \ '"clicks": 334, "shares": 675, "title": "Vision"}, ' \ '{"url": "http://gravity4.com/blog/introducing-belimitless/", ' \ '"clicks": 7834, "shares": 1275, ' \ '"title": "Introducing #Belimitless"}, ' \ '{"url": "http://gravity4.com/blog/tom-brady-super-bowl-sunday-doesnt-rely-on-luck-why-do-you/", ' \ '"clicks": 3334, "shares": 7512, ' \ '"title": "Tom Brady Doesn\'t Rely on Luck. Why Do You?"}, ' \ '{"url": "http://gravity4.com/blog/imagination-by-gravity4/", ' \ '"clicks": 8753, "shares": 7125, "title": "Imagination by Gravity4"}, ' \ '{"url": "http://gravity4.com/blog/ibeacon/", "clicks": 33124, ' \ '"shares": 23675, "title": "iBeacon. Shop Smarter"}, ' \ '{"url": "http://gravity4.com/blog/g4labs/", ' \ '"clicks": 3334, "shares": 1675, ' \ '"title": "Introducing, Gravity4 Labs."}, ' \ '{"url": "http://gravity4.com/opt-out/", ' \ '"clicks": 0, "shares": 0, "title": "Opt-out"}]' self.assertEqual(response.content, json_response) # referring_domains request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'referring_domains' }) response = views.reports(request) json_response = '[{"url": "http://addnow.com/2014/09/piwik-piwik-pro-trustradius-buyers-guide/", ' \ '"shares": 58}, {"url": "http://addnow.com/2014/10/clearcode-featured-agency-post/", ' \ '"shares": 11273}, ' \ '{"url": "http://addnow.com/2014/07/target-engaged-customers/", ' \ '"shares": 3235}, ' \ '{"url": "http://addnow.com/2014/07/rejoiner-ecommerce-solution-cart-abandonment/", ' \ '"shares": 612}, ' \ '{"url": "http://addnow.com/2014/08/hire-right-app-developers/", ' \ '"shares": 23}, {"url": "http://addnow.com/2014/12/agile-vs-waterfall-method/", ' \ '"shares": 725}, {"url": "http://addnow.com/2014/12/importance-of-branding-ux-ui-software-development/", ' \ '"shares": 8236}, {"url": "http://addnow.com/2014/10/programmers/", "shares": 826}, ' \ '{"url": "http://addnow.com/2014/10/hiring-process/", "shares": 269}, ' \ '{"url": "http://addnow.com/2014/09/computers/", "shares": 1252}]' self.assertEqual(response.content, json_response) # referring_searches request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'referring_searches' }) response = views.reports(request) json_response = '[{"searches": 58, "query": "Development"}, ' \ '{"searches": 612, "query": "Clearcode"}, ' \ '{"searches": 23, "query": "Software House"}, ' \ '{"searches": 11273, "query": "Interactive agency"}, ' \ '{"searches": 3235, "query": "Carrer in IT"}, ' \ '{"searches": 8236, "query": "PHP Developer"}, ' \ '{"searches": 725, "query": "Programming"}, ' \ '{"searches": 8236, "query": "PHP Developer"}, ' \ '{"searches": 826, "query": "SEO"}, ' \ '{"searches": 269, "query": "UX Design"}, ' \ '{"searches": 1252, "query": "Continuos integration"}]' self.assertEqual(response.content, json_response) # copied_keywords request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'copied_keywords' }) response = views.reports(request) json_response = '[{"keywords": "Development", "times": 58}, ' \ '{"keywords": "Interactive agency", "times": 11273}, ' \ '{"keywords": "Carrer in IT", "times": 3235}, ' \ '{"keywords": "Coding service", "times": 612}, ' \ '{"keywords": "Software House", "times": 23}, ' \ '{"keywords": "Programming", "times": 725}, ' \ '{"keywords": "PHP Developer", "times": 8236}, ' \ '{"keywords": "SEO", "times": 826}, ' \ '{"keywords": "UX Design", "times": 269}, ' \ '{"keywords": "Continuos integration", "times": 1252}]' self.assertEqual(response.content, json_response) # top_countries request = self.factory.get('report', data={ 'site_id': 1, 'collection': 'top_countries' }) response = views.reports(request) json_response = '[{"id": "NZ", "viral": 2, "clicks": 826, ' \ '"shares": 58, "country": "New Zealand"}, ' \ '{"id": "US", "viral": 62, "clicks": 25273, ' \ '"shares": 11273, "country": "United States"}, ' \ '{"id": "AU", "viral": 9, "clicks": 10264, ' \ '"shares": 3235, "country": "Australia"}, ' \ '{"id": "UK", "viral": 5, "clicks": 2746, ' \ '"shares": 612, "country": "United Kingdom"}, ' \ '{"id": "UK", "viral": 1, "clicks": 127, ' \ '"shares": 23, "country": "United Kingdom"}, ' \ '{"id": "BR", "viral": 7, "clicks": 5273, ' \ '"shares": 725, "country": "Brazil"}, ' \ '{"id": "CA", "viral": 21, "clicks": 17274, ' \ '"shares": 8236, "country": "Canada"}, ' \ '{"id": "AR", "viral": 3, "clicks": 1742, ' \ '"shares": 826, "country": "Argentina"}, ' \ '{"id": "MX", "viral": 4, "clicks": 742, ' \ '"shares": 269, "country": "Mexico"}, ' \ '{"id": "IN", "viral": 12, "clicks": 4242, ' \ '"shares": 1252, "country": "India"}]' self.assertEqual(response.content, json_response) # the same but for site_id=2 # event_source_all request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'event_source_all' }) response = views.reports(request) json_response = '[{"clicks": 34, "shares": 789, "label": "googlePlus"}, ' \ '{"clicks": 206, "shares": 1200, "label": "facebook"}, ' \ '{"clicks": 93, "shares": 543, "label": "twitter"}, ' \ '{"clicks": 57, "shares": 123, "label": "pinterest"}, ' \ '{"clicks": 38, "shares": 235, "label": "linkedin"}, ' \ '{"clicks": 0, "shares": 5, "label": "other"}]' self.assertEqual(response.content, json_response) # event_tool_all request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'event_tool_all' }) response = views.reports(request) json_response = '[{"clicks": 765, "shares": 345, "label": "copy-paste"}, ' \ '{"clicks": 871, "shares": 45, "label": "sharing-buttons"}, ' \ '{"clicks": 91, "shares": 5, "label": "address-bar"}]' self.assertEqual(response.content, json_response) # event_month request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'event_month' }) response = views.reports(request) json_response = '[{"clicks": 34, "shares": 13, "month": 1401}, ' \ '{"clicks": 56, "shares": 17, "month": 1402}, ' \ '{"clicks": 45, "shares": 19, "month": 1403}, ' \ '{"clicks": 56, "shares": 18, "month": 1404}, ' \ '{"clicks": 56, "shares": 15, "month": 1405}, ' \ '{"clicks": 30, "shares": 25, "month": 1406}, ' \ '{"clicks": 87, "shares": 35, "month": 1407}, ' \ '{"clicks": 56, "shares": 98, "month": 1408}, ' \ '{"clicks": 65, "shares": 1, "month": 1409}, ' \ '{"clicks": 65, "shares": 5, "month": 1410}, ' \ '{"clicks": 45, "shares": 1, "month": 1411}, ' \ '{"clicks": 25, "shares": 1, "month": 1412}, ' \ '{"clicks": 87, "shares": 0, "month": 1501}, ' \ '{"clicks": 5, "shares": 5, "month": 1502}]' self.assertEqual(response.content, json_response) # event_url_all request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'event_url_all' }) response = views.reports(request) json_response = '[{"url": "http://demo.com/contact/", "clicks": 343, "shares": 343, "title": "Contact"}, ' \ '{"url": "http://demo.com/team/", "clicks": 234, "shares": 345, "title": "Team"}, ' \ '{"url": "http://demo.com/labs/", "clicks": 34, "shares": 75, "title": "Labs"}, ' \ '{"url": "http://demo.com/pricing/", "clicks": 633, "shares": 467, "title": "Pricing"}, ' \ '{"url": "http://demo.com/product/", "clicks": 34, "shares": 675, "title": "Product"}, ' \ '{"url": "http://demo.com/vision/", "clicks": 34, "shares": 75, "title": "Vision"}, ' \ '{"url": "http://demo.com/blog/title1/", "clicks": 834, "shares": 275, "title": "Title 1"}, ' \ '{"url": "http://demo.com/blog/title2/", "clicks": 34, "shares": 12, "title": "Tile 2"}, ' \ '{"url": "http://demo.com/blog/title3/", "clicks": 53, "shares": 25, "title": "Title 3"}, ' \ '{"url": "http://demo.com/blog/title4/", "clicks": 3324, "shares": 2375, "title": "Title 4"}, ' \ '{"url": "http://demo.com/blog/title4/", "clicks": 334, "shares": 675, "title": "Title 5"}, ' \ '{"url": "http://demo.com/opt-out/", "clicks": 0, "shares": 0, "title": "Opt-out"}]' self.assertEqual(response.content, json_response) # referring_domains request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'referring_domains' }) response = views.reports(request) json_response = '[{"url": "http://addnow.com/2014/09/piwik-piwik-pro-trustradius-buyers-guide/", "shares": 581}, ' \ '{"url": "http://addnow.com/2014/10/clearcode-featured-agency-post/", "shares": 1273}, ' \ '{"url": "http://addnow.com/2014/07/target-engaged-customers/", "shares": 335}, ' \ '{"url": "http://addnow.com/2014/07/rejoiner-ecommerce-solution-cart-abandonment/", "shares": 1612}, ' \ '{"url": "http://addnow.com/2014/08/hire-right-app-developers/", "shares": 223}, ' \ '{"url": "http://addnow.com/2014/12/agile-vs-waterfall-method/", "shares": 75}, ' \ '{"url": "http://addnow.com/2014/12/importance-of-branding-ux-ui-software-development/", "shares": 836}, ' \ '{"url": "http://addnow.com/2014/10/programmers/", "shares": 8426}, ' \ '{"url": "http://addnow.com/2014/10/hiring-process/", "shares": 2619}, ' \ '{"url": "http://addnow.com/2014/09/computers/", "shares": 12}]' self.assertEqual(response.content, json_response) # referring_searches request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'referring_searches' }) response = views.reports(request) json_response = '[{"searches": 158, "query": "Development"}, ' \ '{"searches": 2612, "query": "Clearcode"}, ' \ '{"searches": 230, "query": "Software House"}, ' \ '{"searches": 1273, "query": "Interactive agency"}, ' \ '{"searches": 13235, "query": "Carrer in IT"}, ' \ '{"searches": 823, "query": "PHP Developer"}, ' \ '{"searches": 1725, "query": "Programming"}, ' \ '{"searches": 836, "query": "PHP Developer"}, ' \ '{"searches": 8426, "query": "SEO"}, ' \ '{"searches": 2619, "query": "UX Design"}, ' \ '{"searches": 12, "query": "Continuos integration"}]' self.assertEqual(response.content, json_response) # copied_keywords request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'copied_keywords' }) response = views.reports(request) json_response = '[{"keywords": "Development", "times": 581}, ' \ '{"keywords": "Interactive agency", "times": 1273}, ' \ '{"keywords": "Carrer in IT", "times": 335}, ' \ '{"keywords": "Coding service", "times": 1612}, ' \ '{"keywords": "Software House", "times": 223}, ' \ '{"keywords": "Programming", "times": 75}, ' \ '{"keywords": "PHP Developer", "times": 836}, ' \ '{"keywords": "SEO", "times": 8426}, ' \ '{"keywords": "UX Design", "times": 2619}, ' \ '{"keywords": "Continuos integration", "times": 12}]' self.assertEqual(response.content, json_response) # top_countries request = self.factory.get('report', data={ 'site_id': 2, 'collection': 'top_countries' }) response = views.reports(request) json_response = '[{"id": "NZ", "viral": 3, "clicks": 2826, "shares": 581, "country": "New Zealand"}, ' \ '{"id": "US", "viral": 26, "clicks": 5273, "shares": 1273, "country": "United States"}, ' \ '{"id": "AU", "viral": 11, "clicks": 1264, "shares": 335, "country": "Australia"}, ' \ '{"id": "UK", "viral": 5, "clicks": 2746, "shares": 1612, "country": "United Kingdom"}, ' \ '{"id": "UK", "viral": 1, "clicks": 1127, "shares": 223, "country": "United Kingdom"}, ' \ '{"id": "BR", "viral": 7, "clicks": 273, "shares": 75, "country": "Brazil"}, ' \ '{"id": "CA", "viral": 21, "clicks": 1274, "shares": 836, "country": "Canada"}, ' \ '{"id": "AR", "viral": 3, "clicks": 11742, "shares": 8326, "country": "Argentina"}, ' \ '{"id": "MX", "viral": 4, "clicks": 6742, "shares": 2619, "country": "Mexico"}, ' \ '{"id": "IN", "viral": 12, "clicks": 242, "shares": 12, "country": "India"}]' self.assertEqual(response.content, json_response)
class SubmitFeedbackTest(EnterpriseServiceMockMixin, TestCase): """ Class to test the submit_feedback function in views. """ def setUp(self): """Set up data for the test case""" super(SubmitFeedbackTest, self).setUp() self._request_factory = RequestFactory() self._anon_user = AnonymousUser() self._auth_user = UserFactory.create( email="*****@*****.**", username="******", profile__name="Test User" ) self._anon_fields = { "email": "*****@*****.**", "name": "Test User", "subject": "a subject", "details": "some details", "issue_type": "test_issue" } # This does not contain issue_type nor course_id to ensure that they are optional self._auth_fields = {"subject": "a subject", "details": "some details"} # Create a service user, because the track selection page depends on it UserFactory.create( username='******', email="*****@*****.**", password="******", ) def _build_and_run_request(self, user, fields): """ Generate a request and invoke the view, returning the response. The request will be a POST request from the given `user`, with the given `fields` in the POST body. """ req = self._request_factory.post( "/submit_feedback", data=fields, HTTP_REFERER=TEST_REQUEST_HEADERS["HTTP_REFERER"], HTTP_USER_AGENT=TEST_REQUEST_HEADERS["HTTP_USER_AGENT"], REMOTE_ADDR=TEST_REQUEST_HEADERS["REMOTE_ADDR"], SERVER_NAME=TEST_REQUEST_HEADERS["SERVER_NAME"], ) req.site = SiteFactory.create() req.user = user return views.submit_feedback(req) def _assert_bad_request(self, response, field, zendesk_mock_class, datadog_mock): """ Assert that the given `response` contains correct failure data. It should have a 400 status code, and its content should be a JSON object containing the specified `field` and an `error`. """ self.assertEqual(response.status_code, 400) resp_json = json.loads(response.content) self.assertIn("field", resp_json) self.assertEqual(resp_json["field"], field) self.assertIn("error", resp_json) # There should be absolutely no interaction with Zendesk self.assertFalse(zendesk_mock_class.return_value.mock_calls) self.assertFalse(datadog_mock.mock_calls) def _test_bad_request_omit_field(self, user, fields, omit_field, zendesk_mock_class, datadog_mock): """ Invoke the view with a request missing a field and assert correctness. The request will be a POST request from the given `user`, with POST fields taken from `fields` minus the entry specified by `omit_field`. The response should have a 400 (bad request) status code and specify the invalid field and an error message, and the Zendesk API should not have been invoked. """ filtered_fields = {k: v for (k, v) in fields.items() if k != omit_field} resp = self._build_and_run_request(user, filtered_fields) self._assert_bad_request(resp, omit_field, zendesk_mock_class, datadog_mock) def _test_bad_request_empty_field(self, user, fields, empty_field, zendesk_mock_class, datadog_mock): """ Invoke the view with an empty field and assert correctness. The request will be a POST request from the given `user`, with POST fields taken from `fields`, replacing the entry specified by `empty_field` with the empty string. The response should have a 400 (bad request) status code and specify the invalid field and an error message, and the Zendesk API should not have been invoked. """ altered_fields = fields.copy() altered_fields[empty_field] = "" resp = self._build_and_run_request(user, altered_fields) self._assert_bad_request(resp, empty_field, zendesk_mock_class, datadog_mock) def _test_success(self, user, fields): """ Generate a request, invoke the view, and assert success. The request will be a POST request from the given `user`, with the given `fields` in the POST body. The response should have a 200 (success) status code. """ resp = self._build_and_run_request(user, fields) self.assertEqual(resp.status_code, 200) def _build_zendesk_ticket(self, recipient, name, email, subject, details, tags, custom_fields=None): """ Build a Zendesk ticket that can be used in assertions to verify that the correct data was submitted to create a Zendesk ticket. """ ticket = { "ticket": { "recipient": recipient, "requester": {"name": name, "email": email}, "subject": subject, "comment": {"body": details}, "tags": tags } } if custom_fields is not None: ticket["ticket"]["custom_fields"] = custom_fields return ticket def _build_zendesk_ticket_update(self, request_headers, username=None): """ Build a Zendesk ticket update that can be used in assertions to verify that the correct data was submitted to update a Zendesk ticket. """ body = [] if username: body.append("username: {}".format(username)) # FIXME the tests rely on the body string being built in this specific order, which doesn't seem # reliable given that the view builds the string by iterating over a dictionary. header_text_mapping = [ ("Client IP", "REMOTE_ADDR"), ("Host", "SERVER_NAME"), ("Page", "HTTP_REFERER"), ("Browser", "HTTP_USER_AGENT") ] for text, header in header_text_mapping: body.append("{}: {}".format(text, request_headers[header])) body = "Additional information:\n\n" + "\n".join(body) return {"ticket": {"comment": {"public": False, "body": body}}} def _assert_zendesk_called(self, zendesk_mock, ticket_id, ticket, ticket_update): """Assert that Zendesk was called with the correct ticket and ticket_update.""" expected_zendesk_calls = [mock.call.create_ticket(ticket), mock.call.update_ticket(ticket_id, ticket_update)] self.assertEqual(zendesk_mock.mock_calls, expected_zendesk_calls) def _assert_datadog_called(self, datadog_mock, tags): """Assert that datadog was called with the correct tags.""" expected_datadog_calls = [mock.call.increment(views.DATADOG_FEEDBACK_METRIC, tags=tags)] self.assertEqual(datadog_mock.mock_calls, expected_datadog_calls) def test_bad_request_anon_user_no_name(self, zendesk_mock_class, datadog_mock): """Test a request from an anonymous user not specifying `name`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "name", zendesk_mock_class, datadog_mock) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "name", zendesk_mock_class, datadog_mock) def test_bad_request_anon_user_no_email(self, zendesk_mock_class, datadog_mock): """Test a request from an anonymous user not specifying `email`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "email", zendesk_mock_class, datadog_mock) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "email", zendesk_mock_class, datadog_mock) def test_bad_request_anon_user_invalid_email(self, zendesk_mock_class, datadog_mock): """Test a request from an anonymous user specifying an invalid `email`.""" fields = self._anon_fields.copy() fields["email"] = "This is not a valid email address!" resp = self._build_and_run_request(self._anon_user, fields) self._assert_bad_request(resp, "email", zendesk_mock_class, datadog_mock) def test_bad_request_anon_user_no_subject(self, zendesk_mock_class, datadog_mock): """Test a request from an anonymous user not specifying `subject`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "subject", zendesk_mock_class, datadog_mock) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "subject", zendesk_mock_class, datadog_mock) def test_bad_request_anon_user_no_details(self, zendesk_mock_class, datadog_mock): """Test a request from an anonymous user not specifying `details`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "details", zendesk_mock_class, datadog_mock) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "details", zendesk_mock_class, datadog_mock) def test_valid_request_anon_user(self, zendesk_mock_class, datadog_mock): """ Test a valid request from an anonymous user. The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API. """ zendesk_mock_instance = zendesk_mock_class.return_value user = self._anon_user fields = self._anon_fields ticket_id = 42 zendesk_mock_instance.create_ticket.return_value = ticket_id ticket = self._build_zendesk_ticket( recipient=TEST_SUPPORT_EMAIL, name=fields["name"], email=fields["email"], subject=fields["subject"], details=fields["details"], tags=[fields["issue_type"], "LMS"] ) ticket_update = self._build_zendesk_ticket_update(TEST_REQUEST_HEADERS) self._test_success(user, fields) self._assert_zendesk_called(zendesk_mock_instance, ticket_id, ticket, ticket_update) self._assert_datadog_called(datadog_mock, ["issue_type:{}".format(fields["issue_type"])]) @mock.patch("openedx.core.djangoapps.site_configuration.helpers.get_value", fake_get_value) def test_valid_request_anon_user_configuration_override(self, zendesk_mock_class, datadog_mock): """ Test a valid request from an anonymous user to a mocked out site with configuration override The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API with the additional tag that will come from site configuration override. """ zendesk_mock_instance = zendesk_mock_class.return_value user = self._anon_user fields = self._anon_fields ticket_id = 42 zendesk_mock_instance.create_ticket.return_value = ticket_id ticket = self._build_zendesk_ticket( recipient=fake_get_value("email_from_address"), name=fields["name"], email=fields["email"], subject=fields["subject"], details=fields["details"], tags=[fields["issue_type"], "LMS", "site_name_{}".format(fake_get_value("SITE_NAME").replace(".", "_"))] ) ticket_update = self._build_zendesk_ticket_update(TEST_REQUEST_HEADERS) self._test_success(user, fields) self._assert_zendesk_called(zendesk_mock_instance, ticket_id, ticket, ticket_update) self._assert_datadog_called(datadog_mock, ["issue_type:{}".format(fields["issue_type"])]) @data("course-v1:testOrg+testCourseNumber+testCourseRun", "", None) @override_settings(ZENDESK_CUSTOM_FIELDS=TEST_ZENDESK_CUSTOM_FIELD_CONFIG) def test_valid_request_anon_user_with_custom_fields(self, course_id, zendesk_mock_class, datadog_mock): """ Test a valid request from an anonymous user when configured to use Zendesk Custom Fields. The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API. When course_id is present, it should be sent to Zendesk via a custom field. When course_id is blank or missing, the request should still be processed successfully. """ zendesk_mock_instance = zendesk_mock_class.return_value user = self._anon_user fields = self._anon_fields.copy() if course_id is not None: fields["course_id"] = course_id ticket_id = 42 zendesk_mock_instance.create_ticket.return_value = ticket_id zendesk_tags = [fields["issue_type"], "LMS"] datadog_tags = ["issue_type:{}".format(fields["issue_type"])] zendesk_custom_fields = None if course_id: # FIXME the tests rely on the tags being in this specific order, which doesn't seem # reliable given that the view builds the list by iterating over a dictionary. zendesk_tags.insert(0, course_id) datadog_tags.insert(0, "course_id:{}".format(course_id)) zendesk_custom_fields = [ {"id": TEST_ZENDESK_CUSTOM_FIELD_CONFIG["course_id"], "value": course_id} ] ticket = self._build_zendesk_ticket( recipient=TEST_SUPPORT_EMAIL, name=fields["name"], email=fields["email"], subject=fields["subject"], details=fields["details"], tags=zendesk_tags, custom_fields=zendesk_custom_fields ) ticket_update = self._build_zendesk_ticket_update(TEST_REQUEST_HEADERS) self._test_success(user, fields) self._assert_zendesk_called(zendesk_mock_instance, ticket_id, ticket, ticket_update) self._assert_datadog_called(datadog_mock, datadog_tags) def test_bad_request_auth_user_no_subject(self, zendesk_mock_class, datadog_mock): """Test a request from an authenticated user not specifying `subject`.""" self._test_bad_request_omit_field(self._auth_user, self._auth_fields, "subject", zendesk_mock_class, datadog_mock) self._test_bad_request_empty_field(self._auth_user, self._auth_fields, "subject", zendesk_mock_class, datadog_mock) def test_bad_request_auth_user_no_details(self, zendesk_mock_class, datadog_mock): """Test a request from an authenticated user not specifying `details`.""" self._test_bad_request_omit_field(self._auth_user, self._auth_fields, "details", zendesk_mock_class, datadog_mock) self._test_bad_request_empty_field(self._auth_user, self._auth_fields, "details", zendesk_mock_class, datadog_mock) def test_valid_request_auth_user(self, zendesk_mock_class, datadog_mock): """ Test a valid request from an authenticated user. The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API. """ zendesk_mock_instance = zendesk_mock_class.return_value user = self._auth_user fields = self._auth_fields ticket_id = 42 zendesk_mock_instance.create_ticket.return_value = ticket_id ticket = self._build_zendesk_ticket( recipient=TEST_SUPPORT_EMAIL, name=user.profile.name, email=user.email, subject=fields["subject"], details=fields["details"], tags=["LMS"] ) ticket_update = self._build_zendesk_ticket_update(TEST_REQUEST_HEADERS, user.username) self._test_success(user, fields) self._assert_zendesk_called(zendesk_mock_instance, ticket_id, ticket, ticket_update) self._assert_datadog_called(datadog_mock, []) @data( ("course-v1:testOrg+testCourseNumber+testCourseRun", True), ("course-v1:testOrg+testCourseNumber+testCourseRun", False), ("", None), (None, None) ) @unpack @override_settings(ZENDESK_CUSTOM_FIELDS=TEST_ZENDESK_CUSTOM_FIELD_CONFIG) def test_valid_request_auth_user_with_custom_fields(self, course_id, enrolled, zendesk_mock_class, datadog_mock): """ Test a valid request from an authenticated user when configured to use Zendesk Custom Fields. The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API. When course_id is present, it should be sent to Zendesk via a custom field, along with the enrollment mode if the user has an active enrollment for that course. When course_id is blank or missing, the request should still be processed successfully. """ zendesk_mock_instance = zendesk_mock_class.return_value user = self._auth_user fields = self._auth_fields.copy() if course_id is not None: fields["course_id"] = course_id ticket_id = 42 zendesk_mock_instance.create_ticket.return_value = ticket_id zendesk_tags = ["LMS"] datadog_tags = [] zendesk_custom_fields = None if course_id: # FIXME the tests rely on the tags being in this specific order, which doesn't seem # reliable given that the view builds the list by iterating over a dictionary. zendesk_tags.insert(0, course_id) datadog_tags.insert(0, "course_id:{}".format(course_id)) zendesk_custom_fields = [ {"id": TEST_ZENDESK_CUSTOM_FIELD_CONFIG["course_id"], "value": course_id} ] if enrolled is not None: enrollment = CourseEnrollmentFactory.create( user=user, course_id=course_id, is_active=enrolled ) if enrollment.is_active: zendesk_custom_fields.append( {"id": TEST_ZENDESK_CUSTOM_FIELD_CONFIG["enrollment_mode"], "value": enrollment.mode} ) ticket = self._build_zendesk_ticket( recipient=TEST_SUPPORT_EMAIL, name=user.profile.name, email=user.email, subject=fields["subject"], details=fields["details"], tags=zendesk_tags, custom_fields=zendesk_custom_fields ) ticket_update = self._build_zendesk_ticket_update(TEST_REQUEST_HEADERS, user.username) self._test_success(user, fields) self._assert_zendesk_called(zendesk_mock_instance, ticket_id, ticket, ticket_update) self._assert_datadog_called(datadog_mock, datadog_tags) @httpretty.activate @data( ("course-v1:testOrg+testCourseNumber+testCourseRun", True), ("course-v1:testOrg+testCourseNumber+testCourseRun", False), ) @unpack @override_settings(ZENDESK_CUSTOM_FIELDS=TEST_ZENDESK_CUSTOM_FIELD_CONFIG) @mock.patch.dict("django.conf.settings.FEATURES", dict(ENABLE_ENTERPRISE_INTEGRATION=True)) def test_valid_request_auth_user_with_enterprise_info(self, course_id, enrolled, zendesk_mock_class, datadog_mock): """ Test a valid request from an authenticated user with enterprise tags. """ self.mock_enterprise_learner_api() zendesk_mock_instance = zendesk_mock_class.return_value user = self._auth_user fields = self._auth_fields.copy() if course_id is not None: fields["course_id"] = course_id ticket_id = 42 zendesk_mock_instance.create_ticket.return_value = ticket_id zendesk_tags = ["enterprise_learner", "LMS"] datadog_tags = ['learner_type:enterprise_learner'] zendesk_custom_fields = [] if course_id: zendesk_tags.insert(0, course_id) datadog_tags.insert(0, "course_id:{}".format(course_id)) zendesk_custom_fields.append({"id": TEST_ZENDESK_CUSTOM_FIELD_CONFIG["course_id"], "value": course_id}) if enrolled is not None: enrollment = CourseEnrollmentFactory.create( user=user, course_id=course_id, is_active=enrolled ) if enrollment.is_active: zendesk_custom_fields.append( {"id": TEST_ZENDESK_CUSTOM_FIELD_CONFIG["enrollment_mode"], "value": enrollment.mode} ) zendesk_custom_fields.append( { "id": TEST_ZENDESK_CUSTOM_FIELD_CONFIG["enterprise_customer_name"], "value": 'TestShib' } ) ticket = self._build_zendesk_ticket( recipient=TEST_SUPPORT_EMAIL, name=user.profile.name, email=user.email, subject=fields["subject"], details=fields["details"], tags=zendesk_tags, custom_fields=zendesk_custom_fields ) ticket_update = self._build_zendesk_ticket_update(TEST_REQUEST_HEADERS, user.username) self._test_success(user, fields) self._assert_zendesk_called(zendesk_mock_instance, ticket_id, ticket, ticket_update) self._assert_datadog_called(datadog_mock, datadog_tags) @httpretty.activate @override_settings(ZENDESK_CUSTOM_FIELDS=TEST_ZENDESK_CUSTOM_FIELD_CONFIG) @mock.patch.dict("django.conf.settings.FEATURES", dict(ENABLE_ENTERPRISE_INTEGRATION=True)) def test_request_with_anonymous_user_without_enterprise_info(self, zendesk_mock_class, datadog_mock): """ Test tags related to enterprise should not be there in case an unauthenticated user. """ ticket_id = 42 self.mock_enterprise_learner_api() user = self._anon_user zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.create_ticket.return_value = ticket_id datadog_valid_tags = ["issue_type:{}".format(self._anon_fields["issue_type"])] datadog_invalid_tags = ['learner_type:enterprise_learner'] resp = self._build_and_run_request(user, self._anon_fields) self.assertEqual(resp.status_code, 200) expected_datadog_calls = [mock.call.increment(views.DATADOG_FEEDBACK_METRIC, tags=datadog_valid_tags)] self.assertEqual(datadog_mock.mock_calls, expected_datadog_calls) not_expected_datadog_calls = [mock.call.increment(views.DATADOG_FEEDBACK_METRIC, tags=datadog_invalid_tags)] self.assertNotEqual(datadog_mock.mock_calls, not_expected_datadog_calls) @httpretty.activate @override_settings(ZENDESK_CUSTOM_FIELDS=TEST_ZENDESK_CUSTOM_FIELD_CONFIG) @mock.patch.dict("django.conf.settings.FEATURES", dict(ENABLE_ENTERPRISE_INTEGRATION=True)) def test_tags_in_request_with_auth_user_with_enterprise_info(self, zendesk_mock_class, datadog_mock): """ Test tags related to enterprise should be there in case the request is generated by an authenticated user. """ ticket_id = 42 self.mock_enterprise_learner_api() user = self._auth_user zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.create_ticket.return_value = ticket_id datadog_valid_tags = ['learner_type:enterprise_learner'] resp = self._build_and_run_request(user, self._auth_fields) self.assertEqual(resp.status_code, 200) self._assert_datadog_called(datadog_mock, datadog_valid_tags) def test_get_request(self, zendesk_mock_class, datadog_mock): """Test that a GET results in a 405 even with all required fields""" req = self._request_factory.get("/submit_feedback", data=self._anon_fields) req.user = self._anon_user resp = views.submit_feedback(req) self.assertEqual(resp.status_code, 405) self.assertIn("Allow", resp) self.assertEqual(resp["Allow"], "POST") # There should be absolutely no interaction with Zendesk self.assertFalse(zendesk_mock_class.mock_calls) self.assertFalse(datadog_mock.mock_calls) def test_zendesk_error_on_create(self, zendesk_mock_class, datadog_mock): """ Test Zendesk returning an error on ticket creation. We should return a 500 error with no body """ err = ZendeskError(msg="", error_code=404) zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.create_ticket.side_effect = err resp = self._build_and_run_request(self._anon_user, self._anon_fields) self.assertEqual(resp.status_code, 500) self.assertFalse(resp.content) self._assert_datadog_called(datadog_mock, ["issue_type:{}".format(self._anon_fields["issue_type"])]) def test_zendesk_error_on_update(self, zendesk_mock_class, datadog_mock): """ Test for Zendesk returning an error on ticket update. If Zendesk returns any error on ticket update, we return a 200 to the browser because the update contains additional information that is not necessary for the user to have submitted their feedback. """ err = ZendeskError(msg="", error_code=500) zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.update_ticket.side_effect = err resp = self._build_and_run_request(self._anon_user, self._anon_fields) self.assertEqual(resp.status_code, 200) self._assert_datadog_called(datadog_mock, ["issue_type:{}".format(self._anon_fields["issue_type"])]) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_FEEDBACK_SUBMISSION": False}) def test_not_enabled(self, zendesk_mock_class, datadog_mock): """ Test for Zendesk submission not enabled in `settings`. We should raise Http404. """ with self.assertRaises(Http404): self._build_and_run_request(self._anon_user, self._anon_fields) def test_zendesk_not_configured(self, zendesk_mock_class, datadog_mock): """ Test for Zendesk not fully configured in `settings`. For each required configuration parameter, test that setting it to `None` causes an otherwise valid request to return a 500 error. """ def test_case(missing_config): with mock.patch(missing_config, None): with self.assertRaises(Exception): self._build_and_run_request(self._anon_user, self._anon_fields) test_case("django.conf.settings.ZENDESK_URL") test_case("django.conf.settings.ZENDESK_USER") test_case("django.conf.settings.ZENDESK_API_KEY") @mock.patch("openedx.core.djangoapps.site_configuration.helpers.get_value", fake_support_backend_values) def test_valid_request_over_email(self, zendesk_mock_class, datadog_mock): # pylint: disable=unused-argument with mock.patch("util.views.send_mail") as patched_send_email: resp = self._build_and_run_request(self._anon_user, self._anon_fields) self.assertEqual(patched_send_email.call_count, 1) self.assertIn(self._anon_fields["email"], str(patched_send_email.call_args)) self.assertEqual(resp.status_code, 200) @mock.patch("openedx.core.djangoapps.site_configuration.helpers.get_value", fake_support_backend_values) def test_exception_request_over_email(self, zendesk_mock_class, datadog_mock): # pylint: disable=unused-argument with mock.patch("util.views.send_mail", side_effect=SMTPException) as patched_send_email: resp = self._build_and_run_request(self._anon_user, self._anon_fields) self.assertEqual(patched_send_email.call_count, 1) self.assertIn(self._anon_fields["email"], str(patched_send_email.call_args)) self.assertEqual(resp.status_code, 500)
class TestGetProblemGradeDistribution(SharedModuleStoreTestCase): """ Tests related to class_dashboard/dashboard_data.py """ @classmethod def setUpClass(cls): super(TestGetProblemGradeDistribution, cls).setUpClass() cls.course = CourseFactory.create( display_name=u"test course omega \u03a9", ) with cls.store.bulk_operations(cls.course.id, emit_signals=False): section = ItemFactory.create( parent_location=cls.course.location, category="chapter", display_name=u"test factory section omega \u03a9", ) cls.sub_section = ItemFactory.create( parent_location=section.location, category="sequential", display_name=u"test subsection omega \u03a9", ) cls.unit = ItemFactory.create( parent_location=cls.sub_section.location, category="vertical", metadata={ 'graded': True, 'format': 'Homework' }, display_name=u"test unit omega \u03a9", ) cls.items = [] for i in xrange(USER_COUNT - 1): item = ItemFactory.create( parent_location=cls.unit.location, category="problem", data=StringResponseXMLFactory().build_xml(answer='foo'), metadata={'rerandomize': 'always'}, display_name=u"test problem omega \u03a9 " + str(i)) cls.items.append(item) cls.item = item def setUp(self): super(TestGetProblemGradeDistribution, self).setUp() self.request_factory = RequestFactory() self.instructor = AdminFactory.create() self.client.login(username=self.instructor.username, password='******') self.attempts = 3 self.users = [ UserFactory.create(username="******" + str(__)) for __ in xrange(USER_COUNT) ] for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) for i, item in enumerate(self.items): for j, user in enumerate(self.users): StudentModuleFactory.create( grade=1 if i < j else 0, max_grade=1 if i < j else 0.5, student=user, course_id=self.course.id, module_state_key=item.location, state=json.dumps({'attempts': self.attempts}), ) for j, user in enumerate(self.users): StudentModuleFactory.create( course_id=self.course.id, module_type='sequential', module_state_key=item.location, ) def test_get_problem_grade_distribution(self): prob_grade_distrib, total_student_count = get_problem_grade_distribution( self.course.id) for problem in prob_grade_distrib: max_grade = prob_grade_distrib[problem]['max_grade'] self.assertEquals(1, max_grade) for val in total_student_count.values(): self.assertEquals(USER_COUNT, val) def test_get_sequential_open_distibution(self): sequential_open_distrib = get_sequential_open_distrib(self.course.id) for problem in sequential_open_distrib: num_students = sequential_open_distrib[problem] self.assertEquals(USER_COUNT, num_students) def test_get_problemset_grade_distrib(self): prob_grade_distrib, __ = get_problem_grade_distribution(self.course.id) probset_grade_distrib = get_problem_set_grade_distrib( self.course.id, prob_grade_distrib) for problem in probset_grade_distrib: max_grade = probset_grade_distrib[problem]['max_grade'] self.assertEquals(1, max_grade) grade_distrib = probset_grade_distrib[problem]['grade_distrib'] sum_attempts = 0 for item in grade_distrib: sum_attempts += item[1] self.assertEquals(USER_COUNT, sum_attempts) def test_get_d3_problem_grade_distrib(self): d3_data = get_d3_problem_grade_distrib(self.course.id) for data in d3_data: for stack_data in data['data']: sum_values = 0 for problem in stack_data['stackData']: sum_values += problem['value'] self.assertEquals(USER_COUNT, sum_values) def test_get_d3_sequential_open_distrib(self): d3_data = get_d3_sequential_open_distrib(self.course.id) for data in d3_data: for stack_data in data['data']: for problem in stack_data['stackData']: value = problem['value'] self.assertEquals(0, value) def test_get_d3_section_grade_distrib(self): d3_data = get_d3_section_grade_distrib(self.course.id, 0) for stack_data in d3_data: sum_values = 0 for problem in stack_data['stackData']: sum_values += problem['value'] self.assertEquals(USER_COUNT, sum_values) def test_get_students_problem_grades(self): attributes = '?module_id=' + text_type(self.item.location) request = self.request_factory.get( reverse('get_students_problem_grades') + attributes) response = get_students_problem_grades(request) response_content = json.loads(response.content)['results'] response_max_exceeded = json.loads(response.content)['max_exceeded'] self.assertEquals(USER_COUNT, len(response_content)) self.assertEquals(False, response_max_exceeded) for item in response_content: if item['grade'] == 0: self.assertEquals(0, item['percent']) else: self.assertEquals(100, item['percent']) def test_get_students_problem_grades_max(self): with patch('class_dashboard.dashboard_data.MAX_SCREEN_LIST_LENGTH', 2): attributes = '?module_id=' + text_type(self.item.location) request = self.request_factory.get( reverse('get_students_problem_grades') + attributes) response = get_students_problem_grades(request) response_results = json.loads(response.content)['results'] response_max_exceeded = json.loads( response.content)['max_exceeded'] # Only 2 students in the list and response_max_exceeded is True self.assertEquals(2, len(response_results)) self.assertEquals(True, response_max_exceeded) def test_get_students_problem_grades_csv(self): tooltip = 'P1.2.1 Q1 - 3382 Students (100%: 1/1 questions)' attributes = '?module_id=' + text_type( self.item.location) + '&tooltip=' + tooltip + '&csv=true' request = self.request_factory.get( reverse('get_students_problem_grades') + attributes) response = get_students_problem_grades(request) # Check header and a row for each student in csv response self.assertContains(response, '"Name","Username","Grade","Percent"') self.assertContains(response, '"metric0","0.0","0.0"') self.assertContains(response, '"metric1","0.0","0.0"') self.assertContains(response, '"metric2","0.0","0.0"') self.assertContains(response, '"metric3","0.0","0.0"') self.assertContains(response, '"metric4","0.0","0.0"') self.assertContains(response, '"metric5","0.0","0.0"') self.assertContains(response, '"metric6","0.0","0.0"') self.assertContains(response, '"metric7","0.0","0.0"') self.assertContains(response, '"metric8","0.0","0.0"') self.assertContains(response, '"metric9","0.0","0.0"') self.assertContains(response, '"metric10","1.0","100.0"') def test_get_students_opened_subsection(self): attributes = '?module_id=' + text_type(self.item.location) request = self.request_factory.get( reverse('get_students_opened_subsection') + attributes) response = get_students_opened_subsection(request) response_results = json.loads(response.content)['results'] response_max_exceeded = json.loads(response.content)['max_exceeded'] self.assertEquals(USER_COUNT, len(response_results)) self.assertEquals(False, response_max_exceeded) def test_get_students_opened_subsection_max(self): with patch('class_dashboard.dashboard_data.MAX_SCREEN_LIST_LENGTH', 2): attributes = '?module_id=' + text_type(self.item.location) request = self.request_factory.get( reverse('get_students_opened_subsection') + attributes) response = get_students_opened_subsection(request) response_results = json.loads(response.content)['results'] response_max_exceeded = json.loads( response.content)['max_exceeded'] # Only 2 students in the list and response_max_exceeded is True self.assertEquals(2, len(response_results)) self.assertEquals(True, response_max_exceeded) def test_get_students_opened_subsection_csv(self): tooltip = '4162 students opened Subsection 5: Relational Algebra Exercises' attributes = '?module_id=' + text_type( self.item.location) + '&tooltip=' + tooltip + '&csv=true' request = self.request_factory.get( reverse('get_students_opened_subsection') + attributes) response = get_students_opened_subsection(request) self.assertContains(response, '"Name","Username"') # Check response contains 1 line for each user +1 for the header self.assertEquals(USER_COUNT + 1, len(response.content.splitlines())) def test_post_metrics_data_subsections_csv(self): url = reverse('post_metrics_data_csv') sections = json.dumps(["Introduction"]) tooltips = json.dumps([[{ "subsection_name": "Pre-Course Survey", "subsection_num": 1, "type": "subsection", "num_students": 18963 }]]) course_id = self.course.id data_type = 'subsection' data = json.dumps({ 'sections': sections, 'tooltips': tooltips, 'course_id': text_type(course_id), 'data_type': data_type, }) response = self.client.post(url, {'data': data}) # Check response contains 1 line for header, 1 line for Section and 1 line for Subsection self.assertEquals(3, len(response.content.splitlines())) def test_post_metrics_data_problems_csv(self): url = reverse('post_metrics_data_csv') sections = json.dumps(["Introduction"]) tooltips = json.dumps([[[ { 'student_count_percent': 0, 'problem_name': 'Q1', 'grade': 0, 'percent': 0, 'label': 'P1.2.1', 'max_grade': 1, 'count_grade': 26, 'type': u'problem' }, { 'student_count_percent': 99, 'problem_name': 'Q1', 'grade': 1, 'percent': 100, 'label': 'P1.2.1', 'max_grade': 1, 'count_grade': 4763, 'type': 'problem' }, ]]]) course_id = self.course.id data_type = 'problem' data = json.dumps({ 'sections': sections, 'tooltips': tooltips, 'course_id': text_type(course_id), 'data_type': data_type, }) response = self.client.post(url, {'data': data}) # Check response contains 1 line for header, 1 line for Sections and 2 lines for problems self.assertEquals(4, len(response.content.splitlines())) def test_get_section_display_name(self): section_display_name = get_section_display_name(self.course.id) self.assertMultiLineEqual(section_display_name[0], u"test factory section omega \u03a9") def test_get_array_section_has_problem(self): b_section_has_problem = get_array_section_has_problem(self.course.id) self.assertEquals(b_section_has_problem[0], True) def test_has_instructor_access_for_class(self): """ Test for instructor access """ ret_val = bool( has_instructor_access_for_class(self.instructor, self.course.id)) self.assertEquals(ret_val, True)
class EmailChangeConfirmationTests(EmailTestMixin, TransactionTestCase): """Test that confirmation of email change requests function even in the face of exceptions thrown while sending email""" def setUp(self): super(EmailChangeConfirmationTests, self).setUp() self.user = UserFactory.create() self.profile = UserProfile.objects.get(user=self.user) self.req_factory = RequestFactory() self.request = self.req_factory.get('unused_url') self.request.user = self.user self.user.email_user = Mock() self.pending_change_request = PendingEmailChangeFactory.create( user=self.user) self.key = self.pending_change_request.activation_key def assertRolledBack(self): """Assert that no changes to user, profile, or pending email have been made to the db""" self.assertEquals(self.user.email, User.objects.get(username=self.user.username).email) self.assertEquals(self.profile.meta, UserProfile.objects.get(user=self.user).meta) self.assertEquals(1, PendingEmailChange.objects.count()) def assertFailedBeforeEmailing(self, email_user): """Assert that the function failed before emailing a user""" self.assertRolledBack() self.assertFalse(email_user.called) def check_confirm_email_change(self, expected_template, expected_context): """Call `confirm_email_change` and assert that the content was generated as expected `expected_template`: The name of the template that should have been used to generate the content `expected_context`: The context dictionary that should have been used to generate the content """ response = confirm_email_change(self.request, self.key) self.assertEquals( mock_render_to_response(expected_template, expected_context).content, response.content) def assertChangeEmailSent(self, email_user): """Assert that the correct email was sent to confirm an email change""" context = { 'old_email': self.user.email, 'new_email': self.pending_change_request.new_email, } self.assertEmailUser(email_user, 'emails/email_change_subject.txt', context, 'emails/confirm_email_change.txt', context) # Thorough tests for safe_get_host are elsewhere; here we just want a quick URL sanity check request = RequestFactory().post('unused_url') request.user = self.user request.META['HTTP_HOST'] = "aGenericValidHostName" self.append_allowed_hosts("aGenericValidHostName") mako_middleware_process_request(request) body = render_to_string('emails/confirm_email_change.txt', context) url = safe_get_host(request) self.assertIn(url, body) def test_not_pending(self, email_user): self.key = 'not_a_key' self.check_confirm_email_change('invalid_email_key.html', {}) self.assertFailedBeforeEmailing(email_user) def test_duplicate_email(self, email_user): UserFactory.create(email=self.pending_change_request.new_email) self.check_confirm_email_change('email_exists.html', {}) self.assertFailedBeforeEmailing(email_user) @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS") def test_old_email_fails(self, email_user): email_user.side_effect = [Exception, None] self.check_confirm_email_change('email_change_failed.html', { 'email': self.user.email, }) self.assertRolledBack() self.assertChangeEmailSent(email_user) @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS") def test_new_email_fails(self, email_user): email_user.side_effect = [None, Exception] self.check_confirm_email_change( 'email_change_failed.html', {'email': self.pending_change_request.new_email}) self.assertRolledBack() self.assertChangeEmailSent(email_user) @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS") def test_successful_email_change(self, email_user): self.check_confirm_email_change( 'email_change_successful.html', { 'old_email': self.user.email, 'new_email': self.pending_change_request.new_email }) self.assertChangeEmailSent(email_user) meta = json.loads(UserProfile.objects.get(user=self.user).meta) self.assertIn('old_emails', meta) self.assertEquals(self.user.email, meta['old_emails'][0][0]) self.assertEquals(self.pending_change_request.new_email, User.objects.get(username=self.user.username).email) self.assertEquals(0, PendingEmailChange.objects.count()) @patch('student.views.PendingEmailChange.objects.get', Mock(side_effect=TestException)) @patch('student.views.transaction.rollback', wraps=django.db.transaction.rollback) def test_always_rollback(self, rollback, _email_user): with self.assertRaises(TestException): confirm_email_change(self.request, self.key) rollback.assert_called_with()
class TestRedirectUrlPattern(TestCase): def setUp(self): self.rf = RequestFactory() def test_name(self): """ Should return a RegexURLPattern with a matching name attribute """ url_pattern = redirect(r'^the/dude$', 'abides', name='Lebowski') self.assertTrue(isinstance(url_pattern, RegexURLPattern)) self.assertEqual(url_pattern.name, 'Lebowski') def test_no_query(self): """ Should return a 301 redirect """ pattern = redirect(r'^the/dude$', 'abides') request = self.rf.get('the/dude') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides') def test_preserve_query(self): """ Should preserve querys from the original request by default """ pattern = redirect(r'^the/dude$', 'abides') request = self.rf.get('the/dude?aggression=not_stand') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides?aggression=not_stand') def test_replace_query(self): """ Should replace query params if any are provided """ pattern = redirect(r'^the/dude$', 'abides', query={'aggression': 'not_stand'}) request = self.rf.get('the/dude?aggression=unchecked') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides?aggression=not_stand') def test_merge_query(self): """ Should merge query params if requested """ pattern = redirect(r'^the/dude$', 'abides', query={'aggression': 'not_stand'}, merge_query=True) request = self.rf.get('the/dude?hates=the-eagles') response = pattern.callback(request) self.assertEqual(response.status_code, 301) url = urlparse(response['location']) query_dict = parse_qs(url.query) self.assertTrue(url.path, 'abides') self.assertEqual(query_dict, {'aggression': ['not_stand'], 'hates': ['the-eagles']}) def test_empty_query(self): """ Should strip query params if called with empty query """ pattern = redirect(r'^the/dude$', 'abides', query={}) request = self.rf.get('the/dude?white=russian') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides') def test_temporary_redirect(self): """ Should use a temporary redirect (status code 302) if permanent == False """ pattern = redirect(r'^the/dude$', 'abides', permanent=False) request = self.rf.get('the/dude') response = pattern.callback(request) self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], 'abides') def test_anchor(self): """ Should append anchor text to the end, including after any querystring """ pattern = redirect(r'^the/dude$', 'abides', anchor='toe') request = self.rf.get('the/dude?want=a') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides?want=a#toe') def test_callable(self): """ Should use the return value of the callable as redirect location """ def opinion(request): return '/just/your/opinion/man' pattern = redirect(r'^the/dude$', opinion) request = self.rf.get('the/dude') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], '/just/your/opinion/man') @patch('redirect_urls.utils.reverse') def test_to_view(self, mock_reverse): """ Should use return value of reverse as redirect location """ mock_reverse.return_value = '/just/your/opinion/man' pattern = redirect(r'^the/dude$', 'yeah.well.you.know.thats') request = self.rf.get('the/dude') response = pattern.callback(request) mock_reverse.assert_called_with('yeah.well.you.know.thats', args=None, kwargs=None) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], '/just/your/opinion/man') @patch('redirect_urls.utils.reverse') def test_to_view_args_kwargs(self, mock_reverse): """ Should call reverse with specified args and/or kwargs. """ mock_reverse.return_value = '/just/your/opinion/man' pattern = redirect(r'^the/dude$', 'yeah.well.you.know.thats', to_args=['dude'], to_kwargs={'tapes': 'credence'}) request = self.rf.get('the/dude') response = pattern.callback(request) mock_reverse.assert_called_with('yeah.well.you.know.thats', args=['dude'], kwargs={'tapes': 'credence'}) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], '/just/your/opinion/man') def test_cache_headers(self): """ Should add cache headers based on argument. """ pattern = redirect(r'^the/dude$', 'abides', cache_timeout=2) request = self.rf.get('the/dude') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides') self.assertEqual(response['cache-control'], 'max-age=7200') # 2 hours def test_vary_header(self): """ Should add vary header based on argument. """ pattern = redirect(r'^the/dude$', 'abides', vary='Accept-Language') request = self.rf.get('the/dude') response = pattern.callback(request) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'abides') self.assertEqual(response['Vary'], 'Accept-Language') def test_value_capture_and_substitution(self): """ Should be able to capture info from URL and use in redirection. """ resolver = get_resolver([redirect(r'^iam/the/(?P<name>.+)/$', '/donnie/the/{name}/')]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/donnie/the/walrus/') def test_locale_value_capture(self): """ Should prepend locale value automatically. """ resolver = get_resolver([redirect(r'^iam/the/(?P<name>.+)/$', '/donnie/the/{name}/')]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/pt-BR/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/pt-BR/donnie/the/walrus/') def test_locale_value_capture_no_locale(self): """ Should get locale value in kwargs and not break if no locale in URL. """ resolver = get_resolver([redirect(r'^iam/the/(?P<name>.+)/$', '/donnie/the/{name}/')]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/donnie/the/walrus/') def test_locale_value_capture_ignore_locale(self): """ Should be able to ignore the original locale. """ resolver = get_resolver([redirect(r'^iam/the/(?P<name>.+)/$', '/donnie/the/{name}/', prepend_locale=False)]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/zh-TW/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/donnie/the/walrus/') def test_no_locale_prefix(self): """ Should be able to define a redirect that ignores locale prefix. Also when not using any named captures (like implied locale) unnamed captures should work. For some reason Django only allows unnamed captures to pass through if there are no named ones. """ resolver = get_resolver([redirect(r'^iam/the/(.+)/$', '/donnie/the/{}/', locale_prefix=False)]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/donnie/the/walrus/') def test_empty_unnamed_captures(self): """ Should be able to define an optional unnamed capture. """ resolver = get_resolver([redirect(r'^iam/the(/.+)?/$', '/donnie/the{}/', locale_prefix=False)]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/iam/the/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/donnie/the/') def test_match_flags(self): """ Should be able to set regex flags for redirect URL. """ resolver = get_resolver([ redirect(r'^iam/the/walrus/$', '/coo/coo/cachoo/'), redirect(r'^iam/the/walrus/$', '/dammit/donnie/', re_flags='i'), ]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/IAm/The/Walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/dammit/donnie/') # also with locale resp = middleware.process_request(self.rf.get('/es-ES/Iam/The/Walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/es-ES/dammit/donnie/') # sanity check resp = middleware.process_request(self.rf.get('/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/coo/coo/cachoo/') def test_non_ascii_strip_tags(self): """ Should deal with non-ascii characters when there's a substitution as well as strip tags. This is from errors that happened on www.m.o. The following URL caused a 500: https://www.mozilla.org/editor/midasdemo/securityprefs.html%3C/span%3E%3C/a%3E%C2%A0 """ resolver = get_resolver([redirect(r'^editor/(?P<page>.*)$', 'http://www-archive.mozilla.org/editor/{page}')]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/editor/midasdemo/securityprefs.html' '%3C/span%3E%3C/a%3E%C2%A0')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], 'http://www-archive.mozilla.org/editor/midasdemo/' 'securityprefs.html%C2%A0') @patch('redirect_urls.utils.reverse') def test_urls_dont_call_reverse(self, reverse_mock): """ Should not call reverse() for an obvious URL. """ resolver = get_resolver([ redirect(r'^iam/the/walrus/$', '/coo/coo/cachoo/'), redirect(r'^iam/the/ape-man/$', 'https://example.com/egg-man/'), ]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/iam/the/walrus/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], '/coo/coo/cachoo/') resp = middleware.process_request(self.rf.get('/iam/the/ape-man/')) self.assertEqual(resp.status_code, 301) self.assertEqual(resp['Location'], 'https://example.com/egg-man/') reverse_mock.assert_not_called() def test_will_not_return_protocol_relative_redirect(self): """Allowing a protocol relative URL can allow an unintended domain redirect.""" resolver = get_resolver([ redirect(r'^(.+)/$', '/{}/', locale_prefix=False), ]) middleware = RedirectsMiddleware(resolver) resp = middleware.process_request(self.rf.get('/%2fexample.com/')) self.assertEqual(resp['Location'], '/example.com/')
class VerifyTests(TestCase): def setUp(self): self.factory = RequestFactory() def verify(self, request_type, **kwargs): """ Call the verify view function. Kwargs are passed as GET or POST arguments. """ if request_type == 'get': request = self.factory.get('/browserid/verify', kwargs) else: request = self.factory.post('/browserid/verify', kwargs) verify_view = views.Verify.as_view() with patch.object(auth, 'login'): response = verify_view(request) return response def test_no_assertion(self): """If no assertion is given, return a failure result.""" with self.settings(LOGIN_REDIRECT_URL_FAILURE='/fail'): response = self.verify('post', blah='asdf') self.assertEqual(response.status_code, 403) self.assert_json_equals(response.content, {'redirect': '/fail'}) @mock_browserid(None) def test_auth_fail(self): """If authentication fails, redirect to the failure URL.""" with self.settings(LOGIN_REDIRECT_URL_FAILURE='/fail'): response = self.verify('post', assertion='asdf') self.assertEqual(response.status_code, 403) self.assert_json_equals(response.content, {'redirect': '/fail'}) @mock_browserid('*****@*****.**') def test_auth_success_redirect_success(self): """If authentication succeeds, redirect to the success URL.""" user = auth.models.User.objects.create_user('asdf', '*****@*****.**') request = self.factory.post('/browserid/verify', {'assertion': 'asdf'}) with self.settings(LOGIN_REDIRECT_URL='/success'): with patch('django_browserid.views.auth.login') as login: verify = views.Verify.as_view() response = verify(request) login.assert_called_with(request, user) self.assertEqual(response.status_code, 200) self.assert_json_equals(response.content, { 'email': '*****@*****.**', 'redirect': '/success' }) def test_sanity_checks(self): """Run sanity checks on all incoming requests.""" with patch('django_browserid.views.sanity_checks') as sanity_checks: self.verify('post') self.assertTrue(sanity_checks.called) @patch('django_browserid.views.auth.login') def test_login_success_no_next(self, *args): """ If _get_next returns None, use success_url for the redirect parameter. """ view = views.Verify() view.request = self.factory.post('/') view.user = Mock(email='*****@*****.**') with patch('django_browserid.views._get_next', return_value=None) as _get_next: with patch.object(views.Verify, 'success_url', '/?asdf'): response = view.login_success() self.assert_json_equals(response.content, { 'email': '*****@*****.**', 'redirect': '/?asdf' }) _get_next.assert_called_with(view.request) @patch('django_browserid.views.auth.login') def test_login_success_next(self, *args): """ If _get_next returns a URL, use it for the redirect parameter. """ view = views.Verify() view.request = self.factory.post('/') view.user = Mock(email='*****@*****.**') with patch('django_browserid.views._get_next', return_value='/?qwer') as _get_next: with patch.object(views.Verify, 'success_url', '/?asdf'): response = view.login_success() self.assert_json_equals(response.content, { 'email': '*****@*****.**', 'redirect': '/?qwer' }) _get_next.assert_called_with(view.request)
class TestSubscriptionPaymentRequired(TestCase): def setUp(self): self.settings(ROOT_URLCONF='tests.test_urls') self.factory = RequestFactory() def test_direct(self): subscription_payment_required(function=None) def test_anonymous(self): @subscription_payment_required def a_view(request): return HttpResponse() request = self.factory.get('/account/') request.user = AnonymousUser() self.assertRaises(ImproperlyConfigured, a_view, request) def test_user_unpaid(self): # create customer object with no subscription user = get_user_model().objects.create_user(username="******", email="*****@*****.**") Customer.objects.create(subscriber=user, stripe_id="cus_xxxxxxxxxxxxxxx", card_fingerprint="YYYYYYYY", card_last_4="2342", card_kind="Visa") @subscription_payment_required def a_view(request): return HttpResponse() request = self.factory.get('/account/') request.user = user response = a_view(request) self.assertEqual(response.status_code, 302) def test_user_active_subscription(self): period_start = datetime.datetime(2013, 4, 1, tzinfo=timezone.utc) period_end = datetime.datetime(2030, 4, 30, tzinfo=timezone.utc) start = datetime.datetime(2013, 1, 1, tzinfo=timezone.utc) user = get_user_model().objects.create_user(username="******", email="*****@*****.**") customer = Customer.objects.create(subscriber=user, stripe_id="cus_xxxxxxxxxxxxxxx", card_fingerprint="YYYYYYYY", card_last_4="2342", card_kind="Visa") CurrentSubscription.objects.create(customer=customer, plan="test", current_period_start=period_start, current_period_end=period_end, amount=(500 / decimal.Decimal("100.0")), status="active", start=start, quantity=1) @subscription_payment_required def a_view(request): return HttpResponse() request = self.factory.get('/account/') request.user = user response = a_view(request) self.assertEqual(response.status_code, 200)
class SubmitFeedbackViaZendeskTest(TestCase): def setUp(self): """Set up data for the test case""" self._request_factory = RequestFactory() self._anon_user = AnonymousUser() self._auth_user = UserFactory.create( email="*****@*****.**", username="******", profile__name="Test User" ) # This contains a tag to ensure that tags are submitted correctly self._anon_fields = { "email": "*****@*****.**", "name": "Test User", "subject": "a subject", "details": "some details", "tag": "a tag" } # This does not contain a tag to ensure that tag is optional self._auth_fields = {"subject": "a subject", "details": "some details"} def _test_request(self, user, fields): """ Generate a request and invoke the view, returning the response. The request will be a POST request from the given `user`, with the given `fields` in the POST body. """ req = self._request_factory.post( "/submit_feedback", data=fields, HTTP_REFERER="test_referer", HTTP_USER_AGENT="test_user_agent" ) req.user = user return views.submit_feedback_via_zendesk(req) def _assert_bad_request(self, response, field, zendesk_mock_class): """ Assert that the given `response` contains correct failure data. It should have a 400 status code, and its content should be a JSON object containing the specified `field` and an `error`. """ self.assertEqual(response.status_code, 400) resp_json = json.loads(response.content) self.assertTrue("field" in resp_json) self.assertEqual(resp_json["field"], field) self.assertTrue("error" in resp_json) # There should be absolutely no interaction with Zendesk self.assertFalse(zendesk_mock_class.return_value.mock_calls) def _test_bad_request_omit_field(self, user, fields, omit_field, zendesk_mock_class): """ Invoke the view with a request missing a field and assert correctness. The request will be a POST request from the given `user`, with POST fields taken from `fields` minus the entry specified by `omit_field`. The response should have a 400 (bad request) status code and specify the invalid field and an error message, and the Zendesk API should not have been invoked. """ filtered_fields = {k: v for (k, v) in fields.items() if k != omit_field} resp = self._test_request(user, filtered_fields) self._assert_bad_request(resp, omit_field, zendesk_mock_class) def _test_bad_request_empty_field(self, user, fields, empty_field, zendesk_mock_class): """ Invoke the view with an empty field and assert correctness. The request will be a POST request from the given `user`, with POST fields taken from `fields`, replacing the entry specified by `empty_field` with the empty string. The response should have a 400 (bad request) status code and specify the invalid field and an error message, and the Zendesk API should not have been invoked. """ altered_fields = fields.copy() altered_fields[empty_field] = "" resp = self._test_request(user, altered_fields) self._assert_bad_request(resp, empty_field, zendesk_mock_class) def _test_success(self, user, fields): """ Generate a request, invoke the view, and assert success. The request will be a POST request from the given `user`, with the given `fields` in the POST body. The response should have a 200 (success) status code. """ resp = self._test_request(user, fields) self.assertEqual(resp.status_code, 200) def test_bad_request_anon_user_no_name(self, zendesk_mock_class): """Test a request from an anonymous user not specifying `name`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "name", zendesk_mock_class) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "name", zendesk_mock_class) def test_bad_request_anon_user_no_email(self, zendesk_mock_class): """Test a request from an anonymous user not specifying `email`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "email", zendesk_mock_class) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "email", zendesk_mock_class) def test_bad_request_anon_user_no_subject(self, zendesk_mock_class): """Test a request from an anonymous user not specifying `subject`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "subject", zendesk_mock_class) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "subject", zendesk_mock_class) def test_bad_request_anon_user_no_details(self, zendesk_mock_class): """Test a request from an anonymous user not specifying `details`.""" self._test_bad_request_omit_field(self._anon_user, self._anon_fields, "details", zendesk_mock_class) self._test_bad_request_empty_field(self._anon_user, self._anon_fields, "details", zendesk_mock_class) def test_valid_request_anon_user(self, zendesk_mock_class): """ Test a valid request from an anonymous user. The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API. """ zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.create_ticket.return_value = 42 self._test_success(self._anon_user, self._anon_fields) expected_calls = [ mock.call.create_ticket( { "ticket": { "requester": {"name": "Test User", "email": "*****@*****.**"}, "subject": "a subject", "comment": {"body": "some details"}, "tags": ["a tag"] } } ), mock.call.update_ticket( 42, { "ticket": { "comment": { "public": False, "body": "Additional information:\n\n" "HTTP_USER_AGENT: test_user_agent\n" "HTTP_REFERER: test_referer" } } } ) ] self.assertEqual(zendesk_mock_instance.mock_calls, expected_calls) def test_bad_request_auth_user_no_subject(self, zendesk_mock_class): """Test a request from an authenticated user not specifying `subject`.""" self._test_bad_request_omit_field(self._auth_user, self._auth_fields, "subject", zendesk_mock_class) self._test_bad_request_empty_field(self._auth_user, self._auth_fields, "subject", zendesk_mock_class) def test_bad_request_auth_user_no_details(self, zendesk_mock_class): """Test a request from an authenticated user not specifying `details`.""" self._test_bad_request_omit_field(self._auth_user, self._auth_fields, "details", zendesk_mock_class) self._test_bad_request_empty_field(self._auth_user, self._auth_fields, "details", zendesk_mock_class) def test_valid_request_auth_user(self, zendesk_mock_class): """ Test a valid request from an authenticated user. The response should have a 200 (success) status code, and a ticket with the given information should have been submitted via the Zendesk API. """ zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.create_ticket.return_value = 42 self._test_success(self._auth_user, self._auth_fields) expected_calls = [ mock.call.create_ticket( { "ticket": { "requester": {"name": "Test User", "email": "*****@*****.**"}, "subject": "a subject", "comment": {"body": "some details"}, "tags": [] } } ), mock.call.update_ticket( 42, { "ticket": { "comment": { "public": False, "body": "Additional information:\n\n" "username: test\n" "HTTP_USER_AGENT: test_user_agent\n" "HTTP_REFERER: test_referer" } } } ) ] self.assertEqual(zendesk_mock_instance.mock_calls, expected_calls) def test_get_request(self, zendesk_mock_class): """Test that a GET results in a 405 even with all required fields""" req = self._request_factory.get("/submit_feedback", data=self._anon_fields) req.user = self._anon_user resp = views.submit_feedback_via_zendesk(req) self.assertEqual(resp.status_code, 405) self.assertIn("Allow", resp) self.assertEqual(resp["Allow"], "POST") # There should be absolutely no interaction with Zendesk self.assertFalse(zendesk_mock_class.mock_calls) def test_zendesk_error_on_create(self, zendesk_mock_class): """ Test Zendesk returning an error on ticket creation. We should return a 500 error with no body """ err = ZendeskError(msg="", error_code=404) zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.create_ticket.side_effect = err resp = self._test_request(self._anon_user, self._anon_fields) self.assertEqual(resp.status_code, 500) self.assertFalse(resp.content) def test_zendesk_error_on_update(self, zendesk_mock_class): """ Test for Zendesk returning an error on ticket update. If Zendesk returns any error on ticket update, we return a 200 to the browser because the update contains additional information that is not necessary for the user to have submitted their feedback. """ err = ZendeskError(msg="", error_code=500) zendesk_mock_instance = zendesk_mock_class.return_value zendesk_mock_instance.update_ticket.side_effect = err resp = self._test_request(self._anon_user, self._anon_fields) self.assertEqual(resp.status_code, 200) @mock.patch.dict("django.conf.settings.MITX_FEATURES", {"ENABLE_FEEDBACK_SUBMISSION": False}) def test_not_enabled(self, zendesk_mock_class): """ Test for Zendesk submission not enabled in `settings`. We should raise Http404. """ with self.assertRaises(Http404): self._test_request(self._anon_user, self._anon_fields) def test_zendesk_not_configured(self, zendesk_mock_class): """ Test for Zendesk not fully configured in `settings`. For each required configuration parameter, test that setting it to `None` causes an otherwise valid request to return a 500 error. """ def test_case(missing_config): with mock.patch(missing_config, None): with self.assertRaises(Exception): self._test_request(self._anon_user, self._anon_fields) test_case("django.conf.settings.ZENDESK_URL") test_case("django.conf.settings.ZENDESK_USER") test_case("django.conf.settings.ZENDESK_API_KEY")
class TestPrefixer(TestCase): def setUp(self): self.factory = RequestFactory() @override_settings(LANGUAGE_CODE='en-US') def test_get_language_default_language_code(self): """ Should return default set by settings.LANGUAGE_CODE if no 'lang' url parameter and no Accept-Language header """ request = self.factory.get('/') self.assertFalse('lang' in request.GET) self.assertFalse(request.META.get('HTTP_ACCEPT_LANGUAGE')) prefixer = Prefixer(request) eq_(prefixer.get_language(), 'en-US') @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US', 'de': 'de'}) def test_get_language_valid_lang_param(self): """ Should return lang param value if it is in settings.LANGUAGE_URL_MAP """ request = self.factory.get('/?lang=de') eq_(request.GET.get('lang'), 'de') ok_('de' in settings.LANGUAGE_URL_MAP) prefixer = Prefixer(request) eq_(prefixer.get_language(), 'de') @override_settings(LANGUAGE_CODE='en-US', LANGUAGE_URL_MAP={'en-us': 'en-US'}) def test_get_language_invalid_lang_param(self): """ Should return default set by settings.LANGUAGE_CODE if lang param value is not in settings.LANGUAGE_URL_MAP """ request = self.factory.get('/?lang=de') ok_('lang' in request.GET) self.assertFalse('de' in settings.LANGUAGE_URL_MAP) prefixer = Prefixer(request) eq_(prefixer.get_language(), 'en-US') def test_get_language_returns_best(self): """ Should pass Accept-Language header value to get_best_language and return result """ request = self.factory.get('/') request.META['HTTP_ACCEPT_LANGUAGE'] = 'de, es' prefixer = Prefixer(request) prefixer.get_best_language = Mock(return_value='de') eq_(prefixer.get_language(), 'de') prefixer.get_best_language.assert_called_once_with('de, es') @override_settings(LANGUAGE_CODE='en-US') def test_get_language_no_best(self): """ Should return default set by settings.LANGUAGE_CODE if get_best_language return value is None """ request = self.factory.get('/') request.META['HTTP_ACCEPT_LANGUAGE'] = 'de, es' prefixer = Prefixer(request) prefixer.get_best_language = Mock(return_value=None) eq_(prefixer.get_language(), 'en-US') prefixer.get_best_language.assert_called_once_with('de, es') @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US', 'de': 'de'}) def test_get_best_language_exact_match(self): """ Should return exact match if it is in settings.LANGUAGE_URL_MAP """ request = self.factory.get('/') prefixer = Prefixer(request) eq_(prefixer.get_best_language('de, es'), 'de') @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US', 'es-ar': 'es-AR'}) def test_get_best_language_prefix_match(self): """ Should return a language with a matching prefix from settings.LANGUAGE_URL_MAP if it exists but no exact match does """ request = self.factory.get('/') prefixer = Prefixer(request) eq_(prefixer.get_best_language('es-CL'), 'es-AR') @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US'}) def test_get_best_language_no_match(self): """ Should return None if there is no exact match or matching prefix """ request = self.factory.get('/') prefixer = Prefixer(request) eq_(prefixer.get_best_language('de'), None) @override_settings(LANGUAGE_URL_MAP={'en-us': 'en-US'}) def test_get_best_language_handles_parse_accept_lang_header_error(self): """ Should return None despite error raised by bug described in https://code.djangoproject.com/ticket/21078 """ request = self.factory.get('/') prefixer = Prefixer(request) eq_(prefixer.get_best_language('en; q=1,'), None)
class BaseDueDateTests(ModuleStoreTestCase): """ Base class that verifies that due dates are rendered correctly on a page """ __test__ = False def get_text(self, course): # pylint: disable=unused-argument """Return the rendered text for the page to be verified""" raise NotImplementedError def set_up_course(self, **course_kwargs): """ Create a stock course with a specific due date. :param course_kwargs: All kwargs are passed to through to the :class:`CourseFactory` """ course = CourseFactory.create(**course_kwargs) chapter = ItemFactory.create(category='chapter', parent_location=course.location) section = ItemFactory.create(category='sequential', parent_location=chapter.location, due=datetime(2013, 9, 18, 11, 30, 00)) vertical = ItemFactory.create(category='vertical', parent_location=section.location) ItemFactory.create(category='problem', parent_location=vertical.location) course = modulestore().get_course(course.id) self.assertIsNotNone(course.get_children()[0].get_children()[0].due) CourseEnrollmentFactory(user=self.user, course_id=course.id) return course def setUp(self): super(BaseDueDateTests, self).setUp() self.request_factory = RequestFactory() self.user = UserFactory.create() self.request = self.request_factory.get("foo") self.request.user = self.user self.time_with_tz = "due Sep 18, 2013 at 11:30 UTC" self.time_without_tz = "due Sep 18, 2013 at 11:30" def test_backwards_compatability(self): # The test course being used has show_timezone = False in the policy file # (and no due_date_display_format set). This is to test our backwards compatibility-- # in course_module's init method, the date_display_format will be set accordingly to # remove the timezone. course = self.set_up_course(due_date_display_format=None, show_timezone=False) text = self.get_text(course) self.assertIn(self.time_without_tz, text) self.assertNotIn(self.time_with_tz, text) # Test that show_timezone has been cleared (which means you get the default value of True). self.assertTrue(course.show_timezone) def test_defaults(self): course = self.set_up_course() text = self.get_text(course) self.assertIn(self.time_with_tz, text) def test_format_none(self): # Same for setting the due date to None course = self.set_up_course(due_date_display_format=None) text = self.get_text(course) self.assertIn(self.time_with_tz, text) def test_format_plain_text(self): # plain text due date course = self.set_up_course(due_date_display_format="foobar") text = self.get_text(course) self.assertNotIn(self.time_with_tz, text) self.assertIn("due foobar", text) def test_format_date(self): # due date with no time course = self.set_up_course(due_date_display_format=u"%b %d %y") text = self.get_text(course) self.assertNotIn(self.time_with_tz, text) self.assertIn("due Sep 18 13", text) def test_format_hidden(self): # hide due date completely course = self.set_up_course(due_date_display_format=u"") text = self.get_text(course) self.assertNotIn("due ", text) def test_format_invalid(self): # improperly formatted due_date_display_format falls through to default # (value of show_timezone does not matter-- setting to False to make that clear). course = self.set_up_course(due_date_display_format=u"%%%", show_timezone=False) text = self.get_text(course) self.assertNotIn("%%%", text) self.assertIn(self.time_with_tz, text)
class SignUpTests(TestCase): """ Tests signup functionality. """ def setUp(self): # By default it will end-up being '*' which breaks multitier tests. settings.ALLOWED_HOSTS = ('localhost',) # Every test needs access to the request factory. self.factory = RequestFactory() def test_redirect_ok(self): """ Tests to validate the redirect URL. """ request = self.factory.get('/?next=/example/') url = validate_redirect(request) self.assertTrue(url == "/example/") def test_redirect_fail1(self): """ Tests to validate the redirect URL. """ request = self.factory.get('/?next=http://example.com/example/') url = validate_redirect(request) if '*' in settings.ALLOWED_HOSTS: self.assertTrue(url == "/example/") else: self.assertTrue(url is None) def test_redirect_url_ok(self): """ Tests to validate the redirect URL. """ url = validate_redirect_url("/example/") self.assertTrue(url == "/example/") def test_redirect_url_fail1(self): """ Tests to validate the redirect URL. """ url = validate_redirect_url("http://example.com/example/") if '*' in settings.ALLOWED_HOSTS: self.assertTrue(url == "/example/") else: self.assertTrue(url is None) def test_activate_password(self): user = ActivatedUser.objects.create_inactive_user(REGISTRATION_EMAIL) client = Client() response = client.get(reverse('registration_activate', args=(user.email_verification_key,)), follow=True) # pylint: disable=maybe-no-member self.assertTrue(response.status_code == 200) self.assertTrue(re.match( r'\S+/accounts/activate/(?P<verification_key>%s)/password/(?P<token>.+)/$' % signup_settings.EMAIL_VERIFICATION_PAT, response.redirect_chain[-1][0])) def test_register(self): client = Client() response = client.post(reverse('registration_register'), {'full_name': 'John Smith', 'email': REGISTRATION_EMAIL}, follow=True) # XXX Haven't found out how to get this assertion to pass, # status_code 302 vs 200 expected. # self.assertRedirects(response, settings.LOGIN_REDIRECT_URL) self.assertTrue(re.match(r'\S+/app/[\w.@+-]+/', response.redirect_chain[-1][0]))
class TestNewslettersAPI(TestCase): def setUp(self): self.url = reverse('newsletters_api') self.rf = RequestFactory() def test_newsletters_view(self): # We can fetch the newsletter data nl1 = models.Newsletter.objects.create( slug='slug', title='title', active=False, languages='en-US,fr', vendor_id='VENDOR1', ) models.Newsletter.objects.create(slug='slug2', vendor_id='VENDOR2') models.Newsletter.objects.create(slug='slug3', vendor_id='VENDOR3', private=True) req = self.rf.get(self.url) resp = views.newsletters(req) data = json.loads(resp.content) newsletters = data['newsletters'] self.assertEqual(3, len(newsletters)) # Find the 'slug' newsletter in the response obj = newsletters['slug'] self.assertTrue(newsletters['slug3']['private']) self.assertEqual(nl1.title, obj['title']) self.assertEqual(nl1.active, obj['active']) for lang in ['en-US', 'fr']: self.assertIn(lang, obj['languages']) def test_strip_languages(self): # If someone edits Newsletter and puts whitespace in the languages # field, we strip it on save nl1 = models.Newsletter.objects.create( slug='slug', title='title', active=False, languages='en-US, fr, de ', vendor_id='VENDOR1', ) nl1 = models.Newsletter.objects.get(id=nl1.id) self.assertEqual('en-US,fr,de', nl1.languages) def test_newsletter_languages(self): # newsletter_languages() returns the set of languages # of the newsletters # (Note that newsletter_languages() is not part of the external # API, but is used internally) models.Newsletter.objects.create( slug='slug', title='title', active=False, languages='en-US', vendor_id='VENDOR1', ) models.Newsletter.objects.create( slug='slug2', title='title', active=False, languages='fr, de ', vendor_id='VENDOR2', ) models.Newsletter.objects.create( slug='slug3', title='title', active=False, languages='en-US, fr', vendor_id='VENDOR3', ) expect = set(['en-US', 'fr', 'de']) self.assertEqual(expect, newsletter_languages()) def test_newsletters_cached(self): models.Newsletter.objects.create( slug='slug', title='title', vendor_id='VEND1', active=False, languages='en-US, fr, de ', ) # This should get the data cached newsletter_fields() # Now request it again and it shouldn't have to generate the # data from scratch. with patch('basket.news.newsletters._get_newsletters_data') as get: newsletter_fields() self.assertFalse(get.called) def test_cache_clearing(self): # Our caching of newsletter data doesn't result in wrong answers # when newsletters change models.Newsletter.objects.create( slug='slug', title='title', vendor_id='VEND1', active=False, languages='en-US, fr, de ', ) vendor_ids = newsletter_fields() self.assertEqual([u'VEND1'], vendor_ids) # Now add another newsletter models.Newsletter.objects.create( slug='slug2', title='title2', vendor_id='VEND2', active=False, languages='en-US, fr, de ', ) vendor_ids2 = set(newsletter_fields()) self.assertEqual(set([u'VEND1', u'VEND2']), vendor_ids2) def test_cache_clear_on_delete(self): # Our caching of newsletter data doesn't result in wrong answers # when newsletters are deleted nl1 = models.Newsletter.objects.create( slug='slug', title='title', vendor_id='VEND1', active=False, languages='en-US, fr, de ', ) vendor_ids = newsletter_fields() self.assertEqual([u'VEND1'], vendor_ids) # Now delete it nl1.delete() vendor_ids = newsletter_fields() self.assertEqual([], vendor_ids)
class ProgressPageTests(ModuleStoreTestCase): """ Tests that verify that the progress page works correctly. """ def setUp(self): super(ProgressPageTests, self).setUp() self.request_factory = RequestFactory() self.user = UserFactory.create() self.request = self.request_factory.get("foo") self.request.user = self.user mako_middleware_process_request(self.request) self.setup_course() def setup_course(self, **options): """Create the test course.""" course = CourseFactory.create( start=datetime(2013, 9, 16, 7, 17, 28), grade_cutoffs={u'çü†øƒƒ': 0.75, 'Pass': 0.5}, **options ) # pylint: disable=attribute-defined-outside-init self.course = modulestore().get_course(course.id) CourseEnrollmentFactory(user=self.user, course_id=self.course.id) self.chapter = ItemFactory.create(category='chapter', parent_location=self.course.location) self.section = ItemFactory.create(category='sequential', parent_location=self.chapter.location) self.vertical = ItemFactory.create(category='vertical', parent_location=self.section.location) @ddt.data('"><script>alert(1)</script>', '<script>alert(1)</script>', '</script><script>alert(1)</script>') def test_progress_page_xss_prevent(self, malicious_code): """ Test that XSS attack is prevented """ resp = views.progress(self.request, course_id=unicode(self.course.id), student_id=self.user.id) self.assertEqual(resp.status_code, 200) # Test that malicious code does not appear in html self.assertNotIn(malicious_code, resp.content) def test_pure_ungraded_xblock(self): ItemFactory.create(category='acid', parent_location=self.vertical.location) resp = views.progress(self.request, course_id=self.course.id.to_deprecated_string()) self.assertEqual(resp.status_code, 200) @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) def test_student_progress_with_valid_and_invalid_id(self, default_store): """ Check that invalid 'student_id' raises Http404 for both old mongo and split mongo courses. """ # Create new course with respect to 'default_store' self.course = CourseFactory.create(default_store=default_store) # Invalid Student Ids (Integer and Non-int) invalid_student_ids = [ 991021, 'azU3N_8$', ] for invalid_id in invalid_student_ids: self.assertRaises( Http404, views.progress, self.request, course_id=unicode(self.course.id), student_id=invalid_id ) # Enroll student into course CourseEnrollment.enroll(self.user, self.course.id, mode='honor') resp = views.progress(self.request, course_id=self.course.id.to_deprecated_string(), student_id=self.user.id) # Assert that valid 'student_id' returns 200 status self.assertEqual(resp.status_code, 200) def test_non_asci_grade_cutoffs(self): resp = views.progress(self.request, course_id=self.course.id.to_deprecated_string()) self.assertEqual(resp.status_code, 200) def test_generate_cert_config(self): resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertNotContains(resp, 'Request Certificate') # Enable the feature, but do not enable it for this course CertificateGenerationConfiguration(enabled=True).save() resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertNotContains(resp, 'Request Certificate') # Enable certificate generation for this course certs_api.set_cert_generation_enabled(self.course.id, True) resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertNotContains(resp, 'Request Certificate') @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': True}) @patch('courseware.grades.grade', Mock(return_value={'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': []})) def test_view_certificate_link(self): """ If certificate web view is enabled then certificate web view button should appear for user who certificate is available/generated """ certificate = GeneratedCertificateFactory.create( user=self.user, course_id=self.course.id, status=CertificateStatuses.downloadable, download_url="http://www.example.com/certificate.pdf", mode='honor' ) # Enable the feature, but do not enable it for this course CertificateGenerationConfiguration(enabled=True).save() # Enable certificate generation for this course certs_api.set_cert_generation_enabled(self.course.id, True) #course certificate configurations certificates = [ { 'id': 1, 'name': 'Name 1', 'description': 'Description 1', 'course_title': 'course_title_1', 'signatories': [], 'version': 1, 'is_active': True } ] self.course.certificates = {'certificates': certificates} self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertContains(resp, u"View Certificate") self.assertContains(resp, u"You can keep working for a higher grade") cert_url = certs_api.get_certificate_url( user_id=self.user.id, course_id=self.course.id ) self.assertContains(resp, cert_url) # when course certificate is not active certificates[0]['is_active'] = False self.store.update_item(self.course, self.user.id) resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertNotContains(resp, u"View Your Certificate") self.assertNotContains(resp, u"You can now view your certificate") self.assertContains(resp, u"We're creating your certificate.") @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': False}) @patch('courseware.grades.grade', Mock(return_value={'grade': 'Pass', 'percent': 0.75, 'section_breakdown': [], 'grade_breakdown': []})) def test_view_certificate_link_hidden(self): """ If certificate web view is disabled then certificate web view button should not appear for user who certificate is available/generated """ GeneratedCertificateFactory.create( user=self.user, course_id=self.course.id, status=CertificateStatuses.downloadable, download_url="http://www.example.com/certificate.pdf", mode='honor' ) # Enable the feature, but do not enable it for this course CertificateGenerationConfiguration(enabled=True).save() # Enable certificate generation for this course certs_api.set_cert_generation_enabled(self.course.id, True) resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertContains(resp, u"Download Your Certificate") @ddt.data( *itertools.product(((18, 4, True), (18, 4, False)), (True, False)) ) @ddt.unpack def test_query_counts(self, (sql_calls, mongo_calls, self_paced), self_paced_enabled): """Test that query counts remain the same for self-paced and instructor-paced courses.""" SelfPacedConfiguration(enabled=self_paced_enabled).save() self.setup_course(self_paced=self_paced) with self.assertNumQueries(sql_calls), check_mongo_calls(mongo_calls): resp = views.progress(self.request, course_id=unicode(self.course.id)) self.assertEqual(resp.status_code, 200)
class ProyectosTest(TestCase): """ Clase que realiza el Test del modulo de administracion de proyectos """ def setUp(self): """ Funcion que inicializa el RequestFactory y un usuario de prueba para realizar los test """ # Se crea el Request factory pars simular peticiones self.factory = RequestFactory() # Se crea el User que realiza las peticiones self.user = User.objects.create_user(username='******', email='*****@*****.**', password='******') def test_view_IndexView(self): """ Funcion que realiza el test sobre la vista UserIndexView que genera lista de proyectos """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') # se crean 10 proyectos para controlar que se retorne la lista completa de proyectos, que seran 11 en total for i in range(10): proyecto = Proyecto.objects.create(codigo='co%s' % i, nombre_corto='test%s' % i, nombre_largo='test%s' % i, cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get('/proyectos/') view = IndexView.as_view() response = view(request) self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name[0], 'proyectos/index.html') # verificamos los proyectos retornados self.assertEqual(len(response.context_data['object_list']), 10) print 'Test de IndexView de Proyecto realizado exitosamente' def test_view_ProyectoCreate(self): """ Funcion que realiza el test sobre la vista ProyectoCreate que crea un nuevo proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user3 = User.objects.create_user(username='******', email='*****@*****.**', password='******') # se crea un proyecto proyecto = Proyecto.objects.create(codigo='codi', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user3) self.assertEqual(proyecto.codigo, 'codi') self.assertEqual(proyecto.nombre_corto, 'test') print 'Test de ProyectoCreate realizado exitosamente' def test_view_ProyectoUpdate(self): """ Funcion que realiza el test sobre la vista ProyectoUpdate que modifica un proyecto existente """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user4 = User.objects.create_user(username='******', email='*****@*****.**', password='******') # se crea un proyecto proyecto = Proyecto.objects.create(codigo='codi', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user4) # se crean nuevos valores para los atributos nuevo_codigo = 'new' new_nombre = 'Hola' # Se modifican los atributos del proyecto proyecto.codigo = nuevo_codigo proyecto.nombre_corto = new_nombre proyecto.save() self.assertEqual(proyecto.codigo, 'new') self.assertEqual(proyecto.nombre_corto, 'Hola') print 'Test de ProyectoUpdate realizado exitosamente' def test_view_cancelar_proyecto(self): """ Funcion que realiza el test sobre la vista cancelar_proyecto que cambia el estado de un proyecto a cancelado """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user5 = User.objects.create_user(username='******', email='*****@*****.**', password='******') # se crea un proyecto proyecto = Proyecto.objects.create(codigo='codi', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user5) # se marca al proyecto proyecto.cancelado = True proyecto.save() self.assertEqual(proyecto.cancelado, True) print 'Test de cancelarProyecto realizado exitosamente' def test_view_proyecto_index(self): """ Funcion que realiza el test sobre la vista proyecto_index que genera el index del proyecto seleccionado """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:proyecto_index', args=[proyecto.pk])) request.user = self.user view = proyecto_index response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_index realizado exitosamente' def test_view_listar_equipo(self): """ Funcion que realiza el test sobre la vista listar_equipo que genera lista de usuarios que se encuentran en el equipo del proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') lista_usuarios = [] for i in range(10): user = User.objects.create_user(username='******' % i, email='*****@*****.**' % i, password='******') user.save() lista_usuarios.append(user) proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) proyecto.equipo = lista_usuarios proyecto.save() cantidad = len(lista_usuarios) cantidad_equipo = proyecto.equipo.all().count() self.assertEqual(cantidad_equipo, cantidad) print 'Test de listar_equipo realizado exitosamente' def test_view_AddMiembro(self): """ Funcion que realiza el test sobre la vista AddMiembro que agrega un usuario al equipo del proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') lista_usuarios = [] for i in range(10): user = User.objects.create_user(username='******' % i, email='*****@*****.**' % i, password='******') user.save() lista_usuarios.append(user) proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) proyecto.equipo = lista_usuarios proyecto.save() user_nuevo = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto.equipo.add(user_nuevo) proyecto.save() lista_usuarios.append(user_nuevo) cantidad = len(lista_usuarios) cantidad_equipo = proyecto.equipo.all().count() self.assertEqual(cantidad_equipo, cantidad) print 'Test de AddMiembro realizado exitosamente' def test_view_delete_miembro(self): """ Funcion que realiza el test sobre la vista delete_miembro que elimina un usuario del equipo del proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') lista_usuarios = [] for i in range(10): user = User.objects.create_user(username='******' % i, email='*****@*****.**' % i, password='******') user.save() lista_usuarios.append(user) proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) proyecto.equipo = lista_usuarios proyecto.save() user_eliminar = User.objects.get(username='******') proyecto.equipo.remove(user_eliminar) proyecto.save() lista_usuarios.remove(user_eliminar) cantidad = len(lista_usuarios) cantidad_equipo = proyecto.equipo.all().count() self.assertEqual(cantidad_equipo, cantidad) print 'Test de delete_miembro realizado exitosamente' def test_view_proyecto_reportes(self): """ Funcion que realiza el test sobre la vista proyecto_reportes que genera el index de los reportes del proyecto seleccionado """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:proyecto_reportes', args=[proyecto.pk])) request.user = self.user view = proyecto_reportes response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_reportes realizado exitosamente' def test_view_proyecto_reporte_trabajos_equipo(self): """ Funcion que realiza el test sobre la vista proyecto_reporte_trabajos_equipo que genera el reporte de los trabajos realizados por cada equipo """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:reporte_trabajo_equipo', args=[proyecto.pk])) request.user = self.user view = proyecto_reporte_trabajos_equipo response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_reporte_trabajos_equipo realizado exitosamente' def test_view_reporte_grafico_reportlab(self): """ Funcion que realiza el test sobre la vista reporte_grafico_reportlab que genera el reporte de los burndown_chart de los sprints """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:reporte_grafico_sprints', args=[proyecto.pk])) request.user = self.user view = reporte_grafico_reportlab response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de reporte_grafico_reportlab realizado exitosamente' def test_view_proyecto_reporte_trabajos_usuario(self): """ Funcion que realiza el test sobre la vista proyecto_reporte_trabajos_usuario que genera el reporte de los trabajos realizados por cada usuario """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) for i in range(10): sprint_s = Sprint.objects.create(nombre='sprint%s' % i, duracion='%d' % i, proyecto=proyecto, estado='Activo') sprint_s.save() sprint = Sprint.objects.filter(estado='Activo') group = Group.objects.create(name='Developer') group.save() rolProyecto = RolProyecto(group=group, es_rol_proyecto=True) rolProyecto.save() row_rol = RolProyecto_Proyecto(user=self.user, rol_proyecto=rolProyecto, proyecto=proyecto) row_rol.save() # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:reporte_trabajo_usuario', args=[proyecto.pk])) request.user = self.user view = proyecto_reporte_trabajos_usuario response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_reporte_trabajos_usuario realizado exitosamente' def test_view_proyecto_reporte_actividades(self): """ Funcion que realiza el test sobre la vista proyecto_reporte_actividades que genera el reporte de las actividades a realizar en el proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:proyecto_reporte_actividades', args=[proyecto.pk])) request.user = self.user view = proyecto_reporte_actividades response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_reporte_actividades realizado exitosamente' def test_view_proyecto_reporte_product_backlog(self): """ Funcion que realiza el test sobre la vista proyecto_reporte_product_backlog que genera el reporte de los user stories del product backlog del proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:proyecto_reporte_product_backlog', args=[proyecto.pk])) request.user = self.user view = proyecto_reporte_product_backlog response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_reporte_product_backlog realizado exitosamente' def test_view_proyecto_reporte_sprint_backlog(self): """ Funcion que realiza el test sobre la vista proyecto_reporte_sprint_backlog que genera el reporte de los user stories del sprint backlog del sprint actual """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user2 = User.objects.create_user(username='******', email='*****@*****.**', password='******') proyecto = Proyecto.objects.create(codigo='co', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user2) for i in range(10): sprint_s = Sprint.objects.create(nombre='sprint%s' % i, duracion='%d' % i, proyecto=proyecto, estado='Activo') sprint_s.save() sprint = Sprint.objects.filter(estado='Activo') # verificamos que la vista devuelva el template adecuado request = self.factory.get( reverse('proyectos:proyecto_reporte_sprint_backlog', args=[proyecto.pk])) request.user = self.user view = proyecto_reporte_sprint_backlog response = view(request, pk=proyecto.pk) self.assertEqual(response.status_code, 200) print 'Test de proyecto_reporte_sprint_backlog realizado exitosamente' def test_view_iniciar_proyecto(self): """ Funcion que realiza el test sobre la vista iniciar_proyecto que inicia el proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user3 = User.objects.create_user(username='******', email='*****@*****.**', password='******') # se crea un proyecto proyecto = Proyecto.objects.create(codigo='codi', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user3) proyecto.save() proyecto.estado = "Activo" proyecto.save() self.assertEqual(proyecto.codigo, 'codi') self.assertEqual(proyecto.nombre_corto, 'test') self.assertEqual(proyecto.estado, 'Activo') print 'Test de iniciar_proyecto realizado exitosamente' def test_view_finalizar_proyecto(self): """ Funcion que realiza el test sobre la vista finalizar_proyecto que inicia el proyecto """ # se loguea el usuario testuser user = self.client.login(username='******', password='******') self.assertTrue(user) user3 = User.objects.create_user(username='******', email='*****@*****.**', password='******') # se crea un proyecto proyecto = Proyecto.objects.create(codigo='codi', nombre_corto='test', nombre_largo='test', cancelado=False, scrum_master=user3) proyecto.save() proyecto.estado = "Finalizado" proyecto.save() self.assertEqual(proyecto.codigo, 'codi') self.assertEqual(proyecto.nombre_corto, 'test') self.assertEqual(proyecto.estado, 'Finalizado') print 'Test de finalizar_proyecto realizado exitosamente'
class ViewsTestCase(ModuleStoreTestCase): """ Tests for views.py methods. """ def setUp(self): super(ViewsTestCase, self).setUp() self.course = CourseFactory.create() self.chapter = ItemFactory.create(category='chapter', parent_location=self.course.location) self.section = ItemFactory.create(category='sequential', parent_location=self.chapter.location, due=datetime(2013, 9, 18, 11, 30, 00)) self.vertical = ItemFactory.create(category='vertical', parent_location=self.section.location) self.component = ItemFactory.create(category='problem', parent_location=self.vertical.location) self.course_key = self.course.id self.user = UserFactory(username='******', password='******', email='*****@*****.**') self.date = datetime(2013, 1, 22, tzinfo=UTC) self.enrollment = CourseEnrollment.enroll(self.user, self.course_key) self.enrollment.created = self.date self.enrollment.save() self.request_factory = RequestFactory() chapter = 'Overview' self.chapter_url = '%s/%s/%s' % ('/courses', self.course_key, chapter) self.org = u"ꜱᴛᴀʀᴋ ɪɴᴅᴜꜱᴛʀɪᴇꜱ" self.org_html = "<p>'+Stark/Industries+'</p>" @unittest.skipUnless(settings.FEATURES.get('ENABLE_SHOPPING_CART'), "Shopping Cart not enabled in settings") @patch.dict(settings.FEATURES, {'ENABLE_PAID_COURSE_REGISTRATION': True}) def test_course_about_in_cart(self): in_cart_span = '<span class="add-to-cart">' # don't mock this course due to shopping cart existence checking course = CourseFactory.create(org="new", number="unenrolled", display_name="course") request = self.request_factory.get(reverse('about_course', args=[course.id.to_deprecated_string()])) request.user = AnonymousUser() mako_middleware_process_request(request) response = views.course_about(request, course.id.to_deprecated_string()) self.assertEqual(response.status_code, 200) self.assertNotIn(in_cart_span, response.content) # authenticated user with nothing in cart request.user = self.user response = views.course_about(request, course.id.to_deprecated_string()) self.assertEqual(response.status_code, 200) self.assertNotIn(in_cart_span, response.content) # now add the course to the cart cart = shoppingcart.models.Order.get_cart_for_user(self.user) shoppingcart.models.PaidCourseRegistration.add_to_order(cart, course.id) response = views.course_about(request, course.id.to_deprecated_string()) self.assertEqual(response.status_code, 200) self.assertIn(in_cart_span, response.content) def test_user_groups(self): # depreciated function mock_user = MagicMock() mock_user.is_authenticated.return_value = False self.assertEqual(views.user_groups(mock_user), []) def test_get_current_child(self): self.assertIsNone(views.get_current_child(MagicMock())) mock_xmodule = MagicMock() mock_xmodule.position = -1 mock_xmodule.get_display_items.return_value = ['one', 'two'] self.assertEqual(views.get_current_child(mock_xmodule), 'one') mock_xmodule_2 = MagicMock() mock_xmodule_2.position = 3 mock_xmodule_2.get_display_items.return_value = [] self.assertIsNone(views.get_current_child(mock_xmodule_2)) def test_redirect_to_course_position(self): mock_module = MagicMock() mock_module.descriptor.id = 'Underwater Basketweaving' mock_module.position = 3 mock_module.get_display_items.return_value = [] self.assertRaises(Http404, views.redirect_to_course_position, mock_module, views.CONTENT_DEPTH) def test_invalid_course_id(self): response = self.client.get('/courses/MITx/3.091X/') self.assertEqual(response.status_code, 404) def test_incomplete_course_id(self): response = self.client.get('/courses/MITx/') self.assertEqual(response.status_code, 404) def test_index_invalid_position(self): request_url = '/'.join([ '/courses', self.course.id.to_deprecated_string(), 'courseware', self.chapter.location.name, self.section.location.name, 'f' ]) self.client.login(username=self.user.username, password="******") response = self.client.get(request_url) self.assertEqual(response.status_code, 404) def test_unicode_handling_in_url(self): url_parts = [ '/courses', self.course.id.to_deprecated_string(), 'courseware', self.chapter.location.name, self.section.location.name, '1' ] self.client.login(username=self.user.username, password="******") for idx, val in enumerate(url_parts): url_parts_copy = url_parts[:] url_parts_copy[idx] = val + u'χ' request_url = '/'.join(url_parts_copy) response = self.client.get(request_url) self.assertEqual(response.status_code, 404) def test_registered_for_course(self): self.assertFalse(views.registered_for_course('Basketweaving', None)) mock_user = MagicMock() mock_user.is_authenticated.return_value = False self.assertFalse(views.registered_for_course('dummy', mock_user)) mock_course = MagicMock() mock_course.id = self.course_key self.assertTrue(views.registered_for_course(mock_course, self.user)) @override_settings(PAID_COURSE_REGISTRATION_CURRENCY=["USD", "$"]) def test_get_cosmetic_display_price(self): """ Check that get_cosmetic_display_price() returns the correct price given its inputs. """ registration_price = 99 self.course.cosmetic_display_price = 10 # Since registration_price is set, it overrides the cosmetic_display_price and should be returned self.assertEqual(views.get_cosmetic_display_price(self.course, registration_price), "$99") registration_price = 0 # Since registration_price is not set, cosmetic_display_price should be returned self.assertEqual(views.get_cosmetic_display_price(self.course, registration_price), "$10") self.course.cosmetic_display_price = 0 # Since both prices are not set, there is no price, thus "Free" self.assertEqual(views.get_cosmetic_display_price(self.course, registration_price), "Free") def test_jump_to_invalid(self): # TODO add a test for invalid location # TODO add a test for no data * request = self.request_factory.get(self.chapter_url) self.assertRaisesRegexp(Http404, 'Invalid course_key or usage_key', views.jump_to, request, 'bar', ()) @unittest.skip def test_no_end_on_about_page(self): # Toy course has no course end date or about/end_date blob self.verify_end_date('edX/toy/TT_2012_Fall') @unittest.skip def test_no_end_about_blob(self): # test_end has a course end date, no end_date HTML blob self.verify_end_date("edX/test_end/2012_Fall", "Sep 17, 2015") @unittest.skip def test_about_blob_end_date(self): # test_about_blob_end_date has both a course end date and an end_date HTML blob. # HTML blob wins self.verify_end_date("edX/test_about_blob_end_date/2012_Fall", "Learning never ends") def verify_end_date(self, course_id, expected_end_text=None): """ Visits the about page for `course_id` and tests that both the text "Classes End", as well as the specified `expected_end_text`, is present on the page. If `expected_end_text` is None, verifies that the about page *does not* contain the text "Classes End". """ request = self.request_factory.get("foo") request.user = self.user # TODO: Remove the dependency on MakoMiddleware (by making the views explicitly supply a RequestContext) mako_middleware_process_request(request) result = views.course_about(request, course_id) if expected_end_text is not None: self.assertContains(result, "Classes End") self.assertContains(result, expected_end_text) else: self.assertNotContains(result, "Classes End") def test_submission_history_accepts_valid_ids(self): # log into a staff account admin = AdminFactory() self.client.login(username=admin.username, password='******') url = reverse('submission_history', kwargs={ 'course_id': self.course_key.to_deprecated_string(), 'student_username': '******', 'location': self.component.location.to_deprecated_string(), }) response = self.client.get(url) # Tests that we do not get an "Invalid x" response when passing correct arguments to view self.assertFalse('Invalid' in response.content) def test_submission_history_xss(self): # log into a staff account admin = AdminFactory() self.client.login(username=admin.username, password='******') # try it with an existing user and a malicious location url = reverse('submission_history', kwargs={ 'course_id': self.course_key.to_deprecated_string(), 'student_username': '******', 'location': '<script>alert("hello");</script>' }) response = self.client.get(url) self.assertFalse('<script>' in response.content) # try it with a malicious user and a non-existent location url = reverse('submission_history', kwargs={ 'course_id': self.course_key.to_deprecated_string(), 'student_username': '******', 'location': 'dummy' }) response = self.client.get(url) self.assertFalse('<script>' in response.content) def test_submission_history_contents(self): # log into a staff account admin = AdminFactory.create() self.client.login(username=admin.username, password='******') usage_key = self.course_key.make_usage_key('problem', 'test-history') state_client = DjangoXBlockUserStateClient(admin) # store state via the UserStateClient state_client.set( username=admin.username, block_key=usage_key, state={'field_a': 'x', 'field_b': 'y'} ) set_score(admin.id, usage_key, 0, 3) state_client.set( username=admin.username, block_key=usage_key, state={'field_a': 'a', 'field_b': 'b'} ) set_score(admin.id, usage_key, 3, 3) url = reverse('submission_history', kwargs={ 'course_id': unicode(self.course_key), 'student_username': admin.username, 'location': unicode(usage_key), }) response = self.client.get(url) response_content = HTMLParser().unescape(response.content) # We have update the state 4 times: twice to change content, and twice # to set the scores. We'll check that the identifying content from each is # displayed (but not the order), and also the indexes assigned in the output # #1 - #4 self.assertIn('#1', response_content) self.assertIn(json.dumps({'field_a': 'a', 'field_b': 'b'}, sort_keys=True, indent=2), response_content) self.assertIn("Score: 0.0 / 3.0", response_content) self.assertIn(json.dumps({'field_a': 'x', 'field_b': 'y'}, sort_keys=True, indent=2), response_content) self.assertIn("Score: 3.0 / 3.0", response_content) self.assertIn('#4', response_content) def _email_opt_in_checkbox(self, response, org_name_string=None): """Check if the email opt-in checkbox appears in the response content.""" checkbox_html = '<input id="email-opt-in" type="checkbox" name="opt-in" class="email-opt-in" value="true" checked>' if org_name_string: # Verify that the email opt-in checkbox appears, and that the expected # organization name is displayed. self.assertContains(response, checkbox_html, html=True) self.assertContains(response, org_name_string) else: # Verify that the email opt-in checkbox does not appear self.assertNotContains(response, checkbox_html, html=True)
class FieldOverridePerformanceTestCase(ProceduralCourseTestMixin, ModuleStoreTestCase): """ Base class for instrumenting SQL queries and Mongo reads for field override providers. """ __test__ = False # Tell Django to clean out all databases, not just default multi_db = True # TEST_DATA must be overridden by subclasses TEST_DATA = None ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache'] def setUp(self): """ Create a test client, course, and user. """ super(FieldOverridePerformanceTestCase, self).setUp() self.request_factory = RequestFactory() self.student = UserFactory.create() self.request = self.request_factory.get("foo") self.request.user = self.student patcher = mock.patch('edxmako.request_context.get_current_request', return_value=self.request) patcher.start() self.addCleanup(patcher.stop) self.course = None self.ccx = None def setup_course(self, size, enable_ccx, view_as_ccx): """ Build a gradable course where each node has `size` children. """ grading_policy = { "GRADER": [{ "drop_count": 2, "min_count": 12, "short_label": "HW", "type": "Homework", "weight": 0.15 }, { "drop_count": 2, "min_count": 12, "type": "Lab", "weight": 0.15 }, { "drop_count": 0, "min_count": 1, "short_label": "Midterm", "type": "Midterm Exam", "weight": 0.3 }, { "drop_count": 0, "min_count": 1, "short_label": "Final", "type": "Final Exam", "weight": 0.4 }], "GRADE_CUTOFFS": { "Pass": 0.5 } } self.course = CourseFactory.create( graded=True, start=datetime.now(UTC), grading_policy=grading_policy, enable_ccx=enable_ccx, ) self.populate_course(size) course_key = self.course.id if enable_ccx: self.ccx = CcxFactory.create(course_id=self.course.id) if view_as_ccx: course_key = CCXLocator.from_course_locator( self.course.id, self.ccx.id) CourseEnrollment.enroll(self.student, course_key) def grade_course(self, course, view_as_ccx): """ Renders the progress page for the given course. """ course_key = course.id if view_as_ccx: course_key = CCXLocator.from_course_locator( course_key, self.ccx.id) return progress(self.request, course_id=unicode(course_key), student_id=self.student.id) def assertMongoCallCount(self, calls): """ Assert that mongodb is queried ``calls`` times in the surrounded context. """ return check_mongo_calls_range(max_finds=calls) def assertXBlockInstantiations(self, instantiations): """ Assert that exactly ``instantiations`` XBlocks are instantiated in the surrounded context. """ return check_sum_of_calls(XBlock, ['__init__'], instantiations, instantiations, include_arguments=False) def instrument_course_progress_render(self, course_width, enable_ccx, view_as_ccx, default_queries, history_queries, reads, xblocks): """ Renders the progress page, instrumenting Mongo reads and SQL queries. """ self.setup_course(course_width, enable_ccx, view_as_ccx) # Switch to published-only mode to simulate the LMS with self.settings(MODULESTORE_BRANCH='published-only'): # Clear all caches before measuring for cache in settings.CACHES: caches[cache].clear() # Refill the metadata inheritance cache modulestore().get_course(self.course.id, depth=None) # We clear the request cache to simulate a new request in the LMS. RequestCache.clear_request_cache() # Reset the list of provider classes, so that our django settings changes # can actually take affect. OverrideFieldData.provider_classes = None with self.assertNumQueries(default_queries, using='default'): with self.assertNumQueries(history_queries, using='student_module_history'): with self.assertMongoCallCount(reads): with self.assertXBlockInstantiations(xblocks): self.grade_course(self.course, view_as_ccx) @ddt.data(*itertools.product(('no_overrides', 'ccx'), range(1, 4), (True, False), (True, False))) @ddt.unpack @override_settings( FIELD_OVERRIDE_PROVIDERS=(), ) def test_field_overrides(self, overrides, course_width, enable_ccx, view_as_ccx): """ Test without any field overrides. """ providers = { 'no_overrides': (), 'ccx': ('ccx.overrides.CustomCoursesForEdxOverrideProvider', ) } if overrides == 'no_overrides' and view_as_ccx: raise SkipTest( "Can't view a ccx course if field overrides are disabled.") if not enable_ccx and view_as_ccx: raise SkipTest( "Can't view a ccx course if ccx is disabled on the course") if self.MODULESTORE == TEST_DATA_MONGO_MODULESTORE and view_as_ccx: raise SkipTest("Can't use a MongoModulestore test as a CCX course") with self.settings(FIELD_OVERRIDE_PROVIDERS=providers[overrides]): default_queries, history_queries, reads, xblocks = self.TEST_DATA[( overrides, course_width, enable_ccx, view_as_ccx)] self.instrument_course_progress_render(course_width, enable_ccx, view_as_ccx, default_queries, history_queries, reads, xblocks)
class BaseTestCase(TestCase): """ Test case for users app """ def setUp(self): self.test_user = data_user.copy() user = User.objects.create_user(username=data_user['email'], email=data_user['email'], password=data_user['password1']) def test_1_privacy(self): """ Test for privacy policy view """ response = self.client.get(reverse('privacy-policy'), follow=True) self.assertEqual(response.status_code, 200) def test_2_group_required(self): """ Test case for group anonymous required """ func = base_views.BlogDetailView anonymous_required(func) def test_3_group_required_none(self): """ Test case for group required decorator """ func = base_views.BlogDetailView group_required(func) def test_4_is_valid_password(self): """ Test case for is_valid_password utils """ self.factory = RequestFactory() response = self.factory.post('', data={'password': '******'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') response = is_valid_password(response) self.assertContains(response, 'The password is invalid') response = self.factory.post('', data={'password': '******'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') response = is_valid_password(response) self.assertContains(response, 'The password is correct') self.factory = RequestFactory() response = self.factory.post('', data={'password': '******'}) def test_5_group_required(self): """ Test case for group required decorator """ user = User.objects.get(email=data_user['email']) self.factory = RequestFactory() @group_required('default') def test(request): return 200 request = self.factory.get('/foo') request.user = user response = test(request) self.assertEqual(response.status_code, 302) group = Group.objects.create(name='default', ) user.groups.add(group) request = self.factory.get('/foo') request.user = user response = test(request) self.assertEqual(response, 200) def test_6_contact(self): """ Test for contact view """ response = self.client.get(reverse('contact'), follow=True) self.assertEqual(response.status_code, 200) data = { 'contact_email': '*****@*****.**', 'content': 'test content', 'contact_name': 'john doe' } response = self.client.post(reverse('contact'), data, follow=True) self.assertEqual(response.status_code, 200)
class UserViews(TestCase): """view user and edit profile""" def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() with patch( "bookwyrm.suggested_users.rerank_suggestions_task.delay" ), patch("bookwyrm.activitystreams.populate_stream_task.delay"), patch( "bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "*****@*****.**", "*****@*****.**", "password", local=True, localname="mouse", ) self.rat = models.User.objects.create_user("*****@*****.**", "*****@*****.**", "password", local=True, localname="rat") self.book = models.Edition.objects.create( title="test", parent_work=models.Work.objects.create(title="test work")) with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" ), patch("bookwyrm.suggested_users.rerank_suggestions_task.delay" ), patch( "bookwyrm.activitystreams.add_book_statuses_task.delay"): models.ShelfBook.objects.create( book=self.book, user=self.local_user, shelf=self.local_user.shelf_set.first(), ) models.SiteSettings.objects.create() self.anonymous_user = AnonymousUser self.anonymous_user.is_authenticated = False def test_user_page(self): """there are so many views, this just makes sure it LOADS""" # extras that are rendered on the user page models.AnnualGoal.objects.create(user=self.local_user, goal=12, privacy="followers") view = views.User.as_view() request = self.factory.get("") request.user = self.local_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "mouse") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) request.user = self.anonymous_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "mouse") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = True result = view(request, "mouse") self.assertIsInstance(result, ActivitypubResponse) self.assertEqual(result.status_code, 200) def test_user_page_domain(self): """when the user domain has dashes in it""" with patch("bookwyrm.models.user.set_remote_server"): models.User.objects.create_user( "nutria", "", "nutriaword", local=False, remote_id="https://ex--ample.co----m/users/nutria", inbox="https://ex--ample.co----m/users/nutria/inbox", outbox="https://ex--ample.co----m/users/nutria/outbox", ) view = views.User.as_view() request = self.factory.get("") request.user = self.local_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "[email protected]") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) def test_user_page_blocked(self): """there are so many views, this just makes sure it LOADS""" view = views.User.as_view() request = self.factory.get("") request.user = self.local_user self.rat.blocks.add(self.local_user) with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False with self.assertRaises(Http404): view(request, "rat") def test_followers_page(self): """there are so many views, this just makes sure it LOADS""" view = views.Followers.as_view() request = self.factory.get("") request.user = self.local_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "mouse") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = True result = view(request, "mouse") self.assertIsInstance(result, ActivitypubResponse) self.assertEqual(result.status_code, 200) def test_followers_page_anonymous(self): """there are so many views, this just makes sure it LOADS""" view = views.Followers.as_view() request = self.factory.get("") request.user = self.anonymous_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "mouse") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") def test_followers_page_blocked(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Followers.as_view() request = self.factory.get("") request.user = self.local_user self.rat.blocks.add(self.local_user) with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False with self.assertRaises(Http404): view(request, "rat") def test_following_page(self): """there are so many views, this just makes sure it LOADS""" view = views.Following.as_view() request = self.factory.get("") request.user = self.local_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "mouse") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = True result = view(request, "mouse") self.assertIsInstance(result, ActivitypubResponse) self.assertEqual(result.status_code, 200) def test_following_page_anonymous(self): """there are so many views, this just makes sure it LOADS""" view = views.Following.as_view() request = self.factory.get("") request.user = self.anonymous_user with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False result = view(request, "mouse") self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) def test_following_page_blocked(self): """there are so many views, this just makes sure it LOADS""" view = views.Following.as_view() request = self.factory.get("") request.user = self.local_user self.rat.blocks.add(self.local_user) with patch("bookwyrm.views.user.is_api_request") as is_api: is_api.return_value = False with self.assertRaises(Http404): view(request, "rat") def test_hide_suggestions(self): """update suggestions settings""" self.assertTrue(self.local_user.show_suggested_users) request = self.factory.post("") request.user = self.local_user result = views.hide_suggestions(request) self.assertEqual(result.status_code, 302) self.local_user.refresh_from_db() self.assertFalse(self.local_user.show_suggested_users) def test_user_redirect(self): """test the basic redirect""" request = self.factory.get("@mouse") request.user = self.anonymous_user result = views.user_redirect(request, "mouse") self.assertEqual(result.status_code, 302)
class ViewTestCase(RepoTestCase): fake_search = True def setUp(self): super(ViewTestCase, self).setUp() if self.fake_search: Fulltext.FAKE = True # Many tests needs access to the request factory. self.factory = RequestFactory() # Create user self.user = create_test_user() group = Group.objects.get(name='Users') self.user.groups.add(group) # Create project to have some test base self.component = self.create_component() self.project = self.component.project # Invalidate caches self.project.stats.invalidate() cache.clear() # Login self.client.login(username='******', password='******') # Prepopulate kwargs self.kw_project = { 'project': self.project.slug } self.kw_component = { 'project': self.project.slug, 'component': self.component.slug, } self.kw_translation = { 'project': self.project.slug, 'component': self.component.slug, 'lang': 'cs', } self.kw_lang_project = { 'project': self.project.slug, 'lang': 'cs', } # Store URL for testing self.translation_url = self.get_translation().get_absolute_url() self.project_url = self.project.get_absolute_url() self.component_url = self.component.get_absolute_url() def tearDown(self): super(ViewTestCase, self).tearDown() if self.fake_search: Fulltext.FAKE = False def update_fulltext_index(self): wait_for_celery() def make_manager(self): """Make user a Manager.""" # Sitewide privileges self.user.groups.add( Group.objects.get(name='Managers') ) # Project privileges self.project.add_user(self.user, '@Administration') def get_request(self, *args, **kwargs): """Wrapper to get fake request object.""" request = self.factory.get(*args, **kwargs) request.user = self.user setattr(request, 'session', 'session') messages = FallbackStorage(request) setattr(request, '_messages', messages) return request def get_translation(self): return self.component.translation_set.get( language_code='cs' ) def get_unit(self, source='Hello, world!\n'): translation = self.get_translation() return translation.unit_set.get(source__startswith=source) def change_unit(self, target): unit = self.get_unit() unit.target = target unit.save_backend(self.get_request('/')) def edit_unit(self, source, target, **kwargs): """Do edit single unit using web interface.""" unit = self.get_unit(source) params = { 'checksum': unit.checksum, 'contentsum': hash_to_checksum(unit.content_hash), 'translationsum': hash_to_checksum(unit.get_target_hash()), 'target_0': target, 'review': '20', } params.update(kwargs) return self.client.post( self.get_translation().get_translate_url(), params ) def assert_redirects_offset(self, response, exp_path, exp_offset): """Assert that offset in response matches expected one.""" self.assertEqual(response.status_code, 302) # We don't use all variables # pylint: disable=unused-variable scheme, netloc, path, query, fragment = urlsplit(response['Location']) self.assertEqual(path, exp_path) exp_offset = 'offset={0:d}'.format(exp_offset) self.assertTrue( exp_offset in query, 'Offset {0} not in {1}'.format(exp_offset, query) ) def assert_png(self, response): """Check whether response contains valid PNG image.""" # Check response status code self.assertEqual(response.status_code, 200) self.assert_png_data(response.content) def assert_png_data(self, content): """Check whether data is PNG image""" # Try to load PNG with PIL image = Image.open(BytesIO(content)) self.assertEqual(image.format, 'PNG') def assert_svg(self, response): """Check whether response is a SVG image.""" # Check response status code self.assertEqual(response.status_code, 200) dom = minidom.parseString(response.content) self.assertEqual(dom.firstChild.nodeName, 'svg') def assert_backend(self, expected_translated): """Check that backend has correct data.""" translation = self.get_translation() translation.commit_pending('test', None) store = translation.component.file_format_cls( translation.get_filename(), None ) messages = set() translated = 0 for unit in store.all_units(): if not unit.is_translatable(): continue id_hash = unit.get_id_hash() self.assertFalse( id_hash in messages, 'Duplicate string in in backend file!' ) if unit.is_translated(): translated += 1 self.assertEqual( translated, expected_translated, 'Did not found expected number of ' + 'translations ({0} != {1}).'.format( translated, expected_translated ) )