source: main/waeup.sirp/trunk/src/waeup/sirp/hostels/tests.py @ 7193

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

Further increase overall test coverage.

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