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

Last change on this file since 7070 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
Line 
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"""
17Tests for hostels and their UI components.
18"""
19import shutil
20import tempfile
21import grok
22from zope.event import notify
23
24from zope.interface.verify import verifyClass, verifyObject
25from zope.component.hooks import setSite, clearSite
26from zope.testbrowser.testing import Browser
27from zope.security.interfaces import Unauthorized
28from zope.catalog.interfaces import ICatalog
29from zope.component import queryUtility
30from waeup.sirp.app import University
31from waeup.sirp.hostels.interfaces import (
32    IHostelsContainer, IHostel, IBed)
33from waeup.sirp.hostels.container import HostelsContainer
34from waeup.sirp.hostels.hostel import Hostel, Bed
35from waeup.sirp.testing import (FunctionalLayer, FunctionalTestCase)
36from waeup.sirp.students.student import Student
37from waeup.sirp.students.accommodation import BedTicket
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            )
61        self.assertTrue(
62            verifyClass(
63                IBed, Bed)
64            )
65        self.assertTrue(
66            verifyObject(
67                IBed, Bed())
68            )
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)
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
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
110        # The students_catalog must be informed that the
111        # session attribute has changed
112        notify(grok.ObjectModifiedEvent(self.student))
113
114        # Set accommodation_session
115        self.app['configuration'].accommodation_session = 2004
116
117        # Create a hostel
118        hostel = Hostel()
119        hostel.hostel_id = u'hall-x'
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
129        self.container_path = 'http://localhost/app/hostels'
130        self.student_path = 'http://localhost/app/students/%s' % self.student_id
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
144class BedCatalogTests(HostelsFullSetup):
145
146    layer = FunctionalLayer
147
148    def test_get_catalog(self):
149        # We can get a beds catalog if we wish
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')
156        results = cat.searchResults(bed_type=(u'abc', u'abc'))
157        results = [x for x in results] # Turn results generator into list
158        assert len(results) == 1
159        assert results[0] is self.app['hostels']['hall-x']['xyz']
160
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
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
182    def test_add_search_edit_delete_manage_hostels(self):
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)
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)
197        hall = self.app['hostels']['hall-1']
198        hall.blocks_for_female = ['A','B']
199        self.browser.open(self.container_path + '/hall-1')
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)
203        self.browser.open(self.container_path + '/hall-1/manage')
204        self.browser.getControl(name="form.rooms_per_floor").value = '1'
205        self.browser.getControl("Save").click()
206        self.assertTrue('Form has been saved' in self.browser.contents)
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']
212        hall.beds_for_fresh = ['A']
213        hall.beds_for_returning = ['B']
214        hall.beds_for_final = ['C']
215        hall.beds_for_all = ['D','E']
216        self.browser.getControl("Update all beds").click()
217        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
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
224        # Reserve bed
225        self.browser.getControl("Switch reservation", index=0).click()
226        self.assertTrue('No item selected' in self.browser.contents)
227        ctrl = self.browser.getControl(name='val_id')
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
231        ctrl.getControl(value='hall-1_A_101_D').selected = True
232        self.browser.getControl("Switch reservation", index=0).click()
233        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
234            in self.browser.contents)
235        assert self.app['hostels']['hall-1'][
236            'hall-1_A_101_D'].bed_type == 'regular_female_reserved'
237        expected = 'name="form.beds_reserved.0." size="20" type="text" value="A_101_A"  />'
238        self.assertTrue(expected in self.browser.contents)
239        # Provoke exception
240        self.app['hostels']['hall-1']['hall-1_A_101_D'].bed_type = u'nonsense'
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()
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'
248        # Change hostel configuration
249        hall.beds_for_all = ['D']
250        self.browser.getControl("Update all beds").click()
251        expected = '...10 empty beds removed, 8 beds added, 0 occupied beds modified...'
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]
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)
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')
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')
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> --')
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)
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)
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)
325        # Remove entire hostel
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)
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.