source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_browser.py @ 7184

Last change on this file since 7184 was 7184, checked in by Henrik Bettermann, 13 years ago

Reorganise permissions:

The navigation viewlets now manage the permission requirements themselves. No need to do this in pagetemplates.

Rename permission waeup.View to waeup.viewAcademics because it only refers to the academic section.

Add permission waeup.Authenticated (which is used in students). The StudentRecordOwner? explicitly needs this permission. Otherwise the MyData? tab disappears when changing the password.

Roles do not need to get the waeup.Public permission. This is already guaranteed in site.zcml.

  • Property svn:keywords set to Id
File size: 40.5 KB
Line 
1##
2## test_browser.py
3## Login : <uli@pu.smp.net>
4## Started on  Tue Mar 29 11:31:11 2011 Uli Fouquet
5## $Id: test_browser.py 7184 2011-11-24 09:20:13Z henrik $
6##
7## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""
23Test the applicant-related UI components.
24"""
25import shutil
26import tempfile
27from StringIO import StringIO
28from datetime import datetime, date, timedelta
29from mechanize import LinkNotFoundError
30from zope.component import createObject, getUtility
31from zope.component.hooks import setSite, clearSite
32from zope.security.interfaces import Unauthorized
33from zope.testbrowser.testing import Browser
34from hurry.workflow.interfaces import IWorkflowInfo
35from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
36from waeup.sirp.app import University
37from waeup.sirp.applicants.container import ApplicantsContainer
38from waeup.sirp.applicants.applicant import Applicant
39from waeup.sirp.interfaces import IExtFileStore, IFileStoreNameChooser
40from waeup.sirp.university.faculty import Faculty
41from waeup.sirp.university.department import Department
42
43PH_LEN = 2059  # Length of placeholder file
44
45class ApplicantsFullSetup(FunctionalTestCase):
46    # A test case that only contains a setup and teardown
47    #
48    # Complete setup for applicants handlings is rather complex and
49    # requires lots of things created before we can start. This is a
50    # setup that does all this, creates a university, creates PINs,
51    # etc.  so that we do not have to bother with that in different
52    # test cases.
53
54    layer = FunctionalLayer
55
56    def setUp(self):
57        super(ApplicantsFullSetup, self).setUp()
58
59        # Setup a sample site for each test
60        app = University()
61        self.dc_root = tempfile.mkdtemp()
62        app['datacenter'].setStoragePath(self.dc_root)
63
64        # Prepopulate the ZODB...
65        self.getRootFolder()['app'] = app
66        # we add the site immediately after creation to the
67        # ZODB. Catalogs and other local utilities are not setup
68        # before that step.
69        self.app = self.getRootFolder()['app']
70        # Set site here. Some of the following setup code might need
71        # to access grok.getSite() and should get our new app then
72        setSite(app)
73
74        self.root_path = 'http://localhost/app/applicants'
75        self.manage_root_path = self.root_path + '/@@manage'
76        self.add_container_path = self.root_path + '/@@add'
77        self.container_path = 'http://localhost/app/applicants/app2009'
78        self.manage_container_path = self.container_path + '/@@manage'
79
80        # Add an applicants container
81        applicantscontainer = ApplicantsContainer()
82        applicantscontainer.ac_prefix = 'APP'
83        applicantscontainer.prefix = 'app'
84        applicantscontainer.year = 2009
85        applicantscontainer.application_category = 'basic'
86        delta = timedelta(days=10)
87        applicantscontainer.startdate = date.today() - delta
88        applicantscontainer.enddate = date.today() + delta
89        self.app['applicants']['app2009'] = applicantscontainer
90
91        # Populate university
92        certificate = createObject('waeup.Certificate')
93        certificate.code = 'CERT1'
94        certificate.application_category = 'basic'
95        self.certificate = certificate
96        self.app['faculties']['fac1'] = Faculty()
97        self.app['faculties']['fac1']['dep1'] = Department()
98        self.department = self.app['faculties']['fac1']['dep1']
99        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
100            certificate)
101
102        # Put the prepopulated site into test ZODB and prepare test
103        # browser
104        self.browser = Browser()
105        self.browser.handleErrors = False
106
107        # Create 5 access codes with prefix'FOO' and cost 9.99 each
108        pin_container = self.app['accesscodes']
109        pin_container.createBatch(
110            datetime.now(), 'some_userid', 'APP', 9.99, 5)
111        pins = pin_container[pin_container.keys()[0]].values()
112        self.pins = [x.representation for x in pins]
113        self.existing_pin = self.pins[0]
114        parts = self.existing_pin.split('-')[1:]
115        self.existing_series, self.existing_number = parts
116
117        # Add an applicant
118        self.applicant = Applicant()
119        self.pin_applicant = unicode(self.pins[1])
120        self.applicant.access_code = self.pin_applicant
121        app['applicants']['app2009'][self.pin_applicant] = self.applicant
122
123    def tearDown(self):
124        super(ApplicantsFullSetup, self).tearDown()
125        clearSite()
126        shutil.rmtree(self.dc_root)
127
128class ApplicantsRootUITests(ApplicantsFullSetup):
129    # Tests for ApplicantsRoot class
130
131    layer = FunctionalLayer
132
133    def test_anonymous_access(self):
134        # Anonymous users can access applicants root
135        self.browser.open(self.root_path)
136        self.assertEqual(self.browser.headers['Status'], '200 Ok')
137        self.assertFalse(
138            'Manage' in self.browser.contents)
139
140   
141    def test_anonymous_no_actions(self):
142        # Make sure anonymous users cannot access actions
143        self.browser.open(self.root_path)
144        self.assertRaises(
145            LookupError, self.browser.getControl, "Add local role")
146        # Manage screen neither linked nor accessible for anonymous
147        self.assertRaises(
148            LinkNotFoundError,
149            self.browser.getLink, 'Manage application section')
150        self.assertRaises(
151            Unauthorized, self.browser.open, self.manage_root_path)
152        # Add container screen not accessible for anonymous
153        self.assertRaises(
154            Unauthorized, self.browser.open, self.add_container_path)
155        return
156
157    def test_manage_access(self):
158        # Managers can access the manage pages of applicants root
159        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
160        self.browser.open(self.root_path)
161        self.assertTrue('Manage application section' in self.browser.contents)
162        # There is a manage link
163        link = self.browser.getLink('Manage application section')
164        link.click()
165        self.assertEqual(self.browser.headers['Status'], '200 Ok')
166        self.assertEqual(self.browser.url, self.manage_root_path)
167
168    def test_manage_actions_access(self):
169        # Managers can access the action on manage screen
170        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
171        self.browser.open(self.manage_root_path)
172        self.browser.getControl("Add local role").click()
173        self.assertTrue('No user selected' in self.browser.contents)
174        return
175
176    # We have no local roles yet
177    #def test_local_roles_add_delete(self):
178    #    # Managers can assign and delete local roles of applicants root
179    #    myusers = self.app['users']
180    #    myusers.addUser('bob', 'bobssecret')
181    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
182    #    self.browser.open(self.manage_root_path)
183    #    self.browser.getControl(name="user").value = ['bob']
184    #    self.browser.getControl(name="local_role").value = [
185    #        'waeup.local.ApplicationsOfficer']
186    #    self.browser.getControl("Add local role").click()
187    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
188    #    # Remove the role assigned
189    #    ctrl = self.browser.getControl(name='role_id')
190    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
191    #    self.browser.getControl("Remove selected local roles").click()
192    #    self.assertTrue('Successfully removed:' in self.browser.contents)
193    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
194    #    return
195
196    def test_add_delete_container(self):
197        # Managers can add and delete applicants containers
198        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
199        self.browser.open(self.manage_root_path)
200        self.browser.getControl("Cancel").click()
201        self.assertEqual(self.browser.url, self.root_path)
202        self.browser.open(self.manage_root_path)
203        self.browser.getControl("Add applicants container").click()
204        self.assertEqual(self.browser.headers['Status'], '200 Ok')
205        self.assertEqual(self.browser.url, self.add_container_path)
206        self.browser.getControl(name="form.prefix").value = ['app']
207        self.browser.getControl("Add applicants container").click()
208        self.assertTrue(
209            'There were errors' in self.browser.contents)
210        self.browser.getControl(name="form.prefix").value = ['app']
211        self.browser.getControl(name="form.year").value = ['2010']
212        self.browser.getControl(name="form.provider").value = [
213            'waeup.sirp.applicants.ApplicantsContainer']
214        self.browser.getControl(name="form.ac_prefix").value = ['APP']
215        self.browser.getControl(name="form.application_category").value = ['basic']
216        self.browser.getControl("Add applicants container").click()
217        self.assertTrue('Added:' in self.browser.contents)
218        self.browser.open(self.add_container_path)
219        self.browser.getControl("Cancel").click()
220        self.assertEqual(self.browser.url, self.manage_root_path + '#tab-1')
221        self.browser.open(self.add_container_path)
222        self.browser.getControl(name="form.prefix").value = ['app']
223        self.browser.getControl(name="form.year").value = ['2010']
224        self.browser.getControl(name="form.provider").value = [
225            'waeup.sirp.applicants.ApplicantsContainer']
226        self.browser.getControl(name="form.ac_prefix").value = ['APP']
227        self.browser.getControl(name="form.application_category").value = ['basic']
228        self.browser.getControl("Add applicants container").click()
229        self.assertTrue('exists already in the database' in self.browser.contents)
230        self.browser.open(self.manage_root_path)
231        ctrl = self.browser.getControl(name='val_id')
232        ctrl.getControl(value='app2010').selected = True
233        self.browser.getControl("Remove selected", index=0).click()
234        self.assertTrue('Successfully removed:' in self.browser.contents)
235        self.browser.open(self.add_container_path)
236        self.browser.getControl(name="form.prefix").value = ['app']
237        self.browser.getControl(name="form.year").value = ['2010']
238        self.browser.getControl(name="form.provider").value = [
239            'waeup.sirp.applicants.ApplicantsContainer']
240        self.browser.getControl(name="form.ac_prefix").value = ['APP']
241        self.browser.getControl(name="form.application_category").value = ['basic']
242        self.browser.getControl("Add applicants container").click()
243        del self.app['applicants']['app2010']
244        ctrl = self.browser.getControl(name='val_id')
245        ctrl.getControl(value='app2010').selected = True
246        self.browser.getControl("Remove selected", index=0).click()
247        self.assertMatches('...Could not delete...', self.browser.contents)
248        return
249
250    def test_add_delete_applicants(self):
251        # Managers can add and delete applicants
252        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
253        self.add_applicant_path = self.container_path + '/addapplicant'
254        self.container_manage_path = self.container_path + '/@@manage'
255        self.browser.open(self.container_manage_path)
256        self.browser.getControl("Add applicant").click()
257        self.assertEqual(self.browser.headers['Status'], '200 Ok')
258        self.assertEqual(self.browser.url, self.add_applicant_path)
259        self.browser.getControl(name="form.ac_series").value = self.existing_series
260        self.browser.getControl(name="form.ac_number").value = self.existing_number
261        self.browser.getControl("Create application record").click()
262        self.assertTrue('Application initialized' in self.browser.contents)
263        self.browser.open(self.add_applicant_path)
264        self.browser.getControl(name="form.ac_series").value = '123'
265        self.browser.getControl(name="form.ac_number").value = '456'
266        self.browser.getControl("Create application record").click()
267        self.assertTrue('is not a valid access code' in self.browser.contents)
268        self.browser.open(self.container_manage_path)
269        self.assertEqual(self.browser.headers['Status'], '200 Ok')
270        ctrl = self.browser.getControl(name='val_id')
271        ctrl.getControl(value=self.existing_pin).selected = True
272        self.browser.getControl("Remove selected", index=0).click()
273        self.assertTrue('Successfully removed:' in self.browser.contents)
274        self.browser.open(self.add_applicant_path)
275        existing_pin = self.pins[2]
276        parts = existing_pin.split('-')[1:]
277        existing_series, existing_number = parts
278        self.browser.getControl(name="form.ac_series").value = existing_series
279        self.browser.getControl(name="form.ac_number").value = existing_number
280        self.browser.getControl("Create application record").click()
281        self.assertTrue('Application initialized' in self.browser.contents)
282        self.browser.open(self.container_manage_path)
283        self.assertTrue(existing_pin in self.browser.contents)
284        del self.app['applicants']['app2009'][existing_pin]
285        ctrl = self.browser.getControl(name='val_id')
286        ctrl.getControl(value=existing_pin).selected = True
287        self.browser.getControl("Remove selected", index=0).click()
288        self.assertMatches('...Could not delete...', self.browser.contents)
289        return
290
291    def test_manage_and_view_applicant(self):
292        # Managers can manage applicants
293        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
294        self.applicant_path = 'http://localhost/app/applicants/app2009/%s' % self.pin_applicant
295        self.applicant_view_path = self.applicant_path + '/index'
296        self.applicant_manage_path = self.applicant_path + '/edit_full'
297        self.applicant_slip_path = self.applicant_path + '/application_slip.pdf'
298        self.browser.open(self.applicant_manage_path)
299        self.assertEqual(self.browser.headers['Status'], '200 Ok')
300        self.browser.getControl(name="form.email").value = 'abc'
301        self.browser.getControl("Save").click()
302        self.assertMatches('...Invalid email address...', self.browser.contents)
303        self.browser.getControl(name="form.email").value = 'abc@def.gh'
304        self.browser.getControl(name="form.firstname").value = 'John'
305        self.browser.getControl(name="form.lastname").value = 'Tester'
306        self.browser.getControl(name="form.course1").value = ['CERT1']
307        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
308        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
309        self.browser.getControl(name="form.lga").value = ['foreigner']
310        self.browser.getControl(name="form.sex").value = ['m']
311        self.browser.getControl(name="transition").value = ['start']
312        self.browser.getControl("Save").click()
313        self.assertMatches('...Form has been saved...', self.browser.contents)
314        self.assertMatches('...Application started by zope.mgr...', self.browser.contents)
315        self.browser.open(self.applicant_view_path)
316        self.assertEqual(self.browser.headers['Status'], '200 Ok')
317        self.browser.open(self.applicant_slip_path)
318        self.assertEqual(self.browser.headers['Status'], '200 Ok')
319        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
320        self.browser.open(self.applicant_manage_path)
321        self.browser.getControl(name="form.course_admitted").value = []
322        self.browser.getControl("Save").click()
323        self.browser.open(self.applicant_slip_path)
324        self.assertEqual(self.browser.headers['Status'], '200 Ok')
325        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
326        return
327
328    def test_view_applicant(self):
329        # Applicants can login and view their application
330        self.login_path = 'http://localhost/app/applicants/app2009/login'
331        self.browser.open(self.login_path)
332        pin = self.pins[2]
333        parts = pin.split('-')[1:]
334        existing_series, existing_number = parts
335        ac_series = self.browser.getControl(name="form.ac_series")
336        ac_series.value = existing_series
337        ac_number = self.browser.getControl(name="form.ac_number")
338        ac_number.value = existing_number
339        self.browser.getControl(name="SUBMIT").click()
340        self.assertTrue(self.browser.url != self.login_path)
341        self.assertEqual(self.browser.headers['Status'], '200 Ok')
342        return
343
344    def test_passport_edit_view(self):
345        # We get a default image after login
346        login_path = 'http://localhost/app/applicants/app2009/login'
347        self.browser.open(login_path)
348        pin = self.pins[2]
349        parts = pin.split('-')[1:]
350        existing_series, existing_number = parts
351        ac_series = self.browser.getControl(name="form.ac_series")
352        ac_series.value = existing_series
353        ac_number = self.browser.getControl(name="form.ac_number")
354        ac_number.value = existing_number
355        self.browser.getControl(name="SUBMIT").click()
356        pin = self.pins[2]
357        #appl = self.getRootFolder()['app']['applicants']['app2009']
358        #appl = appl[pin]
359        #passp = appl.passport
360        #passp_len = len(passp.file.read())
361        #self.assertEqual(passp_len, PH_LEN)
362        #image_url = "%s/%s" % (self.browser.url, 'placeholder.jpg')
363        image_url = "%s/%s" % (self.browser.url, 'passport.jpg')
364        #self.browser.open(image_url)
365        self.browser.open('passport.jpg')
366        self.assertEqual(self.browser.headers['status'], '200 Ok')
367        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
368        self.assertTrue('JFIF' in self.browser.contents)
369        self.assertEqual(
370            self.browser.headers['content-length'], str(PH_LEN))
371
372
373    def test_edit_applicant(self):
374        # Applicants can edit their record
375        self.login_path = 'http://localhost/app/applicants/app2009/login'
376        self.browser.open(self.login_path)
377        pin = self.pins[2]
378        parts = pin.split('-')[1:]
379        existing_series, existing_number = parts
380        ac_series = self.browser.getControl(name="form.ac_series")
381        ac_series.value = existing_series
382        ac_number = self.browser.getControl(name="form.ac_number")
383        ac_number.value = existing_number
384        self.browser.getControl(name="SUBMIT").click()
385        self.assertTrue(self.browser.url != self.login_path)
386        self.assertEqual(self.browser.headers['Status'], '200 Ok')
387        self.browser.getControl(name="form.firstname").value = 'John'
388        self.browser.getControl(name="form.lastname").value = 'Tester'
389        self.browser.getControl(name="form.course1").value = ['CERT1']
390        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
391        self.browser.getControl(name="form.lga").value = ['foreigner']
392        self.browser.getControl(name="form.sex").value = ['m']
393        self.browser.getControl("Save").click()
394        self.assertMatches('...Form has been saved...', self.browser.contents)
395        return
396
397class ApplicantsContainerUITests(ApplicantsFullSetup):
398    # Tests for ApplicantsContainer class views and pages
399
400    layer = FunctionalLayer
401
402    def test_anonymous_access(self):
403        # Anonymous users can access applicants containers
404        self.browser.open(self.container_path)
405        self.assertEqual(self.browser.headers['Status'], '200 Ok')
406        self.assertFalse(
407            'Manage' in self.browser.contents)
408        return
409
410    def test_manage_access(self):
411        # Managers can access the manage pages of applicants
412        # containers and can perform actions
413        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
414        self.browser.open(self.manage_container_path)
415        self.assertEqual(self.browser.headers['Status'], '200 Ok')
416        self.assertEqual(self.browser.url, self.manage_container_path)
417        self.browser.getControl("Save").click()
418        self.assertTrue('Data saved' in self.browser.contents)
419        self.browser.getControl("Remove selected", index=0).click()
420        self.assertTrue('No applicant selected' in self.browser.contents)
421        self.browser.getControl("Add local role").click()
422        self.assertTrue('No user selected' in self.browser.contents)
423        self.browser.getControl("Cancel", index=0).click()
424        self.assertEqual(self.browser.url, self.container_path)
425        return
426
427    # We have no local roles yet
428    #def test_local_roles_add_delete(self):
429    #    # Managers can assign and delete local roles of applicants containers
430    #    myusers = self.app['users']
431    #    myusers.addUser('bob', 'bobssecret')
432    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
433    #    self.browser.open(self.manage_container_path)
434    #    self.browser.getControl(name="user").value = ['bob']
435    #    self.browser.getControl(name="local_role").value = [
436    #        'waeup.local.ApplicationsOfficer']
437    #    self.browser.getControl("Add local role").click()
438    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
439    #    ctrl = self.browser.getControl(name='role_id')
440    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
441    #    self.browser.getControl("Remove selected local roles").click()
442    #    self.assertTrue('Successfully removed:' in self.browser.contents)
443    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
444    #    return
445
446class LoginTest(FunctionalTestCase):
447    # Here we check login view of applicants containers.
448    #
449    # Tests in here do only cover login attempts without any PINs
450    # created before.
451
452    layer = FunctionalLayer
453
454    def setUp(self):
455        super(LoginTest, self).setUp()
456
457        # Setup a sample site for each test
458        app = University()
459        self.dc_root = tempfile.mkdtemp()
460        app['datacenter'].setStoragePath(self.dc_root)
461        self.login_path = 'http://localhost/app/applicants/testapplicants/login'
462
463        # Add an applicants container where we can login (or not)
464        applicantscontainer = ApplicantsContainer()
465        applicantscontainer.ac_prefix = 'APP'
466        delta = timedelta(days=10)
467        applicantscontainer.startdate = date.today() - delta
468        applicantscontainer.enddate = date.today() + delta
469        app['applicants']['testapplicants'] = applicantscontainer
470
471        # Put the prepopulated site into test ZODB and prepare test
472        # browser
473        self.getRootFolder()['app'] = app
474        self.browser = Browser()
475        self.browser.handleErrors = False
476
477    def tearDown(self):
478        super(LoginTest, self).tearDown()
479        shutil.rmtree(self.dc_root)
480
481    def test_anonymous_access(self):
482        # Anonymous users can access a login page
483        self.browser.open(self.login_path)
484        self.assertEqual(self.browser.headers['Status'], '200 Ok')
485        return
486
487    def test_anonymous_invalid_creds(self):
488        # Anonymous users giving invalid credentials stay at the page
489        self.browser.open(self.login_path)
490        # We do not give credentials but send the form as-is
491        submit = self.browser.getControl(name='SUBMIT')
492        submit.click()
493        # We are still at the same page...
494        self.assertEqual(self.browser.url, self.login_path)
495        self.assertEqual(self.browser.headers['Status'], '200 Ok')
496        return
497
498    def test_anonymous_invalid_creds_warning(self):
499        # Entering wrong credentials will yield a warning
500        self.browser.open(self.login_path)
501        # We do not give credentials but send the form as-is
502        submit = self.browser.getControl(name='SUBMIT')
503        submit.click()
504        self.assertTrue(
505            'Entered credentials are invalid' in self.browser.contents)
506        return
507
508    def test_manager_no_warnings(self):
509        # Browsing the login screen as a manager, won't raise warnings
510        # Authenticate ourself as manager
511        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
512        self.browser.open(self.login_path)
513        # Submit the form w/o any credentials
514        self.browser.getControl(name="SUBMIT").click()
515        self.assertTrue(
516            'Entered credentials are invalid' not in self.browser.contents)
517        return
518
519    def test_manager_no_redirect(self):
520        # Browsing the login screen as a manager won't trigger a redirect
521        # Authenticate ourself as manager
522        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
523        self.browser.open(self.login_path)
524        # Submit the form w/o any credentials
525        self.browser.getControl(name="SUBMIT").click()
526        self.assertEqual(self.browser.url, self.login_path)
527        return
528
529    def test_display_entered_values(self):
530        # After submit the entered values are displayed in the form
531        self.browser.open(self.login_path)
532        # Enter some value we can look for after submit
533        ac_series = self.browser.getControl(name="form.ac_series")
534        ac_series.value = '666'
535        self.browser.getControl(name="SUBMIT").click()
536        self.assertTrue('666' in self.browser.contents)
537        return
538
539class LoginTestWithPINs(LoginTest):
540    # Here we check login view of applicants containers with PINs provided.
541
542    # As setting up pins is time-consuming we only set them up when
543    # really needed (i.e. in this separate TestCase).
544
545    layer = FunctionalLayer
546
547    def setUp(self):
548        super(LoginTestWithPINs, self).setUp()
549
550        # Create 5 access codes with prefix'FOO' and cost 9.99 each
551        pin_container = self.getRootFolder()['app']['accesscodes']
552        pin_container.createBatch(
553            datetime.now(), 'some_userid', 'APP', 9.99, 5)
554        pins = pin_container[pin_container.keys()[0]].values()
555        self.pins = [x.representation for x in pins]
556        self.existing_pin = self.pins[0]
557        parts = self.existing_pin.split('-')[1:]
558        self.existing_series, self.existing_number = parts
559        self.browser.handleErrors = False
560
561    def tearDown(self):
562        super(LoginTestWithPINs, self).tearDown()
563
564    def test_anonymous_valid_login(self):
565        # If we enter valid credentials, we get to the applicants form
566        self.browser.open(self.login_path)
567        # Enter some value we can look for after submit
568        ac_series = self.browser.getControl(name="form.ac_series")
569        ac_series.value = self.existing_series
570        ac_number = self.browser.getControl(name="form.ac_number")
571        ac_number.value = self.existing_number
572        self.browser.getControl(name="SUBMIT").click()
573        # We should be redirected to applicants form.
574        self.assertTrue(self.browser.url != self.login_path)
575        # Applicants see their Access Code in the contact form
576        self.browser.getLink("Contact").click()
577        self.assertTrue(
578            'Access Code:' in self.browser.contents)
579        return
580
581    def test_anonymous_invalid_login(self):
582        # If we enter wrong credentials we won't get far
583        self.browser.open(self.login_path)
584        # Enter some value we can look for after submit
585        ac_series = self.browser.getControl(name="form.ac_series")
586        ac_series.value = 'illegal series'
587        ac_number = self.browser.getControl(name="form.ac_number")
588        ac_number.value = 'invalid number'
589        self.browser.getControl(name="SUBMIT").click()
590        # We get a warning message
591        self.assertTrue(
592            'Entered credentials are invalid' in self.browser.contents)
593        # We stay at the login page (no redirect)
594        self.assertTrue(self.browser.url == self.login_path)
595        return
596
597class ApplicantsPassportTests(ApplicantsFullSetup):
598    # Tests for uploading/browsing the passport image of appplicants
599
600    layer = FunctionalLayer
601
602    def setUp(self):
603        super(ApplicantsPassportTests, self).setUp()
604        self.login_path = 'http://localhost/app/applicants/app2009/login'
605        self.pin = self.pins[2]
606        self.existing_series, self.existing_number = self.pin.split('-')[1:]
607        self.edit_path = 'http://localhost/app/applicants/app2009/%s/edit' % (
608            self.pin)
609        self.edit_full_path = 'http://localhost/app/applicants/%s/%s/%s' % (
610            'app2009', self.pin, 'edit_full')
611
612    def tearDown(self):
613        super(ApplicantsPassportTests, self).tearDown()
614
615    def login(self):
616        # Perform an applicant login. This creates an applicant record.
617        #
618        # This helper also sets `self.applicant`, which is the
619        # applicant object created.
620        self.browser.open(self.login_path)
621        ac_series = self.browser.getControl(name="form.ac_series")
622        ac_series.value = self.existing_series
623        ac_number = self.browser.getControl(name="form.ac_number")
624        ac_number.value = self.existing_number
625        self.browser.getControl(name="SUBMIT").click()
626        self.applicant = self.app['applicants']['app2009'][self.pin]
627
628    def fill_correct_values(self):
629        # Fill the edit form with suitable values
630        self.browser.getControl(name="form.firstname").value = 'John'
631        self.browser.getControl(name="form.lastname").value = 'Tester'
632        self.browser.getControl(name="form.course1").value = ['CERT1']
633        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
634        self.browser.getControl(name="form.lga").value = ['foreigner']
635        self.browser.getControl(name="form.sex").value = ['m']
636
637    def image_url(self, filename):
638        return self.edit_path.replace('edit', filename)
639
640    def test_after_login_default_browsable(self):
641        # After login we see the placeholder image in the edit view
642        #import pdb; pdb.set_trace()
643        self.login()
644        self.assertEqual(self.browser.url, self.edit_path)
645        # There is a correct <img> link included
646        self.assertTrue(
647            '<img src="passport.jpg" />' in self.browser.contents)
648        # Browsing the link shows a real image
649        self.browser.open(self.image_url('passport.jpg'))
650        self.assertEqual(
651            self.browser.headers['content-type'], 'image/jpeg')
652        self.assertEqual(len(self.browser.contents), PH_LEN)
653
654    def test_after_submit_default_browsable(self):
655        # After submitting an applicant form the default image is
656        # still visible
657        self.login()
658        self.browser.getControl("Save").click() # submit form
659        # There is a correct <img> link included
660        self.assertTrue(
661            '<img src="passport.jpg" />' in self.browser.contents)
662        # Browsing the link shows a real image
663        self.browser.open(self.image_url('passport.jpg'))
664        self.assertEqual(
665            self.browser.headers['content-type'], 'image/jpeg')
666        self.assertEqual(len(self.browser.contents), PH_LEN)
667
668    def test_uploaded_image_respects_file_size_restriction(self):
669        # When we upload an image that is too big ( > 10 KB) we will
670        # get an error message
671        self.login()
672        # Create a pseudo image file and select it to be uploaded in form
673        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
674        pseudo_image = StringIO(photo_content)
675        ctrl = self.browser.getControl(name='form.passport')
676        file_ctrl = ctrl.mech_control
677        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
678        self.browser.getControl("Save").click() # submit form
679        # There is a correct <img> link included
680        self.assertTrue(
681            '<img src="passport.jpg" />' in self.browser.contents)
682        # We get a warning message
683        self.assertTrue(
684            'Uploaded image is too big' in self.browser.contents)
685        # Browsing the image gives us the default image, not the
686        # uploaded one.
687        self.browser.open(self.image_url('passport.jpg'))
688        self.assertEqual(
689            self.browser.headers['content-type'], 'image/jpeg')
690        self.assertEqual(len(self.browser.contents), PH_LEN)
691        # There is really no file stored for the applicant
692        img = getUtility(IExtFileStore).getFile(
693            IFileStoreNameChooser(self.applicant).chooseName())
694        self.assertTrue(img is None)
695
696    def test_uploaded_image_browsable_w_errors(self):
697        # We can upload a different image and browse it after submit,
698        # even if there are still errors in the form
699        self.login()
700        # Create a pseudo image file and select it to be uploaded in form
701        photo_content = 'I pretend to be a graphics file'
702        pseudo_image = StringIO(photo_content)
703        ctrl = self.browser.getControl(name='form.passport')
704        file_ctrl = ctrl.mech_control
705        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
706        self.browser.getControl("Save").click() # submit form
707        # There is a correct <img> link included
708        self.assertTrue(
709            '<img src="passport.jpg" />' in self.browser.contents)
710        # Browsing the link shows a real image
711        self.browser.open(self.image_url('passport.jpg'))
712        self.assertEqual(
713            self.browser.headers['content-type'], 'image/jpeg')
714        self.assertEqual(self.browser.contents, photo_content)
715
716    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
717        # After uploading a new passport pic the file is correctly
718        # stored in an imagestorage
719        self.login()
720        # Create a pseudo image file and select it to be uploaded in form
721        pseudo_image = StringIO('I pretend to be a graphics file')
722        ctrl = self.browser.getControl(name='form.passport')
723        file_ctrl = ctrl.mech_control
724        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
725        self.browser.getControl("Save").click() # submit form
726        storage = getUtility(IExtFileStore)
727        file_id = IFileStoreNameChooser(self.applicant).chooseName()
728        pseudo_image.seek(0) # reset our file data source
729        self.assertEqual(
730            storage.getFile(file_id).read(), pseudo_image.read())
731        return
732
733    def test_uploaded_image_browsable_wo_errors(self):
734        # We can upload a different image and browse it after submit,
735        # if there are no errors in form
736        self.login()
737        self.fill_correct_values() # fill other fields with correct values
738        # Create a pseudo image file and select it to be uploaded in form
739        pseudo_image = StringIO('I pretend to be a graphics file')
740        ctrl = self.browser.getControl(name='form.passport')
741        file_ctrl = ctrl.mech_control
742        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
743        self.browser.getControl("Save").click() # submit form
744        # There is a correct <img> link included
745        self.assertTrue(
746            '<img src="passport.jpg" />' in self.browser.contents)
747        # Browsing the link shows a real image
748        self.browser.open(self.image_url('passport.jpg'))
749        self.assertEqual(
750            self.browser.headers['content-type'], 'image/jpeg')
751        self.assertEqual(len(self.browser.contents), 31)
752
753    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
754        # After uploading a new passport pic the file is correctly
755        # stored in an imagestorage if form contains no errors
756        self.login()
757        self.fill_correct_values() # fill other fields with correct values
758        # Create a pseudo image file and select it to be uploaded in form
759        pseudo_image = StringIO('I pretend to be a graphics file')
760        ctrl = self.browser.getControl(name='form.passport')
761        file_ctrl = ctrl.mech_control
762        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
763        self.browser.getControl("Save").click() # submit form
764        storage = getUtility(IExtFileStore)
765        file_id = IFileStoreNameChooser(self.applicant).chooseName()
766        # The stored image can be fetched
767        fd = storage.getFile(file_id)
768        file_len = len(fd.read())
769        self.assertEqual(file_len, 31)
770
771    def test_uploaded_images_equal(self):
772        # Make sure uploaded images do really differ if we eject a
773        # change notfication (and do not if we don't)
774        self.login() # Create applicant form
775        self.fill_correct_values() # fill other fields with correct values
776        self.browser.getControl("Save").click() # submit form
777        # Now go on as an officer
778        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
779        self.browser.open(self.edit_full_path)
780
781        # Create a pseudo image file and select it to be uploaded in form
782        pseudo_image = StringIO('I pretend to be a graphics file')
783        ctrl = self.browser.getControl(name='form.passport')
784        file_ctrl = ctrl.mech_control
785        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
786        file_id = IFileStoreNameChooser(self.applicant).chooseName()
787        setSite(self.app)
788        passport0 = getUtility(IExtFileStore).getFile(file_id)
789        self.browser.getControl("Save").click() # submit form with changed pic
790        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
791        self.browser.getControl("Save").click() # submit form w/o changes
792        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
793        self.assertTrue(passport0 is None)
794        self.assertTrue(passport0 != passport1)
795        self.assertTrue(passport1 == passport2)
796        return
797
798    def test_final_submit(self):
799        # Make sure that a correctly filled form with passport picture
800        # can be submitted
801        self.login() # Create applicant form
802        self.fill_correct_values() # fill other fields with correct values
803        # Create a pseudo image file and select it to be uploaded in form
804        pseudo_image = StringIO('I pretend to be a graphics file')
805        ctrl = self.browser.getControl(name='form.passport')
806        file_ctrl = ctrl.mech_control
807        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
808        self.browser.getControl("Final Submit").click() # (finally) submit form
809        self.assertEqual(self.browser.headers['Status'], '200 Ok')
810        self.assertTrue(
811            'Passport confirmation box not ticked' in self.browser.contents)
812        self.browser.getControl(name="confirm_passport").value = True
813        IWorkflowInfo(self.applicant).fireTransition('submit')
814        self.browser.getControl("Final Submit").click() # submit form again
815        self.assertTrue(
816            'Wrong state' in self.browser.contents)
817        IWorkflowInfo(self.applicant).fireTransition('reset1')
818        # Now do the whole thing again but with correct state
819        self.login()
820        self.fill_correct_values()
821        pseudo_image = StringIO('I pretend to be a graphics file')
822        ctrl = self.browser.getControl(name='form.passport')
823        file_ctrl = ctrl.mech_control
824        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
825        self.browser.getControl(name="confirm_passport").value = True
826        self.browser.getControl("Final Submit").click()
827        self.assertTrue(
828            '... submitted ...' in self.browser.contents)
829        self.browser.goBack(count=1)
830        self.browser.getControl("Save").click()
831        self.assertTrue(
832            'The requested form is locked' in self.browser.contents)
833        self.browser.goBack(count=1)
834        #import pdb; pdb.set_trace()
835        self.browser.getControl("Final Submit").click()
836        self.assertTrue(
837            'The requested form is locked' in self.browser.contents)
838        return
839
840    def test_locking(self):
841        # Make sure that locked forms can't be submitted
842        self.login() # Create applicant form
843        self.fill_correct_values() # fill other fields with correct values
844        # Create a pseudo image file and select it to be uploaded in form
845        pseudo_image = StringIO('I pretend to be a graphics file')
846        ctrl = self.browser.getControl(name='form.passport')
847        file_ctrl = ctrl.mech_control
848        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
849        self.browser.getControl("Save").click()
850        self.browser.getLink("Logout").click()
851
852        # Login as manager and lock the form
853        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
854        self.browser.open(self.edit_full_path)
855        self.browser.getControl(name="form.locked").value = True
856        self.browser.getControl("Save").click()
857        self.browser.getLink("Logout").click()
858
859        # Login as applicant again and try to open the edit form
860        self.login()
861        self.browser.open(self.edit_path)
862        self.assertEqual(self.browser.headers['Status'], '200 Ok')
863        #print self.browser.contents
864        self.assertTrue(
865            'The requested form is locked' in self.browser.contents)
866        return
Note: See TracBrowser for help on using the repository browser.