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

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

More copyright adjustments.

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