source: main/waeup.kofa/trunk/src/waeup/kofa/doctests/batchprocessing_browser.txt @ 17930

Last change on this file since 17930 was 17787, checked in by Henrik Bettermann, 6 months ago

Add SessionConfigurationProcessor.
Add ConfigurationContainerProcessor.
Add ConfigurationContainerExporter.

File size: 20.7 KB
Line 
1Batch Processing via Browser
2****************************
3
4Preliminaries:
5
6We define a function that looks up a form with several submit buttons
7for the one with a given value (this functionality is missing in
8zope.testbrowser):
9
10    >>> def lookup_submit_value(name, value, browser):
11    ...   """Find a button with a certain value."""
12    ...   for num in range(0, 100):
13    ...     try:
14    ...       button = browser.getControl(name=name, index=num)
15    ...       if button.value.endswith(value):
16    ...         return button
17    ...     except IndexError:
18    ...       break
19    ...   return None
20
21Create a site:
22
23    >>> from waeup.kofa.app import University
24    >>> getRootFolder()['app'] = University()
25    >>> from zope.component.hooks import setSite
26    >>> setSite(getRootFolder()['app'])
27
28Create a datacenter storage path:
29
30    >>> import os
31    >>> import tempfile
32    >>> dc_path = tempfile.mkdtemp()
33
34Log in:
35
36    >>> from zope.testbrowser.testing import Browser
37    >>> browser = Browser()
38    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
39    >>> browser.handleErrors = False
40
41Set datacenter path and deselect moving old data:
42
43    >>> browser.open('http://localhost/app')
44    >>> browser.getLink('Data Center').click()
45    >>> browser.getLink('Edit settings').click()
46    >>> browser.getControl(name='newpath').value = dc_path
47    >>> browser.getControl(name='move').value = False
48    >>> browser.getControl(name='save').click()
49
50Set non-usable datacenter path:
51
52    >>> browser.getLink('Edit settings').click()
53    >>> browser.getControl(name='newpath').value = '/'
54    >>> browser.getControl(name='save').click()
55    >>> 'Given storage path cannot be used.' in browser.contents
56    True
57    >>> browser.getControl('Back to Data Center').click()
58
59
60Batch Processing Faculties
61==========================
62
63Go to datacenter page:
64
65    >>> browser.open('http://localhost/app/datacenter')
66
67Prepare a CSV file for faculties (extended ascii values are accepted):
68
69    >>> open('faculties.csv', 'wb').write(
70    ... """code,title,title_prefix
71    ... FAC1,Faculty 1,faculty
72    ... FAC2,Faculty 2,institute
73    ... FAC3,Fäcülty 3,school
74    ... """)
75
76Upload the file:
77
78    >>> import cStringIO
79    >>> browser.getLink('Upload data').click()
80    >>> filecontents = cStringIO.StringIO(
81    ...   open('faculties.csv', 'rb').read())
82    >>> filewidget = browser.getControl(name='uploadfile:file')
83    >>> filewidget.add_file(filecontents, 'text/plain', 'faculties.csv')
84    >>> browser.getControl(name='SUBMIT').click()
85
86Step 1: start batch processing:
87
88    >>> browser.getLink('Process data').click()
89    >>> browser.getLink('Switch maintenance mode').click()
90    >>> button = lookup_submit_value(
91    ...   'select', 'faculties_zope.mgr.csv', browser)
92    >>> button.click()
93
94Step 2: select a processor and mode:
95
96    >>> importerselect = browser.getControl(name='importer')
97    >>> importerselect.displayOptions
98    ['AccessCodeBatch Processor',
99    'AccessCode Processor',
100    'ApplicantOnlinePayment Processor',
101    'Applicant Processor',
102    'ApplicantRefereeReport Processor',
103    'ApplicantsContainer Processor',
104    'Bed Processor (update only)',
105    'CertificateCourse Processor',
106    'Certificate Processor',
107    'ConfigurationConainer Processor (update only)',
108    'Course Processor',
109    'CourseTicket Processor',
110    'Department Processor',
111    'Faculty Processor',
112    'Hostel Processor',
113    'Public HTML Document Processor',
114    'StudentOnlinePayment Processor',
115    'Public PDF Document Processor',
116    'Public REST Document Processor',
117    'SessionConfiguration Processor',
118    'Student Processor',
119    'StudentStudyCourse Processor',
120    'StudentStudyLevel Processor',
121    'User Processor',
122    'Verdict Processor (special processor, update only)']
123
124    >>> importerselect.getControl('Faculty Processor').selected = True
125
126    >>> modeselect = browser.getControl(name='mode')
127    >>> modeselect.options
128    ['create', 'update', 'remove']
129
130    >>> modeselect.getControl(value='create').selected = True
131    >>> browser.getControl('Proceed to step 3').click()
132
133Step 3: Fix headerlines
134
135We get informed that there are no problems with the current header:
136
137    >>> print browser.contents
138    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
139    ...
140    Header fields OK
141    ...
142
143The submit button is enabled:
144
145    >>> browser.getControl('Perform import').disabled
146    False
147
148    >>> browser.getControl('Perform import').click()
149
150Step 4: See import results
151
152The import was successful:
153
154    >>> print browser.contents
155    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
156    ...Successfully processed 3 rows...
157    ...Batch processing finished...
158    ...File:...faculties_zope.mgr.csv...
159
160We can grep the entries generated in logfile:
161
162    >>> browser.open('http://localhost/app/datacenter/logs')
163    >>> browser.getControl('Show', index=0).click()
164    >>> print browser.contents
165    <!DOCTYPE ...
166    ...<h1 class="kofa-content-label">Logfile datacenter.log</h1>...
167
168    >>> browser.getControl(name='query').value = "zope.mgr"
169    >>> browser.getControl('Search').click()
170    >>> 'zope.mgr - processed' in browser.contents
171    True
172
173
174Batch Processing Departments
175============================
176
177    >>> browser.open('http://localhost/app/datacenter')
178
179Prepare a CSV file for departments:
180
181    >>> open('departments.csv', 'wb').write(
182    ... """code,faculty_code,title,title_prefix
183    ... DEP1,FAC1,Department 1,department
184    ... DEP2,FAC2,Department 2,centre
185    ... """)
186
187Upload the file:
188
189    >>> import cStringIO
190    >>> browser.getLink('Upload data').click()
191    >>> filecontents = cStringIO.StringIO(
192    ...   open('departments.csv', 'rb').read())
193    >>> filewidget = browser.getControl(name='uploadfile:file')
194    >>> filewidget.add_file(filecontents, 'text/plain', 'departments.csv')
195    >>> browser.getControl(name='SUBMIT').click()
196
197Step 1: start batch processing:
198
199    >>> browser.getLink('Process data').click()
200    >>> browser.getLink('Switch maintenance mode').click()
201    >>> button = lookup_submit_value(
202    ...   'select', 'departments_zope.mgr.csv', browser)
203    >>> button.click()
204
205Step 2: select a processor and mode:
206
207    >>> importerselect = browser.getControl(name='importer')
208    >>> importerselect.getControl('Department Processor').selected = True
209    >>> modeselect = browser.getControl(name='mode')
210    >>> modeselect.getControl(value='create').selected = True
211    >>> browser.getControl('Proceed to step 3').click()
212
213Step 3: Fix headerlines
214
215We get informed that there are no problems with the current header:
216
217    >>> print browser.contents
218    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
219    ...
220    Header fields OK
221    ...
222
223The submit button is enabled:
224
225    >>> browser.getControl('Perform import').disabled
226    False
227
228    >>> browser.getControl('Perform import').click()
229
230Step 4: See import results
231
232The import was successful:
233
234    >>> print browser.contents
235    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
236    ...Successfully processed 2 rows...
237    ...Batch processing finished...
238    ...File:...departments_zope.mgr.csv...
239
240Batch Processing Courses
241========================
242
243    >>> browser.open('http://localhost/app/datacenter')
244
245Prepare a CSV file for courses:
246
247    >>> open('courses.csv', 'wb').write(
248    ... """code,faculty_code,department_code,title,level,passmark,credits,semester
249    ... CRS1,FAC1,DEP1,Course 1,100,40,2,1
250    ... CRS2,FAC1,DEP1,Course 2,100,40,2,2
251    ... """)
252
253Upload the file:
254
255    >>> import cStringIO
256    >>> browser.getLink('Upload data').click()
257    >>> filecontents = cStringIO.StringIO(
258    ...   open('courses.csv', 'rb').read())
259    >>> filewidget = browser.getControl(name='uploadfile:file')
260    >>> filewidget.add_file(filecontents, 'text/plain', 'courses.csv')
261    >>> browser.getControl(name='SUBMIT').click()
262
263Step 1: start batch processing:
264
265    >>> browser.getLink('Process data').click()
266    >>> browser.getLink('Switch maintenance mode').click()
267    >>> button = lookup_submit_value(
268    ...   'select', 'courses_zope.mgr.csv', browser)
269    >>> button.click()
270
271Step 2: select a processor and mode:
272
273    >>> importerselect = browser.getControl(name='importer')
274    >>> importerselect.getControl('Course Processor', index=1).selected = True
275    >>> modeselect = browser.getControl(name='mode')
276    >>> modeselect.getControl(value='create').selected = True
277    >>> browser.getControl('Proceed to step 3').click()
278
279Step 3: Fix headerlines
280
281We get informed that there are no problems with the current header:
282
283    >>> print browser.contents
284    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
285    ...
286    Header fields OK
287    ...
288
289The submit button is enabled:
290
291    >>> browser.getControl('Perform import').disabled
292    False
293
294    >>> browser.getControl('Perform import').click()
295
296Step 4: See import results
297
298The import was successful:
299
300    >>> print browser.contents
301    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
302    ...Successfully processed 2 rows...
303    ...Batch processing finished...
304    ...File:...courses_zope.mgr.csv...
305
306Batch Processing Certificates
307=============================
308
309    >>> browser.open('http://localhost/app/datacenter')
310
311Prepare a CSV file for certificates:
312
313    >>> open('certificates.csv', 'wb').write(
314    ... """code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category
315    ... CERT1,FAC1,DEP1,Certificate 1,pg_ft,999,999,basic
316    ... CERT2,FAC1,DEP1,Certificate 2,ug_ft,200,300,cest
317    ... """)
318
319Upload the file:
320
321    >>> import cStringIO
322    >>> browser.getLink('Upload data').click()
323    >>> filecontents = cStringIO.StringIO(
324    ...   open('certificates.csv', 'rb').read())
325    >>> filewidget = browser.getControl(name='uploadfile:file')
326    >>> filewidget.add_file(filecontents, 'text/plain', 'certificates.csv')
327    >>> browser.getControl(name='SUBMIT').click()
328
329Step 1: start batch processing:
330
331    >>> browser.getLink('Process data').click()
332    >>> browser.getLink('Switch maintenance mode').click()
333    >>> button = lookup_submit_value(
334    ...   'select', 'certificates_zope.mgr.csv', browser)
335    >>> button.click()
336
337
338Step 2: select a processor and mode:
339
340    >>> importerselect = browser.getControl(name='importer')
341    >>> importerselect.getControl('Certificate Processor').selected = True
342    >>> modeselect = browser.getControl(name='mode')
343    >>> modeselect.getControl(value='create').selected = True
344    >>> browser.getControl('Proceed to step 3').click()
345
346Step 3: Fix headerlines
347
348We get informed that there are no problems with the current header:
349
350    >>> print browser.contents
351    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
352    ...
353    Header fields OK
354    ...
355
356The submit button is enabled:
357
358    >>> browser.getControl('Perform import').disabled
359    False
360
361    >>> browser.getControl('Perform import').click()
362
363Step 4: See import results
364
365The import was successful:
366
367    >>> print browser.contents
368    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
369    ...Successfully processed 2 rows...
370    ...Batch processing finished...
371    ...File:...certificates_zope.mgr.csv...
372
373Batch Processing Certificate Courses
374====================================
375
376    >>> browser.open('http://localhost/app/datacenter')
377
378Prepare a CSV file for certificate courses:
379
380    >>> open('mycertcourses.csv', 'wb').write(
381    ... """course,faculty_code,department_code,certificate_code,level,mandatory
382    ... CRS1,FAC1,DEP1,CERT1,100,True
383    ... CRS2,FAC1,DEP1,CERT1,100,True
384    ... """)
385
386Upload the file:
387
388    >>> import cStringIO
389    >>> browser.getLink('Upload data').click()
390    >>> filecontents = cStringIO.StringIO(
391    ...   open('mycertcourses.csv', 'rb').read())
392    >>> filewidget = browser.getControl(name='uploadfile:file')
393    >>> filewidget.add_file(filecontents, 'text/plain', 'mycertcourses.csv')
394    >>> browser.getControl(name='SUBMIT').click()
395
396Step 1: start batch processing:
397
398    >>> browser.getLink('Process data').click()
399    >>> browser.getLink('Switch maintenance mode').click()
400    >>> button = lookup_submit_value(
401    ...   'select', 'mycertcourses_zope.mgr.csv', browser)
402    >>> button.click()
403
404Step 2: select a processor and mode:
405
406    >>> importerselect = browser.getControl(name='importer')
407    >>> importerselect.getControl('CertificateCourse Processor').selected = True
408    >>> modeselect = browser.getControl(name='mode')
409    >>> modeselect.getControl(value='create').selected = True
410    >>> browser.getControl('Proceed to step 3').click()
411
412Step 3: Fix headerlines
413
414We get informed that there are no problems with the current header:
415
416    >>> print browser.contents
417    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
418    ...
419    Header fields OK
420    ...
421
422The submit button is enabled:
423
424    >>> browser.getControl('Perform import').disabled
425    False
426
427    >>> browser.getControl('Perform import').click()
428
429Step 4: See import results
430
431The import was successful:
432
433    >>> print browser.contents
434    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
435    ...Successfully processed 2 rows...
436    ...Batch processing finished...
437    ...File:...mycertcourses_zope.mgr.csv...
438
439Batch Processing Users
440======================
441
442    >>> browser.open('http://localhost/app/datacenter')
443
444Prepare a CSV file for users:
445
446    >>> open('users.csv', 'wb').write(
447    ... """name,title,public_name,email,phone,roles
448    ... uli,Uli Fouquet,Chief Developer,uli@abc.de,+49-234-567,[]
449    ... henrik,Henrik Bettermann,Admin,henrik@abc.de,+49-234-567,"['waeup.PortalManager', 'waeup.ImportManager']"
450    ... anne,Anne Palina,,anne@abc.de,+49-234-567,"['waeup.Nonsense']"
451    ... """)
452
453Upload the file:
454
455    >>> import cStringIO
456    >>> browser.getLink('Upload data').click()
457    >>> filecontents = cStringIO.StringIO(
458    ...   open('users.csv', 'rb').read())
459    >>> filewidget = browser.getControl(name='uploadfile:file')
460    >>> filewidget.add_file(filecontents, 'text/plain', 'users.csv')
461    >>> browser.getControl(name='SUBMIT').click()
462
463Step 1: start batch processing:
464
465    >>> browser.getLink('Process data').click()
466    >>> browser.getLink('Switch maintenance mode').click()
467    >>> button = lookup_submit_value(
468    ...   'select', 'users_zope.mgr.csv', browser)
469    >>> button.click()
470
471Step 2: select a processor and mode:
472
473    >>> importerselect = browser.getControl(name='importer')
474    >>> importerselect.getControl('User Processor').selected = True
475    >>> modeselect = browser.getControl(name='mode')
476    >>> modeselect.getControl(value='create').selected = True
477    >>> browser.getControl('Proceed to step 3').click()
478
479Step 3: Fix headerlines
480
481We get informed that there are no problems with the current header:
482
483    >>> print browser.contents
484    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
485    ...
486    Header fields OK
487    ...
488
489The submit button is enabled:
490
491    >>> browser.getControl('Perform import').disabled
492    False
493
494    >>> browser.getControl('Perform import').click()
495
496Step 4: See import results
497
498The import was successful:
499
500    >>> print browser.contents
501    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
502    ...Successfully processed 2 rows...
503    ...Batch processing finished...
504    ...File:...users_zope.mgr.csv...
505
506User henrik has got the global roles:
507
508   >>> henrik = getRootFolder()['app']['users']['henrik']
509   >>> henrik.roles
510   ['waeup.PortalManager', 'waeup.AcademicsOfficer', 'waeup.ImportManager']
511
512Pending Files
513=============
514
515When an error occurs during an import, two files are generated: a CSV
516file with finished files and a CSV file with pending data. Both are
517stored in the appropriate subdirectories in datacenter. We try to
518create faculties, from which one already exists.
519
520Go to datacenter page:
521
522    >>> browser.open('http://localhost/app/datacenter')
523
524Prepare a CSV file for faculties:
525
526    >>> open('newfaculties.csv', 'wb').write(
527    ... """code,title,title_prefix
528    ... FAC1,Faculty 1,faculty
529    ... FAC4,Faculty 4,school
530    ... FAC 5,Faculty 5,faculty
531    ... """)
532
533Upload the file:
534
535    >>> import cStringIO
536    >>> browser.getLink('Upload data').click()
537    >>> filecontents = cStringIO.StringIO(
538    ...   open('newfaculties.csv', 'rb').read())
539    >>> filewidget = browser.getControl(name='uploadfile:file')
540    >>> filewidget.add_file(filecontents, 'text/plain', 'newfaculties.csv')
541    >>> browser.getControl(name='SUBMIT').click()
542
543Since we now have a user with waeup.ImportManager role, an email has been sent:
544    >>> print browser.contents
545    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
546    ...
547    ...All import managers have been notified by email...
548    ...
549
550Step 1: start batch processing:
551
552    >>> browser.getLink('Process data').click()
553    >>> browser.getLink('Switch maintenance mode').click()
554    >>> button = lookup_submit_value(
555    ...   'select', 'newfaculties_zope.mgr.csv', browser)
556    >>> button.click()
557
558Step 2: select a processor and mode:
559
560    >>> importerselect = browser.getControl(name='importer')
561    >>> importerselect.getControl('Faculty Processor').selected = True
562    >>> modeselect = browser.getControl(name='mode')
563    >>> modeselect.getControl(value='create').selected = True
564    >>> browser.getControl('Proceed to step 3').click()
565
566Step 3: Fix headerlines
567
568As there should be no problem with the headers, we can immediately
569perfom the import:
570
571    >>> browser.getControl('Perform import').click()
572
573Two lines could not be imported:
574
575    >>> print browser.contents
576    <!DOCTYPE html PUBLIC...
577    ...
578    ...Processing of 2 rows failed...
579    ...Successfully processed 1 rows...
580    ...
581
582Now there are two files as a result in datacenter storage's root and
583``finished`` dirs:
584
585    >>> pending_file = dc_path + '/newfaculties_zope.mgr.create.pending.csv'
586    >>> print open(pending_file).read()
587    title_prefix,code,title,--ERRORS--
588    faculty,FAC1,Faculty 1,This object already exists.
589    faculty,FAC 5,Faculty 5,code: Invalid input
590
591    >>> finished_file = dc_path + '/finished/newfaculties_zope.mgr.create.finished.csv'
592    >>> print open(finished_file).read()
593    title_prefix,code,title
594    school,FAC4,Faculty 4
595
596The finished-file contains the dataset we could import, while the
597pending file contains the dataset that failed, appended by an error
598message.
599
600
601Fixing the Pending File
602-----------------------
603
604We 'edit' the pending file (setting code to ``FAC5`` and title
605appropriately, and removing the --ERROR-- column) and finish the
606import this way:
607
608    >>> open(dc_path + '/newfaculties_zope.mgr.create.pending.csv', 'wb').write(
609    ... """title_prefix,--IGNORE--,code,title
610    ... faculty,,FAC5,Faculty 5
611    ... """)
612
613Step 1: start batch processing:
614
615    >>> browser.open('http://localhost/app/datacenter')
616    >>> browser.getLink('Process data').click()
617    >>> browser.getLink('Switch maintenance mode').click()
618    >>> button = lookup_submit_value(
619    ...   'select', 'newfaculties_zope.mgr.create.pending.csv', browser)
620    >>> button.click()
621
622Step 2: select a processor and mode:
623
624    >>> importerselect = browser.getControl(name='importer')
625    >>> importerselect.getControl('Faculty Processor').selected = True
626    >>> modeselect = browser.getControl(name='mode')
627    >>> modeselect.getControl(value='create').selected = True
628    >>> browser.getControl('Proceed to step 3').click()
629
630Step 3/4: Fix headerlines and import:
631
632As there should be no problem with the headers, we can immediately
633perfom the import:
634
635    >>> browser.getControl('Perform import').click()
636
637This time everything should work:
638
639    >>> print browser.contents
640    <!DOCTYPE html PUBLIC...
641    ...
642    ...Successfully processed 1 rows...
643    ...
644
645Oh no, we forgot Anne Palina. Her user record was not imported because
646she has a non-existent role:
647
648    >>> sorted(os.listdir(dc_path))
649    ['deleted', 'finished', 'graduated', 'logs', 'unfinished', 'users_zope.mgr.create.pending.csv']
650
651    >>> os.listdir(dc_path + '/unfinished')
652    ['users_zope.mgr.csv']
653
654    >>> pending_file = dc_path + '/users_zope.mgr.create.pending.csv'
655    >>> print open(pending_file).read()
656    name,roles,title,public_name,phone,email,--ERRORS--
657    anne,['waeup.Nonsense'],Anne Palina,<IGNORE>,+49-234-567,anne@abc.de,roles: invalid role
658
659There are many finished-files:
660
661    >>> sorted(os.listdir(dc_path + '/finished'))
662    ['certificates_zope.mgr.create.finished.csv', ...,
663    'users_zope.mgr.create.finished.csv']
664
665Processed (finished) Files
666==========================
667
668    >>> browser.open('http://localhost/app/datacenter/processed')
669    >>> 'download?filename=finished/certificates_zope.mgr.create.finished.csv' in browser.contents
670    True
671
672Log Files
673=========
674
675    >>> browser.open('http://localhost/app/datacenter/logs')
676    >>> 'datacenter.log' in browser.contents
677    True
678    >>> browser.getControl('Show', index=0).click()
679    >>> browser.getControl('Back', index=0).click()
680    >>> browser.getControl('Back to Data Center').click()
681    >>> 'Storage path:' in browser.contents
682    True
683
684
685Clean up:
686
687    >>> import shutil
688    >>> shutil.rmtree(dc_path)
Note: See TracBrowser for help on using the repository browser.