source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/applicants/tests/test_browser.py

Last change on this file was 17296, checked in by Henrik Bettermann, 20 months ago

Adjust to base package.

  • Property svn:keywords set to Id
File size: 24.6 KB
Line 
1## $Id: test_browser.py 17296 2023-01-16 20:41:05Z 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##
18import os
19import shutil
20import tempfile
21import datetime
22import grok
23import pytz
24from zope.event import notify
25from zope.intid.interfaces import IIntIds
26from zope.interface.verify import verifyClass, verifyObject
27from zope.schema.interfaces import ConstraintNotSatisfied
28from zope.component.hooks import setSite, clearSite
29from zope.component import createObject, getUtility
30from zope.catalog.interfaces import ICatalog
31from zope.testbrowser.testing import Browser
32from hurry.workflow.interfaces import IWorkflowState
33from waeup.kofa.app import University
34from waeup.kofa.university.faculty import Faculty
35from waeup.kofa.university.department import Department
36from waeup.kofa.testing import FunctionalTestCase
37from waeup.kofa.configuration import SessionConfiguration
38from waeup.kofa.applicants.container import ApplicantsContainer
39from waeup.kofa.applicants.tests.test_batching import ApplicantImportExportSetup
40from waeup.kofa.interfaces import IBatchProcessor, IUserAccount
41from kofacustom.nigeria.testing import FunctionalLayer
42from kofacustom.nigeria.applicants.export import NigeriaApplicantExporter
43from kofacustom.nigeria.applicants.batching import NigeriaApplicantProcessor
44
45session_1 = datetime.datetime.now().year - 2
46app_container_name = u'app%s' % session_1
47pgft_container_name = u'pgft%s' % session_1
48cbt_container_name = u'cbt%s' % session_1
49
50class ApplicantUITest(FunctionalTestCase):
51    """Perform some browser tests.
52    """
53    layer = FunctionalLayer
54
55    def setUp(self):
56        super(ApplicantUITest, self).setUp()
57        # Setup a sample site for each test
58        app = University()
59        self.dc_root = tempfile.mkdtemp()
60        app['datacenter'].setStoragePath(self.dc_root)
61
62        # Prepopulate the ZODB...
63        self.getRootFolder()['app'] = app
64        # we add the site immediately after creation to the
65        # ZODB. Catalogs and other local utilities are not setup
66        # before that step.
67        self.app = self.getRootFolder()['app']
68        # Set site here. Some of the following setup code might need
69        # to access grok.getSite() and should get our new app then
70        setSite(app)
71
72        # Add three different applicants containers
73        self.pgcontainer = ApplicantsContainer()
74        self.pgcontainer.code = pgft_container_name
75        self.pgcontainer.prefix = u'pgft'
76        self.pgcontainer.application_category = u'pg_ft'
77        self.pgcontainer.year = session_1
78        self.pgcontainer.application_fee = 300.0
79        self.pgcontainer.title = u'This is the %s container' % pgft_container_name
80        self.app['applicants'][pgft_container_name] = self.pgcontainer
81
82        self.ugcontainer = ApplicantsContainer()
83        self.ugcontainer.code = app_container_name
84        self.ugcontainer.prefix = u'app'
85        self.ugcontainer.application_category = u'basic'
86        self.ugcontainer.year = session_1
87        self.ugcontainer.application_fee = 200.0
88        self.ugcontainer.title = u'This is the %s container' % app_container_name
89        self.app['applicants'][app_container_name] = self.ugcontainer
90        self.ugcontainer.mode = 'update'
91        delta = datetime.timedelta(days=10)
92        self.ugcontainer.startdate = datetime.datetime.now(pytz.utc) - delta
93        self.ugcontainer.enddate = datetime.datetime.now(pytz.utc) + delta
94
95        self.cbtcontainer = ApplicantsContainer()
96        self.cbtcontainer.code = cbt_container_name
97        self.cbtcontainer.prefix = u'cbt'
98        self.cbtcontainer.application_category = u'basic'
99        self.cbtcontainer.year = session_1
100        self.cbtcontainer.application_fee = 300.0
101        self.cbtcontainer.title = u'This is the %s container' % cbt_container_name
102        self.app['applicants'][cbt_container_name] = self.cbtcontainer
103        self.cbtcontainer.mode = 'update'
104        delta = datetime.timedelta(days=10)
105        self.cbtcontainer.startdate = datetime.datetime.now(pytz.utc) - delta
106        self.cbtcontainer.enddate = datetime.datetime.now(pytz.utc) + delta
107
108        # Populate university
109        self.certificate = createObject('waeup.Certificate')
110        self.certificate.code = 'CERT1'
111        self.certificate.application_category = 'basic'
112        self.certificate.start_level = 100
113        self.certificate.end_level = 500
114        self.certificate.study_mode = u'ug_ft'
115        self.app['faculties']['fac1'] = Faculty()
116        self.app['faculties']['fac1']['dep1'] = Department()
117        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
118            self.certificate)
119        self.certificate2 = createObject('waeup.Certificate')
120        self.certificate2.code = 'CERT2'
121        self.certificate2.application_category = 'pg_ft'
122        self.certificate2.start_level = 100
123        self.certificate2.end_level = 500
124        self.certificate.study_mode = u'pg_ft'
125        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
126            self.certificate2)
127
128        # Add (customized) applicants
129        pgapplicant = createObject(u'waeup.Applicant')
130        pgapplicant.firstname = u'Anna'
131        pgapplicant.lastname = u'Post'
132        self.app['applicants'][pgft_container_name].addApplicant(pgapplicant)
133        self.pgapplication_number = pgapplicant.application_number
134        self.pgapplicant = self.app['applicants'][pgft_container_name][
135            self.pgapplication_number]
136
137        ugapplicant = createObject(u'waeup.Applicant')
138        ugapplicant.firstname = u'Klaus'
139        ugapplicant.lastname = u'Under'
140        self.app['applicants'][app_container_name].addApplicant(ugapplicant)
141        self.ugapplication_number = ugapplicant.application_number
142        self.ugapplicant = self.app['applicants'][app_container_name][
143            self.ugapplication_number]
144
145        cbtapplicant = createObject(u'waeup.Applicant')
146        cbtapplicant.firstname = u'Anna'
147        cbtapplicant.lastname = u'Cbt'
148        self.app['applicants'][cbt_container_name].addApplicant(cbtapplicant)
149        self.cbtapplication_number = cbtapplicant.application_number
150        self.cbtapplicant = self.app['applicants'][cbt_container_name][
151            self.cbtapplication_number]
152        IUserAccount(self.cbtapplicant).setPassword('apwd')
153
154        self.login_path = 'http://localhost/app/login'
155        self.logout_path = 'http://localhost/app/logout'
156        self.pgapplicant_path = ('http://localhost/app/applicants/%s/%s'
157            % (pgft_container_name, self.pgapplication_number))
158        self.ugapplicant_path = ('http://localhost/app/applicants/%s/%s'
159            % (app_container_name, self.ugapplication_number))
160        self.cbtapplicant_path = ('http://localhost/app/applicants/%s/%s'
161            % (cbt_container_name, self.cbtapplication_number))
162
163        self.browser = Browser()
164        self.browser.handleErrors = False
165
166        configuration = SessionConfiguration()
167        configuration.academic_session = session_1
168        configuration.application_fee = 200.0
169        self.app['configuration'].addSessionConfiguration(configuration)
170
171    def tearDown(self):
172        super(ApplicantUITest, self).tearDown()
173        shutil.rmtree(self.dc_root)
174        clearSite()
175        return
176
177    def fill_correct_values(self):
178        self.browser.getControl(name="form.reg_number").value = '1234'
179        self.browser.getControl(name="form.firstname").value = 'John'
180        self.browser.getControl(name="form.lastname").value = 'Tester'
181        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
182        self.browser.getControl(name="form.lga").value = ['foreigner']
183        self.browser.getControl(name="form.nationality").value = ['NG']
184        self.browser.getControl(name="form.sex").value = ['m']
185        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
186
187    def test_manage_and_view_applicant(self):
188        # Managers can manage pg applicants.
189        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
190        # The IPGApplicant interface is really used in all pages.
191        self.browser.open(self.pgapplicant_path)
192        self.assertEqual(self.browser.headers['Status'], '200 Ok')
193        self.assertTrue('Employer' in self.browser.contents)
194        self.browser.open(self.pgapplicant_path + '/manage')
195        self.assertEqual(self.browser.headers['Status'], '200 Ok')
196        self.assertTrue('Employer' in self.browser.contents)
197        self.browser.open(self.pgapplicant_path + '/edit')
198        self.assertEqual(self.browser.headers['Status'], '200 Ok')
199        self.assertTrue('Employer' in self.browser.contents)
200        self.browser.open(self.pgapplicant_path + '/application_slip.pdf')
201        self.assertEqual(self.browser.headers['Status'], '200 Ok')
202        # If we view the applicant in the ug container,
203        # the employer field doesn't appear.
204        self.browser.open(self.ugapplicant_path)
205        self.assertEqual(self.browser.headers['Status'], '200 Ok')
206        self.assertFalse('Employer' in self.browser.contents)
207        self.browser.open(self.ugapplicant_path + '/manage')
208        self.assertEqual(self.browser.headers['Status'], '200 Ok')
209        # We can save the applicant.
210        self.fill_correct_values()
211        self.browser.getControl(name="form.course1").value = ['CERT1']
212        self.browser.getControl("Save").click()
213        self.assertMatches('...Form has been saved...', self.browser.contents)
214        self.assertFalse('Employer' in self.browser.contents)
215        self.browser.open(self.ugapplicant_path + '/edit')
216        self.assertEqual(self.browser.headers['Status'], '200 Ok')
217        self.assertFalse('Employer' in self.browser.contents)
218        self.browser.open(self.ugapplicant_path + '/application_slip.pdf')
219        self.assertEqual(self.browser.headers['Status'], '200 Ok')
220        return
221
222    def test_set_wrong_course1(self):
223        self.ugapplicant.course1 = self.certificate
224        self.assertRaises(
225            ConstraintNotSatisfied,
226            setattr, self.ugapplicant, 'course1', self.certificate2)
227        self.pgapplicant.course1 = self.certificate2
228        self.assertRaises(
229            ConstraintNotSatisfied,
230            setattr, self.pgapplicant, 'course1', self.certificate)
231        return
232
233    def test_application_payment(self):
234        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
235
236        # UG (UTME) applicant
237        self.browser.open(self.ugapplicant_path)
238        self.browser.open(self.ugapplicant_path + '/manage')
239        self.assertEqual(self.browser.headers['Status'], '200 Ok')
240        self.fill_correct_values()
241        self.browser.getControl(name="form.course1").value = ['CERT1']
242        self.browser.getControl("Save").click()
243        self.assertMatches('...Form has been saved...', self.browser.contents)
244        self.browser.getControl("Add online payment ticket").click()
245        self.assertMatches('...Payment ticket created...',
246                           self.browser.contents)
247        self.assertMatches('...Amount Authorized...',
248                           self.browser.contents)
249        payment_id = self.ugapplicant.keys()[0]
250        payment = self.ugapplicant[payment_id]
251        self.assertEqual(payment.p_item,'This is the %s container' % app_container_name)
252        self.assertEqual(payment.p_session,session_1)
253        self.assertEqual(payment.p_category,'application')
254        self.assertEqual(payment.amount_auth, 200.0)
255
256        # PG applicants pay more
257        self.browser.open(self.pgapplicant_path)
258        self.browser.open(self.pgapplicant_path + '/manage')
259        self.assertEqual(self.browser.headers['Status'], '200 Ok')
260        self.fill_correct_values()
261        self.browser.getControl(name="form.course1").value = ['CERT2']
262        self.browser.getControl(name="form.reg_number").value = '2345'
263        self.browser.getControl(name="form.firstname").value = 'Anna'
264        self.browser.getControl("Save").click()
265        self.assertMatches('...Form has been saved...', self.browser.contents)
266        self.browser.getControl("Add online payment ticket").click()
267        self.assertMatches('...Payment ticket created...',
268                           self.browser.contents)
269        self.assertMatches('...Amount Authorized...',
270                           self.browser.contents)
271        payment_id = self.pgapplicant.keys()[0]
272        payment = self.pgapplicant[payment_id]
273        self.assertEqual(payment.p_item,'This is the %s container' % pgft_container_name)
274        self.assertEqual(payment.p_session,session_1)
275        self.assertEqual(payment.p_category,'application')
276        self.assertEqual(payment.amount_auth, 300.0)
277        return
278
279    def test_hide_screening_data(self):
280        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
281        self.browser.open(self.ugapplicant_path + '/manage')
282        self.assertEqual(self.browser.headers['Status'], '200 Ok')
283        self.fill_correct_values()
284        self.browser.getControl(name="form.screening_venue").value = 'Mensa'
285        self.browser.getControl(name="form.screening_date").value = 'Easter'
286        self.browser.getControl(name="form.course1").value = ['CERT1']
287        self.browser.getControl("Save").click()
288        self.assertMatches('...Form has been saved...', self.browser.contents)
289        self.browser.getControl("Save").click()
290        # Venue and date are not shown
291        self.browser.open(self.ugapplicant_path)
292        self.assertFalse('Screening' in self.browser.contents)
293        IWorkflowState(self.ugapplicant).setState('paid')
294        # Venue and date are shown if applicant has paid
295        self.browser.open(self.ugapplicant_path)
296        self.assertTrue('Screening' in self.browser.contents)
297        return
298
299    def test_register_applicant_update(self):
300        # An applicant can register himself.
301        self.ugapplicant.reg_number = u'1234'
302        notify(grok.ObjectModifiedEvent(self.ugapplicant))
303        self.browser.open('http://localhost/app/applicants/%s/' % app_container_name)
304        self.browser.getLink("Register for application").click()
305        # Fill the edit form with suitable values
306        self.browser.getControl(name="form.lastname").value = 'Under'
307        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
308        self.browser.getControl(name="form.reg_number").value = '1234'
309        self.browser.getControl("Send login credentials").click()
310        self.assertMatches('...Your registration was successful...',
311            self.browser.contents)
312        self.assertFalse('...<td>Password:</td>...' in self.browser.contents)
313        # The new applicant can be found in the catalog via the email address
314        cat = getUtility(ICatalog, name='applicants_catalog')
315        results = list(
316            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
317        applicant = results[0]
318        self.assertEqual(applicant.lastname,'Under')
319        # The applicant can be found in the catalog via the reg_number
320        results = list(
321            cat.searchResults(
322            reg_number=(applicant.reg_number, applicant.reg_number)))
323        self.assertEqual(applicant,results[0])
324        return
325
326    def test_create_ugstudent(self):
327        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
328        manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
329            app_container_name, self.ugapplicant.application_number, 'manage')
330        self.browser.open(manage_path)
331        self.fill_correct_values()
332        self.browser.getControl("Save").click()
333        IWorkflowState(self.ugapplicant).setState('admitted')
334        self.browser.getControl(name="form.course1").value = ['CERT1']
335        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
336        self.browser.getControl("Save").click()
337        self.browser.getLink("Create student").click()
338        student_id =  self.app['students'].keys()[0]
339        self.assertTrue(('Student %s created' % student_id)
340            in self.browser.contents)
341        student = self.app['students'][student_id]
342        self.assertEqual(student.email, 'xx@yy.zz')
343        self.assertEqual(student.firstname, 'John')
344        self.assertEqual(student.lastname, 'Tester')
345        # Also additional attributes have been copied.
346        self.assertEqual(student.lga, 'foreigner')
347        self.assertEqual(student.nationality, 'NG')
348        return
349
350    def test_applicant_access(self):
351        # Applicants can edit their record
352        self.browser.open(self.login_path)
353        self.browser.getControl(
354            name="form.login").value = self.cbtapplicant.applicant_id
355        self.browser.getControl(name="form.password").value = 'apwd'
356        self.browser.getControl("Login").click()
357        self.assertTrue(
358            'You logged in as an applicant.' in self.browser.contents)
359        self.browser.getLink("Edit application record").click()
360        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
361        self.browser.getControl(name="form.lga").value = ['foreigner']
362        self.browser.getControl(name="form.nationality").value = ['NG']
363        self.browser.getControl(name="form.sex").value = ['m']
364        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
365        self.browser.getControl(name="form.course1").value = ['CERT1']
366        self.browser.getControl("Save").click()
367        self.assertMatches('...Form has been saved...', self.browser.contents)
368
369class ApplicantExporterTest(ApplicantImportExportSetup):
370
371    layer = FunctionalLayer
372
373    def setUp(self):
374        super(ApplicantExporterTest, self).setUp()
375        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
376        self.cat = getUtility(ICatalog, name='applicants_catalog')
377        self.intids = getUtility(IIntIds)
378        return
379
380    def setup_applicant(self, applicant):
381        # set predictable values for `applicant`
382        applicant.reg_number = u'123456'
383        applicant.applicant_id = u'dp2011_654321'
384        applicant.firstname = u'Anna'
385        applicant.lastname = u'Tester'
386        applicant.middlename = u'M.'
387        applicant.nationality = u'NG'
388        applicant.date_of_birth = datetime.date(1981, 2, 4)
389        applicant.sex = 'f'
390        applicant.email = 'anna@sample.com'
391        applicant.phone = u'+234-123-12345'
392        applicant.course1 = self.certificate
393        applicant.course2 = self.certificate
394        applicant.course_admitted = self.certificate
395        applicant.notice = u'Some notice\nin lines.'
396        applicant.jamb_subjects = u'Line 1\nLine 2'
397        applicant.jamb_subjects_list = ['english_language', 'fine_art']
398        applicant.screening_score = 98
399        applicant.screening_venue = u'Exam Room'
400        applicant.screening_date = u'Saturday, 16th June 2012 2:00:00 PM'
401        applicant.password = 'any password'
402        return applicant
403
404    def test_export_reimport_all(self):
405        # we can export all applicants in a portal
406        # set values we can expect in export file
407        self.applicant = self.setup_applicant(self.applicant)
408        exporter = NigeriaApplicantExporter()
409        exporter.export_all(self.app, self.outfile)
410        result = open(self.outfile, 'rb').read()
411        self.assertMatches(result,
412            'aggregate,applicant_id,bank_account_name,bank_account_number,'
413            'bank_name,course1,course2,course_admitted,date_of_birth,'
414            'disabilities,email,'
415            'emp2_end,emp2_position,emp2_reason,emp2_start,emp_end,'
416            'emp_position,emp_reason,emp_start,employer,employer2,'
417            'firstname,fst_sit_date,fst_sit_fname,fst_sit_no,'
418            'fst_sit_results,fst_sit_type,hq_degree,hq_disc,'
419            'hq_fname,hq_matric_no,hq_school,hq_session,hq_type,'
420            'jamb_reg_number,jamb_score,jamb_subjects,jamb_subjects_list,'
421            'lastname,lga,locked,middlename,nationality,notice,nysc_lga,'
422            'nysc_year,phone,presently_inst,programme_type,reg_number,'
423            'result_uploaded,scd_sit_date,scd_sit_fname,scd_sit_no,'
424            'scd_sit_results,scd_sit_type,screening_date,screening_score,'
425            'screening_venue,sex,special_application,student_id,'
426            'suspended,password,state,history,container_code,'
427            'application_number,display_fullname,application_date\r\n'
428
429            ',dp2011_654321,,,,CERT1,CERT1,CERT1,1981-02-04#,,'
430            'anna@sample.com,,,,,,,,,,,Anna,,,,,,,,,,,,,,,Line 1++Line 2,'
431            '"[\'english_language\', \'fine_art\']",'
432            'Tester,,0,M.,NG,"Some notice\nin lines.",,,+234-123-12345#,,,'
433            '123456,,,,,,,"Saturday, 16th June 2012 2:00:00 PM",98,'
434            'Exam Room,f,,,0,any password,initialized,'
435            '[u\'2016-08-19 07:30:05 WAT - Application initialized by system\'],'
436            'dp2011,654321,Anna M. Tester,\r\n')
437        # We can import the same file if we ignore some columns.
438        # Since the applicants_catalog hasn't been notified, the same
439        # record with same reg_number can be imported twice.
440        processor = NigeriaApplicantProcessor()
441        result = processor.doImport(
442            self.outfile,
443            [
444            'aggregate','ignore_applicant_id','bank_account_name','bank_account_number',
445            'bank_name','course1','course2','course_admitted','date_of_birth',
446            'disabilities','email',
447            'emp2_end','emp2_position','emp2_reason','emp2_start','emp_end',
448            'emp_position','emp_reason','emp_start','employer','employer2',
449            'firstname','fst_sit_date','fst_sit_fname','fst_sit_no',
450            'fst_sit_results','fst_sit_type','hq_degree','hq_disc',
451            'hq_fname','hq_matric_no','hq_school','hq_session','hq_type',
452            'jamb_reg_number','jamb_score','jamb_subjects','jamb_subjects_list',
453            'lastname','lga','locked','middlename','nationality','notice','nysc_lga',
454            'nysc_year','phone','presently_inst','programme_type','reg_number',
455            'result_uploaded','scd_sit_date','scd_sit_fname','scd_sit_no',
456            'scd_sit_results','scd_sit_type','screening_date','screening_score',
457            'screening_venue','sex','special_application','student_id',
458            'suspended','password','state','history','container_code',
459            'application_number','display_fullname','application_date'
460            ],
461            mode='create')
462        num_succ, num_fail, finished_path, failed_path = result
463        #content = open(failed_path).read()
464        self.assertEqual(num_succ,1)
465        self.assertEqual(num_fail,0)
466        # Now we ignore also the container_code and import the same file
467        # in update mode which means that INigeriaApplicantUpdateByRegNo
468        # is used for field conversion. applicant_id must be ignored
469        # too since the previous import has notified the applicants_catalog
470        # so that the portal 'knows' that reg_number is in use.
471        processor = NigeriaApplicantProcessor()
472        result = processor.doImport(
473            self.outfile,
474            [
475            'aggregate','ignore_applicant_id','bank_account_name','bank_account_number',
476            'bank_name','course1','course2','course_admitted','date_of_birth',
477            'disabilities', 'email',
478            'emp2_end','emp2_position','emp2_reason','emp2_start','emp_end',
479            'emp_position','emp_reason','emp_start','employer','employer2',
480            'firstname','fst_sit_date','fst_sit_fname','fst_sit_no',
481            'fst_sit_results','fst_sit_type','hq_degree','hq_disc',
482            'hq_fname','hq_matric_no','hq_school','hq_session','hq_type',
483            'jamb_reg_number','jamb_score','jamb_subjects','jamb_subjects_list',
484            'lastname','lga','locked','middlename','nationality','notice','nysc_lga',
485            'nysc_year','phone','presently_inst','programme_type','reg_number',
486            'result_uploaded','scd_sit_date','scd_sit_fname','scd_sit_no',
487            'scd_sit_results','scd_sit_type','screening_date','screening_score',
488            'screening_venue','sex','special_application','student_id',
489            'suspended','password','state','ignore_history','ignore_container_code',
490            'ignore_application_number','display_fullname','application_date'
491            ],
492            mode='update')
493        num_succ, num_fail, finished_path, failed_path = result
494        self.assertEqual(num_succ,1)
495        self.assertEqual(num_fail,0)
496        return
Note: See TracBrowser for help on using the repository browser.