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

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

Redirect to specified tabs using the request's QUERY_STRING value. This suboptimal solution will be replaced later by a pure Javascript solution.

  • Property svn:keywords set to Id
File size: 15.3 KB
Line 
1## $Id: tests.py 7484 2012-01-16 07:06:21Z 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.firstname = u'Anna'
112        student.lastname = u'Tester'
113        student.reg_number = u'123'
114        student.matric_number = u'234'
115        student.sex = u'f'
116        self.app['students'].addStudent(student)
117        self.student_id = student.student_id
118        self.student = self.app['students'][self.student_id]
119        self.student['studycourse'].current_session = 2004
120        self.student['studycourse'].entry_session = 2004
121        # The students_catalog must be informed that the
122        # session attribute has changed
123        notify(grok.ObjectModifiedEvent(self.student))
124
125        # Set accommodation_session
126        self.app['configuration'].accommodation_session = 2004
127
128        # Create a hostel
129        hostel = Hostel()
130        hostel.hostel_id = u'hall-x'
131        self.app['hostels'][hostel.hostel_id] = hostel
132
133        # Create a bed
134        bed = Bed()
135        bed.bed_id = u'xyz'
136        bed.bed_number = 1
137        bed.bed_type = u'abc'
138        self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed
139
140        self.container_path = 'http://localhost/app/hostels'
141        self.student_path = 'http://localhost/app/students/%s' % self.student_id
142        self.manage_container_path = self.container_path + '/@@manage'
143        self.add_hostel_path = self.container_path + '/addhostel'
144
145        # Put the prepopulated site into test ZODB and prepare test
146        # browser
147        self.browser = Browser()
148        self.browser.handleErrors = False
149
150    def tearDown(self):
151        super(HostelsFullSetup, self).tearDown()
152        clearSite()
153        shutil.rmtree(self.dc_root)
154
155class BedCatalogTests(HostelsFullSetup):
156
157    layer = FunctionalLayer
158
159    def test_get_catalog(self):
160        # We can get a beds catalog if we wish
161        cat = queryUtility(ICatalog, name='beds_catalog')
162        assert cat is not None
163
164    def test_search_by_type(self):
165        # We can find a certain bed
166        cat = queryUtility(ICatalog, name='beds_catalog')
167        results = cat.searchResults(bed_type=(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
172    def test_search_by_owner(self):
173        # We can find a certain bed
174        myobj = self.app['hostels']['hall-x']['xyz']
175        myobj.owner = u'abc'
176        notify(grok.ObjectModifiedEvent(myobj))
177        cat = queryUtility(ICatalog, name='beds_catalog')
178        results = cat.searchResults(owner=(u'abc', u'abc'))
179        results = [x for x in results] # Turn results generator into list
180        assert len(results) == 1
181        assert results[0] is self.app['hostels']['hall-x']['xyz']
182
183class HostelsUITests(HostelsFullSetup):
184
185    layer = FunctionalLayer
186
187    def test_anonymous_access(self):
188        # Anonymous users can't access hostels containers
189        self.assertRaises(
190            Unauthorized, self.browser.open, self.manage_container_path)
191        return
192
193    def test_add_search_edit_delete_manage_hostels(self):
194        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
195        self.browser.open(self.container_path)
196        self.browser.getLink("Manage accommodation").click()
197        self.assertEqual(self.browser.headers['Status'], '200 Ok')
198        self.assertEqual(self.browser.url, self.manage_container_path)
199        self.browser.getControl("Add hostel").click()
200        self.assertEqual(self.browser.headers['Status'], '200 Ok')
201        self.assertEqual(self.browser.url, self.add_hostel_path)
202        self.browser.getControl("Create hostel").click()
203        self.assertEqual(self.browser.headers['Status'], '200 Ok')
204        self.assertTrue('Hostel created' in self.browser.contents)
205        self.browser.open(self.container_path + '/addhostel')
206        self.browser.getControl("Create hostel").click()
207        self.assertTrue('The hostel already exists' in self.browser.contents)
208        hall = self.app['hostels']['hall-1']
209        hall.blocks_for_female = ['A','B']
210        self.browser.open(self.container_path + '/hall-1')
211        expected = '''...<ul id="form.blocks_for_female" ><li>Block A</li>
212<li>Block B</li></ul>...'''
213        self.assertMatches(expected,self.browser.contents)
214        self.browser.open(self.container_path + '/hall-1/manage')
215        self.browser.getControl(name="form.rooms_per_floor").value = '1'
216        self.browser.getControl("Save").click()
217        self.assertTrue('Form has been saved' in self.browser.contents)
218        # Since the testbrowser does not support Javascrip the
219        # save action cleared the settings above and we have to set them
220        # again
221        self.assertTrue(len(hall.blocks_for_female) == 0)
222        hall.blocks_for_female = ['A','B']
223        hall.beds_for_fresh = ['A']
224        hall.beds_for_returning = ['B']
225        hall.beds_for_final = ['C']
226        hall.beds_for_all = ['D','E']
227        self.browser.getControl("Update all beds").click()
228        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
229        self.assertMatches(expected,self.browser.contents)
230        cat = queryUtility(ICatalog, name='beds_catalog')
231        results = cat.searchResults(
232            bed_type=('regular_female_all', 'regular_female_all'))
233        results = [x for x in results]
234        assert len(results) == 4
235        # Reserve bed
236        self.browser.getControl("Switch reservation", index=0).click()
237        self.assertTrue('No item selected' in self.browser.contents)
238        ctrl = self.browser.getControl(name='val_id')
239        ctrl.getControl(value='hall-1_A_101_A').selected = True
240        ctrl.getControl(value='hall-1_A_101_B').selected = True
241        ctrl.getControl(value='hall-1_A_101_C').selected = True
242        ctrl.getControl(value='hall-1_A_101_D').selected = True
243        self.browser.getControl("Switch reservation", index=0).click()
244        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
245            in self.browser.contents)
246        assert self.app['hostels']['hall-1'][
247            'hall-1_A_101_D'].bed_type == 'regular_female_reserved'
248        expected = 'name="form.beds_reserved.0." size="20" type="text" value="A_101_A"  />'
249        self.assertTrue(expected in self.browser.contents)
250        # Provoke exception
251        self.app['hostels']['hall-1']['hall-1_A_101_D'].bed_type = u'nonsense'
252        ctrl = self.browser.getControl(name='val_id')
253        ctrl.getControl(value='hall-1_A_101_D').selected = True
254        self.browser.getControl("Switch reservation", index=0).click()
255        self.assertMatches(
256            '...need more than 1 value to unpack...', self.browser.contents)
257        self.app['hostels']['hall-1'][
258            'hall-1_A_101_D'].bed_type = u'regular_female_reserved'
259        # Change hostel configuration
260        hall.beds_for_all = ['D']
261        self.browser.getControl("Update all beds").click()
262        expected = '...10 empty beds removed, 8 beds added, 0 occupied beds modified...'
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]
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)
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')
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')
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,
295          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> --')
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)
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)
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,
312            self.container_path + '/hall-1/@@manage?tab2')
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)
336        # Remove entire hostel
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)
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.