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

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

Merge changes from branch ulif-extimgstore back into trunk.
Beside external image storage also waeupdocs should work again.

File size: 39.7 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 DISABLEDtest_after_login_default_stored_in_imagestorage(self):
650        # After login the applicants placeholder image is stored in
651        # an imagestorage
652        storage = self.app['images']
653        # In the beginning, the storage is empty
654        self.assertEqual([x for x in storage.keys()], [])
655        self.login()
656        # After login, it is filled
657        self.assertEqual(
658            [x for x in storage.keys()],
659            [u'b48a1d39bbcb32e955d9ff2dea4ed0e6'])
660        file_id = self.applicant.passport.data
661        self.assertEqual(
662            file_id, u'b48a1d39bbcb32e955d9ff2dea4ed0e6-1')
663        # The stored image can be fetched
664        fd = storage.retrieveFile(file_id)
665        file_len = len(fd.read())
666        self.assertEqual(file_len, PH_LEN)
667
668    def test_after_submit_default_browsable(self):
669        # After submitting an applicant form the default image is
670        # still visible
671        self.login()
672        self.browser.getControl("Save").click() # submit form
673        # There is a correct <img> link included
674        self.assertTrue(
675            '<img src="passport.jpg" />' in self.browser.contents)
676        # Browsing the link shows a real image
677        self.browser.open(self.image_url('passport.jpg'))
678        self.assertEqual(
679            self.browser.headers['content-type'], 'image/jpeg')
680        self.assertEqual(len(self.browser.contents), PH_LEN)
681
682    def test_uploaded_image_browsable_w_errors(self):
683        # We can upload a different image and browse it after submit,
684        # even if there are still errors in the form
685        self.login()
686        # Create a pseudo image file and select it to be uploaded in form
687        photo_content = 'I pretend to be a graphics file'
688        pseudo_image = StringIO(photo_content)
689        ctrl = self.browser.getControl(name='form.passport')
690        file_ctrl = ctrl.mech_control
691        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
692        self.browser.getControl("Save").click() # submit form
693        # There is a correct <img> link included
694        self.assertTrue(
695            '<img src="passport.jpg" />' in self.browser.contents)
696        # Browsing the link shows a real image
697        self.browser.open(self.image_url('passport.jpg'))
698        self.assertEqual(
699            self.browser.headers['content-type'], 'image/jpeg')
700        self.assertEqual(self.browser.contents, photo_content)
701
702    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
703        # After uploading a new passport pic the file is correctly
704        # stored in an imagestorage
705        self.login()
706        # Create a pseudo image file and select it to be uploaded in form
707        pseudo_image = StringIO('I pretend to be a graphics file')
708        ctrl = self.browser.getControl(name='form.passport')
709        file_ctrl = ctrl.mech_control
710        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
711        self.browser.getControl("Save").click() # submit form
712        storage = getUtility(IExtFileStore)
713        file_id = IFileStoreNameChooser(self.applicant).chooseName()
714        pseudo_image.seek(0) # reset our file data source
715        self.assertEqual(
716            storage.getFile(file_id).read(), pseudo_image.read())
717        return
718
719    def test_uploaded_image_browsable_wo_errors(self):
720        # We can upload a different image and browse it after submit,
721        # if there are no errors in form
722        self.login()
723        self.fill_correct_values() # fill other fields with correct values
724        # Create a pseudo image file and select it to be uploaded in form
725        pseudo_image = StringIO('I pretend to be a graphics file')
726        ctrl = self.browser.getControl(name='form.passport')
727        file_ctrl = ctrl.mech_control
728        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
729        self.browser.getControl("Save").click() # submit form
730        # There is a correct <img> link included
731        self.assertTrue(
732            '<img src="passport.jpg" />' in self.browser.contents)
733        # Browsing the link shows a real image
734        self.browser.open(self.image_url('passport.jpg'))
735        self.assertEqual(
736            self.browser.headers['content-type'], 'image/jpeg')
737        self.assertEqual(len(self.browser.contents), 31)
738
739    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
740        # After uploading a new passport pic the file is correctly
741        # stored in an imagestorage if form contains no errors
742        self.login()
743        self.fill_correct_values() # fill other fields with correct values
744        # Create a pseudo image file and select it to be uploaded in form
745        pseudo_image = StringIO('I pretend to be a graphics file')
746        ctrl = self.browser.getControl(name='form.passport')
747        file_ctrl = ctrl.mech_control
748        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
749        self.browser.getControl("Save").click() # submit form
750        storage = getUtility(IExtFileStore)
751        file_id = IFileStoreNameChooser(self.applicant).chooseName()
752        # The stored image can be fetched
753        fd = storage.getFile(file_id)
754        file_len = len(fd.read())
755        self.assertEqual(file_len, 31)
756
757    def test_uploaded_images_equal(self):
758        # Make sure uploaded images do really differ if we eject a
759        # change notfication (and do not if we don't)
760        self.login() # Create applicant form
761        self.fill_correct_values() # fill other fields with correct values
762        self.browser.getControl("Save").click() # submit form
763        # Now go on as an officer
764        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
765        self.browser.open(self.edit_full_path)
766
767        # Create a pseudo image file and select it to be uploaded in form
768        pseudo_image = StringIO('I pretend to be a graphics file')
769        ctrl = self.browser.getControl(name='form.passport')
770        file_ctrl = ctrl.mech_control
771        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
772        file_id = IFileStoreNameChooser(self.applicant).chooseName()
773        setSite(self.app)
774        passport0 = getUtility(IExtFileStore).getFile(file_id)
775        self.browser.getControl("Save").click() # submit form with changed pic
776        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
777        self.browser.getControl("Save").click() # submit form w/o changes
778        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
779        self.assertTrue(passport0 is None)
780        self.assertTrue(passport0 != passport1)
781        self.assertTrue(passport1 == passport2)
782        return
783
784    def test_final_submit(self):
785        # Make sure that a correctly filled form with passport picture
786        # can be submitted
787        self.login() # Create applicant form
788        self.fill_correct_values() # fill other fields with correct values
789        # Create a pseudo image file and select it to be uploaded in form
790        pseudo_image = StringIO('I pretend to be a graphics file')
791        ctrl = self.browser.getControl(name='form.passport')
792        file_ctrl = ctrl.mech_control
793        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
794        self.browser.getControl("Final Submit").click() # (finally) submit form
795        self.assertEqual(self.browser.headers['Status'], '200 Ok')
796        self.assertTrue(
797            'Passport confirmation box not ticked' in self.browser.contents)
798        self.browser.getControl(name="confirm_passport").value = True
799        IWorkflowInfo(self.applicant).fireTransition('submit')
800        self.browser.getControl("Final Submit").click() # submit form again
801        self.assertTrue(
802            'Wrong state' in self.browser.contents)
803        IWorkflowInfo(self.applicant).fireTransition('reset1')
804        # Now do the whole thing again but with correct state
805        self.login()
806        self.fill_correct_values()
807        pseudo_image = StringIO('I pretend to be a graphics file')
808        ctrl = self.browser.getControl(name='form.passport')
809        file_ctrl = ctrl.mech_control
810        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
811        self.browser.getControl(name="confirm_passport").value = True
812        self.browser.getControl("Final Submit").click()
813        self.assertTrue(
814            '... submitted ...' in self.browser.contents)
815        self.browser.goBack(count=1)
816        self.browser.getControl("Save").click()
817        self.assertTrue(
818            'The requested form is locked' in self.browser.contents)
819        self.browser.goBack(count=1)
820        #import pdb; pdb.set_trace()
821        self.browser.getControl("Final Submit").click()
822        self.assertTrue(
823            'The requested form is locked' in self.browser.contents)
824        return
825
826    def test_locking(self):
827        # Make sure that locked forms can't be submitted
828        self.login() # Create applicant form
829        self.fill_correct_values() # fill other fields with correct values
830        # Create a pseudo image file and select it to be uploaded in form
831        pseudo_image = StringIO('I pretend to be a graphics file')
832        ctrl = self.browser.getControl(name='form.passport')
833        file_ctrl = ctrl.mech_control
834        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
835        self.browser.getControl("Save").click()
836        self.browser.getLink("Logout").click()
837
838        # Login as manager and lock the form
839        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
840        self.browser.open(self.edit_full_path)
841        self.browser.getControl(name="form.locked").value = True
842        self.browser.getControl("Save").click()
843        self.browser.getLink("Logout").click()
844
845        # Login as applicant again and try to open the edit form
846        self.login()
847        self.browser.open(self.edit_path)
848        self.assertEqual(self.browser.headers['Status'], '200 Ok')
849        #print self.browser.contents
850        self.assertTrue(
851            'The requested form is locked' in self.browser.contents)
852        return
Note: See TracBrowser for help on using the repository browser.