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

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

More copyright adjustments.

  • Property svn:keywords set to Id
File size: 15.3 KB
Line 
1## $Id: tests.py 7195 2011-11-25 07:34:07Z 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 shutil
22import tempfile
23import grok
24from zope.event import notify
25
26from zope.interface.verify import verifyClass, verifyObject
27from zope.component.hooks import setSite, clearSite
28from zope.testbrowser.testing import Browser
29from zope.security.interfaces import Unauthorized
30from zope.catalog.interfaces import ICatalog
31from zope.component import queryUtility
32from waeup.sirp.app import University
33from waeup.sirp.hostels.interfaces import (
34    IHostelsContainer, IHostel, IBed)
35from waeup.sirp.hostels.container import HostelsContainer
36from waeup.sirp.hostels.hostel import Hostel, Bed
37from waeup.sirp.testing import (FunctionalLayer, FunctionalTestCase)
38from waeup.sirp.students.student import Student
39from waeup.sirp.students.accommodation import BedTicket
40from waeup.sirp.university.department import Department
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            )
64        self.assertTrue(
65            verifyClass(
66                IBed, Bed)
67            )
68        self.assertTrue(
69            verifyObject(
70                IBed, Bed())
71            )
72        return
73
74    def test_base(self):
75        # We cannot call the fundamental methods of a base in that case
76        container = HostelsContainer()
77        hostel = Hostel()
78        self.assertRaises(
79            NotImplementedError, container.archive)
80        self.assertRaises(
81            NotImplementedError, container.clear)
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)
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
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
120        # The students_catalog must be informed that the
121        # session attribute has changed
122        notify(grok.ObjectModifiedEvent(self.student))
123
124        # Set accommodation_session
125        self.app['configuration'].accommodation_session = 2004
126
127        # Create a hostel
128        hostel = Hostel()
129        hostel.hostel_id = u'hall-x'
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
139        self.container_path = 'http://localhost/app/hostels'
140        self.student_path = 'http://localhost/app/students/%s' % self.student_id
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
154class BedCatalogTests(HostelsFullSetup):
155
156    layer = FunctionalLayer
157
158    def test_get_catalog(self):
159        # We can get a beds catalog if we wish
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')
166        results = cat.searchResults(bed_type=(u'abc', u'abc'))
167        results = [x for x in results] # Turn results generator into list
168        assert len(results) == 1
169        assert results[0] is self.app['hostels']['hall-x']['xyz']
170
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
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
192    def test_add_search_edit_delete_manage_hostels(self):
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)
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)
207        hall = self.app['hostels']['hall-1']
208        hall.blocks_for_female = ['A','B']
209        self.browser.open(self.container_path + '/hall-1')
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)
213        self.browser.open(self.container_path + '/hall-1/manage')
214        self.browser.getControl(name="form.rooms_per_floor").value = '1'
215        self.browser.getControl("Save").click()
216        self.assertTrue('Form has been saved' in self.browser.contents)
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']
222        hall.beds_for_fresh = ['A']
223        hall.beds_for_returning = ['B']
224        hall.beds_for_final = ['C']
225        hall.beds_for_all = ['D','E']
226        self.browser.getControl("Update all beds").click()
227        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
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
234        # Reserve bed
235        self.browser.getControl("Switch reservation", index=0).click()
236        self.assertTrue('No item selected' in self.browser.contents)
237        ctrl = self.browser.getControl(name='val_id')
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
241        ctrl.getControl(value='hall-1_A_101_D').selected = True
242        self.browser.getControl("Switch reservation", index=0).click()
243        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
244            in self.browser.contents)
245        assert self.app['hostels']['hall-1'][
246            'hall-1_A_101_D'].bed_type == 'regular_female_reserved'
247        expected = 'name="form.beds_reserved.0." size="20" type="text" value="A_101_A"  />'
248        self.assertTrue(expected in self.browser.contents)
249        # Provoke exception
250        self.app['hostels']['hall-1']['hall-1_A_101_D'].bed_type = u'nonsense'
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()
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'
258        # Change hostel configuration
259        hall.beds_for_all = ['D']
260        self.browser.getControl("Update all beds").click()
261        expected = '...10 empty beds removed, 8 beds added, 0 occupied beds modified...'
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]
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)
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')
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')
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> --')
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)
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)
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)
335        # Remove entire hostel
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)
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.