class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @attr('docs_activity') @attr('bug715923') @patch('devmo.models.UserDocsActivityFeed.fetch_user_feed') def test_bug715923_feed_parsing_errors(self, fetch_user_feed): fetch_user_feed.return_value = """ THIS IS NOT EVEN XML, SO BROKEN """ try: profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username, )) r = self.client.get(url, follow=True) pq(r.content) except Exception, e: raise e ok_(False, "There should be no exception %s" % e)
class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @attr('docs_activity') @attr('bug715923') @patch('devmo.models.UserDocsActivityFeed.fetch_user_feed') def test_bug715923_feed_parsing_errors(self, fetch_user_feed): fetch_user_feed.return_value = """ THIS IS NOT EVEN XML, SO BROKEN """ try: profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) pq(r.content) except Exception, e: raise e ok_(False, "There should be no exception %s" % e)
def test_ban_permission(self): """The ban permission controls access to the ban view.""" client = LocalizingClient() admin = User.objects.get(username='******') testuser = User.objects.get(username='******') # testuser doesn't have ban permission, can't ban. client.login(username='******', password='******') ban_url = reverse('users.ban_user', kwargs={'user_id': admin.id}) resp = client.get(ban_url) eq_(302, resp.status_code) ok_(settings.LOGIN_URL in resp['Location']) client.logout() # admin has ban permission, can ban. client.login(username='******', password='******') ban_url = reverse('users.ban_user', kwargs={'user_id': testuser.id}) resp = client.get(ban_url) eq_(200, resp.status_code)
def test_ban_permission(self): """The ban permission controls access to the ban view.""" client = LocalizingClient() admin = User.objects.get(username="******") testuser = User.objects.get(username="******") # testuser doesn't have ban permission, can't ban. client.login(username="******", password="******") ban_url = reverse("users.ban_user", kwargs={"user_id": admin.id}) resp = client.get(ban_url) eq_(302, resp.status_code) ok_(settings.LOGIN_URL in resp["Location"]) client.logout() # admin has ban permission, can ban. client.login(username="******", password="******") ban_url = reverse("users.ban_user", kwargs={"user_id": testuser.id}) resp = client.get(ban_url) eq_(200, resp.status_code)
class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @attr('docs_activity') @mock_fetch_user_feed def test_profile_view(self): """A user profile can be viewed""" profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.user.username, doc.find('#profile-head.vcard .nickname').text()) eq_(profile.fullname, doc.find('#profile-head.vcard .fn').text()) eq_(profile.title, doc.find('#profile-head.vcard .title').text()) eq_(profile.organization, doc.find('#profile-head.vcard .org').text()) eq_(profile.location, doc.find('#profile-head.vcard .loc').text()) eq_('IRC: ' + profile.irc_nickname, doc.find('#profile-head.vcard .irc').text()) eq_(profile.bio, doc.find('#profile-head.vcard .bio').text()) # There should be 15 doc activity items in the page. feed_trs = doc.find('#docs-activity table.activity tbody tr') eq_(15, feed_trs.length) # Check to find all the items expected from the feed feed = UserDocsActivityFeed(username="******") for idx in range(0, 15): item = feed.items[idx] item_el = feed_trs.eq(idx) eq_(item.current_title, item_el.find('h3').text()) eq_(item.view_url, item_el.find('h3 a').attr('href')) if item.edit_url: eq_(item.edit_url, item_el.find('.actions a.edit').attr('href')) if item.diff_url: eq_(item.diff_url, item_el.find('.actions a.diff').attr('href')) if item.history_url: eq_(item.history_url, item_el.find('.actions a.history').attr('href')) @mock_put_mindtouch_user @mock_fetch_user_feed def test_bug_698971(self): """A non-numeric page number should not cause an error""" (user, deki_user, profile) = create_profile() url = '%s?page=asdf' % reverse('devmo.views.profile_view', args=(user.username,)) try: self.client.get(url, follow=True) except PageNotAnInteger: ok_(False, "Non-numeric page number should not cause an error") @mock_put_mindtouch_user @mock_fetch_user_feed def test_profile_edit(self): profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(0, doc.find('#profile-head .edit .button').length) self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) edit_button = doc.find('#profile-head .edit .button') eq_(1, edit_button.length) url = edit_button.attr('href') r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.fullname, doc.find('#profile-edit input[name="fullname"]').val()) eq_(profile.title, doc.find('#profile-edit input[name="title"]').val()) eq_(profile.organization, doc.find('#profile-edit input[name="organization"]').val()) eq_(profile.location, doc.find('#profile-edit input[name="location"]').val()) eq_(profile.irc_nickname, doc.find('#profile-edit input[name="irc_nickname"]').val()) new_attrs = dict( email="*****@*****.**", fullname="Another Name", title="Another title", organization="Another org", ) r = self.client.post(url, new_attrs, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) eq_(new_attrs['fullname'], doc.find('#profile-head .main .fn').text()) eq_(new_attrs['title'], doc.find('#profile-head .info .title').text()) eq_(new_attrs['organization'], doc.find('#profile-head .info .org').text()) profile = UserProfile.objects.get(user__username=user.username) eq_(new_attrs['fullname'], profile.fullname) eq_(new_attrs['title'], profile.title) eq_(new_attrs['organization'], profile.organization) @mock_put_mindtouch_user @mock_fetch_user_feed def test_profile_edit_websites(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_sites = { u'website': u'http://example.com/', u'twitter': u'http://twitter.com/lmorchard', u'github': u'http://github.com/lmorchard', u'stackoverflow': u'http://stackoverflow.com/users/lmorchard', } # Scrape out the existing significant form field values. form = dict() for fn in ('email', 'fullname', 'title', 'organization', 'location', 'irc_nickname', 'bio', 'interests'): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() form['email'] = '*****@*****.**' # Fill out the form with websites. form.update(dict(('websites_%s' % k, v) for k, v in test_sites.items())) # Submit the form, verify redirect to profile detail r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) # Verify the websites are saved in the profile. eq_(test_sites, p.websites) # Verify the saved websites appear in the editing form url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) for k, v in test_sites.items(): eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val()) # Come up with some bad sites, either invalid URL or bad URL prefix bad_sites = { u'website': u'HAHAHA WHAT IS A WEBSITE', u'twitter': u'http://facebook.com/lmorchard', u'stackoverflow': u'http://overqueueblah.com/users/lmorchard', } form.update(dict(('websites_%s' % k, v) for k, v in bad_sites.items())) # Submit the form, verify errors for all of the bad sites r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-edit').length) tmpl = '#profile-edit #elsewhere .%s .errorlist' for n in ('website', 'twitter', 'stackoverflow'): eq_(1, doc.find(tmpl % n).length) @mock_put_mindtouch_user @mock_fetch_user_feed def test_profile_edit_interests(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = ['javascript', 'css', 'canvas', 'html', 'homebrewing'] form = dict() for fn in ('email', 'fullname', 'title', 'organization', 'location', 'irc_nickname', 'bio', 'interests'): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() form['email'] = '*****@*****.**' form['interests'] = ', '.join(test_tags) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) result_tags = [t.name.replace('profile:interest:', '') for t in p.tags.all_ns('profile:interest:')] result_tags.sort() test_tags.sort() eq_(test_tags, result_tags) test_expertise = ['css', 'canvas'] form['expertise'] = ', '.join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) result_tags = [t.name.replace('profile:expertise:', '') for t in p.tags.all_ns('profile:expertise')] result_tags.sort() test_expertise.sort() eq_(test_expertise, result_tags) # Now, try some expertise tags not covered in interests test_expertise = ['css', 'canvas', 'mobile', 'movies'] form['expertise'] = ', '.join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('.error #id_expertise').length) @mock_put_mindtouch_user @mock_fetch_user_feed def test_bug_709938_interests(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = [u'science,Technology,paradox,knowledge,modeling,big data,' u'vector,meme,heuristics,harmony,mathesis universalis,' u'symmetry,mathematics,computer graphics,field,chemistry,' u'religion,astronomy,physics,biology,literature,' u'spirituality,Art,Philosophy,Psychology,Business,Music,' u'Computer Science'] form = dict() for fn in ('email', 'fullname', 'title', 'organization', 'location', 'irc_nickname', 'bio', 'interests'): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() form['email'] = '*****@*****.**' form['interests'] = test_tags r = self.client.post(url, form, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_(1, doc.find('ul.errorlist li').length) assert ('Ensure this value has at most 255 characters' in doc.find('ul.errorlist li').text()) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock_fetch_user_feed @mock.patch_object(Site.objects, 'get_current') def test_profile_edit_language_saves_to_mindtouch(self, get_current): get_current.return_value.domain = 'dev.mo.org' try: user = User.objects.get(username='******') user.delete() except User.DoesNotExist: pass # log in as a MindTouch user to create django user & profile response = self.client.post(reverse('users.login', locale='en-US'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) user = User.objects.get(username='******') profile = UserProfile.objects.get(user=user) ok_(profile) # use profile edit to change language url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) eq_(200, r.status_code, 'Profile should be found.') doc = pq(r.content) # Scrape out the existing significant form field values. form = dict() for fn in ('email', 'fullname', 'title', 'organization', 'location', 'locale', 'timezone', 'irc_nickname', 'bio', 'interests'): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() # Fill out the form with websites. form.update({'locale': 'nl'}) form.update({'timezone': 'Europe/Amsterdam'}) # Submit the form, verify redirect to profile detail r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) # Verify locale saved in the profile. eq_('nl', p.locale) # Verify the saved locale appears in the editing form url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) ok_('nl', doc.find('#profile-edit select#id_locale option[value="nl"]' '[selected="selected"]')) # TODO: Mock this part out... """ r = requests.get(DekiUserBackend.profile_by_id_url % '=testaccount') doc = pq(r.content) eq_('nl', doc.find('language').text()) """ def _break(self, url, r): logging.debug("URL %s" % url) logging.debug("STAT %s" % r.status_code) logging.debug("HEAD %s" % r.items()) logging.debug("CONT %s" % r.content) ok_(False)
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******', 'next': login_uri }, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login') def test_mindtouch_disabled_login(self, mock_mindtouch_login): """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth.""" # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_mindtouch_login(username, password, force=False): trap['was_called'] = True return False mock_mindtouch_login.side_effect = my_mindtouch_login # Try to log in as a MindTouch user, assert that MindTouch auth was # never attempted. _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) settings.DEKIWIKI_ENDPOINT = _old ok_(not trap['was_called']) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_mindtouch_creds_create_user_and_profile(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() get_current.return_value.domain = 'dev.mo.org' if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') self.assertRaises(User.DoesNotExist, User.objects.get, username='******') # Try to log in as a MindTouch user response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) # Ensure there are no validation errors page = pq(response.content) eq_(0, page.find('.errorlist').length, "There should be no validation errors in login") # Login should have auto-created django user u = User.objects.get(username='******') eq_(True, u.is_active) ok_(u.get_profile()) # Login page should show welcome back doc = pq(response.content) eq_('testaccount', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_request_properties(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' r = RequestFactory().get('/users/login', {'next': '/demos/submit'}, HTTP_REFERER='referer-trumped-by-get') eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().post('/users/login', {'next': '/demos/submit'}) eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().get('/users/login', HTTP_REFERER='/demos/submit') eq_('/demos/submit', _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_no_self_redirects(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' for next in [settings.LOGIN_URL, settings.LOGOUT_URL]: r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_invalid_next_parameter(self, get_current): '''_clean_next_url cleans invalid urls''' get_current.return_value.domain = 'dev.mo.org' for next in self._invalid_nexts(): r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_login_invalid_next_parameter(self, get_current): '''Test with an invalid ?next=http://example.com parameter.''' get_current.return_value.domain = 'testserver.com' valid_next = reverse('home', locale=settings.LANGUAGE_CODE) for invalid_next in self._invalid_nexts(): # Verify that _valid_ next parameter is set in form hidden field. response = self.client.get( urlparams(reverse('users.login'), next=invalid_next)) eq_(200, response.status_code) doc = pq(response.content) eq_(valid_next, doc('input[name="next"]')[0].attrib['value']) # Verify that it gets used on form POST. response = self.client.post( reverse('users.login'), { 'username': '******', 'password': '******', 'next': invalid_next }) eq_(302, response.status_code) eq_('http://testserver' + valid_next, response['location']) self.client.logout() def _invalid_nexts(self): return ['http://foobar.com/evil/', '//goo.gl/y-bad']
class RegisterTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock_missing_get_deki_user @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now response = self.client.post(reverse('users.register'), { 'username': username, 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) assert u.password.startswith('sha256') assert not u.is_active eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 key = RegistrationProfile.objects.all()[0].activation_key assert mail.outbox[0].body.find('activate/%s' % key) > 0 # Now try to log in u.is_active = True u.save() response = self.client.post(reverse('users.login'), { 'username': username, 'password': '******' }, follow=True) eq_(200, response.status_code) eq_('http://testserver/en-US/', response.redirect_chain[0][0]) @mock_missing_get_deki_user @mock_post_mindtouch_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_unicode_password(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now u_str = u'\xe5\xe5\xee\xe9\xf8\xe7\u6709\u52b9' response = self.client.post(reverse('users.register', locale='ja'), { 'username': username, 'email': '*****@*****.**', 'password': u_str, 'password2': u_str }, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) u.is_active = True u.save() assert u.password.startswith('sha256') # make sure you can login now response = self.client.post(reverse('users.login', locale='ja'), { 'username': username, 'password': u_str }, follow=True) eq_(200, response.status_code) eq_('http://testserver/ja/', response.redirect_chain[0][0]) @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_activation(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now user = RegistrationProfile.objects.create_inactive_user( username, 'testpass', '*****@*****.**') assert not user.is_active key = RegistrationProfile.objects.all()[0].activation_key url = reverse('users.activate', args=[key]) response = self.client.get(url, follow=True) eq_(200, response.status_code) user = User.objects.get(pk=user.pk) assert user.is_active @mock_get_deki_user def test_duplicate_username(self): response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_duplicate_mindtouch_username(self): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_duplicate_email(self): User.objects.create(username='******', email='*****@*****.**').save() response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_no_match_passwords(self): response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'bar' }, follow=True) self.assertContains(response, 'must match')
class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug def _get_current_form_field_values(self, doc): # Scrape out the existing significant form field values. form = dict() for fn in ('email', 'fullname', 'title', 'organization', 'location', 'irc_nickname', 'bio', 'interests'): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() return form @attr('docs_activity') def test_profile_view(self): """A user profile can be viewed""" profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.user.username, doc.find('#profile-head.vcard .nickname').text()) eq_(profile.fullname, doc.find('#profile-head.vcard .fn').text()) eq_(profile.title, doc.find('#profile-head.vcard .title').text()) eq_(profile.organization, doc.find('#profile-head.vcard .org').text()) eq_(profile.location, doc.find('#profile-head.vcard .loc').text()) eq_('IRC: ' + profile.irc_nickname, doc.find('#profile-head.vcard .irc').text()) eq_(profile.bio, doc.find('#profile-head.vcard .bio').text()) def test_my_profile_view(self): u = User.objects.get(username='******') self.client.login(username=u.username, password=TESTUSER_PASSWORD) resp = self.client.get('/profile/') eq_(302, resp.status_code) ok_( reverse('devmo.views.profile_view', args=( u.username, )) in resp['Location']) def test_bug_698971(self): """A non-numeric page number should not cause an error""" (user, profile) = create_profile() url = '%s?page=asdf' % reverse('devmo.views.profile_view', args=(user.username, )) try: self.client.get(url, follow=True) except PageNotAnInteger: ok_(False, "Non-numeric page number should not cause an error") def test_profile_edit(self): profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(0, doc.find('#profile-head .edit .button').length) self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_view', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) edit_button = doc.find('#profile-head .edit #edit-profile') eq_(1, edit_button.length) url = edit_button.attr('href') r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.fullname, doc.find('#profile-edit input[name="fullname"]').val()) eq_(profile.title, doc.find('#profile-edit input[name="title"]').val()) eq_(profile.organization, doc.find('#profile-edit input[name="organization"]').val()) eq_(profile.location, doc.find('#profile-edit input[name="location"]').val()) eq_(profile.irc_nickname, doc.find('#profile-edit input[name="irc_nickname"]').val()) new_attrs = dict( email='*****@*****.**', fullname="Another Name", title="Another title", organization="Another org", ) r = self.client.post(url, new_attrs, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) eq_(new_attrs['fullname'], doc.find('#profile-head .main .fn').text()) eq_(new_attrs['title'], doc.find('#profile-head .info .title').text()) eq_(new_attrs['organization'], doc.find('#profile-head .info .org').text()) profile = UserProfile.objects.get(user__username=user.username) eq_(new_attrs['fullname'], profile.fullname) eq_(new_attrs['title'], profile.title) eq_(new_attrs['organization'], profile.organization) def test_my_profile_edit(self): u = User.objects.get(username='******') self.client.login(username=u.username, password=TESTUSER_PASSWORD) resp = self.client.get('/profile/edit') eq_(302, resp.status_code) ok_( reverse('devmo.views.profile_edit', args=( u.username, )) in resp['Location']) def test_profile_edit_beta(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(None, doc.find('input#id_beta').attr('checked')) form = self._get_current_form_field_values(doc) form['beta'] = True r = self.client.post(url, form, follow=True) url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) eq_('checked', doc.find('input#id_beta').attr('checked')) def test_profile_edit_websites(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) test_sites = { u'website': u'http://example.com/', u'twitter': u'http://twitter.com/lmorchard', u'github': u'http://github.com/lmorchard', u'stackoverflow': u'http://stackoverflow.com/users/lmorchard', } form = self._get_current_form_field_values(doc) # Fill out the form with websites. form.update(dict( ('websites_%s' % k, v) for k, v in test_sites.items())) # Submit the form, verify redirect to profile detail r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) # Verify the websites are saved in the profile. eq_(test_sites, p.websites) # Verify the saved websites appear in the editing form url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) for k, v in test_sites.items(): eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val()) # Come up with some bad sites, either invalid URL or bad URL prefix bad_sites = { u'website': u'HAHAHA WHAT IS A WEBSITE', u'twitter': u'http://facebook.com/lmorchard', u'stackoverflow': u'http://overqueueblah.com/users/lmorchard', } form.update(dict(('websites_%s' % k, v) for k, v in bad_sites.items())) # Submit the form, verify errors for all of the bad sites r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-edit').length) tmpl = '#profile-edit #elsewhere .%s .errorlist' for n in ('website', 'twitter', 'stackoverflow'): eq_(1, doc.find(tmpl % n).length) def test_profile_edit_interests(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = ['javascript', 'css', 'canvas', 'html', 'homebrewing'] form = self._get_current_form_field_values(doc) form['interests'] = ', '.join(test_tags) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) result_tags = [ t.name.replace('profile:interest:', '') for t in p.tags.all_ns('profile:interest:') ] result_tags.sort() test_tags.sort() eq_(test_tags, result_tags) test_expertise = ['css', 'canvas'] form['expertise'] = ', '.join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) result_tags = [ t.name.replace('profile:expertise:', '') for t in p.tags.all_ns('profile:expertise') ] result_tags.sort() test_expertise.sort() eq_(test_expertise, result_tags) # Now, try some expertise tags not covered in interests test_expertise = ['css', 'canvas', 'mobile', 'movies'] form['expertise'] = ', '.join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('.error #id_expertise').length) def test_bug_709938_interests(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = [ u'science,Technology,paradox,knowledge,modeling,big data,' u'vector,meme,heuristics,harmony,mathesis universalis,' u'symmetry,mathematics,computer graphics,field,chemistry,' u'religion,astronomy,physics,biology,literature,' u'spirituality,Art,Philosophy,Psychology,Business,Music,' u'Computer Science' ] form = self._get_current_form_field_values(doc) form['interests'] = test_tags r = self.client.post(url, form, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_(1, doc.find('ul.errorlist li').length) assert ('Ensure this value has at most 255 characters' in doc.find('ul.errorlist li').text()) def test_bug_698126_l10n(self): """Test that the form field names are localized""" user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username, )) r = self.client.get(url, follow=True) for field in r.context['form'].fields: # if label is localized it's a lazy proxy object ok_( not isinstance(r.context['form'].fields[field].label, basestring), 'Field %s is a string!' % field) def _break(self, url, r): logging.debug("URL %s" % url) logging.debug("STAT %s" % r.status_code) logging.debug("HEAD %s" % r.items()) logging.debug("CONT %s" % r.content) ok_(False)
class ProfileViewsTest(TestCase): fixtures = ["test_users.json"] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @attr("docs_activity") def test_profile_view(self): """A user profile can be viewed""" profile = UserProfile.objects.get(user__username="******") user = profile.user url = reverse("devmo.views.profile_view", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.user.username, doc.find("#profile-head.vcard .nickname").text()) eq_(profile.fullname, doc.find("#profile-head.vcard .fn").text()) eq_(profile.title, doc.find("#profile-head.vcard .title").text()) eq_(profile.organization, doc.find("#profile-head.vcard .org").text()) eq_(profile.location, doc.find("#profile-head.vcard .loc").text()) eq_("IRC: " + profile.irc_nickname, doc.find("#profile-head.vcard .irc").text()) eq_(profile.bio, doc.find("#profile-head.vcard .bio").text()) def test_my_profile_view(self): u = User.objects.get(username="******") self.client.login(username=u.username, password=TESTUSER_PASSWORD) resp = self.client.get("/profile/") eq_(302, resp.status_code) ok_(reverse("devmo.views.profile_view", args=(u.username,)) in resp["Location"]) def test_bug_698971(self): """A non-numeric page number should not cause an error""" (user, profile) = create_profile() url = "%s?page=asdf" % reverse("devmo.views.profile_view", args=(user.username,)) try: self.client.get(url, follow=True) except PageNotAnInteger: ok_(False, "Non-numeric page number should not cause an error") def test_profile_edit(self): profile = UserProfile.objects.get(user__username="******") user = profile.user url = reverse("devmo.views.profile_view", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(0, doc.find("#profile-head .edit .button").length) self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse("devmo.views.profile_view", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) edit_button = doc.find("#profile-head .edit #edit-profile") eq_(1, edit_button.length) url = edit_button.attr("href") r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.fullname, doc.find('#profile-edit input[name="fullname"]').val()) eq_(profile.title, doc.find('#profile-edit input[name="title"]').val()) eq_(profile.organization, doc.find('#profile-edit input[name="organization"]').val()) eq_(profile.location, doc.find('#profile-edit input[name="location"]').val()) eq_(profile.irc_nickname, doc.find('#profile-edit input[name="irc_nickname"]').val()) new_attrs = dict( email="*****@*****.**", fullname="Another Name", title="Another title", organization="Another org" ) r = self.client.post(url, new_attrs, follow=True) doc = pq(r.content) eq_(1, doc.find("#profile-head").length) eq_(new_attrs["fullname"], doc.find("#profile-head .main .fn").text()) eq_(new_attrs["title"], doc.find("#profile-head .info .title").text()) eq_(new_attrs["organization"], doc.find("#profile-head .info .org").text()) profile = UserProfile.objects.get(user__username=user.username) eq_(new_attrs["fullname"], profile.fullname) eq_(new_attrs["title"], profile.title) eq_(new_attrs["organization"], profile.organization) def test_my_profile_edit(self): u = User.objects.get(username="******") self.client.login(username=u.username, password=TESTUSER_PASSWORD) resp = self.client.get("/profile/edit") eq_(302, resp.status_code) ok_(reverse("devmo.views.profile_edit", args=(u.username,)) in resp["Location"]) def test_profile_edit_websites(self): user = User.objects.get(username="******") self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse("devmo.views.profile_edit", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_sites = { u"website": u"http://example.com/", u"twitter": u"http://twitter.com/lmorchard", u"github": u"http://github.com/lmorchard", u"stackoverflow": u"http://stackoverflow.com/users/lmorchard", } # Scrape out the existing significant form field values. form = dict() for fn in ("email", "fullname", "title", "organization", "location", "irc_nickname", "bio", "interests"): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() form["email"] = "*****@*****.**" # Fill out the form with websites. form.update(dict(("websites_%s" % k, v) for k, v in test_sites.items())) # Submit the form, verify redirect to profile detail r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find("#profile-head").length) p = UserProfile.objects.get(user=user) # Verify the websites are saved in the profile. eq_(test_sites, p.websites) # Verify the saved websites appear in the editing form url = reverse("devmo.views.profile_edit", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) for k, v in test_sites.items(): eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val()) # Come up with some bad sites, either invalid URL or bad URL prefix bad_sites = { u"website": u"HAHAHA WHAT IS A WEBSITE", u"twitter": u"http://facebook.com/lmorchard", u"stackoverflow": u"http://overqueueblah.com/users/lmorchard", } form.update(dict(("websites_%s" % k, v) for k, v in bad_sites.items())) # Submit the form, verify errors for all of the bad sites r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find("#profile-edit").length) tmpl = "#profile-edit #elsewhere .%s .errorlist" for n in ("website", "twitter", "stackoverflow"): eq_(1, doc.find(tmpl % n).length) def test_profile_edit_interests(self): user = User.objects.get(username="******") self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse("devmo.views.profile_edit", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = ["javascript", "css", "canvas", "html", "homebrewing"] form = dict() for fn in ("email", "fullname", "title", "organization", "location", "irc_nickname", "bio", "interests"): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() form["email"] = "*****@*****.**" form["interests"] = ", ".join(test_tags) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find("#profile-head").length) p = UserProfile.objects.get(user=user) result_tags = [t.name.replace("profile:interest:", "") for t in p.tags.all_ns("profile:interest:")] result_tags.sort() test_tags.sort() eq_(test_tags, result_tags) test_expertise = ["css", "canvas"] form["expertise"] = ", ".join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find("#profile-head").length) p = UserProfile.objects.get(user=user) result_tags = [t.name.replace("profile:expertise:", "") for t in p.tags.all_ns("profile:expertise")] result_tags.sort() test_expertise.sort() eq_(test_expertise, result_tags) # Now, try some expertise tags not covered in interests test_expertise = ["css", "canvas", "mobile", "movies"] form["expertise"] = ", ".join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find(".error #id_expertise").length) def test_bug_709938_interests(self): user = User.objects.get(username="******") self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse("devmo.views.profile_edit", args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = [ u"science,Technology,paradox,knowledge,modeling,big data," u"vector,meme,heuristics,harmony,mathesis universalis," u"symmetry,mathematics,computer graphics,field,chemistry," u"religion,astronomy,physics,biology,literature," u"spirituality,Art,Philosophy,Psychology,Business,Music," u"Computer Science" ] form = dict() for fn in ("email", "fullname", "title", "organization", "location", "irc_nickname", "bio", "interests"): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() form["email"] = "*****@*****.**" form["interests"] = test_tags r = self.client.post(url, form, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_(1, doc.find("ul.errorlist li").length) assert "Ensure this value has at most 255 characters" in doc.find("ul.errorlist li").text() def test_bug_698126_l10n(self): """Test that the form field names are localized""" user = User.objects.get(username="******") self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse("devmo.views.profile_edit", args=(user.username,)) r = self.client.get(url, follow=True) for field in r.context["form"].fields: # if label is localized it's a lazy proxy object ok_(not isinstance(r.context["form"].fields[field].label, basestring), "Field %s is a string!" % field) def _break(self, url, r): logging.debug("URL %s" % url) logging.debug("STAT %s" % r.status_code) logging.debug("HEAD %s" % r.items()) logging.debug("CONT %s" % r.content) ok_(False)
class UploadImageTestCase(TestCase): fixtures = ['users.json', 'questions.json'] def setUp(self): super(UploadImageTestCase, self).setUp() self.client = LocalizingClient() self.client.login(username='******', password='******') def tearDown(self): ImageAttachment.objects.all().delete() super(UploadImageTestCase, self).tearDown() def test_model_invalid(self): """Specifying an invalid model returns 400.""" r = post(self.client, 'upload.up_image_async', {'image': ''}, args=['invalid.model', 123]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Model does not exist.', json_r['message']) def test_object_notexist(self): """Upload nothing returns 404 error and html content.""" r = post(self.client, 'upload.up_image_async', {'image': ''}, args=['questions.Question', 123]) eq_(404, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Object does not exist.', json_r['message']) def test_empty_image(self): """Upload nothing returns 400 error and json content.""" r = post(self.client, 'upload.up_image_async', {'image': ''}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_('You have not selected an image to upload.', json_r['errors']['image'][0]) def test_upload_image(self): """Uploading an image works.""" with open('apps/upload/tests/media/test.jpg') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) file = json_r['file'] eq_('test.jpg', file['name']) eq_(90, file['width']) eq_(120, file['height']) name = '098f6b.jpg' message = 'Url "%s" does not contain "%s"' % (file['url'], name) assert (name in file['url']), message eq_(1, ImageAttachment.objects.count()) image = ImageAttachment.objects.all()[0] eq_('pcraciunoiu', image.creator.username) eq_(150, image.file.width) eq_(200, image.file.height) eq_('question', image.content_type.model) eq_(1, image.object_id) def test_upload_unicode_image(self): """Uploading an unicode image works.""" with open(u'apps/upload/tests/media/123ascii\u6709\u52b9.jpg') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) def test_delete_image_logged_out(self): """Can't delete an image logged out.""" # Upload the image first self.test_upload_image() im = ImageAttachment.objects.all()[0] self.client.logout() r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(403, r.status_code) assert ImageAttachment.uncached.exists() def test_delete_image_no_permission(self): """Can't delete an image without permission.""" u = User.objects.get(username='******') assert not u.has_perm('upload.delete_imageattachment') self.test_upload_image() im = ImageAttachment.objects.all()[0] self.client.login(username='******', password='******') r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(403, r.status_code) assert ImageAttachment.uncached.exists() def test_delete_image_owner(self): """Users can delete their own images.""" self.test_upload_image() im = ImageAttachment.objects.all()[0] r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) assert not ImageAttachment.uncached.exists() def test_delete_image_with_permission(self): """Users with permission can delete images.""" u = User.objects.get(username='******') ct = ContentType.objects.get_for_model(ImageAttachment) p = Permission.objects.get_or_create( codename='delete_imageattachment', content_type=ct)[0] u.user_permissions.add(p) assert u.has_perm('upload.delete_imageattachment') self.test_upload_image() im = ImageAttachment.objects.all()[0] self.client.login(username='******', password='******') r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) assert not ImageAttachment.uncached.exists() def test_delete_no_image(self): """Trying to delete a non-existent image 404s.""" r = post(self.client, 'upload.del_image_async', args=[123]) eq_(404, r.status_code) data = json.loads(r.content) eq_('error', data['status']) def test_invalid_image(self): """Make sure invalid files are not accepted as images.""" with open('apps/upload/__init__.py', 'rb') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_('The submitted file is empty.', json_r['errors']['image'][0]) def test_invalid_image_extensions(self): """Make sure invalid extensions are not accepted as images.""" with open('apps/upload/tests/media/test_invalid.ext', 'rb') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_('Please upload an image with one of the following extensions: ' 'jpg, jpeg, png, gif.', json_r['errors']['__all__'][0]) def test_upload_long_filename(self): """Uploading an image with a filename that's too long fails.""" with open('apps/upload/tests/media/a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_yes_.jpg')\ as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_(MSG_IMAGE_LONG % {'length': 251, 'max': settings.MAX_FILENAME_LENGTH}, json_r['errors']['image'][0])
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******', 'next': login_uri}, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login') def test_mindtouch_disabled_login(self, mock_mindtouch_login): """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth.""" # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_mindtouch_login(username, password, force=False): trap['was_called'] = True return False mock_mindtouch_login.side_effect = my_mindtouch_login # Try to log in as a MindTouch user, assert that MindTouch auth was # never attempted. _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) settings.DEKIWIKI_ENDPOINT = _old ok_(not trap['was_called']) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_mindtouch_creds_create_user_and_profile(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() get_current.return_value.domain = 'dev.mo.org' if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') self.assertRaises(User.DoesNotExist, User.objects.get, username='******') # Try to log in as a MindTouch user response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) # Ensure there are no validation errors page = pq(response.content) eq_(0, page.find('.errorlist').length, "There should be no validation errors in login") # Login should have auto-created django user u = User.objects.get(username='******') eq_(True, u.is_active) ok_(u.get_profile()) # Login page should show welcome back doc = pq(response.content) eq_('testaccount', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_request_properties(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' r = RequestFactory().get('/users/login', {'next': '/demos/submit'}, HTTP_REFERER='referer-trumped-by-get') eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().post('/users/login', {'next': '/demos/submit'}) eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().get('/users/login', HTTP_REFERER='/demos/submit') eq_('/demos/submit', _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_no_self_redirects(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' for next in [settings.LOGIN_URL, settings.LOGOUT_URL]: r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_invalid_next_parameter(self, get_current): '''_clean_next_url cleans invalid urls''' get_current.return_value.domain = 'dev.mo.org' for next in self._invalid_nexts(): r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_login_invalid_next_parameter(self, get_current): '''Test with an invalid ?next=http://example.com parameter.''' get_current.return_value.domain = 'testserver.com' valid_next = reverse('home', locale=settings.LANGUAGE_CODE) for invalid_next in self._invalid_nexts(): # Verify that _valid_ next parameter is set in form hidden field. response = self.client.get(urlparams(reverse('users.login'), next=invalid_next)) eq_(200, response.status_code) doc = pq(response.content) eq_(valid_next, doc('input[name="next"]')[0].attrib['value']) # Verify that it gets used on form POST. response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******', 'next': invalid_next}) eq_(302, response.status_code) eq_('http://testserver' + valid_next, response['location']) self.client.logout() def _invalid_nexts(self): return ['http://foobar.com/evil/', '//goo.gl/y-bad']
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******', 'next': login_uri}, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login') def test_mindtouch_disabled_login(self, mock_mindtouch_login): """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth.""" # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_mindtouch_login(username, password, force=False): trap['was_called'] = True return False mock_mindtouch_login.side_effect = my_mindtouch_login # Try to log in as a MindTouch user, assert that MindTouch auth was # never attempted. _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) settings.DEKIWIKI_ENDPOINT = _old ok_(not trap['was_called']) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_mindtouch_creds_create_user_and_profile(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() get_current.return_value.domain = 'dev.mo.org' if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') self.assertRaises(User.DoesNotExist, User.objects.get, username='******') # Try to log in as a MindTouch user response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) # Ensure there are no validation errors page = pq(response.content) eq_(0, page.find('.errorlist').length, "There should be no validation errors in login") # Login should have auto-created django user u = User.objects.get(username='******') eq_(True, u.is_active) ok_(u.get_profile()) # Login page should show welcome back doc = pq(response.content) eq_('testaccount', doc.find('ul.user-state a:first').text())
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******', 'next': login_uri }, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login') def test_mindtouch_disabled_login(self, mock_mindtouch_login): """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth.""" # HACK: mock has an assert_called_with, but I want something like # never_called or call_count. Instead, I have this: trap = {'was_called': False} def my_mindtouch_login(username, password, force=False): trap['was_called'] = True return False mock_mindtouch_login.side_effect = my_mindtouch_login # Try to log in as a MindTouch user, assert that MindTouch auth was # never attempted. _old = settings.DEKIWIKI_ENDPOINT settings.DEKIWIKI_ENDPOINT = False response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) settings.DEKIWIKI_ENDPOINT = _old ok_(not trap['was_called']) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_mindtouch_creds_create_user_and_profile(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() get_current.return_value.domain = 'dev.mo.org' if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') self.assertRaises(User.DoesNotExist, User.objects.get, username='******') # Try to log in as a MindTouch user response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) # Ensure there are no validation errors page = pq(response.content) eq_(0, page.find('.errorlist').length, "There should be no validation errors in login") # Login should have auto-created django user u = User.objects.get(username='******') eq_(True, u.is_active) ok_(u.get_profile()) # Login page should show welcome back doc = pq(response.content) eq_('testaccount', doc.find('ul.user-state a:first').text())
class RegisterTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock_missing_get_deki_user @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now response = self.client.post(reverse('users.register'), { 'username': username, 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) assert u.password.startswith('sha256') assert not u.is_active eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 key = RegistrationProfile.objects.all()[0].activation_key assert mail.outbox[0].body.find('activate/%s' % key) > 0 # Now try to log in u.is_active = True u.save() response = self.client.post(reverse('users.login'), { 'username': username, 'password': '******' }, follow=True) eq_(200, response.status_code) eq_('http://testserver/en-US/', response.redirect_chain[0][0]) @mock_missing_get_deki_user @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_posts_mindtouch_user(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now response = self.client.post(reverse('users.register'), { 'username': username, 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) assert u.password.startswith('sha256') assert not u.is_active eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 key = RegistrationProfile.objects.all()[0].activation_key assert mail.outbox[0].body.find('activate/%s' % key) > 0 if not settings.DEKIWIKI_MOCK: deki_id = u.get_profile().deki_user_id doc = get_deki_user_doc(u) eq_(str(deki_id), doc('user').attr('id')) eq_(username, doc('username').text()) # Now try to log in u.is_active = True u.save() response = self.client.post(reverse('users.login'), { 'username': username, 'password': '******' }, follow=True) eq_(200, response.status_code) eq_('http://testserver/en-US/', response.redirect_chain[0][0]) @mock_missing_get_deki_user @mock_put_mindtouch_user @mock_perform_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_retries_mindtouch_post(self, get_current): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() get_current.return_value.domain = 'dev.mo.org' now = time() username = '******' % now response = self.client.post(reverse('users.register'), { 'username': username, 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) eq_(200, response.status_code) ok_("Please try again later." in response.content) self.assertRaises(User.DoesNotExist, User.objects.get, username=username) @mock_missing_get_deki_user @mock_post_mindtouch_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_unicode_password(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now u_str = u'\xe5\xe5\xee\xe9\xf8\xe7\u6709\u52b9' response = self.client.post(reverse('users.register', locale='ja'), { 'username': username, 'email': '*****@*****.**', 'password': u_str, 'password2': u_str }, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) u.is_active = True u.save() assert u.password.startswith('sha256') # make sure you can login now response = self.client.post(reverse('users.login', locale='ja'), { 'username': username, 'password': u_str }, follow=True) eq_(200, response.status_code) eq_('http://testserver/ja/', response.redirect_chain[0][0]) @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_activation(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now user = RegistrationProfile.objects.create_inactive_user( username, 'testpass', '*****@*****.**') assert not user.is_active key = RegistrationProfile.objects.all()[0].activation_key url = reverse('users.activate', args=[key]) response = self.client.get(url, follow=True) eq_(200, response.status_code) user = User.objects.get(pk=user.pk) assert user.is_active @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_claim_watches(self, get_current): """Claim user watches upon activation.""" old, settings.CELERY_ALWAYS_EAGER = settings.CELERY_ALWAYS_EAGER, True get_current.return_value.domain = 'su.mo.com' watch(email='*****@*****.**', save=True) now = time() username = '******' % now user = RegistrationProfile.objects.create_inactive_user( username, 'testpass', '*****@*****.**') key = RegistrationProfile.objects.all()[0].activation_key self.client.get(reverse('users.activate', args=[key]), follow=True) # Watches are claimed. assert user.watch_set.exists() settings.CELERY_ALWAYS_EAGER = old @mock_get_deki_user def test_duplicate_username(self): response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_duplicate_mindtouch_username(self): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_duplicate_email(self): User.objects.create(username='******', email='*****@*****.**').save() response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo' }, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_no_match_passwords(self): response = self.client.post(reverse('users.register'), { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'bar' }, follow=True) self.assertContains(response, 'must match')
class ProfileViewsTest(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug def _get_current_form_field_values(self, doc): # Scrape out the existing significant form field values. form = dict() for fn in ('email', 'fullname', 'title', 'organization', 'location', 'irc_nickname', 'bio', 'interests'): form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val() return form @attr('docs_activity') def test_profile_view(self): """A user profile can be viewed""" profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.user.username, doc.find('#profile-head.vcard .nickname').text()) eq_(profile.fullname, doc.find('#profile-head.vcard .fn').text()) eq_(profile.title, doc.find('#profile-head.vcard .title').text()) eq_(profile.organization, doc.find('#profile-head.vcard .org').text()) eq_(profile.location, doc.find('#profile-head.vcard .loc').text()) eq_('IRC: ' + profile.irc_nickname, doc.find('#profile-head.vcard .irc').text()) eq_(profile.bio, doc.find('#profile-head.vcard .bio').text()) def test_my_profile_view(self): u = User.objects.get(username='******') self.client.login(username=u.username, password=TESTUSER_PASSWORD) resp = self.client.get('/profile/') eq_(302, resp.status_code) ok_(reverse('devmo.views.profile_view', args=(u.username,)) in resp['Location']) def test_bug_698971(self): """A non-numeric page number should not cause an error""" (user, profile) = create_profile() url = '%s?page=asdf' % reverse('devmo.views.profile_view', args=(user.username,)) try: self.client.get(url, follow=True) except PageNotAnInteger: ok_(False, "Non-numeric page number should not cause an error") def test_profile_edit(self): profile = UserProfile.objects.get(user__username='******') user = profile.user url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(0, doc.find('#profile-head .edit .button').length) self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_view', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) edit_button = doc.find('#profile-head .edit #edit-profile') eq_(1, edit_button.length) url = edit_button.attr('href') r = self.client.get(url, follow=True) doc = pq(r.content) eq_(profile.fullname, doc.find('#profile-edit input[name="fullname"]').val()) eq_(profile.title, doc.find('#profile-edit input[name="title"]').val()) eq_(profile.organization, doc.find('#profile-edit input[name="organization"]').val()) eq_(profile.location, doc.find('#profile-edit input[name="location"]').val()) eq_(profile.irc_nickname, doc.find('#profile-edit input[name="irc_nickname"]').val()) new_attrs = dict( email='*****@*****.**', fullname="Another Name", title="Another title", organization="Another org", ) r = self.client.post(url, new_attrs, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) eq_(new_attrs['fullname'], doc.find('#profile-head .main .fn').text()) eq_(new_attrs['title'], doc.find('#profile-head .info .title').text()) eq_(new_attrs['organization'], doc.find('#profile-head .info .org').text()) profile = UserProfile.objects.get(user__username=user.username) eq_(new_attrs['fullname'], profile.fullname) eq_(new_attrs['title'], profile.title) eq_(new_attrs['organization'], profile.organization) def test_my_profile_edit(self): u = User.objects.get(username='******') self.client.login(username=u.username, password=TESTUSER_PASSWORD) resp = self.client.get('/profile/edit') eq_(302, resp.status_code) ok_(reverse('devmo.views.profile_edit', args=(u.username,)) in resp['Location']) def test_profile_edit_beta(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_(None, doc.find('input#id_beta').attr('checked')) form = self._get_current_form_field_values(doc) form['beta'] = True r = self.client.post(url, form, follow=True) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) eq_('checked', doc.find('input#id_beta').attr('checked')) def test_profile_edit_websites(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_sites = { u'website': u'http://example.com/', u'twitter': u'http://twitter.com/lmorchard', u'github': u'http://github.com/lmorchard', u'stackoverflow': u'http://stackoverflow.com/users/lmorchard', } form = self._get_current_form_field_values(doc) # Fill out the form with websites. form.update(dict(('websites_%s' % k, v) for k, v in test_sites.items())) # Submit the form, verify redirect to profile detail r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) # Verify the websites are saved in the profile. eq_(test_sites, p.websites) # Verify the saved websites appear in the editing form url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) for k, v in test_sites.items(): eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val()) # Come up with some bad sites, either invalid URL or bad URL prefix bad_sites = { u'website': u'HAHAHA WHAT IS A WEBSITE', u'twitter': u'http://facebook.com/lmorchard', u'stackoverflow': u'http://overqueueblah.com/users/lmorchard', } form.update(dict(('websites_%s' % k, v) for k, v in bad_sites.items())) # Submit the form, verify errors for all of the bad sites r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-edit').length) tmpl = '#profile-edit #elsewhere .%s .errorlist' for n in ('website', 'twitter', 'stackoverflow'): eq_(1, doc.find(tmpl % n).length) def test_profile_edit_interests(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = ['javascript', 'css', 'canvas', 'html', 'homebrewing'] form = self._get_current_form_field_values(doc) form['interests'] = ', '.join(test_tags) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) result_tags = [t.name.replace('profile:interest:', '') for t in p.tags.all_ns('profile:interest:')] result_tags.sort() test_tags.sort() eq_(test_tags, result_tags) test_expertise = ['css', 'canvas'] form['expertise'] = ', '.join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('#profile-head').length) p = UserProfile.objects.get(user=user) result_tags = [t.name.replace('profile:expertise:', '') for t in p.tags.all_ns('profile:expertise')] result_tags.sort() test_expertise.sort() eq_(test_expertise, result_tags) # Now, try some expertise tags not covered in interests test_expertise = ['css', 'canvas', 'mobile', 'movies'] form['expertise'] = ', '.join(test_expertise) r = self.client.post(url, form, follow=True) doc = pq(r.content) eq_(1, doc.find('.error #id_expertise').length) def test_bug_709938_interests(self): user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) doc = pq(r.content) test_tags = [u'science,Technology,paradox,knowledge,modeling,big data,' u'vector,meme,heuristics,harmony,mathesis universalis,' u'symmetry,mathematics,computer graphics,field,chemistry,' u'religion,astronomy,physics,biology,literature,' u'spirituality,Art,Philosophy,Psychology,Business,Music,' u'Computer Science'] form = self._get_current_form_field_values(doc) form['interests'] = test_tags r = self.client.post(url, form, follow=True) eq_(200, r.status_code) doc = pq(r.content) eq_(1, doc.find('ul.errorlist li').length) assert ('Ensure this value has at most 255 characters' in doc.find('ul.errorlist li').text()) def test_bug_698126_l10n(self): """Test that the form field names are localized""" user = User.objects.get(username='******') self.client.login(username=user.username, password=TESTUSER_PASSWORD) url = reverse('devmo.views.profile_edit', args=(user.username,)) r = self.client.get(url, follow=True) for field in r.context['form'].fields: # if label is localized it's a lazy proxy object ok_(not isinstance( r.context['form'].fields[field].label, basestring), 'Field %s is a string!' % field) def _break(self, url, r): logging.debug("URL %s" % url) logging.debug("STAT %s" % r.status_code) logging.debug("HEAD %s" % r.items()) logging.debug("CONT %s" % r.content) ok_(False)
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******', 'next': login_uri }, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, { 'username': '******', 'password': '******' }, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_request_properties(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' r = RequestFactory().get('/users/login', {'next': '/demos/submit'}, HTTP_REFERER='referer-trumped-by-get') eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().post('/users/login', {'next': '/demos/submit'}) eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().get('/users/login', HTTP_REFERER='/demos/submit') eq_('/demos/submit', _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_no_self_redirects(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' for next in [settings.LOGIN_URL, settings.LOGOUT_URL]: r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_invalid_next_parameter(self, get_current): '''_clean_next_url cleans invalid urls''' get_current.return_value.domain = 'dev.mo.org' for next in self._invalid_nexts(): r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_login_invalid_next_parameter(self, get_current): '''Test with an invalid ?next=http://example.com parameter.''' get_current.return_value.domain = 'testserver.com' valid_next = reverse('home', locale=settings.LANGUAGE_CODE) for invalid_next in self._invalid_nexts(): # Verify that _valid_ next parameter is set in form hidden field. response = self.client.get( urlparams(reverse('users.login'), next=invalid_next)) eq_(200, response.status_code) doc = pq(response.content) eq_(valid_next, doc('input[name="next"]')[0].attrib['value']) # Verify that it gets used on form POST. response = self.client.post( reverse('users.login'), { 'username': '******', 'password': '******', 'next': invalid_next }) eq_(302, response.status_code) eq_('http://testserver' + valid_next, response['location']) self.client.logout() def _invalid_nexts(self): return ['http://foobar.com/evil/', '//goo.gl/y-bad']
class RegisterTestCase(TestCase): fixtures = ["test_users.json"] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock_missing_get_deki_user @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, "get_current") def test_new_user(self, get_current): get_current.return_value.domain = "su.mo.com" now = time() username = "******" % now response = self.client.post( reverse("users.register"), {"username": username, "email": "*****@*****.**", "password": "******", "password2": "foo"}, follow=True, ) eq_(200, response.status_code) u = User.objects.get(username=username) assert u.password.startswith("sha256") assert not u.is_active eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find("Please confirm your") == 0 key = RegistrationProfile.objects.all()[0].activation_key assert mail.outbox[0].body.find("activate/%s" % key) > 0 # Now try to log in u.is_active = True u.save() response = self.client.post(reverse("users.login"), {"username": username, "password": "******"}, follow=True) eq_(200, response.status_code) eq_("http://testserver/en-US/", response.redirect_chain[0][0]) @mock_missing_get_deki_user @mock_post_mindtouch_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, "get_current") def test_unicode_password(self, get_current): get_current.return_value.domain = "su.mo.com" now = time() username = "******" % now u_str = u"\xe5\xe5\xee\xe9\xf8\xe7\u6709\u52b9" response = self.client.post( reverse("users.register", locale="ja"), {"username": username, "email": "*****@*****.**", "password": u_str, "password2": u_str}, follow=True, ) eq_(200, response.status_code) u = User.objects.get(username=username) u.is_active = True u.save() assert u.password.startswith("sha256") # make sure you can login now response = self.client.post( reverse("users.login", locale="ja"), {"username": username, "password": u_str}, follow=True ) eq_(200, response.status_code) eq_("http://testserver/ja/", response.redirect_chain[0][0]) @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, "get_current") def test_new_user_activation(self, get_current): get_current.return_value.domain = "su.mo.com" now = time() username = "******" % now user = RegistrationProfile.objects.create_inactive_user(username, "testpass", "*****@*****.**") assert not user.is_active key = RegistrationProfile.objects.all()[0].activation_key url = reverse("users.activate", args=[key]) response = self.client.get(url, follow=True) eq_(200, response.status_code) user = User.objects.get(pk=user.pk) assert user.is_active @mock_get_deki_user def test_duplicate_username(self): response = self.client.post( reverse("users.register"), {"username": "******", "email": "*****@*****.**", "password": "******", "password2": "foo"}, follow=True, ) self.assertContains(response, "already exists") @mock_get_deki_user def test_duplicate_mindtouch_username(self): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() response = self.client.post( reverse("users.register"), {"username": "******", "email": "*****@*****.**", "password": "******", "password2": "foo"}, follow=True, ) self.assertContains(response, "already exists") @mock_get_deki_user def test_duplicate_email(self): User.objects.create(username="******", email="*****@*****.**").save() response = self.client.post( reverse("users.register"), {"username": "******", "email": "*****@*****.**", "password": "******", "password2": "foo"}, follow=True, ) self.assertContains(response, "already exists") @mock_get_deki_user def test_no_match_passwords(self): response = self.client.post( reverse("users.register"), {"username": "******", "email": "*****@*****.**", "password": "******", "password2": "bar"}, follow=True, ) self.assertContains(response, "must match")
class RegisterTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock_missing_get_deki_user @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now response = self.client.post(reverse('users.register'), {'username': username, 'email': '*****@*****.**', 'password': '******', 'password2': 'foo'}, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) assert u.password.startswith('sha256') assert not u.is_active eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 key = RegistrationProfile.objects.all()[0].activation_key assert mail.outbox[0].body.find('activate/%s' % key) > 0 # Now try to log in u.is_active = True u.save() response = self.client.post(reverse('users.login'), {'username': username, 'password': '******'}, follow=True) eq_(200, response.status_code) eq_('http://testserver/en-US/', response.redirect_chain[0][0]) @mock_missing_get_deki_user @mock_post_mindtouch_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_unicode_password(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now u_str = u'\xe5\xe5\xee\xe9\xf8\xe7\u6709\u52b9' response = self.client.post(reverse('users.register', locale='ja'), {'username': username, 'email': '*****@*****.**', 'password': u_str, 'password2': u_str}, follow=True) eq_(200, response.status_code) u = User.objects.get(username=username) u.is_active = True u.save() assert u.password.startswith('sha256') # make sure you can login now response = self.client.post(reverse('users.login', locale='ja'), {'username': username, 'password': u_str}, follow=True) eq_(200, response.status_code) eq_('http://testserver/ja/', response.redirect_chain[0][0]) @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_activation(self, get_current): get_current.return_value.domain = 'su.mo.com' now = time() username = '******' % now user = RegistrationProfile.objects.create_inactive_user( username, 'testpass', '*****@*****.**') assert not user.is_active key = RegistrationProfile.objects.all()[0].activation_key url = reverse('users.activate', args=[key]) response = self.client.get(url, follow=True) eq_(200, response.status_code) user = User.objects.get(pk=user.pk) assert user.is_active @mock_put_mindtouch_user @mock_post_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_new_user_claim_watches(self, get_current): """Claim user watches upon activation.""" old, settings.CELERY_ALWAYS_EAGER = settings.CELERY_ALWAYS_EAGER, True get_current.return_value.domain = 'su.mo.com' watch(email='*****@*****.**', save=True) now = time() username = '******' % now user = RegistrationProfile.objects.create_inactive_user( username, 'testpass', '*****@*****.**') key = RegistrationProfile.objects.all()[0].activation_key self.client.get(reverse('users.activate', args=[key]), follow=True) # Watches are claimed. assert user.watch_set.exists() settings.CELERY_ALWAYS_EAGER = old @mock_get_deki_user def test_duplicate_username(self): response = self.client.post(reverse('users.register'), {'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo'}, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_duplicate_mindtouch_username(self): if not settings.DEKIWIKI_ENDPOINT: # Don't even bother with this test, if there's no MindTouch API raise SkipTest() response = self.client.post(reverse('users.register'), {'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo'}, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_duplicate_email(self): User.objects.create(username='******', email='*****@*****.**').save() response = self.client.post(reverse('users.register'), {'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foo'}, follow=True) self.assertContains(response, 'already exists') @mock_get_deki_user def test_no_match_passwords(self): response = self.client.post(reverse('users.register'), {'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'bar'}, follow=True) self.assertContains(response, 'must match')
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock_mindtouch_login @mock_get_deki_user @mock_put_mindtouch_user @mock.patch_object(Site.objects, 'get_current') def test_mindtouch_creds_create_user_and_profile(self, get_current): get_current.return_value.domain = 'dev.mo.org' if not getattr(settings, 'DEKIWIKI_MOCK', False): # HACK: Ensure that expected user details are in MindTouch when not # mocking the API mt_email = '*****@*****.**' user_xml = MINDTOUCH_USER_XML % dict(username="******", email=mt_email, fullname="None", status="active", language="", timezone="-08:00", role="Contributor") DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount', user_xml=user_xml) passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % ( settings.DEKIWIKI_ENDPOINT, '=testaccount', settings.DEKIWIKI_APIKEY) requests.put(passwd_url, data='theplanet') self.assertRaises(User.DoesNotExist, User.objects.get, username='******') # Try to log in as a MindTouch user response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) # Ensure there are no validation errors page = pq(response.content) eq_(0, page.find('.errorlist').length, "There should be no validation errors in login") # Login should have auto-created django user u = User.objects.get(username='******') eq_(True, u.is_active) ok_(u.get_profile()) # Login page should show welcome back doc = pq(response.content) eq_('testaccount', doc.find('ul.user-state a:first').text())
class LoginTestCase(TestCase): fixtures = ['test_users.json'] def setUp(self): self.old_debug = settings.DEBUG settings.DEBUG = True self.client = LocalizingClient() self.client.logout() def tearDown(self): settings.DEBUG = self.old_debug @mock.patch_object(Site.objects, 'get_current') def test_bad_login_fails_both_backends(self, get_current): get_current.return_value.domain = 'dev.mo.org' self.assertRaises(User.DoesNotExist, User.objects.get, username='******') response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) self.assertContains(response, 'Please enter a correct username and ' 'password.') @mock.patch_object(Site.objects, 'get_current') def test_django_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_wont_redirect_to_login(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******', 'next': login_uri}, follow=True) eq_(200, response.status_code) for redirect_url, code in response.redirect_chain: ok_(login_uri not in redirect_url, "Found %s in redirect_chain" % login_uri) doc = pq(response.content) eq_('testuser', doc.find('ul.user-state a:first').text()) @mock.patch_object(Site.objects, 'get_current') def test_logged_in_message(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, follow=True) eq_(200, response.status_code) doc = pq(response.content) eq_("You are already logged in.", doc.find('div#content-main').text()) @mock.patch_object(Site.objects, 'get_current') def test_django_login_redirects_to_next(self, get_current): get_current.return_value.domain = 'dev.mo.org' login_uri = reverse('users.login') response = self.client.post(login_uri, {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) response = self.client.get(login_uri, {'next': '/en-US/demos/submit'}, follow=True) eq_('http://testserver/en-US/demos/submit', response.redirect_chain[0][0]) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_request_properties(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' r = RequestFactory().get('/users/login', {'next': '/demos/submit'}, HTTP_REFERER='referer-trumped-by-get') eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().post('/users/login', {'next': '/demos/submit'}) eq_('/demos/submit', _clean_next_url(r)) r = RequestFactory().get('/users/login', HTTP_REFERER='/demos/submit') eq_('/demos/submit', _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_no_self_redirects(self, get_current): '''_clean_next_url checks POST, GET, and REFERER''' get_current.return_value.domain = 'dev.mo.org' for next in [settings.LOGIN_URL, settings.LOGOUT_URL]: r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_clean_next_url_invalid_next_parameter(self, get_current): '''_clean_next_url cleans invalid urls''' get_current.return_value.domain = 'dev.mo.org' for next in self._invalid_nexts(): r = RequestFactory().get('/users/login', {'next': next}) eq_(None, _clean_next_url(r)) @mock.patch_object(Site.objects, 'get_current') def test_login_invalid_next_parameter(self, get_current): '''Test with an invalid ?next=http://example.com parameter.''' get_current.return_value.domain = 'testserver.com' valid_next = reverse('home', locale=settings.LANGUAGE_CODE) for invalid_next in self._invalid_nexts(): # Verify that _valid_ next parameter is set in form hidden field. response = self.client.get(urlparams(reverse('users.login'), next=invalid_next)) eq_(200, response.status_code) doc = pq(response.content) eq_(valid_next, doc('input[name="next"]')[0].attrib['value']) # Verify that it gets used on form POST. response = self.client.post(reverse('users.login'), {'username': '******', 'password': '******', 'next': invalid_next}) eq_(302, response.status_code) eq_('http://testserver' + valid_next, response['location']) self.client.logout() def _invalid_nexts(self): return ['http://foobar.com/evil/', '//goo.gl/y-bad']
class UploadImageTestCase(TestCase): fixtures = ['users.json', 'questions.json'] def setUp(self): super(UploadImageTestCase, self).setUp() self.client = LocalizingClient() self.client.login(username='******', password='******') def tearDown(self): ImageAttachment.objects.all().delete() super(UploadImageTestCase, self).tearDown() def test_model_invalid(self): """Specifying an invalid model returns 400.""" r = post(self.client, 'upload.up_image_async', {'image': ''}, args=['invalid.model', 123]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Model does not exist.', json_r['message']) def test_object_notexist(self): """Upload nothing returns 404 error and html content.""" r = post(self.client, 'upload.up_image_async', {'image': ''}, args=['questions.Question', 123]) eq_(404, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Object does not exist.', json_r['message']) def test_empty_image(self): """Upload nothing returns 400 error and json content.""" r = post(self.client, 'upload.up_image_async', {'image': ''}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_('You have not selected an image to upload.', json_r['errors']['image'][0]) def test_upload_image(self): """Uploading an image works.""" with open('apps/upload/tests/media/test.jpg') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) file = json_r['file'] eq_('test.jpg', file['name']) eq_(90, file['width']) eq_(120, file['height']) name = '098f6b.jpg' message = 'Url "%s" does not contain "%s"' % (file['url'], name) assert (name in file['url']), message eq_(1, ImageAttachment.objects.count()) image = ImageAttachment.objects.all()[0] eq_('pcraciunoiu', image.creator.username) eq_(150, image.file.width) eq_(200, image.file.height) eq_('question', image.content_type.model) eq_(1, image.object_id) def test_upload_unicode_image(self): """Uploading an unicode image works.""" with open(u'apps/upload/tests/media/123ascii\u6709\u52b9.jpg') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) def test_delete_image_logged_out(self): """Can't delete an image logged out.""" # Upload the image first self.test_upload_image() im = ImageAttachment.objects.all()[0] self.client.logout() r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(403, r.status_code) assert ImageAttachment.uncached.exists() def test_delete_image_no_permission(self): """Can't delete an image without permission.""" u = User.objects.get(username='******') assert not u.has_perm('upload.delete_imageattachment') self.test_upload_image() im = ImageAttachment.objects.all()[0] self.client.login(username='******', password='******') r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(403, r.status_code) assert ImageAttachment.uncached.exists() def test_delete_image_owner(self): """Users can delete their own images.""" self.test_upload_image() im = ImageAttachment.objects.all()[0] r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) assert not ImageAttachment.uncached.exists() def test_delete_image_with_permission(self): """Users with permission can delete images.""" u = User.objects.get(username='******') ct = ContentType.objects.get_for_model(ImageAttachment) p = Permission.objects.get_or_create(codename='delete_imageattachment', content_type=ct)[0] u.user_permissions.add(p) assert u.has_perm('upload.delete_imageattachment') self.test_upload_image() im = ImageAttachment.objects.all()[0] self.client.login(username='******', password='******') r = post(self.client, 'upload.del_image_async', args=[im.id]) eq_(200, r.status_code) json_r = json.loads(r.content) eq_('success', json_r['status']) assert not ImageAttachment.uncached.exists() def test_delete_no_image(self): """Trying to delete a non-existent image 404s.""" r = post(self.client, 'upload.del_image_async', args=[123]) eq_(404, r.status_code) data = json.loads(r.content) eq_('error', data['status']) def test_invalid_image(self): """Make sure invalid files are not accepted as images.""" with open('apps/upload/__init__.py', 'rb') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_('The submitted file is empty.', json_r['errors']['image'][0]) def test_invalid_image_extensions(self): """Make sure invalid extensions are not accepted as images.""" with open('apps/upload/tests/media/test_invalid.ext', 'rb') as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_( 'Please upload an image with one of the following extensions: ' 'jpg, jpeg, png, gif.', json_r['errors']['__all__'][0]) def test_upload_long_filename(self): """Uploading an image with a filename that's too long fails.""" with open('apps/upload/tests/media/a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_worth_' 'more_than_250_characters__a_really_long_filename_yes_.jpg')\ as f: r = post(self.client, 'upload.up_image_async', {'image': f}, args=['questions.Question', 1]) eq_(400, r.status_code) json_r = json.loads(r.content) eq_('error', json_r['status']) eq_('Invalid or no image received.', json_r['message']) eq_( MSG_IMAGE_LONG % { 'length': 251, 'max': settings.MAX_FILENAME_LENGTH }, json_r['errors']['image'][0])