| # Copyright 2013 the Melange authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Unit tests for organization application view.""" |
| |
| import cloudstorage |
| import mock |
| import unittest |
| |
| from django.core.files import uploadedfile |
| from django import forms as django_forms |
| from django import http |
| |
| from google.appengine.api import images |
| from google.appengine.ext import ndb |
| |
| from melange.logic import organization as org_logic |
| from melange.models import connection as connection_model |
| from melange.models import contact as contact_model |
| from melange.models import organization as org_model |
| from melange.models import survey as survey_model |
| from melange.views import organization as org_view |
| |
| from seeder import profile as profile_seeder |
| from seeder import user as user_seeder |
| |
| from soc.models import licenses |
| from soc.modules.gsoc.views.helper import request_data |
| from soc.views import forms |
| |
| from summerofcode.templates import tabs |
| from summerofcode.views import org_app as org_app_view |
| |
| from tests import org_utils |
| from tests import profile_utils |
| from tests import test_utils |
| |
| |
| TEST_ORG_ID = 'test_org_id' |
| TEST_ORG_NAME = u'Test Org Name' |
| TEST_BLOG = 'http://www.test.blog.com/' |
| TEST_DESCRIPTION = u'Test Organization Description' |
| TEST_TAGS = u'tag one,tag_two,tag 3' |
| TEST_SINGLE_TAG = u'tag_two' |
| TEST_LICENSE = licenses.LICENSES[0] |
| TEST_FACEBOOK = u'http://www.test.facebook.com/' |
| TEST_FEED_URL = u'http://www.test.feed.com/' |
| TEST_GOOGLE_PLUS = u'http://www.test.google.plus.com/' |
| TEST_IDEAS_PAGE = 'http://www.test.ideas.com/' |
| TEST_IRC_CHANNEL = 'irc://irc.freenode.net/test' |
| TEST_MAILING_LIST = 'mailinglist@example.com' |
| TEST_TWITTER = u'http://www.test.twitter.com/' |
| TEST_WEB_PAGE = u'http://www.web.page.com/' |
| TEST_IS_VETERAN = True |
| TEST_ELIGIBLE_COUNTRY = True |
| |
| TEST_LOGO_IMAGE_PATH = 'tests/images/melange_logo.png' |
| TEST_LOGO_IMAGE_INVALID_SIZE_PATH = 'tests/images/melange_logo_invalid_size.png' |
| |
| NUMBER_OF_ACCEPTED_ORGS = 4 |
| |
| |
| def _getOrgLogoEditUrl(org): |
| """Returns URL to Edit Organization Logo page. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| A string containing the URL to Edit Organization Logo page. |
| """ |
| return '/gsoc/org/logo/edit/%s' % org.key.id() |
| |
| |
| def _getOrgPreferencesEditUrl(org): |
| """Returns URL to Edit Organization Preferences page. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| A string containing the URL to Edit Organization Preferences page. |
| """ |
| return '/gsoc/org/preferences/edit/%s' % org.key.id() |
| |
| |
| def _getOrgProfileCreateUrl(program): |
| """Returns URL to Create Organization Profile page. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| A string containing the URL to Create Organization Profile page. |
| """ |
| return '/gsoc/org/profile/create/%s' % program.key().name() |
| |
| |
| def _getOrgProfileEditUrl(org): |
| """Returns URL to Edit Organization Profile page. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| A string containing the URL to Edit Organization Profile page. |
| """ |
| return '/gsoc/org/profile/edit/%s' % org.key.id() |
| |
| |
| def _getOrgApplicationSubmitUrl(org): |
| """Returns URL to Submit Organization Application page. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| A string containing the URL to Submit Organization Application page. |
| """ |
| return '/gsoc/org/application/submit/%s' % org.key.id() |
| |
| |
| def _getOrgAppShowUrl(org): |
| """Returns URL to Organization Application Show page. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| A string containing the URL to Organization Application Show page. |
| """ |
| return '/gsoc/org/application/show2/%s' % org.key.id() |
| |
| |
| def _getOrgSurveyResponseShowUrl(org): |
| """Returns URL to Organization Survey Response Show page. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| A string containing the URL to Organization Survey Response Show page. |
| """ |
| return '/gsoc/org/survey_response/show/%s' % org.key.id() |
| |
| |
| def _getPublicOrgListUrl(program): |
| """Returns URL to Public Organization List page. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| A string containing the URL to Public Organization List page. |
| """ |
| return '/gsoc/org/list/public/%s' % program.key().name() |
| |
| |
| def _getOrgApplicationListPageListUrl(program): |
| """Returns URL to Organization Application List page. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| A string containing the URL to Organization Application List page. |
| """ |
| return '/gsoc/org/application/list/%s' % program.key().name() |
| |
| |
| VALID_POSTDATA = { |
| 'org_id': TEST_ORG_ID, |
| 'name': TEST_ORG_NAME, |
| 'blog': TEST_BLOG, |
| 'description': TEST_DESCRIPTION, |
| 'facebook': TEST_FACEBOOK, |
| 'feed_url': TEST_FEED_URL, |
| 'google_plus': TEST_GOOGLE_PLUS, |
| 'license': TEST_LICENSE, |
| 'ideas_page': TEST_IDEAS_PAGE, |
| 'irc_channel': TEST_IRC_CHANNEL, |
| 'mailing_list': TEST_MAILING_LIST, |
| 'tags': TEST_TAGS, |
| 'twitter': TEST_TWITTER, |
| 'web_page': TEST_WEB_PAGE, |
| 'eligible_country': True |
| } |
| |
| # Proposal content which contains dangerous HTML that needs validation |
| RAW_HTML_DESCRIPTION = """ |
| This is description of organization. |
| <form method="POST" action="http://www.example.com/"></form> |
| <p style="background-image: url(www.example.com/some_image.png);"> |
| Another part of the description. Embedded in a paragraph with suspicious style. |
| </p> |
| """ |
| |
| SANITIZED_HTML_DESCRIPTION = """ |
| This is description of organization. |
| <form method="POST" action="http://www.example.com/"></form> |
| <p style=""> |
| Another part of the description. Embedded in a paragraph with suspicious style. |
| </p> |
| """.strip() |
| |
| class OrgProfileCreatePageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgProfileCreatePage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile(self.program.key(), user=user) |
| |
| response = self.get(_getOrgProfileCreateUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| def testOrgProfileCreated(self): |
| """Tests that organization entity is created properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| postdata = { |
| 'org_id': TEST_ORG_ID, |
| 'name': TEST_ORG_NAME, |
| 'blog': TEST_BLOG, |
| 'description': TEST_DESCRIPTION, |
| 'facebook': TEST_FACEBOOK, |
| 'feed_url': TEST_FEED_URL, |
| 'google_plus': TEST_GOOGLE_PLUS, |
| 'license': TEST_LICENSE, |
| 'ideas_page': TEST_IDEAS_PAGE, |
| 'irc_channel': TEST_IRC_CHANNEL, |
| 'mailing_list': TEST_MAILING_LIST, |
| 'tags': TEST_TAGS, |
| 'twitter': TEST_TWITTER, |
| 'web_page': TEST_WEB_PAGE, |
| 'is_veteran': TEST_IS_VETERAN, |
| 'eligible_country': TEST_ELIGIBLE_COUNTRY, |
| } |
| response = self.post( |
| _getOrgProfileCreateUrl(self.program), postdata=postdata) |
| |
| # check that organization entity has been created |
| org = ndb.Key( |
| org_model.Organization._get_kind(), |
| '%s/%s' % (self.program.key().name(), TEST_ORG_ID)).get() |
| self.assertIsNotNone(org) |
| self.assertEqual(org.contact.blog, TEST_BLOG) |
| self.assertEqual(org.contact.facebook, TEST_FACEBOOK) |
| self.assertEqual(org.contact.feed_url, TEST_FEED_URL) |
| self.assertEqual(org.contact.google_plus, TEST_GOOGLE_PLUS) |
| self.assertEqual(org.contact.irc_channel, TEST_IRC_CHANNEL) |
| self.assertEqual(org.contact.mailing_list, TEST_MAILING_LIST) |
| self.assertEqual(org.contact.twitter, TEST_TWITTER) |
| self.assertEqual(org.contact.web_page, TEST_WEB_PAGE) |
| self.assertEqual(org.description, TEST_DESCRIPTION) |
| self.assertEqual(org.ideas_page, TEST_IDEAS_PAGE) |
| self.assertEqual(org.license, TEST_LICENSE) |
| self.assertEqual(org.name, TEST_ORG_NAME) |
| self.assertEqual(org.org_id, TEST_ORG_ID) |
| self.assertEqual(org.tags, TEST_TAGS.split(',')) |
| self.assertTrue(org.is_veteran) |
| |
| # check that the client is redirected to update page |
| self.assertResponseRedirect(response, url=_getOrgApplicationSubmitUrl(org)) |
| |
| # check that a connection with the current user has been started |
| profile = profile.key.get() |
| self.assertIn(org.key, profile.admin_for) |
| connection = connection_model.Connection.query( |
| connection_model.Connection.organization == org.key, |
| ancestor=profile.key).get() |
| self.assertIsNotNone(connection) |
| self.assertEqual(connection.org_role, connection_model.ORG_ADMIN_ROLE) |
| self.assertEqual(connection.user_role, connection_model.ROLE) |
| self.assertFalse(connection.init_by_user) |
| self.assertTrue(connection.seen_by_org) |
| self.assertTrue(connection.seen_by_user) |
| |
| def testInvalidData(self): |
| """Tests that organization is not created if data is not valid.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # the organization is not from the eligible countries |
| postdata = VALID_POSTDATA.copy() |
| postdata['eligible_country'] = False |
| response = self.post( |
| _getOrgProfileCreateUrl(self.program), postdata=postdata) |
| self.assertTrue(response.context['error']) |
| |
| # the organization with the same org_id already exists |
| org_utils.seedSOCOrganization(self.program.key(), org_id='duplicate') |
| postdata = VALID_POSTDATA.copy() |
| postdata['org_id'] = 'duplicate' |
| response = self.post( |
| _getOrgProfileCreateUrl(self.program), postdata=postdata) |
| self.assertResponseBadRequest(response) |
| |
| def testDescriptionSanitized(self): |
| """Tests that submitted description is sanitized properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| postdata = VALID_POSTDATA.copy() |
| postdata['description'] = RAW_HTML_DESCRIPTION |
| response = self.post( |
| _getOrgProfileCreateUrl(self.program), postdata=postdata) |
| |
| # check that the description is sanitized |
| org = ndb.Key( |
| org_model.Organization._get_kind(), |
| '%s/%s' % (self.program.key().name(), TEST_ORG_ID)).get() |
| self.assertEqual(SANITIZED_HTML_DESCRIPTION, org.description) |
| |
| |
| OTHER_TEST_BLOG = 'http://www.other.test.blog.com/' |
| OTHER_TEST_DESCRIPTION = u'Other Organization Description' |
| OTHER_TEST_FACEBOOK = u'http://www.other.test.facebook.com/' |
| OTHER_TEST_NAME = 'Other Org Name' |
| OTHER_TEST_FEED_URL = u'http://www.other.test.feed.com/' |
| OTHER_TEST_GOOGLE_PLUS = 'http://www.other.test.google.plus.com/' |
| OTHER_TEST_IDEAS_PAGE = 'http://www.other.ideas.page.com/' |
| OTHER_TEST_IRC_CHANNEL = 'irc://irc.freenode.net/other' |
| OTHER_TEST_LICENSE = licenses.LICENSES[-1] |
| OTHER_TEST_MAILING_LIST = 'othermailinglist@example.com' |
| OTHER_TEST_TWITTER = u'http://www.other.test.twitter.com/' |
| OTHER_TEST_TAGS = u'other tag one,other_tag_two,other tag 3' |
| OTHER_TEST_WEB_PAGE = u'http://www.other.web.page.com/' |
| OTHER_TEST_IS_VETERAN = False |
| OTHER_TEST_LOGO_IMAGE_PATH = 'tests/images/melange_logo_2.png' |
| |
| class OrgProfileEditPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgProfileEditPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| contact = contact_model.Contact(mailing_list=TEST_MAILING_LIST) |
| self.org = org_utils.seedSOCOrganization( |
| self.program.key(), org_id=TEST_ORG_ID, name=TEST_ORG_NAME, |
| ideas_page=TEST_IDEAS_PAGE, tags=TEST_TAGS.split(','), |
| contact=contact, is_veteran=not OTHER_TEST_IS_VETERAN) |
| |
| self.app_response = survey_model.SurveyResponse(parent=self.org.key) |
| self.app_response.put() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgProfileEditUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testOrgProfileUpdated(self): |
| """Tests that organization entity is updated correctly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # check that mutable properties are updated |
| postdata = { |
| 'blog': OTHER_TEST_BLOG, |
| 'description': OTHER_TEST_DESCRIPTION, |
| 'facebook': OTHER_TEST_FACEBOOK, |
| 'feed_url': OTHER_TEST_FEED_URL, |
| 'google_plus': OTHER_TEST_GOOGLE_PLUS, |
| 'ideas_page': OTHER_TEST_IDEAS_PAGE, |
| 'irc_channel': OTHER_TEST_IRC_CHANNEL, |
| 'license': OTHER_TEST_LICENSE, |
| 'mailing_list': OTHER_TEST_MAILING_LIST, |
| 'name': OTHER_TEST_NAME, |
| 'tags': OTHER_TEST_TAGS, |
| 'twitter': OTHER_TEST_TWITTER, |
| 'web_page': OTHER_TEST_WEB_PAGE, |
| 'is_veteran': OTHER_TEST_IS_VETERAN, |
| } |
| response = self.post(_getOrgProfileEditUrl(self.org), postdata=postdata) |
| self.assertResponseRedirect(response, url=_getOrgProfileEditUrl(self.org)) |
| |
| # check that organization entity has been updated |
| org = ndb.Key( |
| org_model.Organization._get_kind(), |
| '%s/%s' % (self.program.key().name(), TEST_ORG_ID)).get() |
| self.assertEqual(org.contact.blog, OTHER_TEST_BLOG) |
| self.assertEqual(org.contact.mailing_list, OTHER_TEST_MAILING_LIST) |
| self.assertEqual(org.description, OTHER_TEST_DESCRIPTION) |
| self.assertEqual(org.contact.facebook, OTHER_TEST_FACEBOOK) |
| self.assertEqual(org.contact.google_plus, OTHER_TEST_GOOGLE_PLUS) |
| self.assertEqual(org.ideas_page, OTHER_TEST_IDEAS_PAGE) |
| self.assertEqual(org.contact.irc_channel, OTHER_TEST_IRC_CHANNEL) |
| self.assertEqual(org.license, OTHER_TEST_LICENSE) |
| self.assertEqual(org.name, OTHER_TEST_NAME) |
| self.assertEqual(org.tags, OTHER_TEST_TAGS.split(',')) |
| self.assertEqual(org.contact.twitter, OTHER_TEST_TWITTER) |
| self.assertEqual(org.contact.web_page, OTHER_TEST_WEB_PAGE) |
| |
| # check that organization ID is not updated even if it is in POST data |
| postdata = { |
| 'blog': OTHER_TEST_BLOG, |
| 'description': OTHER_TEST_DESCRIPTION, |
| 'facebook': OTHER_TEST_FACEBOOK, |
| 'feed_url': OTHER_TEST_FEED_URL, |
| 'google_plus': OTHER_TEST_GOOGLE_PLUS, |
| 'ideas_page': OTHER_TEST_IDEAS_PAGE, |
| 'license': OTHER_TEST_LICENSE, |
| 'org_id': 'other_org_id', |
| 'name': TEST_ORG_NAME, |
| 'twitter': OTHER_TEST_TWITTER, |
| 'web_page': OTHER_TEST_WEB_PAGE, |
| } |
| response = self.post(_getOrgProfileEditUrl(self.org), postdata=postdata) |
| self.assertResponseRedirect(response, url=_getOrgProfileEditUrl(self.org)) |
| |
| # check that organization entity has been updated |
| org = ndb.Key( |
| org_model.Organization._get_kind(), |
| '%s/%s' % (self.program.key().name(), TEST_ORG_ID)).get() |
| self.assertEqual(org.org_id, TEST_ORG_ID) |
| |
| def testOrgsTabs(self): |
| """Tests that correct organization related tabs are present in context.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgProfileEditUrl(self.org)) |
| |
| # check that tabs are present in context |
| self.assertIn('tabs', response.context) |
| |
| # check that tab to "Edit Profile" page is the selected one |
| self.assertEqual(response.context['tabs'].selected_tab_id, |
| tabs.ORG_PROFILE_TAB_ID) |
| |
| def testDescriptionSanitized(self): |
| """Tests that submitted description is sanitized properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| postdata = VALID_POSTDATA.copy() |
| postdata['description'] = RAW_HTML_DESCRIPTION |
| response = self.post(_getOrgProfileEditUrl(self.org), postdata=postdata) |
| |
| # check that the description is sanitized |
| org = self.org.key.get() |
| self.assertEqual(SANITIZED_HTML_DESCRIPTION, org.description) |
| |
| |
| class OrgApplicationSubmitPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgApplicationSubmitPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| self.org = org_utils.seedSOCOrganization(self.program.key()) |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgApplicationSubmitUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testApplicationCreated(self): |
| """Tests that organization application is created properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # TODO(daniel): submit actual responses in POST data |
| response = self.post(_getOrgApplicationSubmitUrl(self.org)) |
| self.assertResponseRedirect(response) |
| |
| # check that application has been created |
| application = survey_model.SurveyResponse.query(ancestor=self.org.key).get() |
| self.assertIsNotNone(application) |
| |
| def testOrgsTabs(self): |
| """Tests that correct organization related tabs are present in context.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgApplicationSubmitUrl(self.org)) |
| |
| # check that tabs are present in context |
| self.assertIn('tabs', response.context) |
| |
| # check that tab to "Edit Profile" page is the selected one |
| self.assertEqual(response.context['tabs'].selected_tab_id, |
| tabs.ORG_APP_RESPONSE_TAB_ID) |
| |
| |
| class OrgAppShowPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgAppShowPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| self.org = org_utils.seedSOCOrganization( |
| self.program.key(), name=TEST_ORG_NAME) |
| self.app_response = survey_model.SurveyResponse(parent=self.org.key) |
| self.app_response.put() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser(host_for=[self.program]) |
| profile_utils.loginNDB(user) |
| |
| response = self.get(_getOrgAppShowUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testPostMethodNotAllowed(self): |
| """Tests that POST method is not permitted.""" |
| user = user_seeder.seedUser(host_for=[self.program]) |
| profile_utils.loginNDB(user) |
| |
| response = self.post(_getOrgAppShowUrl(self.org)) |
| self.assertResponseMethodNotAllowed(response) |
| |
| |
| class SurveyResponseShowPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for SurveyResponseShowPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| self.org = org_utils.seedSOCOrganization( |
| self.program.key(), name=TEST_ORG_NAME) |
| self.app_response = survey_model.SurveyResponse(parent=self.org.key) |
| self.app_response.put() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgSurveyResponseShowUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testPostMethodNotAllowed(self): |
| """Tests that POST method is not permitted.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.post(_getOrgSurveyResponseShowUrl(self.org)) |
| self.assertResponseMethodNotAllowed(response) |
| |
| |
| class PublicOrganizationListPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for PublicOrganizationListPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| response = self.get(_getPublicOrgListUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| def testOrgListWithTagFiltration(self): |
| """Tests that filtered list of organizations is visible.""" |
| # seed some organizations with accepted status and some tags |
| for _ in range(NUMBER_OF_ACCEPTED_ORGS): |
| org = org_utils.seedSOCOrganization(self.program.key(), |
| tags=OTHER_TEST_TAGS.split(','), status=org_model.Status.ACCEPTED) |
| |
| # seed an organization with test tag |
| other_org = org_utils.seedSOCOrganization(self.program.key(), |
| tags=TEST_TAGS.split(','), status=org_model.Status.ACCEPTED) |
| |
| # check that only orgs which have single test tag in their tags are listed |
| data = self.getListData(_getPublicOrgListUrl(self.program), 0) |
| dataWithTag = self.getListData( |
| _getPublicOrgListUrl(self.program), 0, tag=TEST_SINGLE_TAG) |
| |
| self.assertNotEqual(len(dataWithTag), len(data)) |
| |
| |
| class OrgApplicationListPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgApplicationListPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser(host_for=[self.program]) |
| profile_utils.loginNDB(user) |
| |
| response = self.get(_getOrgApplicationListPageListUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| |
| class _MockView(object): |
| """Simple request handler to be used as a callback for other handlers.""" |
| |
| def get(self, data, access, mutator): |
| """See base.RequestHandler.get for specification.""" |
| pass |
| |
| _NUMBER_OF_ORG_ADMINS = 2 |
| |
| |
| class ApplyOrgAdmissionDecisionHandlerTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ApplyOrgAdmissionDecisionHandler class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| self.pre_accepted_org = org_utils.seedOrganization( |
| self.program.key(), status=org_model.Status.PRE_ACCEPTED) |
| org_utils.seedApplication(self.pre_accepted_org.key, self.org_app.key()) |
| self.pre_rejected_org = org_utils.seedOrganization( |
| self.program.key(), status=org_model.Status.PRE_REJECTED) |
| org_utils.seedApplication(self.pre_rejected_org.key, self.org_app.key()) |
| self.accepted_org = org_utils.seedOrganization( |
| self.program.key(), status=org_model.Status.ACCEPTED) |
| org_utils.seedApplication(self.accepted_org.key, self.org_app.key()) |
| self.rejected_org = org_utils.seedOrganization( |
| self.program.key(), status=org_model.Status.REJECTED) |
| org_utils.seedApplication(self.rejected_org.key, self.org_app.key()) |
| self.applying_org = org_utils.seedOrganization( |
| self.program.key(), status=org_model.Status.APPLYING) |
| org_utils.seedApplication(self.applying_org.key, self.org_app.key()) |
| |
| def testOrganizationStatusIsUpdated(self): |
| """Tests that organization admission decisions are applied correctly.""" |
| kwargs = { |
| 'sponsor': self.sponsor.key().name(), |
| 'program': self.program.program_id, |
| } |
| request = http.HttpRequest() |
| data = request_data.RequestData(request, None, kwargs) |
| |
| handler = org_view.ApplyOrgAdmissionDecisionHandler( |
| _MockView(), url='unused-url') |
| handler.handle(data, None, None) |
| |
| self.executeMapReduceJobs() |
| |
| # check that status have been changed for pre_accepted and pre_rejected orgs |
| self.assertEqual( |
| self.pre_accepted_org.key.get().status, org_model.Status.ACCEPTED) |
| self.assertEqual( |
| self.pre_rejected_org.key.get().status, org_model.Status.REJECTED) |
| |
| # check that status for other orgs have not changed |
| self.assertEqual( |
| self.accepted_org.key.get().status, org_model.Status.ACCEPTED) |
| self.assertEqual( |
| self.rejected_org.key.get().status, org_model.Status.REJECTED) |
| self.assertEqual( |
| self.applying_org.key.get().status, org_model.Status.APPLYING) |
| |
| def testEmailIsSent(self): |
| """Tests that acceptance and rejection emails are sent.""" |
| # seed a couple of organization administrators for both organizations |
| addresses_for_accept_email = [] |
| addresses_for_reject_email = [] |
| for _ in range(_NUMBER_OF_ORG_ADMINS): |
| profile = profile_seeder.seedProfile( |
| self.program.key(), admin_for=[self.pre_accepted_org.key]) |
| addresses_for_accept_email.append(profile.contact.email) |
| |
| profile = profile_seeder.seedProfile( |
| self.program.key(), admin_for=[self.pre_rejected_org.key]) |
| addresses_for_reject_email.append(profile.contact.email) |
| |
| # finalize decision and execute all MapReduce jobs |
| kwargs = { |
| 'sponsor': self.sponsor.key().name(), |
| 'program': self.program.program_id, |
| } |
| request = http.HttpRequest() |
| data = request_data.RequestData(request, None, kwargs) |
| |
| handler = org_view.ApplyOrgAdmissionDecisionHandler( |
| _MockView(), url='unused-url') |
| handler.handle(data, None, None) |
| |
| self.executeMapReduceJobs() |
| |
| # check that emails have been sent |
| for email_address in addresses_for_accept_email: |
| self.assertEmailSent(bcc=email_address) |
| |
| for email_address in addresses_for_reject_email: |
| self.assertEmailSent(bcc=email_address) |
| |
| |
| class OrgLogoEditPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgLogoEditPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.testUp for specification.""" |
| self.init() |
| self.org = org_utils.seedSOCOrganization( |
| self.program.key(), name=TEST_ORG_NAME) |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgLogoEditUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testOrgLogoImageSet(self): |
| """Tests that organization logo image is set properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # set logo image |
| with open(TEST_LOGO_IMAGE_PATH, 'rb') as logo_image_file: |
| postdata = {'logo_image': logo_image_file} |
| response = self.post( |
| _getOrgLogoEditUrl(self.org), postdata=postdata) |
| self.assertResponseRedirect(response, url=_getOrgLogoEditUrl(self.org)) |
| |
| logo_image_file.seek(0) |
| expected_size = len(logo_image_file.read()) |
| |
| # check that logo image is set |
| org = self.org.key.get() |
| self.assertIsNotNone(org.logo_path) |
| |
| # check that the content is saved and that it has a proper size |
| with cloudstorage.open(org.logo_path) as logo_object: |
| self.assertEqual(expected_size, len(logo_object.read())) |
| |
| def testOrgLogoImageUpdated(self): |
| """Tests that organization logo image is updated properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # set an existing logo file |
| with open(TEST_LOGO_IMAGE_PATH, 'r') as logo_image_file: |
| uploaded_file = uploadedfile.UploadedFile(logo_image_file) |
| org_logic.setOrgLogo(self.org.key, uploaded_file) |
| |
| org = self.org.key.get() |
| old_path = org.logo_path |
| |
| # update logo image |
| with open(OTHER_TEST_LOGO_IMAGE_PATH, 'r') as logo_image_file: |
| postdata = {'logo_image': logo_image_file} |
| response = self.post( |
| _getOrgLogoEditUrl(self.org), postdata=postdata) |
| self.assertResponseRedirect(response, url=_getOrgLogoEditUrl(self.org)) |
| |
| # check that logo image is set and updated |
| org = self.org.key.get() |
| self.assertIsNotNone(org.logo_path) |
| self.assertNotEqual(old_path, org.logo_path) |
| |
| # check that the old file is not stored anymore |
| with self.assertRaises(cloudstorage.NotFoundError): |
| cloudstorage.open(old_path) |
| |
| @mock.patch.object( |
| org_logic, 'setOrgLogo', side_effect=images.TransformationError) |
| def testErrorWhileLogoIsSet(self, mock_func): |
| """Tests that errors are handled properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # update logo image |
| with open(OTHER_TEST_LOGO_IMAGE_PATH, 'r') as logo_image_file: |
| postdata = {'logo_image': logo_image_file} |
| response = self.post( |
| _getOrgLogoEditUrl(self.org), postdata=postdata) |
| self.assertResponseBadRequest(response) |
| |
| def testInvalidData(self): |
| """Tests that organization logo is not set if the image is not valid.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| # uploaded image has invalid size |
| with open(TEST_LOGO_IMAGE_INVALID_SIZE_PATH, 'rb') as logo_image_file: |
| postdata = {'logo_image': logo_image_file} |
| response = self.post( |
| _getOrgLogoEditUrl(self.org), postdata=postdata) |
| self.assertTrue(response.context['error']) |
| self.assertIn( |
| forms.ImageField.default_error_messages['invalid_dimensions'] % ( |
| 200, 200, # these are dimensions of the invalid image |
| org_view.LOGO_IMAGE_WIDTH, org_view.LOGO_IMAGE_HEIGHT), |
| response.context['forms'][0].errors['logo_image']) |
| |
| |
| TEST_MAX_SCORE = 7 |
| TEST_SLOT_REQUEST_MIN = 3 |
| TEST_SLOT_REQUEST_MAX = 10 |
| TEST_CONTRIB_TEMPLATE = u'Test Application Template' |
| TEST_SCORING_ENABLED = False |
| TEST_ACCEPTED_STUDENTS_MESSAGE = u'Test Accepted Students Message' |
| TEST_REJECTED_STUDENTS_MESSAGE = u'Test Rejected Students Message' |
| TEST_EXTRA_FIELDS = ['one field', 'second field', 'third field'] |
| |
| class OrgPreferencesEditPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for OrgPreferencesEditPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.testUp for specification.""" |
| self.init() |
| self.org = org_utils.seedSOCOrganization( |
| self.program.key(), name=TEST_ORG_NAME, |
| status=org_model.Status.ACCEPTED) |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgPreferencesEditUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testOrgPreferencesUpdated(self): |
| """Tests that organization entity is updated correctly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| postdata = { |
| 'slot_request_min': unicode(TEST_SLOT_REQUEST_MIN), |
| 'slot_request_max': unicode(TEST_SLOT_REQUEST_MAX), |
| 'max_score': unicode(TEST_MAX_SCORE), |
| 'contrib_template': TEST_CONTRIB_TEMPLATE, |
| 'scoring_enabled': TEST_SCORING_ENABLED, |
| 'accepted_students_message': TEST_ACCEPTED_STUDENTS_MESSAGE, |
| 'rejected_students_message': TEST_REJECTED_STUDENTS_MESSAGE, |
| 'extra_fields': '\n'.join(TEST_EXTRA_FIELDS), |
| } |
| response = self.post(_getOrgPreferencesEditUrl(self.org), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getOrgPreferencesEditUrl(self.org)) |
| |
| org = self.org.key.get() |
| self.assertEqual(org.max_score, TEST_MAX_SCORE) |
| self.assertEqual(org.slot_request_min, TEST_SLOT_REQUEST_MIN) |
| self.assertEqual(org.slot_request_max, TEST_SLOT_REQUEST_MAX) |
| self.assertEqual(org.contrib_template, TEST_CONTRIB_TEMPLATE) |
| self.assertEqual(org.scoring_enabled, TEST_SCORING_ENABLED) |
| self.assertEqual(org.extra_fields, TEST_EXTRA_FIELDS) |
| |
| org_messages = org_model.OrganizationMessages.query( |
| ancestor=org.key).get() |
| self.assertEqual( |
| org_messages.accepted_students_message, TEST_ACCEPTED_STUDENTS_MESSAGE) |
| self.assertEqual( |
| org_messages.rejected_students_message, TEST_REJECTED_STUDENTS_MESSAGE) |
| |
| def testOrgsTabs(self): |
| """Tests that correct organization related tabs are present in context.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, admin_for=[self.org.key]) |
| |
| response = self.get(_getOrgPreferencesEditUrl(self.org)) |
| |
| # check that tabs are present in context |
| self.assertIn('tabs', response.context) |
| |
| # check that tab to "Edit Profile" page is the selected one |
| self.assertEqual(response.context['tabs'].selected_tab_id, |
| tabs.ORG_PREFERENCES_TAB_ID) |
| |
| |
| _TEST_EXTRA_FIELDS = ['field one', 'field two, with comma', 'field - three'] |
| |
| class CleanExtraFieldsTest(unittest.TestCase): |
| """Unit tests for cleanExtraFields function.""" |
| |
| def testListReturned(self): |
| """Tests that a list of extra fields is returned.""" |
| extra_fields = org_app_view.cleanExtraFields('\n'.join(_TEST_EXTRA_FIELDS)) |
| self.assertLessEqual(extra_fields, _TEST_EXTRA_FIELDS) |
| |
| def testInputTooLong(self): |
| """Tests that too long input is not allowed.""" |
| with self.assertRaises(django_forms.ValidationError): |
| org_app_view.cleanExtraFields( |
| 'a' * org_app_view.EXTRA_FIELD_MAX_LENGTH * 2) |