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

Last change on this file since 7083 was 7083, checked in by uli, 13 years ago

Ensure in tests that the maximum upload size restriction really works.

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