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

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

More copyright adjustments.

  • Property svn:keywords set to Id
File size: 40.4 KB
Line 
1## $Id: test_browser.py 7193 2011-11-25 07:21:29Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Test the applicant-related UI components.
20"""
21import shutil
22import tempfile
23from StringIO import StringIO
24from datetime import datetime, date, timedelta
25from mechanize import LinkNotFoundError
26from zope.component import createObject, getUtility
27from zope.component.hooks import setSite, clearSite
28from zope.security.interfaces import Unauthorized
29from zope.testbrowser.testing import Browser
30from hurry.workflow.interfaces import IWorkflowInfo
31from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
32from waeup.sirp.app import University
33from waeup.sirp.applicants.container import ApplicantsContainer
34from waeup.sirp.applicants.applicant import Applicant
35from waeup.sirp.interfaces import IExtFileStore, IFileStoreNameChooser
36from waeup.sirp.university.faculty import Faculty
37from waeup.sirp.university.department import Department
38
39PH_LEN = 2059  # Length of placeholder file
40
41class ApplicantsFullSetup(FunctionalTestCase):
42    # A test case that only contains a setup and teardown
43    #
44    # Complete setup for applicants handlings is rather complex and
45    # requires lots of things created before we can start. This is a
46    # setup that does all this, creates a university, creates PINs,
47    # etc.  so that we do not have to bother with that in different
48    # test cases.
49
50    layer = FunctionalLayer
51
52    def setUp(self):
53        super(ApplicantsFullSetup, self).setUp()
54
55        # Setup a sample site for each test
56        app = University()
57        self.dc_root = tempfile.mkdtemp()
58        app['datacenter'].setStoragePath(self.dc_root)
59
60        # Prepopulate the ZODB...
61        self.getRootFolder()['app'] = app
62        # we add the site immediately after creation to the
63        # ZODB. Catalogs and other local utilities are not setup
64        # before that step.
65        self.app = self.getRootFolder()['app']
66        # Set site here. Some of the following setup code might need
67        # to access grok.getSite() and should get our new app then
68        setSite(app)
69
70        self.root_path = 'http://localhost/app/applicants'
71        self.manage_root_path = self.root_path + '/@@manage'
72        self.add_container_path = self.root_path + '/@@add'
73        self.container_path = 'http://localhost/app/applicants/app2009'
74        self.manage_container_path = self.container_path + '/@@manage'
75
76        # Add an applicants container
77        applicantscontainer = ApplicantsContainer()
78        applicantscontainer.ac_prefix = 'APP'
79        applicantscontainer.prefix = 'app'
80        applicantscontainer.year = 2009
81        applicantscontainer.application_category = 'basic'
82        delta = timedelta(days=10)
83        applicantscontainer.startdate = date.today() - delta
84        applicantscontainer.enddate = date.today() + delta
85        self.app['applicants']['app2009'] = applicantscontainer
86
87        # Populate university
88        certificate = createObject('waeup.Certificate')
89        certificate.code = 'CERT1'
90        certificate.application_category = 'basic'
91        self.certificate = certificate
92        self.app['faculties']['fac1'] = Faculty()
93        self.app['faculties']['fac1']['dep1'] = Department()
94        self.department = self.app['faculties']['fac1']['dep1']
95        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
96            certificate)
97
98        # Put the prepopulated site into test ZODB and prepare test
99        # browser
100        self.browser = Browser()
101        self.browser.handleErrors = False
102
103        # Create 5 access codes with prefix'FOO' and cost 9.99 each
104        pin_container = self.app['accesscodes']
105        pin_container.createBatch(
106            datetime.now(), 'some_userid', 'APP', 9.99, 5)
107        pins = pin_container[pin_container.keys()[0]].values()
108        self.pins = [x.representation for x in pins]
109        self.existing_pin = self.pins[0]
110        parts = self.existing_pin.split('-')[1:]
111        self.existing_series, self.existing_number = parts
112
113        # Add an applicant
114        self.applicant = Applicant()
115        self.pin_applicant = unicode(self.pins[1])
116        self.applicant.access_code = self.pin_applicant
117        app['applicants']['app2009'][self.pin_applicant] = self.applicant
118
119    def tearDown(self):
120        super(ApplicantsFullSetup, self).tearDown()
121        clearSite()
122        shutil.rmtree(self.dc_root)
123
124class ApplicantsRootUITests(ApplicantsFullSetup):
125    # Tests for ApplicantsRoot class
126
127    layer = FunctionalLayer
128
129    def test_anonymous_access(self):
130        # Anonymous users can access applicants root
131        self.browser.open(self.root_path)
132        self.assertEqual(self.browser.headers['Status'], '200 Ok')
133        self.assertFalse(
134            'Manage' in self.browser.contents)
135
136   
137    def test_anonymous_no_actions(self):
138        # Make sure anonymous users cannot access actions
139        self.browser.open(self.root_path)
140        self.assertRaises(
141            LookupError, self.browser.getControl, "Add local role")
142        # Manage screen neither linked nor accessible for anonymous
143        self.assertRaises(
144            LinkNotFoundError,
145            self.browser.getLink, 'Manage application section')
146        self.assertRaises(
147            Unauthorized, self.browser.open, self.manage_root_path)
148        # Add container screen not accessible for anonymous
149        self.assertRaises(
150            Unauthorized, self.browser.open, self.add_container_path)
151        return
152
153    def test_manage_access(self):
154        # Managers can access the manage pages of applicants root
155        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
156        self.browser.open(self.root_path)
157        self.assertTrue('Manage application section' in self.browser.contents)
158        # There is a manage link
159        link = self.browser.getLink('Manage application section')
160        link.click()
161        self.assertEqual(self.browser.headers['Status'], '200 Ok')
162        self.assertEqual(self.browser.url, self.manage_root_path)
163
164    def test_manage_actions_access(self):
165        # Managers can access the action on manage screen
166        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
167        self.browser.open(self.manage_root_path)
168        self.browser.getControl("Add local role").click()
169        self.assertTrue('No user selected' in self.browser.contents)
170        return
171
172    # We have no local roles yet
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.local.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    # We have no local roles yet
424    #def test_local_roles_add_delete(self):
425    #    # Managers can assign and delete local roles of applicants containers
426    #    myusers = self.app['users']
427    #    myusers.addUser('bob', 'bobssecret')
428    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
429    #    self.browser.open(self.manage_container_path)
430    #    self.browser.getControl(name="user").value = ['bob']
431    #    self.browser.getControl(name="local_role").value = [
432    #        'waeup.local.ApplicationsOfficer']
433    #    self.browser.getControl("Add local role").click()
434    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
435    #    ctrl = self.browser.getControl(name='role_id')
436    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
437    #    self.browser.getControl("Remove selected local roles").click()
438    #    self.assertTrue('Successfully removed:' in self.browser.contents)
439    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
440    #    return
441
442class LoginTest(FunctionalTestCase):
443    # Here we check login view of applicants containers.
444    #
445    # Tests in here do only cover login attempts without any PINs
446    # created before.
447
448    layer = FunctionalLayer
449
450    def setUp(self):
451        super(LoginTest, self).setUp()
452
453        # Setup a sample site for each test
454        app = University()
455        self.dc_root = tempfile.mkdtemp()
456        app['datacenter'].setStoragePath(self.dc_root)
457        self.login_path = 'http://localhost/app/applicants/testapplicants/login'
458
459        # Add an applicants container where we can login (or not)
460        applicantscontainer = ApplicantsContainer()
461        applicantscontainer.ac_prefix = 'APP'
462        delta = timedelta(days=10)
463        applicantscontainer.startdate = date.today() - delta
464        applicantscontainer.enddate = date.today() + delta
465        app['applicants']['testapplicants'] = applicantscontainer
466
467        # Put the prepopulated site into test ZODB and prepare test
468        # browser
469        self.getRootFolder()['app'] = app
470        self.browser = Browser()
471        self.browser.handleErrors = False
472
473    def tearDown(self):
474        super(LoginTest, self).tearDown()
475        shutil.rmtree(self.dc_root)
476
477    def test_anonymous_access(self):
478        # Anonymous users can access a login page
479        self.browser.open(self.login_path)
480        self.assertEqual(self.browser.headers['Status'], '200 Ok')
481        return
482
483    def test_anonymous_invalid_creds(self):
484        # Anonymous users giving invalid credentials stay at the page
485        self.browser.open(self.login_path)
486        # We do not give credentials but send the form as-is
487        submit = self.browser.getControl(name='SUBMIT')
488        submit.click()
489        # We are still at the same page...
490        self.assertEqual(self.browser.url, self.login_path)
491        self.assertEqual(self.browser.headers['Status'], '200 Ok')
492        return
493
494    def test_anonymous_invalid_creds_warning(self):
495        # Entering wrong credentials will yield a warning
496        self.browser.open(self.login_path)
497        # We do not give credentials but send the form as-is
498        submit = self.browser.getControl(name='SUBMIT')
499        submit.click()
500        self.assertTrue(
501            'Entered credentials are invalid' in self.browser.contents)
502        return
503
504    def test_manager_no_warnings(self):
505        # Browsing the login screen as a manager, won't raise warnings
506        # Authenticate ourself as manager
507        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
508        self.browser.open(self.login_path)
509        # Submit the form w/o any credentials
510        self.browser.getControl(name="SUBMIT").click()
511        self.assertTrue(
512            'Entered credentials are invalid' not in self.browser.contents)
513        return
514
515    def test_manager_no_redirect(self):
516        # Browsing the login screen as a manager won't trigger a redirect
517        # Authenticate ourself as manager
518        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
519        self.browser.open(self.login_path)
520        # Submit the form w/o any credentials
521        self.browser.getControl(name="SUBMIT").click()
522        self.assertEqual(self.browser.url, self.login_path)
523        return
524
525    def test_display_entered_values(self):
526        # After submit the entered values are displayed in the form
527        self.browser.open(self.login_path)
528        # Enter some value we can look for after submit
529        ac_series = self.browser.getControl(name="form.ac_series")
530        ac_series.value = '666'
531        self.browser.getControl(name="SUBMIT").click()
532        self.assertTrue('666' in self.browser.contents)
533        return
534
535class LoginTestWithPINs(LoginTest):
536    # Here we check login view of applicants containers with PINs provided.
537
538    # As setting up pins is time-consuming we only set them up when
539    # really needed (i.e. in this separate TestCase).
540
541    layer = FunctionalLayer
542
543    def setUp(self):
544        super(LoginTestWithPINs, self).setUp()
545
546        # Create 5 access codes with prefix'FOO' and cost 9.99 each
547        pin_container = self.getRootFolder()['app']['accesscodes']
548        pin_container.createBatch(
549            datetime.now(), 'some_userid', 'APP', 9.99, 5)
550        pins = pin_container[pin_container.keys()[0]].values()
551        self.pins = [x.representation for x in pins]
552        self.existing_pin = self.pins[0]
553        parts = self.existing_pin.split('-')[1:]
554        self.existing_series, self.existing_number = parts
555        self.browser.handleErrors = False
556
557    def tearDown(self):
558        super(LoginTestWithPINs, self).tearDown()
559
560    def test_anonymous_valid_login(self):
561        # If we enter valid credentials, we get to the applicants form
562        self.browser.open(self.login_path)
563        # Enter some value we can look for after submit
564        ac_series = self.browser.getControl(name="form.ac_series")
565        ac_series.value = self.existing_series
566        ac_number = self.browser.getControl(name="form.ac_number")
567        ac_number.value = self.existing_number
568        self.browser.getControl(name="SUBMIT").click()
569        # We should be redirected to applicants form.
570        self.assertTrue(self.browser.url != self.login_path)
571        # Applicants see their Access Code in the contact form
572        self.browser.getLink("Contact").click()
573        self.assertTrue(
574            'Access Code:' in self.browser.contents)
575        return
576
577    def test_anonymous_invalid_login(self):
578        # If we enter wrong credentials we won't get far
579        self.browser.open(self.login_path)
580        # Enter some value we can look for after submit
581        ac_series = self.browser.getControl(name="form.ac_series")
582        ac_series.value = 'illegal series'
583        ac_number = self.browser.getControl(name="form.ac_number")
584        ac_number.value = 'invalid number'
585        self.browser.getControl(name="SUBMIT").click()
586        # We get a warning message
587        self.assertTrue(
588            'Entered credentials are invalid' in self.browser.contents)
589        # We stay at the login page (no redirect)
590        self.assertTrue(self.browser.url == self.login_path)
591        return
592
593class ApplicantsPassportTests(ApplicantsFullSetup):
594    # Tests for uploading/browsing the passport image of appplicants
595
596    layer = FunctionalLayer
597
598    def setUp(self):
599        super(ApplicantsPassportTests, self).setUp()
600        self.login_path = 'http://localhost/app/applicants/app2009/login'
601        self.pin = self.pins[2]
602        self.existing_series, self.existing_number = self.pin.split('-')[1:]
603        self.edit_path = 'http://localhost/app/applicants/app2009/%s/edit' % (
604            self.pin)
605        self.edit_full_path = 'http://localhost/app/applicants/%s/%s/%s' % (
606            'app2009', self.pin, 'edit_full')
607
608    def tearDown(self):
609        super(ApplicantsPassportTests, self).tearDown()
610
611    def login(self):
612        # Perform an applicant login. This creates an applicant record.
613        #
614        # This helper also sets `self.applicant`, which is the
615        # applicant object created.
616        self.browser.open(self.login_path)
617        ac_series = self.browser.getControl(name="form.ac_series")
618        ac_series.value = self.existing_series
619        ac_number = self.browser.getControl(name="form.ac_number")
620        ac_number.value = self.existing_number
621        self.browser.getControl(name="SUBMIT").click()
622        self.applicant = self.app['applicants']['app2009'][self.pin]
623
624    def fill_correct_values(self):
625        # Fill the edit form with suitable values
626        self.browser.getControl(name="form.firstname").value = 'John'
627        self.browser.getControl(name="form.lastname").value = 'Tester'
628        self.browser.getControl(name="form.course1").value = ['CERT1']
629        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
630        self.browser.getControl(name="form.lga").value = ['foreigner']
631        self.browser.getControl(name="form.sex").value = ['m']
632
633    def image_url(self, filename):
634        return self.edit_path.replace('edit', filename)
635
636    def test_after_login_default_browsable(self):
637        # After login we see the placeholder image in the edit view
638        #import pdb; pdb.set_trace()
639        self.login()
640        self.assertEqual(self.browser.url, self.edit_path)
641        # There is a correct <img> link included
642        self.assertTrue(
643            '<img src="passport.jpg" />' in self.browser.contents)
644        # Browsing the link shows a real image
645        self.browser.open(self.image_url('passport.jpg'))
646        self.assertEqual(
647            self.browser.headers['content-type'], 'image/jpeg')
648        self.assertEqual(len(self.browser.contents), PH_LEN)
649
650    def test_after_submit_default_browsable(self):
651        # After submitting an applicant form the default image is
652        # still visible
653        self.login()
654        self.browser.getControl("Save").click() # submit form
655        # There is a correct <img> link included
656        self.assertTrue(
657            '<img src="passport.jpg" />' in self.browser.contents)
658        # Browsing the link shows a real image
659        self.browser.open(self.image_url('passport.jpg'))
660        self.assertEqual(
661            self.browser.headers['content-type'], 'image/jpeg')
662        self.assertEqual(len(self.browser.contents), PH_LEN)
663
664    def test_uploaded_image_respects_file_size_restriction(self):
665        # When we upload an image that is too big ( > 10 KB) we will
666        # get an error message
667        self.login()
668        # Create a pseudo image file and select it to be uploaded in form
669        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
670        pseudo_image = StringIO(photo_content)
671        ctrl = self.browser.getControl(name='form.passport')
672        file_ctrl = ctrl.mech_control
673        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
674        self.browser.getControl("Save").click() # submit form
675        # There is a correct <img> link included
676        self.assertTrue(
677            '<img src="passport.jpg" />' in self.browser.contents)
678        # We get a warning message
679        self.assertTrue(
680            'Uploaded image is too big' in self.browser.contents)
681        # Browsing the image gives us the default image, not the
682        # uploaded one.
683        self.browser.open(self.image_url('passport.jpg'))
684        self.assertEqual(
685            self.browser.headers['content-type'], 'image/jpeg')
686        self.assertEqual(len(self.browser.contents), PH_LEN)
687        # There is really no file stored for the applicant
688        img = getUtility(IExtFileStore).getFile(
689            IFileStoreNameChooser(self.applicant).chooseName())
690        self.assertTrue(img is None)
691
692    def test_uploaded_image_browsable_w_errors(self):
693        # We can upload a different image and browse it after submit,
694        # even if there are still errors in the form
695        self.login()
696        # Create a pseudo image file and select it to be uploaded in form
697        photo_content = 'I pretend to be a graphics file'
698        pseudo_image = StringIO(photo_content)
699        ctrl = self.browser.getControl(name='form.passport')
700        file_ctrl = ctrl.mech_control
701        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
702        self.browser.getControl("Save").click() # submit form
703        # There is a correct <img> link included
704        self.assertTrue(
705            '<img src="passport.jpg" />' in self.browser.contents)
706        # Browsing the link shows a real image
707        self.browser.open(self.image_url('passport.jpg'))
708        self.assertEqual(
709            self.browser.headers['content-type'], 'image/jpeg')
710        self.assertEqual(self.browser.contents, photo_content)
711
712    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
713        # After uploading a new passport pic the file is correctly
714        # stored in an imagestorage
715        self.login()
716        # Create a pseudo image file and select it to be uploaded in form
717        pseudo_image = StringIO('I pretend to be a graphics file')
718        ctrl = self.browser.getControl(name='form.passport')
719        file_ctrl = ctrl.mech_control
720        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
721        self.browser.getControl("Save").click() # submit form
722        storage = getUtility(IExtFileStore)
723        file_id = IFileStoreNameChooser(self.applicant).chooseName()
724        pseudo_image.seek(0) # reset our file data source
725        self.assertEqual(
726            storage.getFile(file_id).read(), pseudo_image.read())
727        return
728
729    def test_uploaded_image_browsable_wo_errors(self):
730        # We can upload a different image and browse it after submit,
731        # if there are no errors in form
732        self.login()
733        self.fill_correct_values() # fill other fields with correct values
734        # Create a pseudo image file and select it to be uploaded in form
735        pseudo_image = StringIO('I pretend to be a graphics file')
736        ctrl = self.browser.getControl(name='form.passport')
737        file_ctrl = ctrl.mech_control
738        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
739        self.browser.getControl("Save").click() # submit form
740        # There is a correct <img> link included
741        self.assertTrue(
742            '<img src="passport.jpg" />' in self.browser.contents)
743        # Browsing the link shows a real image
744        self.browser.open(self.image_url('passport.jpg'))
745        self.assertEqual(
746            self.browser.headers['content-type'], 'image/jpeg')
747        self.assertEqual(len(self.browser.contents), 31)
748
749    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
750        # After uploading a new passport pic the file is correctly
751        # stored in an imagestorage if form contains no errors
752        self.login()
753        self.fill_correct_values() # fill other fields with correct values
754        # Create a pseudo image file and select it to be uploaded in form
755        pseudo_image = StringIO('I pretend to be a graphics file')
756        ctrl = self.browser.getControl(name='form.passport')
757        file_ctrl = ctrl.mech_control
758        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
759        self.browser.getControl("Save").click() # submit form
760        storage = getUtility(IExtFileStore)
761        file_id = IFileStoreNameChooser(self.applicant).chooseName()
762        # The stored image can be fetched
763        fd = storage.getFile(file_id)
764        file_len = len(fd.read())
765        self.assertEqual(file_len, 31)
766
767    def test_uploaded_images_equal(self):
768        # Make sure uploaded images do really differ if we eject a
769        # change notfication (and do not if we don't)
770        self.login() # Create applicant form
771        self.fill_correct_values() # fill other fields with correct values
772        self.browser.getControl("Save").click() # submit form
773        # Now go on as an officer
774        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
775        self.browser.open(self.edit_full_path)
776
777        # Create a pseudo image file and select it to be uploaded in form
778        pseudo_image = StringIO('I pretend to be a graphics file')
779        ctrl = self.browser.getControl(name='form.passport')
780        file_ctrl = ctrl.mech_control
781        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
782        file_id = IFileStoreNameChooser(self.applicant).chooseName()
783        setSite(self.app)
784        passport0 = getUtility(IExtFileStore).getFile(file_id)
785        self.browser.getControl("Save").click() # submit form with changed pic
786        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
787        self.browser.getControl("Save").click() # submit form w/o changes
788        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
789        self.assertTrue(passport0 is None)
790        self.assertTrue(passport0 != passport1)
791        self.assertTrue(passport1 == passport2)
792        return
793
794    def test_final_submit(self):
795        # Make sure that a correctly filled form with passport picture
796        # can be submitted
797        self.login() # Create applicant form
798        self.fill_correct_values() # fill other fields with correct values
799        # Create a pseudo image file and select it to be uploaded in form
800        pseudo_image = StringIO('I pretend to be a graphics file')
801        ctrl = self.browser.getControl(name='form.passport')
802        file_ctrl = ctrl.mech_control
803        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
804        self.browser.getControl("Final Submit").click() # (finally) submit form
805        self.assertEqual(self.browser.headers['Status'], '200 Ok')
806        self.assertTrue(
807            'Passport confirmation box not ticked' in self.browser.contents)
808        self.browser.getControl(name="confirm_passport").value = True
809        IWorkflowInfo(self.applicant).fireTransition('submit')
810        self.browser.getControl("Final Submit").click() # submit form again
811        self.assertTrue(
812            'Wrong state' in self.browser.contents)
813        IWorkflowInfo(self.applicant).fireTransition('reset1')
814        # Now do the whole thing again but with correct state
815        self.login()
816        self.fill_correct_values()
817        pseudo_image = StringIO('I pretend to be a graphics file')
818        ctrl = self.browser.getControl(name='form.passport')
819        file_ctrl = ctrl.mech_control
820        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
821        self.browser.getControl(name="confirm_passport").value = True
822        self.browser.getControl("Final Submit").click()
823        self.assertTrue(
824            '... submitted ...' in self.browser.contents)
825        self.browser.goBack(count=1)
826        self.browser.getControl("Save").click()
827        self.assertTrue(
828            'The requested form is locked' in self.browser.contents)
829        self.browser.goBack(count=1)
830        #import pdb; pdb.set_trace()
831        self.browser.getControl("Final Submit").click()
832        self.assertTrue(
833            'The requested form is locked' in self.browser.contents)
834        return
835
836    def test_locking(self):
837        # Make sure that locked forms can't be submitted
838        self.login() # Create applicant form
839        self.fill_correct_values() # fill other fields with correct values
840        # Create a pseudo image file and select it to be uploaded in form
841        pseudo_image = StringIO('I pretend to be a graphics file')
842        ctrl = self.browser.getControl(name='form.passport')
843        file_ctrl = ctrl.mech_control
844        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
845        self.browser.getControl("Save").click()
846        self.browser.getLink("Logout").click()
847
848        # Login as manager and lock the form
849        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
850        self.browser.open(self.edit_full_path)
851        self.browser.getControl(name="form.locked").value = True
852        self.browser.getControl("Save").click()
853        self.browser.getLink("Logout").click()
854
855        # Login as applicant again and try to open the edit form
856        self.login()
857        self.browser.open(self.edit_path)
858        self.assertEqual(self.browser.headers['Status'], '200 Ok')
859        #print self.browser.contents
860        self.assertTrue(
861            'The requested form is locked' in self.browser.contents)
862        return
Note: See TracBrowser for help on using the repository browser.