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

Last change on this file since 15250 was 15250, checked in by Henrik Bettermann, 6 years ago

Add ReleaseExpiredAllocationsActionButton? which has previously only been used by Uniben.

  • Property svn:keywords set to Id
File size: 31.3 KB
Line 
1## $Id: tests.py 15250 2018-11-23 11:10:19Z 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.app['hostels'].allocation_expiration = 7
191        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
192        cat = queryUtility(ICatalog, name='beds_catalog')
193        bedticket = BedTicket()
194        bedticket.booking_session = 2004
195        bedticket.bed_coordinates = u'anything'
196        self.student['accommodation'].addBedTicket(bedticket)
197        self.app[
198            'hostels']['hall-x']['hall_block_room_bed'].owner = self.student_id
199        notify(grok.ObjectModifiedEvent(
200            self.app['hostels']['hall-x']['hall_block_room_bed']))
201        self.assertEqual(
202            self.app['hostels']['hall-x']['hall_block_room_bed'].bed_type,
203            'regular_male_fr')
204        results = cat.searchResults(owner=(self.student_id, self.student_id))
205        self.assertEqual(len(results), 1)
206        self.browser.open(self.container_path + '/releaseexpired')
207        self.assertTrue('Portal must be in maintenance mode for releasing expired bed allocations'
208            in self.browser.contents)
209        grok.getSite()['configuration'].maintmode_enabled_by = u'any_id'
210        self.browser.open(self.container_path + '/releaseexpired')
211        self.assertTrue('No bed released' in self.browser.contents)
212        delta = timedelta(days=10)
213        bedticket.booking_date = datetime.utcnow() - delta
214        self.browser.open(self.container_path + '/releaseexpired')
215        self.assertTrue(
216            'Successfully released beds: hall_block_room_bed (K1000000)'
217            in self.browser.contents)
218        results = cat.searchResults(owner=(self.student_id, self.student_id))
219        self.assertEqual(len(results), 0)
220        self.assertMatches(bedticket.display_coordinates,
221            '-- booking expired (2015-10-14 08:35:38 UTC) --')
222        # The owner has been removed and the bed reserved.
223        self.assertEqual(
224            self.app['hostels']['hall-x']['hall_block_room_bed'].owner,
225            NOT_OCCUPIED)
226        self.assertEqual(
227            self.app['hostels']['hall-x']['hall_block_room_bed'].bed_type,
228            'regular_male_reserved')
229        # Accommodation session can't be changed if hostels are not empty.
230        self.browser.open(self.manage_container_path)
231        self.browser.getControl(name="form.accommodation_session").value = ['2005']
232        self.browser.getControl("Save").click()
233        self.assertTrue(
234            'You can\'t change the booking session before clearing all hostels'
235            in self.browser.contents)
236        # Releasing is logged.
237        logcontent = open(self.logfile).read()
238        self.assertTrue(
239            'hostels.browser.ReleaseExpiredAllocationsPage - hostels - '
240            'released: hall_block_room_bed (K1000000)'
241            in logcontent)
242        return
243
244    def test_bed_statistics(self):
245        utils = getUtility(IHostelsUtils)
246        self.app['hostels']['hall-x'][
247            'hall_block_room_bed'].owner = NOT_OCCUPIED
248        notify(grok.ObjectModifiedEvent(
249            self.app['hostels']['hall-x']['hall_block_room_bed']))
250        stats = utils.getBedStatistics()
251        self.assertEqual(stats,
252            {'regular_male_fr': (0, 1, 1),
253             'regular_female_fi': (0, 0, 0),
254             'regular_male_re': (0, 0, 0),
255             'regular_female_fr': (0, 0, 0),
256             'regular_female_all': (0, 0, 0),
257             'regular_female_re': (0, 0, 0),
258             'regular_female_reserved': (0, 0, 0),
259             'regular_male_reserved': (0, 0, 0),
260             'regular_male_fi': (0, 0, 0),
261             'regular_male_all': (0, 0, 0)}
262             )
263        self.app[
264            'hostels']['hall-x']['hall_block_room_bed'].owner = self.student_id
265        notify(grok.ObjectModifiedEvent(
266            self.app['hostels']['hall-x']['hall_block_room_bed']))
267        stats = utils.getBedStatistics()
268        self.assertEqual(stats,
269            {'regular_male_fr': (1, 0, 1),
270             'regular_female_fi': (0, 0, 0),
271             'regular_male_re': (0, 0, 0),
272             'regular_female_fr': (0, 0, 0),
273             'regular_female_all': (0, 0, 0),
274             'regular_female_re': (0, 0, 0),
275             'regular_female_reserved': (0, 0, 0),
276             'regular_male_reserved': (0, 0, 0),
277             'regular_male_fi': (0, 0, 0),
278             'regular_male_all': (0, 0, 0)}
279             )
280
281class BedCatalogTests(HostelsFullSetup):
282
283    layer = FunctionalLayer
284
285    def test_get_catalog(self):
286        # We can get a beds catalog if we wish
287        cat = queryUtility(ICatalog, name='beds_catalog')
288        assert cat is not None
289
290    def test_search_by_type(self):
291        # We can find a certain bed
292        cat = queryUtility(ICatalog, name='beds_catalog')
293        results = cat.searchResults(
294            bed_type=(u'regular_male_fr', u'regular_male_fr'))
295        results = [x for x in results] # Turn results generator into list
296        assert len(results) == 1
297        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
298
299    def test_search_by_owner(self):
300        # We can find a certain bed
301        myobj = self.app['hostels']['hall-x']['hall_block_room_bed']
302        myobj.owner = u'abc'
303        notify(grok.ObjectModifiedEvent(myobj))
304        cat = queryUtility(ICatalog, name='beds_catalog')
305        results = cat.searchResults(owner=(u'abc', u'abc'))
306        results = [x for x in results] # Turn results generator into list
307        assert len(results) == 1
308        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
309
310class HostelsUITests(HostelsFullSetup):
311
312    layer = FunctionalLayer
313
314    def test_anonymous_access(self):
315        # Anonymous users can't access hostels containers
316        self.assertRaises(
317            Unauthorized, self.browser.open, self.manage_container_path)
318        return
319
320    def test_add_search_edit_delete_manage_hostels(self):
321        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
322        self.browser.open(self.container_path)
323        self.browser.getLink("Manage accommodation").click()
324        self.assertEqual(self.browser.headers['Status'], '200 Ok')
325        self.assertEqual(self.browser.url, self.manage_container_path)
326        self.browser.getControl("Add hostel").click()
327        self.assertEqual(self.browser.headers['Status'], '200 Ok')
328        self.assertEqual(self.browser.url, self.add_hostel_path)
329        self.browser.getControl("Create hostel").click()
330        self.assertEqual(self.browser.headers['Status'], '200 Ok')
331        self.assertTrue('Hostel created' in self.browser.contents)
332        self.browser.open(self.container_path + '/addhostel')
333        self.browser.getControl("Create hostel").click()
334        self.assertTrue('The hostel already exists' in self.browser.contents)
335        hall = self.app['hostels']['hall-1']
336        hall.blocks_for_female = ['A','B']
337        self.browser.open(self.container_path + '/hall-1')
338        expected = '...<ul id="form.blocks_for_female" ><li>Block A</li>...'
339        self.assertMatches(expected,self.browser.contents)
340        self.browser.open(self.container_path + '/hall-1/manage')
341        self.browser.getControl(name="form.rooms_per_floor").value = '1'
342        self.browser.getControl("Save").click()
343        self.assertTrue('Form has been saved' in self.browser.contents)
344        # Since the testbrowser does not support Javascrip the
345        # save action cleared the settings above and we have to set them
346        # again.
347        self.assertTrue(len(hall.blocks_for_female) == 0)
348        hall.blocks_for_female = ['A','B']
349        hall.beds_for_fresh = ['A']
350        hall.beds_for_returning = ['B']
351        hall.beds_for_final = ['C']
352        hall.beds_for_all = ['D','E']
353        self.browser.getControl("Update all beds").click()
354        self.assertTrue('Portal must be in maintenance mode for bed updates'
355            in self.browser.contents)
356        grok.getSite()['configuration'].maintmode_enabled_by = u'any_id'
357        self.browser.getControl("Update all beds").click()
358        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
359        self.assertMatches(expected,self.browser.contents)
360        cat = queryUtility(ICatalog, name='beds_catalog')
361        results = cat.searchResults(
362            bed_type=('regular_female_all', 'regular_female_all'))
363        results = [(x.bed_id, x.bed_type) for x in results]
364        self.assertEqual(results,
365            [(u'hall-1_A_101_D', u'regular_female_all'),
366             (u'hall-1_A_101_E', u'regular_female_all'),
367             (u'hall-1_B_101_D', u'regular_female_all'),
368             (u'hall-1_B_101_E', u'regular_female_all')])
369        # Reserve beds.
370        self.browser.getControl("Switch reservation", index=0).click()
371        self.assertTrue('No item selected' in self.browser.contents)
372        ctrl = self.browser.getControl(name='val_id')
373        ctrl.getControl(value='hall-1_A_101_A').selected = True
374        ctrl.getControl(value='hall-1_A_101_B').selected = True
375        ctrl.getControl(value='hall-1_A_101_C').selected = True
376        ctrl.getControl(value='hall-1_A_101_D').selected = True
377        self.browser.getControl("Switch reservation", index=0).click()
378        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
379            in self.browser.contents)
380        self.assertEqual(self.app['hostels']['hall-1'][
381            'hall-1_A_101_D'].bed_type, 'regular_female_reserved')
382        # The catalog has been updated.
383        results = cat.searchResults(
384            bed_type=('regular_female_all', 'regular_female_all'))
385        results = [(x.bed_id, x.bed_type) for x in results]
386        self.assertEqual(results,
387            [(u'hall-1_A_101_E', u'regular_female_all'),
388             (u'hall-1_B_101_D', u'regular_female_all'),
389             (u'hall-1_B_101_E', u'regular_female_all')])
390        results = cat.searchResults(
391            bed_type=('regular_female_reserved', 'regular_female_reserved'))
392        results = [(x.bed_id, x.bed_type) for x in results]
393        self.assertEqual(results,
394            [(u'hall-1_A_101_A', u'regular_female_reserved'),
395             (u'hall-1_A_101_B', u'regular_female_reserved'),
396             (u'hall-1_A_101_C', u'regular_female_reserved'),
397             (u'hall-1_A_101_D', u'regular_female_reserved')])
398        # Change hostel configuration with one bed booked.
399        hall['hall-1_A_101_E'].owner = u'anyid'
400        notify(grok.ObjectModifiedEvent(hall['hall-1_A_101_E']))
401        hall.beds_for_fresh = ['A', 'E']
402        hall.beds_for_all = ['D']
403        self.browser.getControl("Update all beds").click()
404        expected = '...9 empty beds removed, 9 beds added, 1 occupied beds modified...'
405        self.assertMatches(expected,self.browser.contents)
406        # Updating beds (including booked beds!) does update catalog.
407        results = cat.searchResults(
408            bed_type=('regular_female_all', 'regular_female_all'))
409        results = [(x.bed_id, x.bed_type) for x in results]
410        # The reservation of hall-1_A_101_D has been cancelled.
411        self.assertEqual(results,
412            [(u'hall-1_A_101_D', u'regular_female_all'),
413             (u'hall-1_B_101_D', u'regular_female_all')])
414        # Release bed which has previously been booked.
415        bedticket = BedTicket()
416        bedticket.booking_session = 2004
417        bedticket.bed_coordinates = u'anything'
418        self.student['accommodation'].addBedTicket(bedticket)
419        self.app['hostels']['hall-1']['hall-1_A_101_D'].owner = self.student_id
420        notify(grok.ObjectModifiedEvent(self.app['hostels']['hall-1']['hall-1_A_101_D']))
421        self.browser.open(self.container_path + '/hall-1/manage')
422        ctrl = self.browser.getControl(name='val_id')
423        self.browser.getControl("Release selected beds", index=0).click()
424        self.assertMatches("...No item selected...", self.browser.contents)
425        ctrl = self.browser.getControl(name='val_id')
426        ctrl.getControl(value='hall-1_A_101_D').selected = True
427        self.browser.getControl("Release selected beds", index=0).click()
428        self.assertMatches(
429          '...Successfully released beds: hall-1_A_101_D (%s)...' % self.student_id,
430          self.browser.contents)
431        self.assertMatches(bedticket.bed_coordinates,
432          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> UTC --')
433        # The catalog has been updated.
434        results = cat.searchResults(owner=(self.student_id, self.student_id))
435        assert len(results) == 0
436        # If we release a free bed, nothing will happen.
437        ctrl = self.browser.getControl(name='val_id')
438        ctrl.getControl(value='hall-1_A_101_D').selected = True
439        self.browser.getControl("Release selected beds", index=0).click()
440        self.assertMatches(
441          '...No allocated bed selected...', self.browser.contents)
442        # Managers can manually allocate eligible students after cancellation.
443        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
444        # 'not occupied' is not accepted.
445        self.browser.getControl("Save").click()
446        self.assertMatches(
447            "...No valid student id...",
448            self.browser.contents)
449        # Invalid student ids are not accepted.
450        self.browser.getControl(name="form.owner").value = 'nonsense'
451        self.browser.getControl("Save").click()
452        self.assertMatches(
453            "...Either student does not exist or student "
454            "is not in accommodation session...",
455            self.browser.contents)
456        self.browser.getControl(name="form.owner").value = self.student_id
457        self.browser.getControl("Save").click()
458        self.assertMatches("...Form has been saved...", self.browser.contents)
459        # Students can only be allocated once.
460        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_B')
461        self.browser.getControl(name="form.owner").value = self.student_id
462        self.browser.getControl("Save").click()
463        self.assertMatches(
464            "...This student resides in bed hall-1_A_101_A...",
465            self.browser.contents)
466        # If we open the same form again, we will be redirected to hostel
467        # manage page. Beds must be released first before they can be
468        # allocated to other students.
469        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
470        self.assertEqual(self.browser.url,
471            self.container_path + '/hall-1/@@manage#tab2')
472        # Updating the beds again will not affect the allocation and also
473        # the bed numbering remains the same.
474        old_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
475        old_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
476        self.browser.getControl("Update all beds").click()
477        # 8 beds have been removed and re-added, 2 beds remains untouched
478        # because they are occupied.
479        expected = '...8 empty beds removed, 8 beds added, 0 occupied beds modified...'
480        self.assertMatches(expected,self.browser.contents)
481        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
482        new_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
483        self.assertEqual(new_number, old_number)
484        self.assertEqual(new_owner, old_owner)
485        # If we change the bed type of an allocated bed, the modification will
486        # be indicated.
487        hall.blocks_for_female = ['B']
488        hall.blocks_for_male = ['A']
489        self.browser.getControl("Update all beds").click()
490        expected = '...8 empty beds removed, 8 beds added, ' + \
491            '2 occupied beds modified (hall-1_A_101_A, hall-1_A_101_E, )...'
492        self.assertMatches(expected,self.browser.contents)
493        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
494        # Also the number of the bed has changed.
495        self.assertFalse(new_number == old_number)
496        # The number of occupied beds are displayed on container page.
497        self.browser.open(self.container_path)
498        self.assertTrue('2 of 10' in self.browser.contents)
499        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
500        # Managers can open the bed statistics page
501        self.browser.getLink("Bed statistics").click()
502        self.assertTrue('Bed Statistics</h1>' in self.browser.contents)
503        # Remove entire hostel.
504        self.browser.open(self.manage_container_path)
505        ctrl = self.browser.getControl(name='val_id')
506        value = ctrl.options[0]
507        ctrl.getControl(value=value).selected = True
508        self.browser.getControl("Remove selected", index=0).click()
509        self.assertTrue('Successfully removed' in self.browser.contents)
510        # Catalog is empty.
511        results = cat.searchResults(
512            bed_type=('regular_female_all', 'regular_female_all'))
513        results = [x for x in results]
514        assert len(results) == 0
515        # Bed has been removed from bedticket
516        self.assertEqual(bedticket.bed, None)
517        # Actions are logged.
518        logcontent = open(self.logfile).read()
519        self.assertTrue(
520            'hall-1 - 9 empty beds removed, 9 beds added, 1 occupied '
521            'beds modified (hall-1_A_101_E, )'
522            in logcontent)
523
524    def test_clear_hostels(self):
525        grok.getSite()['configuration'].maintmode_enabled_by = u'any_id'
526        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
527        self.browser.open(self.container_path)
528        self.browser.getLink("Manage accommodation").click()
529        self.browser.getControl("Add hostel").click()
530        self.browser.getControl("Create hostel").click()
531        hall = self.app['hostels']['hall-1']
532        hall.blocks_for_female = ['A','B']
533        hall.rooms_per_floor = 1
534        hall.beds_for_fresh = ['A']
535        hall.beds_for_returning = ['B']
536        hall.beds_for_final = ['C']
537        hall.beds_for_all = ['D','E']
538        self.browser.open(self.container_path + '/hall-1/manage')
539        self.browser.getControl("Update all beds").click()
540        cat = queryUtility(ICatalog, name='beds_catalog')
541        results = cat.searchResults(bed_type=(None, None))
542        self.assertEqual(len(results), 11)
543        self.browser.getControl("Clear hostel").click()
544        self.assertEqual(len(self.app['hostels']['hall-1']), 0)
545        # Only the bed in hall-x remains in the catalog.
546        results = cat.searchResults(bed_type=(None, None))
547        self.assertEqual(len(results), 1)
548        # We can clear all hostels at the same time.
549        self.browser.open(self.manage_container_path)
550        self.browser.getControl("Clear all hostels").click()
551        results = cat.searchResults(bed_type=(None, None))
552        self.assertEqual(len(results), 0)
553        # Both actions have been logged.
554        logcontent = open(self.logfile).read()
555        self.assertTrue('INFO - zope.mgr - hostels.browser.HostelManageFormPage'
556                        ' - hall-1 - cleared' in logcontent)
557        self.assertTrue('zope.mgr - hostels.browser.HostelsContainerManagePage'
558                        ' - hostels - all hostels cleared' in logcontent)
559
560class ExportTests(HostelsFullSetup):
561
562    layer = FunctionalLayer
563
564    def setUp(self):
565        super(ExportTests, self).setUp()
566        self.workdir = tempfile.mkdtemp()
567        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
568        return
569
570    def test_export_hostels(self):
571        exporter = HostelExporter()
572        exporter.export_all(self.app, self.outfile)
573        result = open(self.outfile, 'rb').read()
574        self.assertEqual(
575            result,
576            'beds_for_all,beds_for_final,beds_for_fresh,beds_for_pre,'
577            'beds_for_returning,blocks_for_female,'
578            'blocks_for_male,floors_per_block,hostel_id,hostel_name,maint_fee,'
579            'rooms_per_floor,sort_id,special_handling\r\n[],[],[],[],[],[],[],'
580            '1,hall-x,Hall 1,0.0,2,10,regular\r\n'
581            )
582        return
583
584    def test_export_beds(self):
585        exporter = BedExporter()
586        exporter.export_all(self.app, self.outfile)
587        result = open(self.outfile, 'rb').read()
588        self.assertEqual(
589            result,
590            'bed_id,bed_number,bed_type,owner,hall,block,room,bed,'
591            'special_handling,sex,bt\r\nhall_block_room_bed,1,regular_male_fr,,'
592            'hall,block,room,bed,regular,male,fr\r\n'
593            )
594        return
595
596    def tearDown(self):
597        super(ExportTests, self).tearDown()
598        clearSite()
599        shutil.rmtree(os.path.dirname(self.outfile))
600
601class HostelBedProcessorTest(HostelsFullSetup):
602
603    layer = FunctionalLayer
604
605    def test_import(self):
606        self.processor = HostelProcessor()
607        self.workdir = tempfile.mkdtemp()
608        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
609        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
610        num, num_warns, fin_file, fail_file = self.processor.doImport(
611            self.csv_file, HOSTEL_HEADER_FIELDS)
612        self.assertEqual(num_warns,0)
613        self.assertEqual(len(self.app['hostels'].keys()), 11) # including hall-x
614        self.assertEqual(self.app['hostels'][
615            'block-a-upper-hostel'].hostel_id,'block-a-upper-hostel')
616        self.assertEqual(self.app['hostels'][
617            'block-a-upper-hostel'].beds_for_final, ['A', 'B'])
618        logcontent = open(self.logfile).read()
619        self.assertTrue(
620            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
621            "updated: "
622            "beds_for_pre=['G'], floors_per_block=1, "
623            "special_handling=regular, "
624            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
625            "hostel_id=block-a-upper-hostel, "
626            "sort_id=20, beds_for_returning=['C', 'D'], "
627            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
628            "blocks_for_female=['A']"
629            in logcontent)
630        shutil.rmtree(os.path.dirname(fin_file))
631        shutil.rmtree(self.workdir)
632        # The manage page can be opened.
633        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
634        self.browser.open(self.container_path + '/block-a-upper-hostel')
635        self.browser.getLink("Manage").click()
636        self.assertEqual(self.browser.headers['Status'], '200 Ok')
637        return
638
639    def test_import_update_hostel_and_beds(self):
640        self.processor = HostelProcessor()
641        self.workdir = tempfile.mkdtemp()
642        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
643        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
644        num, num_warns, fin_file, fail_file = self.processor.doImport(
645            self.csv_file, HOSTEL_HEADER_FIELDS)
646        # We import the same file in update mode
647        num, num_warns, fin_file, fail_file = self.processor.doImport(
648            self.csv_file, HOSTEL_HEADER_FIELDS, 'update')
649        self.assertEqual(num_warns,0)
650        logcontent = open(self.logfile).read()
651        self.assertTrue(
652            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
653            "updated: "
654            "beds_for_pre=['G'], floors_per_block=1, "
655            "special_handling=regular, "
656            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
657            "hostel_id=block-a-upper-hostel, "
658            "sort_id=20, beds_for_returning=['C', 'D'], "
659            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
660            "blocks_for_female=['A']"
661            in logcontent)
662        # Update the beds of first hostel
663        self.app['hostels']['block-a-upper-hostel'].updateBeds()
664        # Import beds
665        self.processor = BedProcessor()
666        self.csv_file = os.path.join(self.workdir, 'sample_bed_data.csv')
667        open(self.csv_file, 'wb').write(BED_SAMPLE_DATA)
668        num, num_warns, fin_file, fail_file = self.processor.doImport(
669            self.csv_file, BED_HEADER_FIELDS, 'update')
670        self.assertEqual(num_warns,2)
671        fail_file_content = open(fail_file).read()
672        logcontent = open(self.logfile).read()
673        self.assertEqual(
674            'owner,bed_id,hostel_id,reserved,--ERRORS--\r\n'
675            '<IGNORE>,block-a-upper-hostel_A_101_C,block-a-upper-hostel,2,'
676            'reserved: invalid value\r\n'
677            'K999,block-a-upper-hostel_A_101_E,block-a-upper-hostel,0,'
678            'owner: student does not exist\r\n',
679            fail_file_content)
680        self.assertTrue(
681            'system - Bed Processor (update only) - sample_bed_data - '
682            'block-a-upper-hostel_A_101_A - updated: nothing'
683            in logcontent)
684        self.assertTrue(
685            'system - Bed Processor (update only) - sample_bed_data - '
686            'block-a-upper-hostel_A_101_B - updated: reserved'
687            in logcontent)
688        self.assertTrue(
689            'system - Bed Processor (update only) - sample_bed_data - '
690            'block-a-upper-hostel_A_101_D - updated: owner=K1000000'
691            in logcontent)
692        self.assertEqual(
693            self.app['hostels']['block-a-upper-hostel']
694                    ['block-a-upper-hostel_A_101_D'].owner, 'K1000000')
695        self.assertEqual(
696            self.app['hostels']['block-a-upper-hostel']
697                    ['block-a-upper-hostel_A_101_B'].bed_type,
698                    'regular_female_reserved')
699        shutil.rmtree(os.path.dirname(fin_file))
700        shutil.rmtree(self.workdir)
701        return
Note: See TracBrowser for help on using the repository browser.