source: main/waeup.kofa/trunk/src/waeup/kofa/hostels/tests.py @ 13806

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

Reserve bed so that it cannot be automatically booked by someone else.

  • Property svn:keywords set to Id
File size: 31.3 KB
Line 
1## $Id: tests.py 13533 2015-12-03 20:04:17Z 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##
18"""
19Tests for hostels and their UI components.
20"""
21import os
22import shutil
23import tempfile
24import grok
25import pytz
26from datetime import datetime, timedelta
27from zope.event import notify
28from zope.interface.verify import verifyClass, verifyObject
29from zope.component.hooks import setSite, clearSite
30from zope.testbrowser.testing import Browser
31from zope.security.interfaces import Unauthorized
32from zope.catalog.interfaces import ICatalog
33from zope.component import queryUtility, getUtility
34from waeup.kofa.app import University
35from waeup.kofa.hostels.interfaces import (
36    IHostelsContainer, IHostel, IBed, IHostelsUtils)
37from waeup.kofa.hostels.vocabularies import NOT_OCCUPIED
38from waeup.kofa.hostels.container import HostelsContainer
39from waeup.kofa.hostels.hostel import Hostel, Bed
40from waeup.kofa.hostels.batching import HostelProcessor, BedProcessor
41from waeup.kofa.hostels.export import BedExporter, HostelExporter
42from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase)
43from waeup.kofa.students.student import Student
44from waeup.kofa.students.accommodation import BedTicket
45from waeup.kofa.university.department import Department
46
47HOSTEL_SAMPLE_DATA = open(
48    os.path.join(os.path.dirname(__file__), 'sample_hostel_data.csv'),
49    'rb').read()
50
51HOSTEL_HEADER_FIELDS = HOSTEL_SAMPLE_DATA.split(
52    '\n')[0].split(',')
53
54BED_SAMPLE_DATA = open(
55    os.path.join(os.path.dirname(__file__), 'sample_bed_data.csv'),
56    'rb').read()
57
58BED_HEADER_FIELDS = BED_SAMPLE_DATA.split(
59    '\n')[0].split(',')
60
61class HostelsContainerTestCase(FunctionalTestCase):
62
63    layer = FunctionalLayer
64
65    def test_interfaces(self):
66        # Make sure the correct interfaces are implemented.
67        self.assertTrue(
68            verifyClass(
69                IHostelsContainer, HostelsContainer)
70            )
71        self.assertTrue(
72            verifyObject(
73                IHostelsContainer, HostelsContainer())
74            )
75        self.assertTrue(
76            verifyClass(
77                IHostel, Hostel)
78            )
79        self.assertTrue(
80            verifyObject(
81                IHostel, Hostel())
82            )
83        self.assertTrue(
84            verifyClass(
85                IBed, Bed)
86            )
87        bed = Bed()
88        bed.bed_id = u'a_b_c_d'
89        bed.bed_type = u'a_b_c'
90        self.assertTrue(
91            verifyObject(
92                IBed, bed)
93            )
94        return
95
96    def test_base(self):
97        # We cannot call the fundamental methods of a base in that case
98        container = HostelsContainer()
99        hostel = Hostel()
100        # We cannot add arbitrary objects
101        department = Department()
102        self.assertRaises(
103            TypeError, container.addHostel, department)
104        self.assertRaises(
105            TypeError, hostel.addBed, department)
106        # Application is expired if startdate or enddate are not set
107        # or current datetime is outside application period.
108        self.assertTrue(container.expired)
109        delta = timedelta(days=10)
110        container.startdate = datetime.now(pytz.utc) - delta
111        self.assertTrue(container.expired)
112        container.enddate = datetime.now(pytz.utc) + delta
113        self.assertFalse(container.expired)
114
115class HostelsFullSetup(FunctionalTestCase):
116
117    def setUp(self):
118        super(HostelsFullSetup, self).setUp()
119
120        # Setup a sample site for each test
121        app = University()
122        self.dc_root = tempfile.mkdtemp()
123        app['datacenter'].setStoragePath(self.dc_root)
124
125        # Prepopulate the ZODB...
126        self.getRootFolder()['app'] = app
127        # we add the site immediately after creation to the
128        # ZODB. Catalogs and other local utilities are not setup
129        # before that step.
130        self.app = self.getRootFolder()['app']
131        # Set site here. Some of the following setup code might need
132        # to access grok.getSite() and should get our new app then
133        setSite(app)
134
135        # Add student with subobjects
136        student = Student()
137        student.firstname = u'Anna'
138        student.lastname = u'Tester'
139        student.reg_number = u'123'
140        student.matric_number = u'234'
141        student.sex = u'f'
142        self.app['students'].addStudent(student)
143        self.student_id = student.student_id
144        self.student = self.app['students'][self.student_id]
145        self.student['studycourse'].current_session = 2004
146        self.student['studycourse'].entry_session = 2004
147
148        # The students_catalog must be informed that the
149        # session attribute has changed
150        notify(grok.ObjectModifiedEvent(self.student))
151
152        # Set accommodation_session
153        self.app['hostels'].accommodation_session = 2004
154
155        # Create a hostel
156        hostel = Hostel()
157        hostel.hostel_id = u'hall-x'
158        self.app['hostels'][hostel.hostel_id] = hostel
159
160        # Create a bed
161        bed = Bed()
162        bed.bed_id = u'hall_block_room_bed'
163        bed.bed_number = 1
164        bed.bed_type = u'regular_male_fr'
165        self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed
166
167        self.container_path = 'http://localhost/app/hostels'
168        self.student_path = 'http://localhost/app/students/%s' % self.student_id
169        self.manage_container_path = self.container_path + '/@@manage'
170        self.add_hostel_path = self.container_path + '/addhostel'
171
172        # Put the prepopulated site into test ZODB and prepare test
173        # browser
174        self.browser = Browser()
175        self.browser.handleErrors = False
176
177        self.logfile = os.path.join(
178            self.app['datacenter'].storage, 'logs', 'hostels.log')
179
180    def tearDown(self):
181        super(HostelsFullSetup, self).tearDown()
182        clearSite()
183        shutil.rmtree(self.dc_root)
184
185class HostelsContainerTests(HostelsFullSetup):
186
187    layer = FunctionalLayer
188
189    def test_release_expired_allocations(self):
190        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
191        cat = queryUtility(ICatalog, name='beds_catalog')
192        bedticket = BedTicket()
193        bedticket.booking_session = 2004
194        bedticket.bed_coordinates = u'anything'
195        self.student['accommodation'].addBedTicket(bedticket)
196        self.app[
197            'hostels']['hall-x']['hall_block_room_bed'].owner = self.student_id
198        notify(grok.ObjectModifiedEvent(
199            self.app['hostels']['hall-x']['hall_block_room_bed']))
200        self.assertEqual(
201            self.app['hostels']['hall-x']['hall_block_room_bed'].bed_type,
202            'regular_male_fr')
203        results = cat.searchResults(owner=(self.student_id, self.student_id))
204        self.assertEqual(len(results), 1)
205        self.browser.open(self.container_path + '/releaseexpired')
206        self.assertTrue('Portal must be in maintenance mode for releasing expired bed allocations'
207            in self.browser.contents)
208        grok.getSite()['configuration'].maintmode_enabled_by = u'any_id'
209        self.browser.open(self.container_path + '/releaseexpired')
210        self.assertTrue('No bed released' in self.browser.contents)
211        delta = timedelta(days=10)
212        bedticket.booking_date = datetime.utcnow() - delta
213        self.browser.open(self.container_path + '/releaseexpired')
214        self.assertTrue(
215            'Successfully released beds: hall_block_room_bed (K1000000)'
216            in self.browser.contents)
217        results = cat.searchResults(owner=(self.student_id, self.student_id))
218        self.assertEqual(len(results), 0)
219        self.assertMatches(bedticket.display_coordinates,
220            '-- booking expired (2015-10-14 08:35:38 UTC) --')
221        # The owner has been removed and the bed reserved.
222        self.assertEqual(
223            self.app['hostels']['hall-x']['hall_block_room_bed'].owner,
224            NOT_OCCUPIED)
225        self.assertEqual(
226            self.app['hostels']['hall-x']['hall_block_room_bed'].bed_type,
227            'regular_male_reserved')
228        # Accommodation session can't be changed if hostels are not empty.
229        self.browser.open(self.manage_container_path)
230        self.browser.getControl(name="form.accommodation_session").value = ['2005']
231        self.browser.getControl("Save").click()
232        self.assertTrue(
233            'You can\'t change the booking session before clearing all hostels'
234            in self.browser.contents)
235        # Releasing is logged.
236        logcontent = open(self.logfile).read()
237        self.assertTrue(
238            'hostels.browser.ReleaseExpiredAllocationsPage - hostels - '
239            'released: hall_block_room_bed (K1000000)'
240            in logcontent)
241        return
242
243    def test_bed_statistics(self):
244        utils = getUtility(IHostelsUtils)
245        self.app['hostels']['hall-x'][
246            'hall_block_room_bed'].owner = NOT_OCCUPIED
247        notify(grok.ObjectModifiedEvent(
248            self.app['hostels']['hall-x']['hall_block_room_bed']))
249        stats = utils.getBedStatistics()
250        self.assertEqual(stats,
251            {'regular_male_fr': (0, 1, 1),
252             'regular_female_fi': (0, 0, 0),
253             'regular_male_re': (0, 0, 0),
254             'regular_female_fr': (0, 0, 0),
255             'regular_female_all': (0, 0, 0),
256             'regular_female_re': (0, 0, 0),
257             'regular_female_reserved': (0, 0, 0),
258             'regular_male_reserved': (0, 0, 0),
259             'regular_male_fi': (0, 0, 0),
260             'regular_male_all': (0, 0, 0)}
261             )
262        self.app[
263            'hostels']['hall-x']['hall_block_room_bed'].owner = self.student_id
264        notify(grok.ObjectModifiedEvent(
265            self.app['hostels']['hall-x']['hall_block_room_bed']))
266        stats = utils.getBedStatistics()
267        self.assertEqual(stats,
268            {'regular_male_fr': (1, 0, 1),
269             'regular_female_fi': (0, 0, 0),
270             'regular_male_re': (0, 0, 0),
271             'regular_female_fr': (0, 0, 0),
272             'regular_female_all': (0, 0, 0),
273             'regular_female_re': (0, 0, 0),
274             'regular_female_reserved': (0, 0, 0),
275             'regular_male_reserved': (0, 0, 0),
276             'regular_male_fi': (0, 0, 0),
277             'regular_male_all': (0, 0, 0)}
278             )
279
280class BedCatalogTests(HostelsFullSetup):
281
282    layer = FunctionalLayer
283
284    def test_get_catalog(self):
285        # We can get a beds catalog if we wish
286        cat = queryUtility(ICatalog, name='beds_catalog')
287        assert cat is not None
288
289    def test_search_by_type(self):
290        # We can find a certain bed
291        cat = queryUtility(ICatalog, name='beds_catalog')
292        results = cat.searchResults(
293            bed_type=(u'regular_male_fr', u'regular_male_fr'))
294        results = [x for x in results] # Turn results generator into list
295        assert len(results) == 1
296        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
297
298    def test_search_by_owner(self):
299        # We can find a certain bed
300        myobj = self.app['hostels']['hall-x']['hall_block_room_bed']
301        myobj.owner = u'abc'
302        notify(grok.ObjectModifiedEvent(myobj))
303        cat = queryUtility(ICatalog, name='beds_catalog')
304        results = cat.searchResults(owner=(u'abc', u'abc'))
305        results = [x for x in results] # Turn results generator into list
306        assert len(results) == 1
307        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
308
309class HostelsUITests(HostelsFullSetup):
310
311    layer = FunctionalLayer
312
313    def test_anonymous_access(self):
314        # Anonymous users can't access hostels containers
315        self.assertRaises(
316            Unauthorized, self.browser.open, self.manage_container_path)
317        return
318
319    def test_add_search_edit_delete_manage_hostels(self):
320        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
321        self.browser.open(self.container_path)
322        self.browser.getLink("Manage accommodation").click()
323        self.assertEqual(self.browser.headers['Status'], '200 Ok')
324        self.assertEqual(self.browser.url, self.manage_container_path)
325        self.browser.getControl("Add hostel").click()
326        self.assertEqual(self.browser.headers['Status'], '200 Ok')
327        self.assertEqual(self.browser.url, self.add_hostel_path)
328        self.browser.getControl("Create hostel").click()
329        self.assertEqual(self.browser.headers['Status'], '200 Ok')
330        self.assertTrue('Hostel created' in self.browser.contents)
331        self.browser.open(self.container_path + '/addhostel')
332        self.browser.getControl("Create hostel").click()
333        self.assertTrue('The hostel already exists' in self.browser.contents)
334        hall = self.app['hostels']['hall-1']
335        hall.blocks_for_female = ['A','B']
336        self.browser.open(self.container_path + '/hall-1')
337        expected = '...<ul id="form.blocks_for_female" ><li>Block A</li>...'
338        self.assertMatches(expected,self.browser.contents)
339        self.browser.open(self.container_path + '/hall-1/manage')
340        self.browser.getControl(name="form.rooms_per_floor").value = '1'
341        self.browser.getControl("Save").click()
342        self.assertTrue('Form has been saved' in self.browser.contents)
343        # Since the testbrowser does not support Javascrip the
344        # save action cleared the settings above and we have to set them
345        # again.
346        self.assertTrue(len(hall.blocks_for_female) == 0)
347        hall.blocks_for_female = ['A','B']
348        hall.beds_for_fresh = ['A']
349        hall.beds_for_returning = ['B']
350        hall.beds_for_final = ['C']
351        hall.beds_for_all = ['D','E']
352        self.browser.getControl("Update all beds").click()
353        self.assertTrue('Portal must be in maintenance mode for bed updates'
354            in self.browser.contents)
355        grok.getSite()['configuration'].maintmode_enabled_by = u'any_id'
356        self.browser.getControl("Update all beds").click()
357        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
358        self.assertMatches(expected,self.browser.contents)
359        cat = queryUtility(ICatalog, name='beds_catalog')
360        results = cat.searchResults(
361            bed_type=('regular_female_all', 'regular_female_all'))
362        results = [(x.bed_id, x.bed_type) for x in results]
363        self.assertEqual(results,
364            [(u'hall-1_A_101_D', u'regular_female_all'),
365             (u'hall-1_A_101_E', u'regular_female_all'),
366             (u'hall-1_B_101_D', u'regular_female_all'),
367             (u'hall-1_B_101_E', u'regular_female_all')])
368        # Reserve beds.
369        self.browser.getControl("Switch reservation", index=0).click()
370        self.assertTrue('No item selected' in self.browser.contents)
371        ctrl = self.browser.getControl(name='val_id')
372        ctrl.getControl(value='hall-1_A_101_A').selected = True
373        ctrl.getControl(value='hall-1_A_101_B').selected = True
374        ctrl.getControl(value='hall-1_A_101_C').selected = True
375        ctrl.getControl(value='hall-1_A_101_D').selected = True
376        self.browser.getControl("Switch reservation", index=0).click()
377        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
378            in self.browser.contents)
379        self.assertEqual(self.app['hostels']['hall-1'][
380            'hall-1_A_101_D'].bed_type, 'regular_female_reserved')
381        # The catalog has been updated.
382        results = cat.searchResults(
383            bed_type=('regular_female_all', 'regular_female_all'))
384        results = [(x.bed_id, x.bed_type) for x in results]
385        self.assertEqual(results,
386            [(u'hall-1_A_101_E', u'regular_female_all'),
387             (u'hall-1_B_101_D', u'regular_female_all'),
388             (u'hall-1_B_101_E', u'regular_female_all')])
389        results = cat.searchResults(
390            bed_type=('regular_female_reserved', 'regular_female_reserved'))
391        results = [(x.bed_id, x.bed_type) for x in results]
392        self.assertEqual(results,
393            [(u'hall-1_A_101_A', u'regular_female_reserved'),
394             (u'hall-1_A_101_B', u'regular_female_reserved'),
395             (u'hall-1_A_101_C', u'regular_female_reserved'),
396             (u'hall-1_A_101_D', u'regular_female_reserved')])
397        # Change hostel configuration with one bed booked.
398        hall['hall-1_A_101_E'].owner = u'anyid'
399        notify(grok.ObjectModifiedEvent(hall['hall-1_A_101_E']))
400        hall.beds_for_fresh = ['A', 'E']
401        hall.beds_for_all = ['D']
402        self.browser.getControl("Update all beds").click()
403        expected = '...9 empty beds removed, 9 beds added, 1 occupied beds modified...'
404        self.assertMatches(expected,self.browser.contents)
405        # Updating beds (including booked beds!) does update catalog.
406        results = cat.searchResults(
407            bed_type=('regular_female_all', 'regular_female_all'))
408        results = [(x.bed_id, x.bed_type) for x in results]
409        # The reservation of hall-1_A_101_D has been cancelled.
410        self.assertEqual(results,
411            [(u'hall-1_A_101_D', u'regular_female_all'),
412             (u'hall-1_B_101_D', u'regular_female_all')])
413        # Release bed which has previously been booked.
414        bedticket = BedTicket()
415        bedticket.booking_session = 2004
416        bedticket.bed_coordinates = u'anything'
417        self.student['accommodation'].addBedTicket(bedticket)
418        self.app['hostels']['hall-1']['hall-1_A_101_D'].owner = self.student_id
419        notify(grok.ObjectModifiedEvent(self.app['hostels']['hall-1']['hall-1_A_101_D']))
420        self.browser.open(self.container_path + '/hall-1/manage')
421        ctrl = self.browser.getControl(name='val_id')
422        self.browser.getControl("Release selected beds", index=0).click()
423        self.assertMatches("...No item selected...", self.browser.contents)
424        ctrl = self.browser.getControl(name='val_id')
425        ctrl.getControl(value='hall-1_A_101_D').selected = True
426        self.browser.getControl("Release selected beds", index=0).click()
427        self.assertMatches(
428          '...Successfully released beds: hall-1_A_101_D (%s)...' % self.student_id,
429          self.browser.contents)
430        self.assertMatches(bedticket.bed_coordinates,
431          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> UTC --')
432        # The catalog has been updated.
433        results = cat.searchResults(owner=(self.student_id, self.student_id))
434        assert len(results) == 0
435        # If we release a free bed, nothing will happen.
436        ctrl = self.browser.getControl(name='val_id')
437        ctrl.getControl(value='hall-1_A_101_D').selected = True
438        self.browser.getControl("Release selected beds", index=0).click()
439        self.assertMatches(
440          '...No allocated bed selected...', self.browser.contents)
441        # Managers can manually allocate eligible students after cancellation.
442        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
443        # 'not occupied' is not accepted.
444        self.browser.getControl("Save").click()
445        self.assertMatches(
446            "...No valid student id...",
447            self.browser.contents)
448        # Invalid student ids are not accepted.
449        self.browser.getControl(name="form.owner").value = 'nonsense'
450        self.browser.getControl("Save").click()
451        self.assertMatches(
452            "...Either student does not exist or student "
453            "is not in accommodation session...",
454            self.browser.contents)
455        self.browser.getControl(name="form.owner").value = self.student_id
456        self.browser.getControl("Save").click()
457        self.assertMatches("...Form has been saved...", self.browser.contents)
458        # Students can only be allocated once.
459        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_B')
460        self.browser.getControl(name="form.owner").value = self.student_id
461        self.browser.getControl("Save").click()
462        self.assertMatches(
463            "...This student resides in bed hall-1_A_101_A...",
464            self.browser.contents)
465        # If we open the same form again, we will be redirected to hostel
466        # manage page. Beds must be released first before they can be
467        # allocated to other students.
468        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
469        self.assertEqual(self.browser.url,
470            self.container_path + '/hall-1/@@manage#tab2')
471        # Updating the beds again will not affect the allocation and also
472        # the bed numbering remains the same.
473        old_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
474        old_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
475        self.browser.getControl("Update all beds").click()
476        # 8 beds have been removed and re-added, 2 beds remains untouched
477        # because they are occupied.
478        expected = '...8 empty beds removed, 8 beds added, 0 occupied beds modified...'
479        self.assertMatches(expected,self.browser.contents)
480        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
481        new_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
482        self.assertEqual(new_number, old_number)
483        self.assertEqual(new_owner, old_owner)
484        # If we change the bed type of an allocated bed, the modification will
485        # be indicated.
486        hall.blocks_for_female = ['B']
487        hall.blocks_for_male = ['A']
488        self.browser.getControl("Update all beds").click()
489        expected = '...8 empty beds removed, 8 beds added, ' + \
490            '2 occupied beds modified (hall-1_A_101_A, hall-1_A_101_E, )...'
491        self.assertMatches(expected,self.browser.contents)
492        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
493        # Also the number of the bed has changed.
494        self.assertFalse(new_number == old_number)
495        # The number of occupied beds are displayed on container page.
496        self.browser.open(self.container_path)
497        self.assertTrue('2 of 10' in self.browser.contents)
498        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
499        # Managers can open the bed statistics page
500        self.browser.getLink("Bed statistics").click()
501        self.assertTrue('Bed Statistics</h1>' in self.browser.contents)
502        # Remove entire hostel.
503        self.browser.open(self.manage_container_path)
504        ctrl = self.browser.getControl(name='val_id')
505        value = ctrl.options[0]
506        ctrl.getControl(value=value).selected = True
507        self.browser.getControl("Remove selected", index=0).click()
508        self.assertTrue('Successfully removed' in self.browser.contents)
509        # Catalog is empty.
510        results = cat.searchResults(
511            bed_type=('regular_female_all', 'regular_female_all'))
512        results = [x for x in results]
513        assert len(results) == 0
514        # Bed has been removed from bedticket
515        self.assertEqual(bedticket.bed, None)
516        # Actions are logged.
517        logcontent = open(self.logfile).read()
518        self.assertTrue(
519            'hall-1 - 9 empty beds removed, 9 beds added, 1 occupied '
520            'beds modified (hall-1_A_101_E, )'
521            in logcontent)
522
523    def test_clear_hostels(self):
524        grok.getSite()['configuration'].maintmode_enabled_by = u'any_id'
525        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
526        self.browser.open(self.container_path)
527        self.browser.getLink("Manage accommodation").click()
528        self.browser.getControl("Add hostel").click()
529        self.browser.getControl("Create hostel").click()
530        hall = self.app['hostels']['hall-1']
531        hall.blocks_for_female = ['A','B']
532        hall.rooms_per_floor = 1
533        hall.beds_for_fresh = ['A']
534        hall.beds_for_returning = ['B']
535        hall.beds_for_final = ['C']
536        hall.beds_for_all = ['D','E']
537        self.browser.open(self.container_path + '/hall-1/manage')
538        self.browser.getControl("Update all beds").click()
539        cat = queryUtility(ICatalog, name='beds_catalog')
540        results = cat.searchResults(bed_type=(None, None))
541        self.assertEqual(len(results), 11)
542        self.browser.getControl("Clear hostel").click()
543        self.assertEqual(len(self.app['hostels']['hall-1']), 0)
544        # Only the bed in hall-x remains in the catalog.
545        results = cat.searchResults(bed_type=(None, None))
546        self.assertEqual(len(results), 1)
547        # We can clear all hostels at the same time.
548        self.browser.open(self.manage_container_path)
549        self.browser.getControl("Clear all hostels").click()
550        results = cat.searchResults(bed_type=(None, None))
551        self.assertEqual(len(results), 0)
552        # Both actions have been logged.
553        logcontent = open(self.logfile).read()
554        self.assertTrue('INFO - zope.mgr - hostels.browser.HostelManageFormPage'
555                        ' - hall-1 - cleared' in logcontent)
556        self.assertTrue('zope.mgr - hostels.browser.HostelsContainerManagePage'
557                        ' - hostels - all hostels cleared' in logcontent)
558
559class ExportTests(HostelsFullSetup):
560
561    layer = FunctionalLayer
562
563    def setUp(self):
564        super(ExportTests, self).setUp()
565        self.workdir = tempfile.mkdtemp()
566        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
567        return
568
569    def test_export_hostels(self):
570        exporter = HostelExporter()
571        exporter.export_all(self.app, self.outfile)
572        result = open(self.outfile, 'rb').read()
573        self.assertEqual(
574            result,
575            'beds_for_all,beds_for_final,beds_for_fresh,beds_for_pre,'
576            'beds_for_returning,blocks_for_female,'
577            'blocks_for_male,floors_per_block,hostel_id,hostel_name,maint_fee,'
578            'rooms_per_floor,sort_id,special_handling\r\n[],[],[],[],[],[],[],'
579            '1,hall-x,Hall 1,0.0,2,10,regular\r\n'
580            )
581        return
582
583    def test_export_beds(self):
584        exporter = BedExporter()
585        exporter.export_all(self.app, self.outfile)
586        result = open(self.outfile, 'rb').read()
587        self.assertEqual(
588            result,
589            'bed_id,bed_number,bed_type,owner,hall,block,room,bed,'
590            'special_handling,sex,bt\r\nhall_block_room_bed,1,regular_male_fr,,'
591            'hall,block,room,bed,regular,male,fr\r\n'
592            )
593        return
594
595    def tearDown(self):
596        super(ExportTests, self).tearDown()
597        clearSite()
598        shutil.rmtree(os.path.dirname(self.outfile))
599
600class HostelBedProcessorTest(HostelsFullSetup):
601
602    layer = FunctionalLayer
603
604    def test_import(self):
605        self.processor = HostelProcessor()
606        self.workdir = tempfile.mkdtemp()
607        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
608        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
609        num, num_warns, fin_file, fail_file = self.processor.doImport(
610            self.csv_file, HOSTEL_HEADER_FIELDS)
611        self.assertEqual(num_warns,0)
612        self.assertEqual(len(self.app['hostels'].keys()), 11) # including hall-x
613        self.assertEqual(self.app['hostels'][
614            'block-a-upper-hostel'].hostel_id,'block-a-upper-hostel')
615        self.assertEqual(self.app['hostels'][
616            'block-a-upper-hostel'].beds_for_final, ['A', 'B'])
617        logcontent = open(self.logfile).read()
618        self.assertTrue(
619            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
620            "updated: "
621            "beds_for_pre=['G'], floors_per_block=1, "
622            "special_handling=regular, "
623            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
624            "hostel_id=block-a-upper-hostel, "
625            "sort_id=20, beds_for_returning=['C', 'D'], "
626            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
627            "blocks_for_female=['A']"
628            in logcontent)
629        shutil.rmtree(os.path.dirname(fin_file))
630        shutil.rmtree(self.workdir)
631        # The manage page can be opened.
632        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
633        self.browser.open(self.container_path + '/block-a-upper-hostel')
634        self.browser.getLink("Manage").click()
635        self.assertEqual(self.browser.headers['Status'], '200 Ok')
636        return
637
638    def test_import_update_hostel_and_beds(self):
639        self.processor = HostelProcessor()
640        self.workdir = tempfile.mkdtemp()
641        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
642        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
643        num, num_warns, fin_file, fail_file = self.processor.doImport(
644            self.csv_file, HOSTEL_HEADER_FIELDS)
645        # We import the same file in update mode
646        num, num_warns, fin_file, fail_file = self.processor.doImport(
647            self.csv_file, HOSTEL_HEADER_FIELDS, 'update')
648        self.assertEqual(num_warns,0)
649        logcontent = open(self.logfile).read()
650        self.assertTrue(
651            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
652            "updated: "
653            "beds_for_pre=['G'], floors_per_block=1, "
654            "special_handling=regular, "
655            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
656            "hostel_id=block-a-upper-hostel, "
657            "sort_id=20, beds_for_returning=['C', 'D'], "
658            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
659            "blocks_for_female=['A']"
660            in logcontent)
661        # Update the beds of first hostel
662        self.app['hostels']['block-a-upper-hostel'].updateBeds()
663        # Import beds
664        self.processor = BedProcessor()
665        self.csv_file = os.path.join(self.workdir, 'sample_bed_data.csv')
666        open(self.csv_file, 'wb').write(BED_SAMPLE_DATA)
667        num, num_warns, fin_file, fail_file = self.processor.doImport(
668            self.csv_file, BED_HEADER_FIELDS, 'update')
669        self.assertEqual(num_warns,2)
670        fail_file_content = open(fail_file).read()
671        logcontent = open(self.logfile).read()
672        self.assertEqual(
673            'owner,bed_id,hostel_id,reserved,--ERRORS--\r\n'
674            '<IGNORE>,block-a-upper-hostel_A_101_C,block-a-upper-hostel,2,'
675            'reserved: invalid value\r\n'
676            'K999,block-a-upper-hostel_A_101_E,block-a-upper-hostel,0,'
677            'owner: student does not exist\r\n',
678            fail_file_content)
679        self.assertTrue(
680            'system - Bed Processor (update only) - sample_bed_data - '
681            'block-a-upper-hostel_A_101_A - updated: nothing'
682            in logcontent)
683        self.assertTrue(
684            'system - Bed Processor (update only) - sample_bed_data - '
685            'block-a-upper-hostel_A_101_B - updated: reserved'
686            in logcontent)
687        self.assertTrue(
688            'system - Bed Processor (update only) - sample_bed_data - '
689            'block-a-upper-hostel_A_101_D - updated: owner=K1000000'
690            in logcontent)
691        self.assertEqual(
692            self.app['hostels']['block-a-upper-hostel']
693                    ['block-a-upper-hostel_A_101_D'].owner, 'K1000000')
694        self.assertEqual(
695            self.app['hostels']['block-a-upper-hostel']
696                    ['block-a-upper-hostel_A_101_B'].bed_type,
697                    'regular_female_reserved')
698        shutil.rmtree(os.path.dirname(fin_file))
699        shutil.rmtree(self.workdir)
700        return
Note: See TracBrowser for help on using the repository browser.