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

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

Show only time zone name.

  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1## $Id: tests.py 8234 2012-04-20 11:27:59Z 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.kofa.app import University
33from waeup.kofa.hostels.interfaces import (
34    IHostelsContainer, IHostel, IBed)
35from waeup.kofa.hostels.container import HostelsContainer
36from waeup.kofa.hostels.hostel import Hostel, Bed
37from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase)
38from waeup.kofa.students.student import Student
39from waeup.kofa.students.accommodation import BedTicket
40from waeup.kofa.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        self.assertTrue('<div>A_101_A</div>' in self.browser.contents)
249
250        # Change hostel configuration
251        hall.beds_for_all = ['D']
252        self.browser.getControl("Update all beds").click()
253        expected = '...10 empty beds removed, 8 beds added, 0 occupied beds modified...'
254        self.assertMatches(expected,self.browser.contents)
255        results = cat.searchResults(
256            bed_type=('regular_female_all', 'regular_female_all'))
257        results = [x for x in results]
258        assert len(results) == 1
259        # Unreserve bed
260        ctrl = self.browser.getControl(name='val_id')
261        ctrl.getControl(value='hall-1_A_101_A').selected = True
262        ctrl.getControl(value='hall-1_A_101_B').selected = True
263        ctrl.getControl(value='hall-1_A_101_C').selected = True
264        ctrl.getControl(value='hall-1_A_101_D').selected = True
265        self.browser.getControl("Switch reservation", index=0).click()
266        assert self.app['hostels']['hall-1'][
267            'hall-1_A_101_D'].bed_type == 'regular_female_all'
268        self.assertFalse(expected in self.browser.contents)
269        # Release bed which has previously been booked
270        bedticket = BedTicket()
271        bedticket.ticket_id = u'2004'
272        bedticket.bed_coordinates = u'anything'
273        self.student['accommodation'].addBedTicket(bedticket)
274        self.app['hostels']['hall-1']['hall-1_A_101_D'].owner = self.student_id
275        self.browser.open(self.container_path + '/hall-1/manage')
276        ctrl = self.browser.getControl(name='val_id')
277        self.browser.getControl("Release selected beds", index=0).click()
278        self.assertMatches("...No item selected...", self.browser.contents)
279        ctrl = self.browser.getControl(name='val_id')
280        ctrl.getControl(value='hall-1_A_101_D').selected = True
281        self.browser.getControl("Release selected beds", index=0).click()
282        self.assertMatches(
283          '...Successfully released beds: hall-1_A_101_D (%s)...' % self.student_id,
284          self.browser.contents)
285        self.assertMatches(bedticket.bed_coordinates,
286          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> UTC --')
287        # If we release a free be, nothing will happen
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          '...No allocated bed selected...', self.browser.contents)
293        # Managers can manually allocate studenst after cancellation
294        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
295        self.browser.getControl(name="form.owner").value = [self.student_id]
296        self.browser.getControl("Save").click()
297        self.assertMatches("...Form has been saved...", self.browser.contents)
298        # If we open the same form again, we will be redirected to hostel
299        # manage page. Beds must be released first before they can be
300        # allocated to other students.
301        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
302        self.assertEqual(self.browser.url,
303            self.container_path + '/hall-1/@@manage?tab2')
304        # Updating the beds again will not affect the allocation and also
305        # the bed numbering remains the same
306        old_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
307        old_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
308        self.browser.getControl("Update all beds").click()
309        # 7 beds have been removed and re-added, 1 bed remains untouched
310        expected = '...7 empty beds removed, 7 beds added, 0 occupied beds modified...'
311        self.assertMatches(expected,self.browser.contents)
312        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
313        new_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
314        self.assertEqual(new_number, old_number)
315        self.assertEqual(new_owner, old_owner)
316        # If we change the bed type of an allocated bed, the modification will
317        # be indicated
318        hall.blocks_for_female = ['B']
319        hall.blocks_for_male = ['A']
320        self.browser.getControl("Update all beds").click()
321        expected = '...7 empty beds removed, 7 beds added, ' + \
322            '1 occupied beds modified (hall-1_A_101_A )...'
323        self.assertMatches(expected,self.browser.contents)
324        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
325        # Also the number of the bed has changed.
326        self.assertFalse(new_number == old_number)
327        # Remove entire hostel
328        self.browser.open(self.manage_container_path)
329        ctrl = self.browser.getControl(name='val_id')
330        value = ctrl.options[0]
331        ctrl.getControl(value=value).selected = True
332        self.browser.getControl("Remove selected", index=0).click()
333        self.assertTrue('Successfully removed' in self.browser.contents)
334        # Catalog is empty
335        results = cat.searchResults(
336            bed_type=('regular_female_all', 'regular_female_all'))
337        results = [x for x in results]
338        assert len(results) == 0
Note: See TracBrowser for help on using the repository browser.