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

Last change on this file since 13235 was 12981, checked in by Henrik Bettermann, 9 years ago

Remove quite old bug in doImport: Replace empty strings *and* lists with
ignore-markers in update *and* create mode.

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