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

Last change on this file since 9031 was 8686, checked in by Henrik Bettermann, 13 years ago

Add expired property.

  • Property svn:keywords set to Id
File size: 15.2 KB
RevLine 
[7195]1## $Id: tests.py 8686 2012-06-12 07:36:23Z 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"""
[6961]21import shutil
22import tempfile
[7003]23import grok
[8686]24import pytz
25from datetime import datetime, timedelta
[7003]26from zope.event import notify
[6951]27from zope.interface.verify import verifyClass, verifyObject
[6961]28from zope.component.hooks import setSite, clearSite
29from zope.testbrowser.testing import Browser
30from zope.security.interfaces import Unauthorized
[6972]31from zope.catalog.interfaces import ICatalog
32from zope.component import queryUtility
[7811]33from waeup.kofa.app import University
34from waeup.kofa.hostels.interfaces import (
[6963]35    IHostelsContainer, IHostel, IBed)
[7811]36from waeup.kofa.hostels.container import HostelsContainer
37from waeup.kofa.hostels.hostel import Hostel, Bed
38from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase)
39from waeup.kofa.students.student import Student
40from waeup.kofa.students.accommodation import BedTicket
41from waeup.kofa.university.department import Department
[6951]42
43class HostelsContainerTestCase(FunctionalTestCase):
44
45    layer = FunctionalLayer
46
47    def test_interfaces(self):
48        # Make sure the correct interfaces are implemented.
49        self.assertTrue(
50            verifyClass(
51                IHostelsContainer, HostelsContainer)
52            )
53        self.assertTrue(
54            verifyObject(
55                IHostelsContainer, HostelsContainer())
56            )
57        self.assertTrue(
58            verifyClass(
59                IHostel, Hostel)
60            )
61        self.assertTrue(
62            verifyObject(
63                IHostel, Hostel())
64            )
[6963]65        self.assertTrue(
66            verifyClass(
67                IBed, Bed)
68            )
69        self.assertTrue(
70            verifyObject(
71                IBed, Bed())
72            )
[6951]73        return
74
75    def test_base(self):
76        # We cannot call the fundamental methods of a base in that case
77        container = HostelsContainer()
[7077]78        hostel = Hostel()
[6951]79        self.assertRaises(
80            NotImplementedError, container.archive)
81        self.assertRaises(
82            NotImplementedError, container.clear)
[7077]83        # We cannot add arbitrary objects
84        department = Department()
85        self.assertRaises(
86            TypeError, container.addHostel, department)
87        self.assertRaises(
88            TypeError, hostel.addBed, department)
[8686]89        # Application is expired if startdate or enddate are not set
90        # or current datetime is outside application period.
91        self.assertTrue(container.expired)
92        delta = timedelta(days=10)
93        container.startdate = datetime.now(pytz.utc) - delta
94        self.assertTrue(container.expired)
95        container.enddate = datetime.now(pytz.utc) + delta
96        self.assertFalse(container.expired)
[6961]97
98class HostelsFullSetup(FunctionalTestCase):
99
100    def setUp(self):
101        super(HostelsFullSetup, self).setUp()
102
103        # Setup a sample site for each test
104        app = University()
105        self.dc_root = tempfile.mkdtemp()
106        app['datacenter'].setStoragePath(self.dc_root)
107
108        # Prepopulate the ZODB...
109        self.getRootFolder()['app'] = app
110        # we add the site immediately after creation to the
111        # ZODB. Catalogs and other local utilities are not setup
112        # before that step.
113        self.app = self.getRootFolder()['app']
114        # Set site here. Some of the following setup code might need
115        # to access grok.getSite() and should get our new app then
116        setSite(app)
117
[7045]118        # Add student with subobjects
119        student = Student()
[7357]120        student.firstname = u'Anna'
121        student.lastname = u'Tester'
[7045]122        student.reg_number = u'123'
123        student.matric_number = u'234'
124        student.sex = u'f'
125        self.app['students'].addStudent(student)
126        self.student_id = student.student_id
127        self.student = self.app['students'][self.student_id]
128        self.student['studycourse'].current_session = 2004
129        self.student['studycourse'].entry_session = 2004
[7068]130        # The students_catalog must be informed that the
131        # session attribute has changed
132        notify(grok.ObjectModifiedEvent(self.student))
[7045]133
134        # Set accommodation_session
[8685]135        self.app['hostels'].accommodation_session = 2004
[7045]136
[6972]137        # Create a hostel
138        hostel = Hostel()
[6973]139        hostel.hostel_id = u'hall-x'
[6972]140        self.app['hostels'][hostel.hostel_id] = hostel
141
142        # Create a bed
143        bed = Bed()
144        bed.bed_id = u'xyz'
145        bed.bed_number = 1
146        bed.bed_type = u'abc'
147        self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed
148
[6961]149        self.container_path = 'http://localhost/app/hostels'
[7068]150        self.student_path = 'http://localhost/app/students/%s' % self.student_id
[6961]151        self.manage_container_path = self.container_path + '/@@manage'
152        self.add_hostel_path = self.container_path + '/addhostel'
153
154        # Put the prepopulated site into test ZODB and prepare test
155        # browser
156        self.browser = Browser()
157        self.browser.handleErrors = False
158
159    def tearDown(self):
160        super(HostelsFullSetup, self).tearDown()
161        clearSite()
162        shutil.rmtree(self.dc_root)
163
[6972]164class BedCatalogTests(HostelsFullSetup):
165
166    layer = FunctionalLayer
167
168    def test_get_catalog(self):
[7045]169        # We can get a beds catalog if we wish
[6972]170        cat = queryUtility(ICatalog, name='beds_catalog')
171        assert cat is not None
172
173    def test_search_by_type(self):
174        # We can find a certain bed
175        cat = queryUtility(ICatalog, name='beds_catalog')
[7003]176        results = cat.searchResults(bed_type=(u'abc', u'abc'))
[6972]177        results = [x for x in results] # Turn results generator into list
178        assert len(results) == 1
[6973]179        assert results[0] is self.app['hostels']['hall-x']['xyz']
[6972]180
[7003]181    def test_search_by_owner(self):
182        # We can find a certain bed
183        myobj = self.app['hostels']['hall-x']['xyz']
184        myobj.owner = u'abc'
185        notify(grok.ObjectModifiedEvent(myobj))
186        cat = queryUtility(ICatalog, name='beds_catalog')
187        results = cat.searchResults(owner=(u'abc', u'abc'))
188        results = [x for x in results] # Turn results generator into list
189        assert len(results) == 1
190        assert results[0] is self.app['hostels']['hall-x']['xyz']
191
[6961]192class HostelsUITests(HostelsFullSetup):
193
194    layer = FunctionalLayer
195
196    def test_anonymous_access(self):
197        # Anonymous users can't access hostels containers
198        self.assertRaises(
199            Unauthorized, self.browser.open, self.manage_container_path)
200        return
201
[6985]202    def test_add_search_edit_delete_manage_hostels(self):
[6961]203        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
204        self.browser.open(self.container_path)
205        self.browser.getLink("Manage accommodation").click()
206        self.assertEqual(self.browser.headers['Status'], '200 Ok')
207        self.assertEqual(self.browser.url, self.manage_container_path)
208        self.browser.getControl("Add hostel").click()
209        self.assertEqual(self.browser.headers['Status'], '200 Ok')
210        self.assertEqual(self.browser.url, self.add_hostel_path)
211        self.browser.getControl("Create hostel").click()
212        self.assertEqual(self.browser.headers['Status'], '200 Ok')
213        self.assertTrue('Hostel created' in self.browser.contents)
[6988]214        self.browser.open(self.container_path + '/addhostel')
215        self.browser.getControl("Create hostel").click()
216        self.assertTrue('The hostel already exists' in self.browser.contents)
[6973]217        hall = self.app['hostels']['hall-1']
[6961]218        hall.blocks_for_female = ['A','B']
[6973]219        self.browser.open(self.container_path + '/hall-1')
[6961]220        expected = '''...<ul id="form.blocks_for_female" ><li>Block A</li>
221<li>Block B</li></ul>...'''
222        self.assertMatches(expected,self.browser.contents)
[6973]223        self.browser.open(self.container_path + '/hall-1/manage')
[6985]224        self.browser.getControl(name="form.rooms_per_floor").value = '1'
[6962]225        self.browser.getControl("Save").click()
226        self.assertTrue('Form has been saved' in self.browser.contents)
[6985]227        # Since the testbrowser does not support Javascrip the
228        # save action cleared the settings above and we have to set them
229        # again
230        self.assertTrue(len(hall.blocks_for_female) == 0)
231        hall.blocks_for_female = ['A','B']
[6988]232        hall.beds_for_fresh = ['A']
233        hall.beds_for_returning = ['B']
234        hall.beds_for_final = ['C']
[6985]235        hall.beds_for_all = ['D','E']
236        self.browser.getControl("Update all beds").click()
[6988]237        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
[6985]238        self.assertMatches(expected,self.browser.contents)
239        cat = queryUtility(ICatalog, name='beds_catalog')
240        results = cat.searchResults(
241            bed_type=('regular_female_all', 'regular_female_all'))
242        results = [x for x in results]
243        assert len(results) == 4
[6988]244        # Reserve bed
245        self.browser.getControl("Switch reservation", index=0).click()
246        self.assertTrue('No item selected' in self.browser.contents)
[6985]247        ctrl = self.browser.getControl(name='val_id')
[6988]248        ctrl.getControl(value='hall-1_A_101_A').selected = True
249        ctrl.getControl(value='hall-1_A_101_B').selected = True
250        ctrl.getControl(value='hall-1_A_101_C').selected = True
[6985]251        ctrl.getControl(value='hall-1_A_101_D').selected = True
252        self.browser.getControl("Switch reservation", index=0).click()
[6988]253        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
[6985]254            in self.browser.contents)
[6988]255        assert self.app['hostels']['hall-1'][
[6985]256            'hall-1_A_101_D'].bed_type == 'regular_female_reserved'
[7802]257        self.assertTrue('<div>A_101_A</div>' in self.browser.contents)
258
[6985]259        # Change hostel configuration
260        hall.beds_for_all = ['D']
261        self.browser.getControl("Update all beds").click()
[6988]262        expected = '...10 empty beds removed, 8 beds added, 0 occupied beds modified...'
[6985]263        self.assertMatches(expected,self.browser.contents)
264        results = cat.searchResults(
265            bed_type=('regular_female_all', 'regular_female_all'))
266        results = [x for x in results]
[6988]267        assert len(results) == 1
268        # Unreserve bed
269        ctrl = self.browser.getControl(name='val_id')
270        ctrl.getControl(value='hall-1_A_101_A').selected = True
271        ctrl.getControl(value='hall-1_A_101_B').selected = True
272        ctrl.getControl(value='hall-1_A_101_C').selected = True
273        ctrl.getControl(value='hall-1_A_101_D').selected = True
274        self.browser.getControl("Switch reservation", index=0).click()
275        assert self.app['hostels']['hall-1'][
276            'hall-1_A_101_D'].bed_type == 'regular_female_all'
277        self.assertFalse(expected in self.browser.contents)
[7045]278        # Release bed which has previously been booked
279        bedticket = BedTicket()
280        bedticket.ticket_id = u'2004'
281        bedticket.bed_coordinates = u'anything'
282        self.student['accommodation'].addBedTicket(bedticket)
283        self.app['hostels']['hall-1']['hall-1_A_101_D'].owner = self.student_id
284        self.browser.open(self.container_path + '/hall-1/manage')
285        ctrl = self.browser.getControl(name='val_id')
[7068]286        self.browser.getControl("Release selected beds", index=0).click()
287        self.assertMatches("...No item selected...", self.browser.contents)
288        ctrl = self.browser.getControl(name='val_id')
[7045]289        ctrl.getControl(value='hall-1_A_101_D').selected = True
290        self.browser.getControl("Release selected beds", index=0).click()
291        self.assertMatches(
292          '...Successfully released beds: hall-1_A_101_D (%s)...' % self.student_id,
293          self.browser.contents)
294        self.assertMatches(bedticket.bed_coordinates,
[8234]295          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> UTC --')
[7070]296        # If we release a free be, nothing will happen
297        ctrl = self.browser.getControl(name='val_id')
298        ctrl.getControl(value='hall-1_A_101_D').selected = True
299        self.browser.getControl("Release selected beds", index=0).click()
300        self.assertMatches(
301          '...No allocated bed selected...', self.browser.contents)
[7068]302        # Managers can manually allocate studenst after cancellation
303        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
304        self.browser.getControl(name="form.owner").value = [self.student_id]
305        self.browser.getControl("Save").click()
306        self.assertMatches("...Form has been saved...", self.browser.contents)
[7070]307        # If we open the same form again, we will be redirected to hostel
308        # manage page. Beds must be released first before they can be
309        # allocated to other students.
310        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
311        self.assertEqual(self.browser.url,
[7484]312            self.container_path + '/hall-1/@@manage?tab2')
[7070]313        # Updating the beds again will not affect the allocation and also
314        # the bed numbering remains the same
315        old_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
316        old_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
317        self.browser.getControl("Update all beds").click()
318        # 7 beds have been removed and re-added, 1 bed remains untouched
319        expected = '...7 empty beds removed, 7 beds added, 0 occupied beds modified...'
320        self.assertMatches(expected,self.browser.contents)
321        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
322        new_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
323        self.assertEqual(new_number, old_number)
324        self.assertEqual(new_owner, old_owner)
325        # If we change the bed type of an allocated bed, the modification will
326        # be indicated
327        hall.blocks_for_female = ['B']
328        hall.blocks_for_male = ['A']
329        self.browser.getControl("Update all beds").click()
330        expected = '...7 empty beds removed, 7 beds added, ' + \
331            '1 occupied beds modified (hall-1_A_101_A )...'
332        self.assertMatches(expected,self.browser.contents)
333        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
334        # Also the number of the bed has changed.
335        self.assertFalse(new_number == old_number)
[6985]336        # Remove entire hostel
[6962]337        self.browser.open(self.manage_container_path)
338        ctrl = self.browser.getControl(name='val_id')
339        value = ctrl.options[0]
340        ctrl.getControl(value=value).selected = True
341        self.browser.getControl("Remove selected", index=0).click()
342        self.assertTrue('Successfully removed' in self.browser.contents)
[6985]343        # Catalog is empty
344        results = cat.searchResults(
345            bed_type=('regular_female_all', 'regular_female_all'))
346        results = [x for x in results]
347        assert len(results) == 0
Note: See TracBrowser for help on using the repository browser.