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

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

Add more tests and increase test coverage.

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