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

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

Implement portal maintenance mode.

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