| # Copyright 2014 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 proposal related views.""" |
| |
| import json |
| import mock |
| import httplib |
| import unittest |
| |
| from google.appengine.ext import ndb |
| |
| from melange.models import organization as org_model |
| from melange.request import exception |
| from melange.request import links |
| from melange.utils import rich_bool |
| |
| from seeder import profile as profile_seeder |
| from seeder import program as program_seeder |
| from seeder import sponsor as sponsor_seeder |
| from seeder import user as user_seeder |
| |
| from soc.modules.gsoc.views.helper import request_data |
| |
| from summerofcode.logic import proposal as proposal_logic |
| from summerofcode.models import proposal as proposal_model |
| from summerofcode.views import proposal as proposal_view |
| |
| from tests import org_utils |
| from tests import profile_utils |
| from tests import test_utils |
| from tests.utils import proposal_utils |
| |
| |
| def _getListProposalsForHostUrl(program): |
| """Returns URL to 'List Proposals For Program Host' page for |
| the specified program. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| The URL to 'List Proposals For Program Host' page. |
| """ |
| return '/gsoc/proposal/list/host/%s' % program.key().name() |
| |
| |
| def _getListProposalsForOrgMemberUrl(program): |
| """Returns URL to 'List Proposals For Organization Member' page for |
| the specified program. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| The URL to 'List Proposals For Organization Member' page. |
| """ |
| return '/gsoc/proposal/list/org/%s' % program.key().name() |
| |
| |
| def _getListProposalsForStudentUrl(program): |
| """Returns URL to 'List Proposals For Student' page for the specified program. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| The URL to 'List Proposals For Student' page. |
| """ |
| return '/gsoc/proposal/list/student/%s' % program.key().name() |
| |
| |
| def _getPickOrganizationToSubmitProposalUrl(program): |
| """Returns URL to 'Pick Organization To Submit Proposal' page for |
| the specified program. |
| |
| Args: |
| program: Program entity. |
| |
| Returns: |
| The URL to 'Pick Organization To Submit Proposal' page. |
| """ |
| return '/gsoc/proposal/pick/%s' % program.key().name() |
| |
| |
| def _getProposalSubmitUrl(org): |
| """Returns URL to 'Proposal Submit' page for the specified organization. |
| |
| Args: |
| org: Organization entity. |
| |
| Returns: |
| The URL to 'Proposal Submit' page. |
| """ |
| return '/gsoc/proposal/submit/%s' % org.key.id() |
| |
| |
| def _getProposalEditUrl(proposal, validated=False): |
| """Returns URL to 'Proposal Edit' page for the specified proposal. |
| |
| Args: |
| proposal: Proposal entity. |
| validated: A bool telling whether the URL is validated or not. |
| |
| Returns: |
| The URL to 'Proposal Edit' page. |
| """ |
| return ('/gsoc/proposal/edit/%s/%s' % ( |
| proposal.key.parent().id(), proposal.key.id()) + |
| ('?validated=True' if validated else '')) |
| |
| |
| def _getProposalScoreUrl(proposal): |
| """Returns URL to 'Proposal Score' handler for the specified proposal. |
| |
| Args: |
| proposal: Proposal entity. |
| |
| Returns: |
| The URL to 'Proposal Score' handler. |
| """ |
| return '/gsoc/proposal/score/%s/%s' % ( |
| proposal.key.parent().id(), proposal.key.id()) |
| |
| |
| def getProposalReviewAsStudentUrl(proposal, validated=False): |
| """Returns URL to 'Proposal Review As Student' page for the |
| specified proposal. |
| |
| Args: |
| proposal: Proposal entity. |
| validated: A bool telling whether the URL is validated or not. |
| |
| Returns: |
| The URL to 'Proposal Edit' page. |
| """ |
| return ('/gsoc/proposal/review/student/%s/%s' % ( |
| proposal.key.parent().id(), proposal.key.id()) + |
| ('?validated=True' if validated else '')) |
| |
| |
| _NUMBER_OF_ACCEPTED_ORGS = 2 |
| |
| class PickOrganizationToSubmitProposalPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for PickOrganizationToSubmitProposalPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| self.timeline_helper.studentSignup() |
| |
| # seed a student |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedStudent(self.program, user=user) |
| |
| def testPageLoads(self): |
| """Tests that the page loads properly.""" |
| response = self.get(_getPickOrganizationToSubmitProposalUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| def testListData(self): |
| """Tests that correct list data is loaded.""" |
| # seed some accepted organizations |
| for _ in range(_NUMBER_OF_ACCEPTED_ORGS): |
| org_utils.seedSOCOrganization( |
| self.program.key(), status=org_model.Status.ACCEPTED) |
| |
| # seed one rejected organization |
| org_utils.seedSOCOrganization( |
| self.program.key(), status=org_model.Status.REJECTED) |
| |
| list_data = self.getListData( |
| _getPickOrganizationToSubmitProposalUrl(self.program), 0) |
| |
| # check that accepted organizations are listed |
| self.assertEqual(len(list_data), _NUMBER_OF_ACCEPTED_ORGS) |
| |
| |
| _TEST_PROPOSAL_SUBMIT_POST_DATA = { |
| 'title': 'Test Title', |
| 'abstract': 'Test abstract', |
| 'full_content': 'Test Content', |
| 'additional_info': 'http://www.addtional.info.com', |
| } |
| |
| # Proposal content which contains dangerous HTML that needs validation |
| RAW_HTML_CONTENT = """ |
| This is content of proposal. |
| <form method="POST" action="http://www.example.com/"></form> |
| <p style="background-image: url(www.example.com/some_image.png);"> |
| Another part of the content. Embedded in a paragraph with suspicious style. |
| </p> |
| """ |
| |
| SANITIZED_HTML_CONTENT = """ |
| This is content of proposal. |
| <form method="POST" action="http://www.example.com/"></form> |
| <p style=""> |
| Another part of the content. Embedded in a paragraph with suspicious style. |
| </p> |
| """.strip() |
| |
| class ProposalSubmitPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProposalSubmitPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| self.timeline_helper.studentSignup() |
| |
| # seed a student |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| student_data_properties = {'enrollment_form': self.createBlob('unused')} |
| self.student = profile_seeder.seedStudent( |
| self.program, user=user, |
| student_data_properties=student_data_properties) |
| |
| # organization is accepted so that students can apply to it |
| self.org.status = org_model.Status.ACCEPTED |
| self.org.put() |
| |
| def testPageLoads(self): |
| """Tests that the page loads properly.""" |
| response = self.get(_getProposalSubmitUrl(self.org)) |
| self.assertResponseOK(response) |
| |
| def testProposalCreated(self): |
| """Tests that a new proposal is created correctly.""" |
| postdata = _TEST_PROPOSAL_SUBMIT_POST_DATA.copy() |
| postdata['visibility'] = proposal_view._VISIBILITY_ORG_MEMBER_ID |
| |
| response = self.post( |
| _getProposalSubmitUrl(self.org), postdata=postdata) |
| |
| # check that a new proposal is created |
| proposal = proposal_model.Proposal.query(ancestor=self.student.key).get() |
| self.assertIsNotNone(proposal) |
| |
| self.assertResponseRedirect( |
| response, url=_getProposalEditUrl(proposal, validated=True)) |
| |
| def testDefaultProposalRanking(self): |
| """Tests that a new proposal has correct default rank in the student's |
| proposal preferences. |
| """ |
| postdata = _TEST_PROPOSAL_SUBMIT_POST_DATA.copy() |
| postdata['visibility'] = proposal_view._VISIBILITY_ORG_MEMBER_ID |
| |
| response = self.post( |
| _getProposalSubmitUrl(self.org), postdata=postdata) |
| |
| proposal = proposal_model.Proposal.query(ancestor=self.student.key).get() |
| student = self.student.key.get() |
| submitted_proposals_list = student.student_data.preference_of_proposals |
| self.assertEqual(proposal.key, submitted_proposals_list[-1]) |
| |
| |
| def testNotificationsSent(self): |
| """Tests that notifications are sent when proposal is submitted.""" |
| # seed a mentor and an organization admin |
| mentor = profile_seeder.seedProfile( |
| self.program.key(), mentor_for=[self.org.key]) |
| admin = profile_seeder.seedProfile( |
| self.program.key(), admin_for=[self.org.key]) |
| |
| postdata = _TEST_PROPOSAL_SUBMIT_POST_DATA.copy() |
| postdata['visibility'] = proposal_view._VISIBILITY_ORG_MEMBER_ID |
| self.post(_getProposalSubmitUrl(self.org), postdata=postdata) |
| |
| # check that emails were sent to the mentor and organization admin |
| self.assertEmailSent(bcc=mentor.contact.email) |
| self.assertEmailSent(bcc=admin.contact.email) |
| |
| # TODO(daniel): check that emails are not sent to those who opt out |
| |
| def testContentSanitized(self): |
| """Tests that submitted data is sanitized properly.""" |
| postdata = _TEST_PROPOSAL_SUBMIT_POST_DATA.copy() |
| postdata['visibility'] = proposal_view._VISIBILITY_ORG_MEMBER_ID |
| postdata['full_content'] = RAW_HTML_CONTENT |
| |
| response = self.post( |
| _getProposalSubmitUrl(self.org), postdata=postdata) |
| |
| # check that proposal is sanitized |
| proposal = proposal_model.Proposal.query(ancestor=self.student.key).get() |
| self.assertEqual(SANITIZED_HTML_CONTENT, proposal.content) |
| |
| |
| _OTHER_PROPOSAL_SUBMIT_POST_DATA = { |
| 'title': u'Other Title', |
| 'abstract': u'Other abstract', |
| 'full_content': u'Other Content', |
| 'additional_info': u'http://www.other.additional.info.com/', |
| } |
| |
| class ProposalEditPageTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProposalEditPage class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| self.timeline_helper.studentSignup() |
| |
| # seed a student |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| student = profile_seeder.seedStudent(self.program, user=user) |
| |
| # organization is accepted so that students can apply to it |
| self.org.status = org_model.Status.ACCEPTED |
| self.org.put() |
| |
| self.proposal = proposal_utils.seedNDBProposal( |
| student.key, self.program.key(), org_key=self.org.key) |
| |
| def testPageLoads(self): |
| """Tests that the page loads properly.""" |
| response = self.get(_getProposalEditUrl(self.proposal)) |
| self.assertResponseOK(response) |
| |
| def testProposalUpdated(self): |
| """Tests that the proposal is updated correctly.""" |
| postdata = _OTHER_PROPOSAL_SUBMIT_POST_DATA.copy() |
| postdata['visibility'] = proposal_view._VISIBILITY_ORG_MEMBER_ID |
| |
| # expected properties after the edit is complete |
| expected_properties = self.proposal.to_dict(exclude=['modified_on']) |
| expected_properties['title'] = _OTHER_PROPOSAL_SUBMIT_POST_DATA['title'] |
| expected_properties['abstract'] = ( |
| _OTHER_PROPOSAL_SUBMIT_POST_DATA['abstract']) |
| expected_properties['additional_info'] = ( |
| _OTHER_PROPOSAL_SUBMIT_POST_DATA['additional_info']) |
| expected_properties['visibility'] = proposal_model.Visibility.ORG_MEMBER |
| |
| revision_number = str(self.proposal.latest_revision.get().revision + 1) |
| proposal_revision_flat = list(self.proposal.key.flat()) |
| proposal_revision_flat.append(proposal_model.ProposalRevision) |
| proposal_revision_flat.append(revision_number) |
| latest_revision_property = proposal_model.Proposal.latest_revision._name |
| expected_properties[latest_revision_property] = ndb.Key( |
| flat=proposal_revision_flat) |
| |
| response = self.post( |
| _getProposalEditUrl(self.proposal), postdata=postdata) |
| self.assertResponseRedirect( |
| response, url=getProposalReviewAsStudentUrl( |
| self.proposal, validated=True)) |
| |
| # check that the proposal is updated correctly |
| proposal = self.proposal.key.get() |
| actual_properties = proposal.to_dict(exclude=['modified_on']) |
| self.assertDictEqual(actual_properties, expected_properties) |
| self.assertEqual( |
| proposal.content, _OTHER_PROPOSAL_SUBMIT_POST_DATA['full_content']) |
| |
| class ListProposalsForHostTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ListProposalsForHost class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that the page loads properly.""" |
| user = user_seeder.seedUser(host_for=[self.program]) |
| profile_utils.loginNDB(user) |
| |
| response = self.get(_getListProposalsForHostUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| def testListData(self): |
| """Tests that correct list data is loaded.""" |
| user = user_seeder.seedUser(host_for=[self.program]) |
| profile_utils.loginNDB(user) |
| |
| # seed other organizations |
| org_one = org_utils.seedSOCOrganization(self.program.key()) |
| org_two = org_utils.seedSOCOrganization(self.program.key()) |
| |
| # seed a few proposals |
| student_one = profile_seeder.seedStudent(self.program) |
| proposal_utils.seedNDBProposal( |
| student_one.key, self.program.key(), org_key=self.org.key, |
| status=proposal_model.Status.ACCEPTED) |
| proposal_utils.seedNDBProposal( |
| student_one.key, self.program.key(), org_key=org_one.key) |
| proposal_utils.seedNDBProposal( |
| student_one.key, self.program.key(), org_key=org_two.key) |
| |
| student_two = profile_seeder.seedStudent(self.program) |
| proposal_utils.seedNDBProposal( |
| student_two.key, self.program.key(), org_key=org_one.key, |
| status=proposal_model.Status.WITHDRAWN) |
| proposal_utils.seedNDBProposal( |
| student_two.key, self.program.key(), org_key=org_one.key, |
| is_ignored=True) |
| |
| # seed another program |
| other_program = program_seeder.seedGSoCProgram() |
| |
| # seed a proposal for the other program |
| other_org = org_utils.seedSOCOrganization(other_program.key()) |
| other_student = profile_seeder.seedStudent(other_program) |
| proposal_utils.seedNDBProposal( |
| other_student.key, other_program.key(), org_key=other_org.key) |
| |
| list_data = self.getListData( |
| _getListProposalsForHostUrl(self.program), 0) |
| |
| # check that all proposals save the last one are included |
| self.assertEqual(len(list_data), 5) |
| |
| |
| class ListProposalsForStudentTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ListProposalsForStudent class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that the page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedStudent(self.program, user=user) |
| |
| response = self.get(_getListProposalsForStudentUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| def testListData(self): |
| """Tests that correct list data is loaded.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedStudent(self.program, user=user) |
| |
| # seed another organization |
| other_org = org_utils.seedSOCOrganization(self.program.key()) |
| |
| # seed a couple of proposals |
| proposal_utils.seedNDBProposal( |
| profile.key, self.program.key(), org_key=self.org.key) |
| proposal_utils.seedNDBProposal( |
| profile.key, self.program.key(), org_key=other_org.key) |
| |
| # seed another student with a proposal |
| other_student = profile_seeder.seedStudent(self.program) |
| proposal_utils.seedNDBProposal( |
| other_student.key, self.program.key(), org_key=self.org.key) |
| |
| list_data = self.getListData( |
| _getListProposalsForStudentUrl(self.program), 0) |
| |
| # check that only two proposals are listed |
| self.assertEqual(len(list_data), 2) |
| |
| def testRankingProposal(self): |
| """Tests that ranking of proposals is done correctly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedStudent(self.program, user=user) |
| |
| # seed a couple of organizations |
| other_org1 = org_utils.seedSOCOrganization(self.program.key()) |
| other_org2 = org_utils.seedSOCOrganization(self.program.key()) |
| |
| # seed a total of three of proposals |
| proposal_utils.seedNDBProposal( |
| profile.key, self.program.key(), org_key=self.org.key) |
| proposal_utils.seedNDBProposal( |
| profile.key, self.program.key(), org_key=other_org1.key) |
| proposal_utils.seedNDBProposal( |
| profile.key, self.program.key(), org_key=other_org2.key) |
| |
| old_list_data = self.getListData( |
| _getListProposalsForStudentUrl(self.program), 0) |
| |
| changed_data = {} |
| changed_data[old_list_data[0]['columns']['key']] = {'rank': old_list_data[1]['columns']['rank']} |
| changed_data[old_list_data[1]['columns']['key']] = {'rank': old_list_data[2]['columns']['rank']} |
| |
| data = json.dumps(changed_data) |
| |
| postdata = { |
| 'data': data, |
| 'button_id': 'save', |
| 'idx': 0, |
| } |
| |
| response = self.post( |
| _getListProposalsForStudentUrl(self.program), postdata=postdata) |
| self.assertResponseOK(response) |
| |
| new_list_data = self.getListData( |
| _getListProposalsForStudentUrl(self.program), 0) |
| |
| self.assertEqual(new_list_data[0]['columns']['rank'], old_list_data[1]['columns']['rank']) |
| self.assertEqual(new_list_data[1]['columns']['rank'], old_list_data[2]['columns']['rank']) |
| self.assertEqual(new_list_data[2]['columns']['rank'], old_list_data[0]['columns']['rank']) |
| |
| |
| _TEST_SCORE_VALUE = 2 |
| |
| class ListProposalsForOrgMemberTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ListProposalsForOrgMember class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| def testPageLoads(self): |
| """Tests that the page loads properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile_seeder.seedProfile( |
| self.program.key(), user=user, mentor_for=[self.org.key]) |
| |
| response = self.get(_getListProposalsForOrgMemberUrl(self.program)) |
| self.assertResponseOK(response) |
| |
| def testListData(self): |
| """Tests that correct list data is loaded.""" |
| # seed another organization |
| org_one = org_utils.seedSOCOrganization(self.program.key()) |
| |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedProfile( |
| self.program.key(), user=user, mentor_for=[self.org.key, org_one.key]) |
| |
| # seed a couple of proposals |
| student = profile_seeder.seedStudent(self.program) |
| proposal_utils.seedNDBProposal( |
| student.key, self.program.key(), org_key=self.org.key, |
| scores=[proposal_model.Score( |
| author=profile.key, value=_TEST_SCORE_VALUE)]) |
| proposal_utils.seedNDBProposal( |
| student.key, self.program.key(), org_key=org_one.key) |
| |
| # seed another organization with a proposal |
| org_two = org_utils.seedSOCOrganization(self.program.key()) |
| proposal_utils.seedNDBProposal( |
| student.key, self.program.key(), org_key=org_two.key) |
| |
| list_data = self.getListData( |
| _getListProposalsForOrgMemberUrl(self.program), 0) |
| |
| # check that only two proposals are listed |
| self.assertEqual(len(list_data), 2) |
| |
| |
| _TEST_PROPOSAL_LIMIT = 3 |
| |
| class ProposalLimitNotReachedAccessCheckerTest(unittest.TestCase): |
| """Unit tests for ProposalLimitNotReachedAccessChecker class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| sponsor = sponsor_seeder.seedSponsor() |
| |
| self.program = program_seeder.seedGSoCProgram( |
| sponsor_key=sponsor.key(), apps_tasks_limit=_TEST_PROPOSAL_LIMIT) |
| |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| self.profile = profile_seeder.seedStudent(self.program, user=user) |
| |
| kwargs = { |
| 'sponsor': sponsor.key().name(), |
| 'program': self.program.program_id |
| } |
| self.data = request_data.RequestData(None, None, kwargs) |
| |
| def testLimitNotReachedAccessGranted(self): |
| """Tests that access is granted if limit is not reached.""" |
| # seed limit - 1 proposals |
| for _ in range(_TEST_PROPOSAL_LIMIT - 1): |
| proposal_utils.seedNDBProposal(self.profile.key, self.program.key()) |
| |
| access_checker = proposal_view.ProposalLimitNotReachedAccessChecker() |
| access_checker.checkAccess(self.data, None) |
| |
| def testLimitReachedAccessGranted(self): |
| """Tests that access is granted if limit is reached.""" |
| # seed limit proposals |
| for _ in range(_TEST_PROPOSAL_LIMIT): |
| proposal_utils.seedNDBProposal(self.profile.key, self.program.key()) |
| |
| access_checker = proposal_view.ProposalLimitNotReachedAccessChecker() |
| with self.assertRaises(exception.UserError) as context: |
| access_checker.checkAccess(self.data, None) |
| self.assertEqual(context.exception.status, httplib.FORBIDDEN) |
| |
| |
| class EnrollmentFormSubmittedAccessCheckerTest(test_utils.SoCTestCase): |
| """Unit tests for EnrollmentFormSubmittedAccessChecker class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| |
| sponsor = sponsor_seeder.seedSponsor() |
| |
| self.program = program_seeder.seedGSoCProgram( |
| sponsor_key=sponsor.key(), apps_tasks_limit=_TEST_PROPOSAL_LIMIT) |
| |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| self.profile = profile_seeder.seedStudent(self.program, user=user) |
| |
| kwargs = { |
| 'sponsor': sponsor.key().name(), |
| 'program': self.program.program_id |
| } |
| self.data = request_data.RequestData(None, None, kwargs) |
| |
| def testEnrollmentFormSubmittedAccessGranted(self): |
| """Tests that access is granted when enrollment form is submitted.""" |
| self.profile.student_data.enrollment_form = self.createBlob('unused') |
| self.profile.put() |
| |
| access_checker = proposal_view.EnrollmentFormSubmittedAccessChecker() |
| access_checker.checkAccess(self.data, None) |
| |
| def testEnrollmentFormNotSubmittedAccessDenied(self): |
| """Tests that access is denied when enrollment form is not submitted.""" |
| access_checker = proposal_view.EnrollmentFormSubmittedAccessChecker() |
| with self.assertRaises(exception.UserError) as context: |
| access_checker.checkAccess(self.data, None) |
| self.assertEqual(context.exception.status, httplib.FORBIDDEN) |
| |
| # Test enrollment form URL |
| enrollment_url = links.ABSOLUTE_LINKER.program( |
| self.data.program, 'gsoc_enrollment_form', secure=True) |
| self.assertIn(enrollment_url, context.exception.message) |
| |
| |
| _TEST_SCORE_VALUE = 4 |
| _TEST_UPDATED_SCORE_VALUE = 1 |
| |
| class ProposalScoreTest(test_utils.GSoCDjangoTestCase): |
| """Unit tests for ProposalScore class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| self.init() |
| student = profile_seeder.seedStudent(self.program) |
| self.proposal = proposal_utils.seedNDBProposal( |
| student.key, self.program.key(), org_key=self.org.key) |
| |
| def testSetScore(self): |
| """Test that a score is set properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedProfile( |
| self.program.key(), user=user, mentor_for=[self.org.key]) |
| |
| postdata = {'value': str(_TEST_SCORE_VALUE)} |
| response = self.post(_getProposalScoreUrl(self.proposal), postdata=postdata) |
| self.assertResponseOK(response) |
| |
| # check that the score is set |
| proposal = self.proposal.key.get() |
| score = proposal.scores[0] |
| self.assertEqual(score.value, _TEST_SCORE_VALUE) |
| self.assertEqual(score.author, profile.key) |
| |
| def testCleanScore(self): |
| """Test that a score is cleaned properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedProfile( |
| self.program.key(), user=user, mentor_for=[self.org.key]) |
| |
| # set an existing score |
| self.proposal.scores.append( |
| proposal_model.Score(author=profile.key, value=_TEST_SCORE_VALUE)) |
| self.proposal.put() |
| |
| postdata = {'value': ''} |
| response = self.post(_getProposalScoreUrl(self.proposal), postdata=postdata) |
| self.assertResponseOK(response) |
| |
| # check that no score is set |
| proposal = self.proposal.key.get() |
| self.assertListEqual(proposal.scores, []) |
| |
| def testUpdateScore(self): |
| """Test that a score is updated properly.""" |
| user = user_seeder.seedUser() |
| profile_utils.loginNDB(user) |
| profile = profile_seeder.seedProfile( |
| self.program.key(), user=user, mentor_for=[self.org.key]) |
| |
| # set an existing score |
| self.proposal.scores.append( |
| proposal_model.Score(author=profile.key, value=_TEST_SCORE_VALUE)) |
| self.proposal.put() |
| |
| postdata = {'value': str(_TEST_UPDATED_SCORE_VALUE)} |
| response = self.post(_getProposalScoreUrl(self.proposal), postdata=postdata) |
| self.assertResponseOK(response) |
| |
| # check that the score is updated |
| proposal = self.proposal.key.get() |
| score = proposal.scores[0] |
| self.assertEqual(score.value, _TEST_UPDATED_SCORE_VALUE) |
| self.assertEqual(score.author, profile.key) |
| |
| |
| class IsUrlProposalEditableAccessCheckerTest(unittest.TestCase): |
| """Unit tests for IsUrlProposalEditableAccessChecker class.""" |
| |
| def setUp(self): |
| """See unittest.TestCase.setUp for specification.""" |
| sponsor = sponsor_seeder.seedSponsor() |
| |
| program = program_seeder.seedGSoCProgram(sponsor_key=sponsor.key()) |
| |
| student = profile_seeder.seedStudent(program) |
| proposal = proposal_utils.seedNDBProposal(student.key, program.key()) |
| |
| kwargs = { |
| 'sponsor': sponsor.key().name(), |
| 'program': program.program_id, |
| 'user': student.profile_id, |
| 'id': proposal.key.id() |
| } |
| self.data = request_data.RequestData(None, None, kwargs) |
| |
| @mock.patch.object( |
| proposal_logic, 'canStudentUpdateProposal', return_value=rich_bool.FALSE) |
| def testStudentCannotUpdateProposalAccessDenied(self, mock_func): |
| """Tests that access is denied if student cannot edit proposal.""" |
| access_checker = proposal_view.IsUrlProposalEditableAccessChecker() |
| with self.assertRaises(exception.UserError) as context: |
| access_checker.checkAccess(self.data, None) |
| self.assertEqual(context.exception.status, httplib.FORBIDDEN) |
| |
| @mock.patch.object( |
| proposal_logic, 'canStudentUpdateProposal', return_value=rich_bool.TRUE) |
| def testStudentCanUpdateProposalAccessGranted(self, mock_func): |
| """Tests that access is granted if student can edit proposal.""" |
| access_checker = proposal_view.IsUrlProposalEditableAccessChecker() |
| access_checker.checkAccess(self.data, None) |