source: main/waeup.kofa/trunk/src/waeup/kofa/hostels/tests.py @ 8762

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

Add expired property.

  • Property svn:keywords set to Id
File size: 15.2 KB
Line 
1## $Id: tests.py 8686 2012-06-12 07:36:23Z 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
24import pytz
25from datetime import datetime, timedelta
26from zope.event import notify
27from zope.interface.verify import verifyClass, verifyObject
28from zope.component.hooks import setSite, clearSite
29from zope.testbrowser.testing import Browser
30from zope.security.interfaces import Unauthorized
31from zope.catalog.interfaces import ICatalog
32from zope.component import queryUtility
33from waeup.kofa.app import University
34from waeup.kofa.hostels.interfaces import (
35    IHostelsContainer, IHostel, IBed)
36from waeup.kofa.hostels.container import HostelsContainer
37from waeup.kofa.hostels.hostel import Hostel, Bed
38from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase)
39from waeup.kofa.students.student import Student
40from waeup.kofa.students.accommodation import BedTicket
41from waeup.kofa.university.department import Department
42
43class HostelsContainerTestCase(FunctionalTestCase):
44
45    layer = FunctionalLayer
46
47    def test_interfaces(self):
48        # Make sure the correct interfaces are implemented.
49        self.assertTrue(
50            verifyClass(
51                IHostelsContainer, HostelsContainer)
52            )
53        self.assertTrue(
54            verifyObject(
55                IHostelsContainer, HostelsContainer())
56            )
57        self.assertTrue(
58            verifyClass(
59                IHostel, Hostel)
60            )
61        self.assertTrue(
62            verifyObject(
63                IHostel, Hostel())
64            )
65        self.assertTrue(
66            verifyClass(
67                IBed, Bed)
68            )
69        self.assertTrue(
70            verifyObject(
71                IBed, Bed())
72            )
73        return
74
75    def test_base(self):
76        # We cannot call the fundamental methods of a base in that case
77        container = HostelsContainer()
78        hostel = Hostel()
79        self.assertRaises(
80            NotImplementedError, container.archive)
81        self.assertRaises(
82            NotImplementedError, container.clear)
83        # We cannot add arbitrary objects
84        department = Department()
85        self.assertRaises(
86            TypeError, container.addHostel, department)
87        self.assertRaises(
88            TypeError, hostel.addBed, department)
89        # Application is expired if startdate or enddate are not set
90        # or current datetime is outside application period.
91        self.assertTrue(container.expired)
92        delta = timedelta(days=10)
93        container.startdate = datetime.now(pytz.utc) - delta
94        self.assertTrue(container.expired)
95        container.enddate = datetime.now(pytz.utc) + delta
96        self.assertFalse(container.expired)
97
98class HostelsFullSetup(FunctionalTestCase):
99
100    def setUp(self):
101        super(HostelsFullSetup, self).setUp()
102
103        # Setup a sample site for each test
104        app = University()
105        self.dc_root = tempfile.mkdtemp()
106        app['datacenter'].setStoragePath(self.dc_root)
107
108        # Prepopulate the ZODB...
109        self.getRootFolder()['app'] = app
110        # we add the site immediately after creation to the
111        # ZODB. Catalogs and other local utilities are not setup
112        # before that step.
113        self.app = self.getRootFolder()['app']
114        # Set site here. Some of the following setup code might need
115        # to access grok.getSite() and should get our new app then
116        setSite(app)
117
118        # Add student with subobjects
119        student = Student()
120        student.firstname = u'Anna'
121        student.lastname = u'Tester'
122        student.reg_number = u'123'
123        student.matric_number = u'234'
124        student.sex = u'f'
125        self.app['students'].addStudent(student)
126        self.student_id = student.student_id
127        self.student = self.app['students'][self.student_id]
128        self.student['studycourse'].current_session = 2004
129        self.student['studycourse'].entry_session = 2004
130        # The students_catalog must be informed that the
131        # session attribute has changed
132        notify(grok.ObjectModifiedEvent(self.student))
133
134        # Set accommodation_session
135        self.app['hostels'].accommodation_session = 2004
136
137        # Create a hostel
138        hostel = Hostel()
139        hostel.hostel_id = u'hall-x'
140        self.app['hostels'][hostel.hostel_id] = hostel
141
142        # Create a bed
143        bed = Bed()
144        bed.bed_id = u'xyz'
145        bed.bed_number = 1
146        bed.bed_type = u'abc'
147        self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed
148
149        self.container_path = 'http://localhost/app/hostels'
150        self.student_path = 'http://localhost/app/students/%s' % self.student_id
151        self.manage_container_path = self.container_path + '/@@manage'
152        self.add_hostel_path = self.container_path + '/addhostel'
153
154        # Put the prepopulated site into test ZODB and prepare test
155        # browser
156        self.browser = Browser()
157        self.browser.handleErrors = False
158
159    def tearDown(self):
160        super(HostelsFullSetup, self).tearDown()
161        clearSite()
162        shutil.rmtree(self.dc_root)
163
164class BedCatalogTests(HostelsFullSetup):
165
166    layer = FunctionalLayer
167
168    def test_get_catalog(self):
169        # We can get a beds catalog if we wish
170        cat = queryUtility(ICatalog, name='beds_catalog')
171        assert cat is not None
172
173    def test_search_by_type(self):
174        # We can find a certain bed
175        cat = queryUtility(ICatalog, name='beds_catalog')
176        results = cat.searchResults(bed_type=(u'abc', u'abc'))
177        results = [x for x in results] # Turn results generator into list
178        assert len(results) == 1
179        assert results[0] is self.app['hostels']['hall-x']['xyz']
180
181    def test_search_by_owner(self):
182        # We can find a certain bed
183        myobj = self.app['hostels']['hall-x']['xyz']
184        myobj.owner = u'abc'
185        notify(grok.ObjectModifiedEvent(myobj))
186        cat = queryUtility(ICatalog, name='beds_catalog')
187        results = cat.searchResults(owner=(u'abc', u'abc'))
188        results = [x for x in results] # Turn results generator into list
189        assert len(results) == 1
190        assert results[0] is self.app['hostels']['hall-x']['xyz']
191
192class HostelsUITests(HostelsFullSetup):
193
194    layer = FunctionalLayer
195
196    def test_anonymous_access(self):
197        # Anonymous users can't access hostels containers
198        self.assertRaises(
199            Unauthorized, self.browser.open, self.manage_container_path)
200        return
201
202    def test_add_search_edit_delete_manage_hostels(self):
203        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
204        self.browser.open(self.container_path)
205        self.browser.getLink("Manage accommodation").click()
206        self.assertEqual(self.browser.headers['Status'], '200 Ok')
207        self.assertEqual(self.browser.url, self.manage_container_path)
208        self.browser.getControl("Add hostel").click()
209        self.assertEqual(self.browser.headers['Status'], '200 Ok')
210        self.assertEqual(self.browser.url, self.add_hostel_path)
211        self.browser.getControl("Create hostel").click()
212        self.assertEqual(self.browser.headers['Status'], '200 Ok')
213        self.assertTrue('Hostel created' in self.browser.contents)
214        self.browser.open(self.container_path + '/addhostel')
215        self.browser.getControl("Create hostel").click()
216        self.assertTrue('The hostel already exists' in self.browser.contents)
217        hall = self.app['hostels']['hall-1']
218        hall.blocks_for_female = ['A','B']
219        self.browser.open(self.container_path + '/hall-1')
220        expected = '''...<ul id="form.blocks_for_female" ><li>Block A</li>
221<li>Block B</li></ul>...'''
222        self.assertMatches(expected,self.browser.contents)
223        self.browser.open(self.container_path + '/hall-1/manage')
224        self.browser.getControl(name="form.rooms_per_floor").value = '1'
225        self.browser.getControl("Save").click()
226        self.assertTrue('Form has been saved' in self.browser.contents)
227        # Since the testbrowser does not support Javascrip the
228        # save action cleared the settings above and we have to set them
229        # again
230        self.assertTrue(len(hall.blocks_for_female) == 0)
231        hall.blocks_for_female = ['A','B']
232        hall.beds_for_fresh = ['A']
233        hall.beds_for_returning = ['B']
234        hall.beds_for_final = ['C']
235        hall.beds_for_all = ['D','E']
236        self.browser.getControl("Update all beds").click()
237        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
238        self.assertMatches(expected,self.browser.contents)
239        cat = queryUtility(ICatalog, name='beds_catalog')
240        results = cat.searchResults(
241            bed_type=('regular_female_all', 'regular_female_all'))
242        results = [x for x in results]
243        assert len(results) == 4
244        # Reserve bed
245        self.browser.getControl("Switch reservation", index=0).click()
246        self.assertTrue('No item selected' in self.browser.contents)
247        ctrl = self.browser.getControl(name='val_id')
248        ctrl.getControl(value='hall-1_A_101_A').selected = True
249        ctrl.getControl(value='hall-1_A_101_B').selected = True
250        ctrl.getControl(value='hall-1_A_101_C').selected = True
251        ctrl.getControl(value='hall-1_A_101_D').selected = True
252        self.browser.getControl("Switch reservation", index=0).click()
253        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
254            in self.browser.contents)
255        assert self.app['hostels']['hall-1'][
256            'hall-1_A_101_D'].bed_type == 'regular_female_reserved'
257        self.assertTrue('<div>A_101_A</div>' in self.browser.contents)
258
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> UTC --')
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.