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

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

Add bed statistics view components.

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