| # 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 user profile related views.""" |
| |
| import datetime |
| |
| from google.appengine.ext import blobstore |
| from google.appengine.ext import ndb |
| |
| from django.utils import html |
| |
| from melange.models import address as address_model |
| from melange.models import education as education_model |
| from melange.models import profile as profile_model |
| from melange.models import signature as signature_model |
| from melange.models import user as user_model |
| from melange.views import profile as profile_view |
| |
| from seeder import document as document_seeder |
| from seeder import profile as profile_seeder |
| from seeder import user as user_seeder |
| |
| from soc.logic import validate |
| from soc.views import base |
| |
| from summerofcode.templates import tabs |
| |
| from tests import profile_utils |
| from tests import test_utils |
| from tests import timeline_utils |
| from tests.utils import project_utils |
| |
| |
| TEST_BIRTH_DATE = datetime.date(1993, 1, 1) |
| TEST_EMAIL = 'test@example.com' |
| TEST_FIRST_NAME = 'Test First' |
| TEST_GENDER = profile_view._GENDER_FEMALE_ID |
| TEST_LAST_NAME = 'Test Last' |
| TEST_PHONE = '1234567890' |
| TEST_PROGRAM_KNOWLEDGE = profile_view._PROGRAM_KNOWLEDGE_FRIEND_ID |
| TEST_PUBLIC_NAME = 'Test Public Name' |
| TEST_RESIDENTIAL_STREET = 'Test Street' |
| TEST_RESIDENTIAL_STREET_EXTRA = 'Test Street Extra' |
| TEST_RESIDENTIAL_CITY = 'Test City' |
| TEST_RESIDENTIAL_PROVINCE = 'CA' |
| TEST_RESIDENTIAL_POSTAL_CODE = '90000' |
| TEST_RESIDENTIAL_COUNTRY = 'United States' |
| TEST_SHIPPING_NAME = 'Test Shipping Name' |
| TEST_SHIPPING_STREET = 'Test Shipping Street' |
| TEST_SHIPPING_STREET_EXTRA = 'Test Shipping Street Extra.' |
| TEST_SHIPPING_CITY = 'Test Shipping City' |
| TEST_SHIPPING_PROVINCE = 'DC' |
| TEST_SHIPPING_POSTAL_CODE = '20000' |
| TEST_SHIPPING_COUNTRY = 'United States' |
| TEST_TEE_SIZE = profile_view._TEE_SIZE_M_ID |
| TEST_TEE_STYLE = profile_view._TEE_STYLE_FEMALE_ID |
| TEST_USER_ID = 'test_user_id' |
| |
| TEST_SCHOOL_COUNTRY = 'United States' |
| TEST_SCHOOL_NAME = 'Melange University' |
| TEST_SCHOOL_WEB_PAGE = u'http://www.test.school.com/' |
| TEST_MAJOR = 'Computer Science' |
| TEST_DEGREE = profile_view._DEGREE_MASTERS_ID |
| TEST_EXPECTED_GRADUATION = 2015 |
| TEST_ENROLLMENT_FORM = blobstore.BlobKey('unused') |
| TEST_TAX_FORM = blobstore.BlobKey('unused') |
| |
| OTHER_TEST_SHIPPING_NAME = 'Other Shipping Name' |
| OTHER_TEST_SHIPPING_STREET = 'Other Shipping Street' |
| OTHER_TEST_SHIPPING_STREET_EXTRA = 'Other Shipping Street Extra' |
| OTHER_TEST_SHIPPING_CITY = 'Other Shipping City' |
| OTHER_TEST_SHIPPING_PROVINCE = 'AL' |
| OTHER_TEST_SHIPPING_POSTAL_CODE = '35005' |
| OTHER_TEST_SHIPPING_COUNTRY = 'United States' |
| |
| OTHER_TEST_SCHOOL_COUNTRY = 'United States' |
| OTHER_TEST_SCHOOL_NAME = 'Other School' |
| OTHER_TEST_MAJOR = 'Economics' |
| OTHER_TEST_DEGREE = profile_view._DEGREE_PHD_ID |
| OTHER_TEST_EXPECTED_GRADUATION = 2016 |
| OTHER_TEST_SCHOOL_WEB_PAGE = u'http://www.other.school.web.page.com/' |
| |
| |
| def _getProfileRegisterAsOrgMemberUrl(program_key): |
| """Returns URL to Register As Organization Member page. |
| |
| Args: |
| program_key: Program key. |
| |
| Returns: |
| A string containing the URL to Register As Organization Member page. |
| """ |
| return '/gsoc/profile/register/org_member/%s' % program_key.name() |
| |
| |
| def _getProfileRegisterAsStudentUrl(program_key, is_json=False): |
| """Returns URL to Register As Student page. |
| |
| Args: |
| program_key: Program key. |
| is_json: A bool telling whether it is JSON data request. |
| |
| Returns: |
| A string containing the URL to Register As Student page. |
| """ |
| return '/gsoc/profile/register/student/%s%s' % ( |
| program_key.name(), '?fmt=json' if is_json else '') |
| |
| |
| def _getEditProfileUrl(program_key, is_json=False, is_validated=False): |
| """Returns URL to Edit Profile page. |
| |
| Args: |
| program_key: Program key. |
| is_json: A bool telling whether it is JSON data request. |
| is_validated: A bool telling whether the URL indicates data validation. |
| |
| Returns: |
| A string containing the URL to Edit Profile page. |
| """ |
| url = '/gsoc/profile/edit/%s' % program_key.name() |
| |
| if is_json or is_validated: |
| url += '?' |
| if is_json: |
| url += 'fmt=json' |
| if is_validated: |
| url += 'validated=true' |
| |
| return url |
| |
| |
| def _getShowProfileUrl(program_key, is_validated=False): |
| """Returns URL to Show Profile page. |
| |
| Args: |
| program_key: Program key. |
| is_validated: A bool telling whether the URL indicates data validation. |
| |
| Returns: |
| A string containing the URL to Show Profile page. |
| """ |
| url = '/gsoc/profile/show/%s' % program_key.name() |
| if is_validated: |
| url += '?validated=true' |
| |
| return url |
| |
| |
| def _getAdminProfileUrl(profile_key): |
| """Returns URL to Admin Profile page. |
| |
| Args: |
| profile_key: Profile key. |
| |
| Returns: |
| A string containing the URL to Admin Profile page. |
| """ |
| return '/gsoc/profile/admin/%s' % profile_key.id() |
| |
| |
| class ProfileOrgMemberCreatePageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProfileOrgMemberCreatePage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| response = self.get(_getProfileRegisterAsOrgMemberUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| def testProfileCreatedWhenNoUserExists(self): |
| """Tests that profile entity is created correctly.""" |
| # check that page loads properly |
| response = self.get(_getProfileRegisterAsOrgMemberUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| # check that username is present in the form |
| form = response.context['forms'][0] |
| self.assertIn('user_id', form.fields) |
| |
| postdata = { |
| 'user_id': TEST_USER_ID, |
| 'public_name': TEST_PUBLIC_NAME, |
| 'first_name': TEST_FIRST_NAME, |
| 'last_name': TEST_LAST_NAME, |
| 'email': TEST_EMAIL, |
| 'phone': TEST_PHONE, |
| 'residential_street': TEST_RESIDENTIAL_STREET, |
| 'residential_city': TEST_RESIDENTIAL_CITY, |
| 'residential_province': TEST_RESIDENTIAL_PROVINCE, |
| 'residential_country': TEST_RESIDENTIAL_COUNTRY, |
| 'residential_postal_code': TEST_RESIDENTIAL_POSTAL_CODE, |
| 'birth_date': TEST_BIRTH_DATE.strftime('%Y-%m-%d'), |
| 'tee_style': TEST_TEE_STYLE, |
| 'tee_size': TEST_TEE_SIZE, |
| 'gender': TEST_GENDER, |
| 'program_knowledge': TEST_PROGRAM_KNOWLEDGE, |
| 'terms_of_service': True, |
| } |
| response = self.post( |
| _getProfileRegisterAsOrgMemberUrl(self.program.key()), |
| postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # check that user entity has been created |
| user_key = ndb.Key(user_model.User._get_kind(), TEST_USER_ID) |
| user = user_key.get() |
| self.assertIsNotNone(user) |
| |
| # check that profile entity has been created |
| profile_key = ndb.Key( |
| user_model.User._get_kind(), TEST_USER_ID, |
| profile_model.Profile._get_kind(), |
| '%s/%s' % (self.program.key().name(), TEST_USER_ID)) |
| profile = profile_key.get() |
| self.assertIsNotNone(profile) |
| |
| # check that Terms Of Service is signed and a signature is created |
| self.assertIn( |
| ndb.Key.from_old_key(self.program.mentor_agreement.key()), |
| profile.accepted_tos) |
| signature = signature_model.Signature.query( |
| signature_model.Signature.profile == profile_key, |
| signature_model.Signature.document == |
| ndb.Key.from_old_key(self.program.mentor_agreement.key())).get() |
| self.assertIsNotNone(signature) |
| |
| def testProfileCreatedWhenUserExists(self): |
| """Tests that a profile is created for a person with user entity.""" |
| # seed user entity |
| user = user_seeder.seedUser(TEST_USER_ID) |
| profile_utils.loginNDB(user) |
| |
| # check that page loads properly |
| response = self.get(_getProfileRegisterAsOrgMemberUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| # check that username is not present in the form |
| form = response.context['forms'][0] |
| self.assertNotIn('username', form.fields) |
| |
| # check POST request |
| postdata = { |
| 'public_name': TEST_PUBLIC_NAME, |
| 'first_name': TEST_FIRST_NAME, |
| 'last_name': TEST_LAST_NAME, |
| 'email': TEST_EMAIL, |
| 'phone': TEST_PHONE, |
| 'residential_street': TEST_RESIDENTIAL_STREET, |
| 'residential_city': TEST_RESIDENTIAL_CITY, |
| 'residential_province': TEST_RESIDENTIAL_PROVINCE, |
| 'residential_country': TEST_RESIDENTIAL_COUNTRY, |
| 'residential_postal_code': TEST_RESIDENTIAL_POSTAL_CODE, |
| 'birth_date': TEST_BIRTH_DATE.strftime('%Y-%m-%d'), |
| 'tee_style': TEST_TEE_STYLE, |
| 'tee_size': TEST_TEE_SIZE, |
| 'gender': TEST_GENDER, |
| 'program_knowledge': TEST_PROGRAM_KNOWLEDGE, |
| 'terms_of_service': True, |
| } |
| response = self.post( |
| _getProfileRegisterAsOrgMemberUrl(self.program.key()), |
| postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # check that profile entity has been created for the existing user |
| profile = profile_model.Profile.query(ancestor=user.key).get() |
| self.assertIsNotNone(profile) |
| self.assertEqual( |
| profile.key.id(), '%s/%s' % (self.program.key().name(), user.key.id())) |
| |
| # check that Terms Of Service is signed and a signature is created |
| self.assertIn( |
| ndb.Key.from_old_key(self.program.mentor_agreement.key()), |
| profile.accepted_tos) |
| signature = signature_model.Signature.query( |
| signature_model.Signature.profile == profile.key, |
| signature_model.Signature.document == |
| ndb.Key.from_old_key(self.program.mentor_agreement.key())).get() |
| self.assertIsNotNone(signature) |
| |
| def testSanitization(self): |
| """Tests that possible malicious content is sanitized properly.""" |
| self.timeline_helper.orgsAnnounced() |
| |
| xss_payload = '><img src=http://www.google.com/images/srpr/logo4w.png>' |
| |
| postdata = { |
| 'user_id': xss_payload, |
| 'public_name': xss_payload, |
| 'first_name': xss_payload, |
| 'last_name': xss_payload, |
| 'email': xss_payload, |
| 'phone': xss_payload, |
| 'residential_street': xss_payload, |
| 'residential_city': xss_payload, |
| 'residential_province': xss_payload, |
| 'residential_country': xss_payload, |
| 'residential_postal_code': xss_payload, |
| 'birth_date': xss_payload, |
| 'tee_style': xss_payload, |
| 'tee_size': xss_payload, |
| 'gender': xss_payload, |
| 'program_knowledge': xss_payload, |
| } |
| |
| response = self.post( |
| _getProfileRegisterAsOrgMemberUrl(self.program.key()), |
| postdata=postdata) |
| self.assertNotIn(xss_payload, response.content) |
| self.assertIn(html.escape(xss_payload), response.content) |
| |
| |
| class ProfileRegisterAsStudentPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProfileRegisterAsStudentPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| # student registration is now |
| self.program.timeline.student_signup_start = timeline_utils.past() |
| self.program.timeline.student_signup_end = timeline_utils.future() |
| self.program.timeline.put() |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| response = self.get(_getProfileRegisterAsStudentUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| def testJsonLoads(self): |
| """Tests that JSON data loads properly.""" |
| response = self.get( |
| _getProfileRegisterAsStudentUrl(self.program.key(), is_json=True)) |
| self.assertNotIn(base.JSON_ERROR_VALUE, response.content) |
| |
| def testStudentProfileCreated(self): |
| """Tests that profile entity is created correctly.""" |
| postdata = { |
| 'user_id': TEST_USER_ID, |
| 'public_name': TEST_PUBLIC_NAME, |
| 'first_name': TEST_FIRST_NAME, |
| 'last_name': TEST_LAST_NAME, |
| 'email': TEST_EMAIL, |
| 'phone': TEST_PHONE, |
| 'residential_street': TEST_RESIDENTIAL_STREET, |
| 'residential_street_extra': TEST_RESIDENTIAL_STREET_EXTRA, |
| 'residential_city': TEST_RESIDENTIAL_CITY, |
| 'residential_province': TEST_RESIDENTIAL_PROVINCE, |
| 'residential_country': TEST_RESIDENTIAL_COUNTRY, |
| 'residential_postal_code': TEST_RESIDENTIAL_POSTAL_CODE, |
| 'birth_date': TEST_BIRTH_DATE.strftime('%Y-%m-%d'), |
| 'tee_style': TEST_TEE_STYLE, |
| 'tee_size': TEST_TEE_SIZE, |
| 'gender': TEST_GENDER, |
| 'program_knowledge': TEST_PROGRAM_KNOWLEDGE, |
| 'school_country': TEST_SCHOOL_COUNTRY, |
| 'school_name': TEST_SCHOOL_NAME, |
| 'school_web_page': TEST_SCHOOL_WEB_PAGE, |
| 'major': TEST_MAJOR, |
| 'degree': TEST_DEGREE, |
| 'expected_graduation': TEST_EXPECTED_GRADUATION, |
| 'terms_of_service': True, |
| } |
| response = self.post( |
| _getProfileRegisterAsStudentUrl(self.program.key()), |
| postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # check that user entity has been created |
| user_key = ndb.Key(user_model.User._get_kind(), TEST_USER_ID) |
| user = user_key.get() |
| self.assertIsNotNone(user) |
| |
| # check that profile entity has been created |
| profile_key = ndb.Key( |
| user_model.User._get_kind(), TEST_USER_ID, |
| profile_model.Profile._get_kind(), |
| '%s/%s' % (self.program.key().name(), TEST_USER_ID)) |
| profile = profile_key.get() |
| self.assertIsNotNone(profile) |
| |
| # check that the created profile is a student |
| self.assertIsNotNone(profile.student_data) |
| self.assertTrue(profile.is_student) |
| |
| # check student data properties |
| self.assertEqual( |
| profile.student_data.education.school_country, TEST_SCHOOL_COUNTRY) |
| self.assertEqual( |
| profile.student_data.education.school_id, TEST_SCHOOL_NAME) |
| self.assertEqual( |
| profile.student_data.education.web_page, TEST_SCHOOL_WEB_PAGE) |
| self.assertEqual(profile.student_data.education.major, TEST_MAJOR) |
| self.assertEqual( |
| profile.student_data.education.expected_graduation, |
| TEST_EXPECTED_GRADUATION) |
| self.assertEqual( |
| profile.student_data.education.degree, education_model.Degree.MASTERS) |
| self.assertEqual(profile.student_data.number_of_proposals, 0) |
| self.assertEqual(profile.student_data.number_of_projects, 0) |
| self.assertEqual(profile.student_data.number_of_passed_evaluations, 0) |
| self.assertEqual(profile.student_data.number_of_failed_evaluations, 0) |
| self.assertListEqual(profile.student_data.project_for_orgs, []) |
| self.assertIsNone(profile.student_data.tax_form) |
| self.assertIsNone(profile.student_data.enrollment_form) |
| |
| # check that Terms Of Service is signed and a signature is created |
| self.assertIn( |
| ndb.Key.from_old_key(self.program.student_agreement.key()), |
| profile.accepted_tos) |
| signature = signature_model.Signature.query( |
| signature_model.Signature.profile == profile_key, |
| signature_model.Signature.document == |
| ndb.Key.from_old_key(self.program.student_agreement.key())).get() |
| self.assertIsNotNone(signature) |
| |
| |
| VALID_POSTDATA = { |
| 'public_name': TEST_PUBLIC_NAME, |
| 'first_name': TEST_FIRST_NAME, |
| 'last_name': TEST_LAST_NAME, |
| 'email': TEST_EMAIL, |
| 'phone': TEST_PHONE, |
| 'residential_street': TEST_RESIDENTIAL_STREET, |
| 'residential_street_extra': TEST_RESIDENTIAL_STREET_EXTRA, |
| 'residential_city': TEST_RESIDENTIAL_CITY, |
| 'residential_province': TEST_RESIDENTIAL_PROVINCE, |
| 'residential_country': TEST_RESIDENTIAL_COUNTRY, |
| 'residential_postal_code': TEST_RESIDENTIAL_POSTAL_CODE, |
| 'shipping_name': TEST_SHIPPING_NAME, |
| 'shipping_street': TEST_SHIPPING_STREET, |
| 'shipping_city': TEST_SHIPPING_CITY, |
| 'shipping_province': TEST_SHIPPING_PROVINCE, |
| 'shipping_country': TEST_SHIPPING_COUNTRY, |
| 'shipping_postal_code': TEST_SHIPPING_POSTAL_CODE, |
| 'is_shipping_address_different': True, |
| 'birth_date': TEST_BIRTH_DATE.strftime('%Y-%m-%d'), |
| 'tee_style': TEST_TEE_STYLE, |
| 'tee_size': TEST_TEE_SIZE, |
| 'gender': TEST_GENDER, |
| 'program_knowledge': TEST_PROGRAM_KNOWLEDGE, |
| } |
| |
| |
| class ProfileEditPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProfileEditPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| shipping_address = address_model.Address( |
| name=TEST_SHIPPING_NAME, street=TEST_SHIPPING_STREET, |
| street_extra=TEST_SHIPPING_STREET_EXTRA, city=TEST_SHIPPING_CITY, |
| province=TEST_SHIPPING_PROVINCE, country=TEST_SHIPPING_COUNTRY, |
| postal_code=TEST_SHIPPING_POSTAL_CODE) |
| |
| # seed an organization member profile |
| self.profile = profile_seeder.seedProfile( |
| self.program.key(), shipping_address=shipping_address, |
| accepted_tos= |
| [ndb.Key.from_old_key(self.program.mentor_agreement.key())]) |
| |
| # seed a student profile |
| student_data = profile_seeder.seedStudentData( |
| enrollment_form=TEST_ENROLLMENT_FORM, tax_form=TEST_TAX_FORM) |
| self.student = profile_seeder.seedProfile( |
| self.program.key(), shipping_address=shipping_address, |
| student_data=student_data, accepted_tos= |
| [ndb.Key.from_old_key(self.program.student_agreement.key())]) |
| |
| def testPageLoads(self): |
| """Tests that page loads properly.""" |
| # check that the page loads for an organization member |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| response = self.get(_getEditProfileUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| # check that the page loads for a student |
| profile_utils.loginNDB(self.student.key.parent().get()) |
| response = self.get(_getEditProfileUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| def testJsonLoads(self): |
| """Tests that JSON data loads properly.""" |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| response = self.get(_getEditProfileUrl(self.program.key(), is_json=True)) |
| self.assertNotIn(base.JSON_ERROR_VALUE, response.content) |
| |
| def testOrgMemberProfileUpdated(self): |
| """Tests that organization member profile is updated properly.""" |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| |
| postdata = { |
| 'public_name': TEST_PUBLIC_NAME, |
| 'first_name': TEST_FIRST_NAME, |
| 'last_name': TEST_LAST_NAME, |
| 'email': TEST_EMAIL, |
| 'phone': TEST_PHONE, |
| 'residential_street': TEST_RESIDENTIAL_STREET, |
| 'residential_street_extra': TEST_RESIDENTIAL_STREET_EXTRA, |
| 'residential_city': TEST_RESIDENTIAL_CITY, |
| 'residential_province': TEST_RESIDENTIAL_PROVINCE, |
| 'residential_country': TEST_RESIDENTIAL_COUNTRY, |
| 'residential_postal_code': TEST_RESIDENTIAL_POSTAL_CODE, |
| 'is_shipping_address_different': True, |
| 'shipping_name': OTHER_TEST_SHIPPING_NAME, |
| 'shipping_street': OTHER_TEST_SHIPPING_STREET, |
| 'shipping_street_extra': OTHER_TEST_SHIPPING_STREET_EXTRA, |
| 'shipping_city': OTHER_TEST_SHIPPING_CITY, |
| 'shipping_province': OTHER_TEST_SHIPPING_PROVINCE, |
| 'shipping_country': OTHER_TEST_SHIPPING_COUNTRY, |
| 'shipping_postal_code': OTHER_TEST_SHIPPING_POSTAL_CODE, |
| 'birth_date': TEST_BIRTH_DATE.strftime('%Y-%m-%d'), |
| 'tee_style': TEST_TEE_STYLE, |
| 'tee_size': TEST_TEE_SIZE, |
| 'gender': TEST_GENDER, |
| 'program_knowledge': TEST_PROGRAM_KNOWLEDGE, |
| } |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # check profile properties |
| profile = self.profile.key.get() |
| self.assertEqual(profile.public_name, TEST_PUBLIC_NAME) |
| self.assertEqual(profile.contact.email, TEST_EMAIL) |
| self.assertEqual(profile.first_name, TEST_FIRST_NAME) |
| self.assertEqual(profile.last_name, TEST_LAST_NAME) |
| self.assertEqual(profile.contact.phone, TEST_PHONE) |
| |
| # check residential address properties |
| self.assertEqual( |
| profile.residential_address.street, TEST_RESIDENTIAL_STREET) |
| self.assertEqual( |
| profile.residential_address.street_extra, TEST_RESIDENTIAL_STREET_EXTRA) |
| self.assertEqual( |
| profile.residential_address.city, TEST_RESIDENTIAL_CITY) |
| self.assertEqual( |
| profile.residential_address.province, TEST_RESIDENTIAL_PROVINCE) |
| self.assertEqual( |
| profile.residential_address.country, TEST_RESIDENTIAL_COUNTRY) |
| self.assertEqual( |
| profile.residential_address.postal_code, TEST_RESIDENTIAL_POSTAL_CODE) |
| |
| # check shipping address properties |
| self.assertEqual( |
| profile.shipping_address.name, OTHER_TEST_SHIPPING_NAME) |
| self.assertEqual( |
| profile.shipping_address.street, OTHER_TEST_SHIPPING_STREET) |
| self.assertEqual( |
| profile.shipping_address.street_extra, OTHER_TEST_SHIPPING_STREET_EXTRA) |
| self.assertEqual( |
| profile.shipping_address.city, OTHER_TEST_SHIPPING_CITY) |
| self.assertEqual( |
| profile.shipping_address.province, OTHER_TEST_SHIPPING_PROVINCE) |
| self.assertEqual( |
| profile.shipping_address.country, OTHER_TEST_SHIPPING_COUNTRY) |
| self.assertEqual( |
| profile.shipping_address.postal_code, OTHER_TEST_SHIPPING_POSTAL_CODE) |
| |
| self.assertEqual(profile.birth_date, TEST_BIRTH_DATE) |
| # : TODO(daniel): handle program_knowledge |
| self.assertEqual(profile.program_knowledge, TEST_PROGRAM_KNOWLEDGE) |
| self.assertEqual(profile.tee_style, profile_model.TeeStyle.FEMALE) |
| self.assertEqual(profile.tee_size, profile_model.TeeSize.M) |
| |
| # check profile is not a student |
| self.assertFalse(profile.is_student) |
| self.assertIsNone(profile.student_data) |
| |
| def testStudentProfileUpdated(self): |
| """Tests that a student profile is updated properly.""" |
| profile_utils.loginNDB(self.student.key.parent().get()) |
| |
| postdata = VALID_POSTDATA.copy() |
| postdata.update({ |
| 'school_country': OTHER_TEST_SCHOOL_COUNTRY, |
| 'school_name': OTHER_TEST_SCHOOL_NAME, |
| 'school_web_page': OTHER_TEST_SCHOOL_WEB_PAGE, |
| 'major': OTHER_TEST_MAJOR, |
| 'degree': OTHER_TEST_DEGREE, |
| 'expected_graduation': OTHER_TEST_EXPECTED_GRADUATION, |
| }) |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| student = self.student.key.get() |
| |
| # check student data properties are updated |
| self.assertEqual( |
| student.student_data.education.school_country, |
| OTHER_TEST_SCHOOL_COUNTRY) |
| self.assertEqual( |
| student.student_data.education.school_id, |
| OTHER_TEST_SCHOOL_NAME) |
| self.assertEqual( |
| student.student_data.education.web_page, |
| OTHER_TEST_SCHOOL_WEB_PAGE) |
| self.assertEqual( |
| student.student_data.education.major, |
| OTHER_TEST_MAJOR) |
| self.assertEqual( |
| student.student_data.education.degree, |
| education_model.Degree.PHD) |
| self.assertIsNone(student.student_data.education.grade) |
| self.assertEqual( |
| student.student_data.education.expected_graduation, |
| OTHER_TEST_EXPECTED_GRADUATION) |
| |
| # check that other student data properties are not changed |
| self.assertEqual(student.student_data.enrollment_form, TEST_ENROLLMENT_FORM) |
| self.assertEqual(student.student_data.tax_form, TEST_TAX_FORM) |
| |
| def testTermsOfServiceChanges(self): |
| """Tests that new Terms of Service must be accepted.""" |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| |
| # create new Terms Of Service document |
| self.program.mentor_agreement = document_seeder.seedDocument( |
| self.program, prefix=self.program.prefix) |
| self.program.put() |
| |
| # check that data error is returned if ToS is not signed |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=VALID_POSTDATA) |
| self.assertTrue(response.context['error']) |
| |
| # check that it is OK when ToS is accepted |
| postdata = VALID_POSTDATA.copy() |
| postdata['terms_of_service'] = True |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| profile = self.profile.key.get() |
| |
| # check that new Terms Of Service is signed and a signature is created |
| self.assertIn( |
| ndb.Key.from_old_key(self.program.mentor_agreement.key()), |
| profile.accepted_tos) |
| signature = signature_model.Signature.query( |
| signature_model.Signature.profile == profile.key, |
| signature_model.Signature.document == |
| ndb.Key.from_old_key(self.program.mentor_agreement.key())).get() |
| self.assertIsNotNone(signature) |
| |
| def testClearShippingAddress(self): |
| """Tests that shipping address is cleared properly.""" |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| |
| postdata = { |
| 'public_name': TEST_PUBLIC_NAME, |
| 'first_name': TEST_FIRST_NAME, |
| 'last_name': TEST_LAST_NAME, |
| 'email': TEST_EMAIL, |
| 'phone': TEST_PHONE, |
| 'residential_street': TEST_RESIDENTIAL_STREET, |
| 'residential_city': TEST_RESIDENTIAL_CITY, |
| 'residential_province': TEST_RESIDENTIAL_PROVINCE, |
| 'residential_country': TEST_RESIDENTIAL_COUNTRY, |
| 'residential_postal_code': TEST_RESIDENTIAL_POSTAL_CODE, |
| 'is_shipping_address_different': False, |
| 'birth_date': TEST_BIRTH_DATE.strftime('%Y-%m-%d'), |
| 'tee_style': TEST_TEE_STYLE, |
| 'tee_size': TEST_TEE_SIZE, |
| 'gender': TEST_GENDER, |
| 'program_knowledge': TEST_PROGRAM_KNOWLEDGE, |
| } |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # check that shipping address is cleared |
| profile = self.profile.key.get() |
| self.assertIsNone(profile.shipping_address) |
| |
| def testIsShippingAddressDifferent(self): |
| """Tests whether is_shipping_address_different is set correctly.""" |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| |
| # different shipping address is used |
| response = self.get(_getEditProfileUrl(self.program.key())) |
| form = response.context['forms'][0] |
| self.assertTrue(form.data['is_shipping_address_different']) |
| |
| # no shipping address is used |
| self.profile.shipping_address = None |
| self.profile.put() |
| response = self.get(_getEditProfileUrl(self.program.key())) |
| form = response.context['forms'][0] |
| self.assertFalse(form.data['is_shipping_address_different']) |
| |
| def testInvalidData(self): |
| """Tests that profile is not updated if data is not valid.""" |
| profile_utils.loginNDB(self.profile.key.parent().get()) |
| |
| # check that data is really valid |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=VALID_POSTDATA) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # the birth date is not eligible (the user is too young to be an org member) |
| days = (365 * validate.ORGANIZATION_MEMBER_MIN_AGE) / 2 |
| self.program.student_min_age_as_of = ( |
| TEST_BIRTH_DATE + datetime.timedelta(days=days)) |
| self.program.put() |
| |
| postdata = VALID_POSTDATA.copy() |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertTrue(response.context['error']) |
| |
| # residential address fields have invalid characters |
| fields = [ |
| 'residential_street', 'residential_street_extra', 'residential_city', |
| 'residential_province', 'residential_country', |
| 'residential_postal_code', 'first_name', 'last_name'] |
| for field in fields: |
| postdata = VALID_POSTDATA.copy() |
| postdata[field] = '!N^al!D' |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertTrue(response.context['error']) |
| |
| # shipping address fields have invalid characters |
| fields = [ |
| 'shipping_street', 'shipping_street_extra', 'shipping_city', |
| 'shipping_province', 'shipping_country', 'shipping_postal_code', |
| 'shipping_name'] |
| for field in fields: |
| postdata = VALID_POSTDATA.copy() |
| postdata[field] = '!N^al!D' |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertTrue(response.context['error']) |
| |
| def testGradeNotSet(self): |
| """Tests that grade of a student profile is not updated. |
| |
| Grade is a property of education model and a field in the generalized |
| profile form which are irrelevant for Summer Of Code programs. This test |
| case ensures that the property is not saved in the datastore even if |
| it is submitted in the POST data. |
| """ |
| profile_utils.loginNDB(self.student.key.parent().get()) |
| |
| # grade is present in the POST data |
| postdata = VALID_POSTDATA.copy() |
| postdata.update({ |
| 'school_country': OTHER_TEST_SCHOOL_COUNTRY, |
| 'school_name': OTHER_TEST_SCHOOL_NAME, |
| 'school_web_page': OTHER_TEST_SCHOOL_WEB_PAGE, |
| 'major': OTHER_TEST_MAJOR, |
| 'degree': OTHER_TEST_DEGREE, |
| 'expected_graduation': OTHER_TEST_EXPECTED_GRADUATION, |
| 'grade': '5' |
| }) |
| response = self.post( |
| _getEditProfileUrl(self.program.key()), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=_getShowProfileUrl(self.program.key(), is_validated=True)) |
| |
| # check that the grade is not set |
| student = self.student.key.get() |
| self.assertIsNone(student.student_data.education.grade) |
| |
| |
| _TEST_FORM_FILE = 'test_file_name.pdf' |
| |
| class ProfileShowPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProfileShowPage 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(_getShowProfileUrl(self.program.key())) |
| self.assertResponseOK(response) |
| |
| def testProfileTabs(self): |
| """Tests that correct profile related tabs are present in context.""" |
| self.timeline_helper.orgsAnnounced() |
| |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile(self.program.key(), user=user) |
| |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| # 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.VIEW_PROFILE_TAB_ID) |
| |
| def testEnrollmentForm(self): |
| """Tests that context for enrollment form is set properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| |
| # seed a student without a form |
| student = profile_seeder.seedStudent(self.program, user=user) |
| |
| # during the program it is possible to submit a form |
| self.timeline_helper.studentSignup() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.ENROLLMENT_FORM_LABEL in forms_fields) |
| |
| enrollment_form_field = forms_fields[profile_view.ENROLLMENT_FORM_LABEL] |
| self.assertIn(profile_view._NO_FORM_SUBMITTED, enrollment_form_field) |
| self.assertIn('Upload', enrollment_form_field) |
| |
| # after the program it is not possible to submit a form |
| self.timeline_helper.offSeason() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.ENROLLMENT_FORM_LABEL in forms_fields) |
| |
| enrollment_form_field = forms_fields[profile_view.ENROLLMENT_FORM_LABEL] |
| self.assertIn(profile_view._NO_FORM_SUBMITTED, enrollment_form_field) |
| self.assertNotIn('Upload', enrollment_form_field) |
| |
| # now a form is submitted |
| student.student_data.enrollment_form = self.createBlob(_TEST_FORM_FILE) |
| student.put() |
| |
| # during the program it is possible to download or re-upload a form |
| self.timeline_helper.studentSignup() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.ENROLLMENT_FORM_LABEL in forms_fields) |
| |
| enrollment_form_field = forms_fields[profile_view.ENROLLMENT_FORM_LABEL] |
| self.assertIn(_TEST_FORM_FILE, enrollment_form_field) |
| self.assertIn('Download', enrollment_form_field) |
| self.assertIn('Re-upload', enrollment_form_field) |
| |
| # after the program it is only possible to download a form |
| self.timeline_helper.offSeason() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.ENROLLMENT_FORM_LABEL in forms_fields) |
| |
| enrollment_form_field = forms_fields[profile_view.ENROLLMENT_FORM_LABEL] |
| self.assertIn(_TEST_FORM_FILE, enrollment_form_field) |
| self.assertIn('Download', enrollment_form_field) |
| self.assertNotIn('Re-upload', enrollment_form_field) |
| |
| def testTaxForm(self): |
| """Tests that context for tax form is set properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| |
| # seed a student without a form |
| student = profile_seeder.seedStudent(self.program, user=user) |
| |
| # no form is required during the sign-up |
| self.timeline_helper.studentSignup() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.TAX_FORM_LABEL in forms_fields) |
| |
| tax_form_field = forms_fields[profile_view.TAX_FORM_LABEL] |
| self.assertIn(profile_view._NO_FORM_REQUIRED, tax_form_field) |
| |
| # no form is required for a student with no projects |
| self.timeline_helper.formSubmission() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.TAX_FORM_LABEL in forms_fields) |
| |
| tax_form_field = forms_fields[profile_view.TAX_FORM_LABEL] |
| self.assertIn(profile_view._NO_FORM_REQUIRED, tax_form_field) |
| |
| # seed a project for the student so a form is required |
| project_utils.seedNDBProject(student, self.program.key()) |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.TAX_FORM_LABEL in forms_fields) |
| |
| tax_form_field = forms_fields[profile_view.TAX_FORM_LABEL] |
| self.assertIn(profile_view._NO_FORM_SUBMITTED, tax_form_field) |
| self.assertIn('Upload', tax_form_field) |
| |
| # it is not possible to submit a form after the program |
| self.timeline_helper.offSeason() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.TAX_FORM_LABEL in forms_fields) |
| |
| tax_form_field = forms_fields[profile_view.TAX_FORM_LABEL] |
| self.assertIn(profile_view._NO_FORM_SUBMITTED, tax_form_field) |
| self.assertNotIn('Upload', tax_form_field) |
| |
| # now a form is submitted |
| student.student_data.tax_form = self.createBlob(_TEST_FORM_FILE) |
| student.put() |
| |
| # during the program it is possible to download or re-upload a form |
| self.timeline_helper.formSubmission() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.TAX_FORM_LABEL in forms_fields) |
| |
| tax_form_field = forms_fields[profile_view.TAX_FORM_LABEL] |
| self.assertIn(_TEST_FORM_FILE, tax_form_field) |
| self.assertIn('Re-upload', tax_form_field) |
| self.assertIn('Download', tax_form_field) |
| |
| # after the program it is only possible to download a form |
| self.timeline_helper.offSeason() |
| response = self.get(_getShowProfileUrl(self.program.key())) |
| |
| forms_fields = dict(response.context['profile_template']._groups[-1].fields) |
| self.assertTrue(profile_view.TAX_FORM_LABEL in forms_fields) |
| |
| tax_form_field = forms_fields[profile_view.TAX_FORM_LABEL] |
| self.assertIn(_TEST_FORM_FILE, tax_form_field) |
| self.assertNotIn('Re-upload', tax_form_field) |
| self.assertIn('Download', tax_form_field) |
| |
| |
| class ProfileAdminPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProfileAdminPage 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) |
| profile_seeder.seedProfile(self.program.key(), user=user) |
| |
| # seed a profile to show |
| profile = profile_seeder.seedProfile(self.program.key()) |
| |
| response = self.get(_getAdminProfileUrl(profile.key)) |
| self.assertResponseOK(response) |