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

Last change on this file since 13501 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
Line 
1## $Id: tests.py 13484 2015-11-19 11:34:48Z 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        results = cat.searchResults(owner=(self.student_id, self.student_id))
201        self.assertEqual(len(results), 1)
202        self.browser.open(self.container_path + '/releaseexpired')
203        self.assertTrue('No bed released' in self.browser.contents)
204        delta = timedelta(days=10)
205        bedticket.booking_date = datetime.utcnow() - delta
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)
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)
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)
224        # Releasing is logged.
225        logcontent = open(self.logfile).read()
226        self.assertTrue(
227            'hostels.browser.ReleaseExpiredAllocationsPage - hostels - '
228            'released: hall_block_room_bed (K1000000)'
229            in logcontent)
230        return
231
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,
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)}
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,
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)}
267             )
268
269class BedCatalogTests(HostelsFullSetup):
270
271    layer = FunctionalLayer
272
273    def test_get_catalog(self):
274        # We can get a beds catalog if we wish
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')
281        results = cat.searchResults(
282            bed_type=(u'regular_male_fr', u'regular_male_fr'))
283        results = [x for x in results] # Turn results generator into list
284        assert len(results) == 1
285        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
286
287    def test_search_by_owner(self):
288        # We can find a certain bed
289        myobj = self.app['hostels']['hall-x']['hall_block_room_bed']
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
296        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
297
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
308    def test_add_search_edit_delete_manage_hostels(self):
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)
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)
323        hall = self.app['hostels']['hall-1']
324        hall.blocks_for_female = ['A','B']
325        self.browser.open(self.container_path + '/hall-1')
326        expected = '...<ul id="form.blocks_for_female" ><li>Block A</li>...'
327        self.assertMatches(expected,self.browser.contents)
328        self.browser.open(self.container_path + '/hall-1/manage')
329        self.browser.getControl(name="form.rooms_per_floor").value = '1'
330        self.browser.getControl("Save").click()
331        self.assertTrue('Form has been saved' in self.browser.contents)
332        # Since the testbrowser does not support Javascrip the
333        # save action cleared the settings above and we have to set them
334        # again.
335        self.assertTrue(len(hall.blocks_for_female) == 0)
336        hall.blocks_for_female = ['A','B']
337        hall.beds_for_fresh = ['A']
338        hall.beds_for_returning = ['B']
339        hall.beds_for_final = ['C']
340        hall.beds_for_all = ['D','E']
341        self.browser.getControl("Update all beds").click()
342        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
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'))
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')])
353        # Reserve beds.
354        self.browser.getControl("Switch reservation", index=0).click()
355        self.assertTrue('No item selected' in self.browser.contents)
356        ctrl = self.browser.getControl(name='val_id')
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
360        ctrl.getControl(value='hall-1_A_101_D').selected = True
361        self.browser.getControl("Switch reservation", index=0).click()
362        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
363            in self.browser.contents)
364        self.assertEqual(self.app['hostels']['hall-1'][
365            'hall-1_A_101_D'].bed_type, 'regular_female_reserved')
366        # The catalog has been updated.
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')])
382        # Change hostel configuration with one bed booked.
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']
386        hall.beds_for_all = ['D']
387        self.browser.getControl("Update all beds").click()
388        expected = '...9 empty beds removed, 9 beds added, 1 occupied beds modified...'
389        self.assertMatches(expected,self.browser.contents)
390        # Updating beds (including booked beds!) does update catalog.
391        results = cat.searchResults(
392            bed_type=('regular_female_all', 'regular_female_all'))
393        results = [(x.bed_id, x.bed_type) for x in results]
394        # The reservation of hall-1_A_101_D has been cancelled.
395        self.assertEqual(results,
396            [(u'hall-1_A_101_D', u'regular_female_all'),
397             (u'hall-1_B_101_D', u'regular_female_all')])
398        # Release bed which has previously been booked.
399        bedticket = BedTicket()
400        bedticket.booking_session = 2004
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
404        notify(grok.ObjectModifiedEvent(self.app['hostels']['hall-1']['hall-1_A_101_D']))
405        self.browser.open(self.container_path + '/hall-1/manage')
406        ctrl = self.browser.getControl(name='val_id')
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')
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,
416          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> UTC --')
417        # The catalog has been updated.
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.
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)
426        # Managers can manually allocate eligible students after cancellation.
427        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
428        # 'not occupied' is not accepted.
429        self.browser.getControl("Save").click()
430        self.assertMatches(
431            "...No valid student id...",
432            self.browser.contents)
433        # Invalid student ids are not accepted.
434        self.browser.getControl(name="form.owner").value = 'nonsense'
435        self.browser.getControl("Save").click()
436        self.assertMatches(
437            "...Either student does not exist or student "
438            "is not in accommodation session...",
439            self.browser.contents)
440        self.browser.getControl(name="form.owner").value = self.student_id
441        self.browser.getControl("Save").click()
442        self.assertMatches("...Form has been saved...", self.browser.contents)
443        # Students can only be allocated once.
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)
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,
455            self.container_path + '/hall-1/@@manage#tab2')
456        # Updating the beds again will not affect the allocation and also
457        # the bed numbering remains the same.
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()
461        # 8 beds have been removed and re-added, 2 beds remains untouched
462        # because they are occupied.
463        expected = '...8 empty beds removed, 8 beds added, 0 occupied beds modified...'
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
470        # be indicated.
471        hall.blocks_for_female = ['B']
472        hall.blocks_for_male = ['A']
473        self.browser.getControl("Update all beds").click()
474        expected = '...8 empty beds removed, 8 beds added, ' + \
475            '2 occupied beds modified (hall-1_A_101_A, hall-1_A_101_E, )...'
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)
480        # The number of occupied beds are displayed on container page.
481        self.browser.open(self.container_path)
482        self.assertTrue('2 of 10' in self.browser.contents)
483        bedticket.bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
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)
487        # Remove entire hostel.
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)
494        # Catalog is empty.
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
499        # Bed has been removed from bedticket
500        self.assertEqual(bedticket.bed, None)
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)
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.
537        logcontent = open(self.logfile).read()
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)
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,'
560            'beds_for_returning,blocks_for_female,'
561            'blocks_for_male,floors_per_block,hostel_id,hostel_name,maint_fee,'
562            'rooms_per_floor,sort_id,special_handling\r\n[],[],[],[],[],[],[],'
563            '1,hall-x,Hall 1,0.0,2,10,regular\r\n'
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,'
574            'special_handling,sex,bt\r\nhall_block_room_bed,1,regular_male_fr,,'
575            'hall,block,room,bed,regular,male,fr\r\n'
576            )
577        return
578
579    def tearDown(self):
580        super(ExportTests, self).tearDown()
581        clearSite()
582        shutil.rmtree(os.path.dirname(self.outfile))
583
584class HostelBedProcessorTest(HostelsFullSetup):
585
586    layer = FunctionalLayer
587
588    def test_import(self):
589        self.processor = HostelProcessor()
590        self.workdir = tempfile.mkdtemp()
591        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
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(
603            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
604            "updated: "
605            "beds_for_pre=['G'], floors_per_block=1, "
606            "special_handling=regular, "
607            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
608            "hostel_id=block-a-upper-hostel, "
609            "sort_id=20, beds_for_returning=['C', 'D'], "
610            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
611            "blocks_for_female=['A']"
612            in logcontent)
613        shutil.rmtree(os.path.dirname(fin_file))
614        shutil.rmtree(self.workdir)
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')
620        return
621
622    def test_import_update_hostel_and_beds(self):
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, "
638            "special_handling=regular, "
639            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
640            "hostel_id=block-a-upper-hostel, "
641            "sort_id=20, beds_for_returning=['C', 'D'], "
642            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
643            "blocks_for_female=['A']"
644            in logcontent)
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')
682        shutil.rmtree(os.path.dirname(fin_file))
683        shutil.rmtree(self.workdir)
684        return
Note: See TracBrowser for help on using the repository browser.