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

Last change on this file since 13168 was 13165, checked in by Henrik Bettermann, 10 years ago

Remove non-implemented methods.

Add methods to hostel section interfaces.

  • Property svn:keywords set to Id
File size: 24.2 KB
Line 
1## $Id: tests.py 13165 2015-07-13 07:53:26Z 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 os
22import shutil
23import tempfile
24import grok
25import pytz
26from datetime import datetime, timedelta
27from zope.event import notify
28from zope.interface.verify import verifyClass, verifyObject
29from zope.component.hooks import setSite, clearSite
30from zope.testbrowser.testing import Browser
31from zope.security.interfaces import Unauthorized
32from zope.catalog.interfaces import ICatalog
33from zope.component import queryUtility
34from waeup.kofa.app import University
35from waeup.kofa.hostels.interfaces import (
36    IHostelsContainer, IHostel, IBed)
37from waeup.kofa.hostels.container import HostelsContainer
38from waeup.kofa.hostels.hostel import Hostel, Bed
39from waeup.kofa.hostels.batching import HostelProcessor
40from waeup.kofa.hostels.export import BedExporter, HostelExporter
41from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase)
42from waeup.kofa.students.student import Student
43from waeup.kofa.students.accommodation import BedTicket
44from waeup.kofa.university.department import Department
45
46HOSTEL_SAMPLE_DATA = open(
47    os.path.join(os.path.dirname(__file__), 'sample_hostel_data.csv'),
48    'rb').read()
49
50HOSTEL_HEADER_FIELDS = HOSTEL_SAMPLE_DATA.split(
51    '\n')[0].split(',')
52
53class HostelsContainerTestCase(FunctionalTestCase):
54
55    layer = FunctionalLayer
56
57    def test_interfaces(self):
58        # Make sure the correct interfaces are implemented.
59        self.assertTrue(
60            verifyClass(
61                IHostelsContainer, HostelsContainer)
62            )
63        self.assertTrue(
64            verifyObject(
65                IHostelsContainer, HostelsContainer())
66            )
67        self.assertTrue(
68            verifyClass(
69                IHostel, Hostel)
70            )
71        self.assertTrue(
72            verifyObject(
73                IHostel, Hostel())
74            )
75        self.assertTrue(
76            verifyClass(
77                IBed, Bed)
78            )
79        self.assertTrue(
80            verifyObject(
81                IBed, Bed())
82            )
83        return
84
85    def test_base(self):
86        # We cannot call the fundamental methods of a base in that case
87        container = HostelsContainer()
88        hostel = Hostel()
89        # We cannot add arbitrary objects
90        department = Department()
91        self.assertRaises(
92            TypeError, container.addHostel, department)
93        self.assertRaises(
94            TypeError, hostel.addBed, department)
95        # Application is expired if startdate or enddate are not set
96        # or current datetime is outside application period.
97        self.assertTrue(container.expired)
98        delta = timedelta(days=10)
99        container.startdate = datetime.now(pytz.utc) - delta
100        self.assertTrue(container.expired)
101        container.enddate = datetime.now(pytz.utc) + delta
102        self.assertFalse(container.expired)
103
104class HostelsFullSetup(FunctionalTestCase):
105
106    def setUp(self):
107        super(HostelsFullSetup, self).setUp()
108
109        # Setup a sample site for each test
110        app = University()
111        self.dc_root = tempfile.mkdtemp()
112        app['datacenter'].setStoragePath(self.dc_root)
113
114        # Prepopulate the ZODB...
115        self.getRootFolder()['app'] = app
116        # we add the site immediately after creation to the
117        # ZODB. Catalogs and other local utilities are not setup
118        # before that step.
119        self.app = self.getRootFolder()['app']
120        # Set site here. Some of the following setup code might need
121        # to access grok.getSite() and should get our new app then
122        setSite(app)
123
124        # Add student with subobjects
125        student = Student()
126        student.firstname = u'Anna'
127        student.lastname = u'Tester'
128        student.reg_number = u'123'
129        student.matric_number = u'234'
130        student.sex = u'f'
131        self.app['students'].addStudent(student)
132        self.student_id = student.student_id
133        self.student = self.app['students'][self.student_id]
134        self.student['studycourse'].current_session = 2004
135        self.student['studycourse'].entry_session = 2004
136        # The students_catalog must be informed that the
137        # session attribute has changed
138        notify(grok.ObjectModifiedEvent(self.student))
139
140        # Set accommodation_session
141        self.app['hostels'].accommodation_session = 2004
142
143        # Create a hostel
144        hostel = Hostel()
145        hostel.hostel_id = u'hall-x'
146        self.app['hostels'][hostel.hostel_id] = hostel
147
148        # Create a bed
149        bed = Bed()
150        bed.bed_id = u'hall_block_room_bed'
151        bed.bed_number = 1
152        bed.bed_type = u'a_b_c'
153        self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed
154
155        self.container_path = 'http://localhost/app/hostels'
156        self.student_path = 'http://localhost/app/students/%s' % self.student_id
157        self.manage_container_path = self.container_path + '/@@manage'
158        self.add_hostel_path = self.container_path + '/addhostel'
159
160        # Put the prepopulated site into test ZODB and prepare test
161        # browser
162        self.browser = Browser()
163        self.browser.handleErrors = False
164
165        self.logfile = os.path.join(
166            self.app['datacenter'].storage, 'logs', 'hostels.log')
167
168    def tearDown(self):
169        super(HostelsFullSetup, self).tearDown()
170        clearSite()
171        shutil.rmtree(self.dc_root)
172
173class BedCatalogTests(HostelsFullSetup):
174
175    layer = FunctionalLayer
176
177    def test_get_catalog(self):
178        # We can get a beds catalog if we wish
179        cat = queryUtility(ICatalog, name='beds_catalog')
180        assert cat is not None
181
182    def test_search_by_type(self):
183        # We can find a certain bed
184        cat = queryUtility(ICatalog, name='beds_catalog')
185        results = cat.searchResults(bed_type=(u'a_b_c', u'a_b_c'))
186        results = [x for x in results] # Turn results generator into list
187        assert len(results) == 1
188        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
189
190    def test_search_by_owner(self):
191        # We can find a certain bed
192        myobj = self.app['hostels']['hall-x']['hall_block_room_bed']
193        myobj.owner = u'abc'
194        notify(grok.ObjectModifiedEvent(myobj))
195        cat = queryUtility(ICatalog, name='beds_catalog')
196        results = cat.searchResults(owner=(u'abc', u'abc'))
197        results = [x for x in results] # Turn results generator into list
198        assert len(results) == 1
199        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
200
201class HostelsUITests(HostelsFullSetup):
202
203    layer = FunctionalLayer
204
205    def test_anonymous_access(self):
206        # Anonymous users can't access hostels containers
207        self.assertRaises(
208            Unauthorized, self.browser.open, self.manage_container_path)
209        return
210
211    def test_add_search_edit_delete_manage_hostels(self):
212        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
213        self.browser.open(self.container_path)
214        self.browser.getLink("Manage accommodation").click()
215        self.assertEqual(self.browser.headers['Status'], '200 Ok')
216        self.assertEqual(self.browser.url, self.manage_container_path)
217        self.browser.getControl("Add hostel").click()
218        self.assertEqual(self.browser.headers['Status'], '200 Ok')
219        self.assertEqual(self.browser.url, self.add_hostel_path)
220        self.browser.getControl("Create hostel").click()
221        self.assertEqual(self.browser.headers['Status'], '200 Ok')
222        self.assertTrue('Hostel created' in self.browser.contents)
223        self.browser.open(self.container_path + '/addhostel')
224        self.browser.getControl("Create hostel").click()
225        self.assertTrue('The hostel already exists' in self.browser.contents)
226        hall = self.app['hostels']['hall-1']
227        hall.blocks_for_female = ['A','B']
228        self.browser.open(self.container_path + '/hall-1')
229        expected = '''...<ul id="form.blocks_for_female" ><li>Block A</li>
230<li>Block B</li></ul>...'''
231        self.assertMatches(expected,self.browser.contents)
232        self.browser.open(self.container_path + '/hall-1/manage')
233        self.browser.getControl(name="form.rooms_per_floor").value = '1'
234        self.browser.getControl("Save").click()
235        self.assertTrue('Form has been saved' in self.browser.contents)
236        # Since the testbrowser does not support Javascrip the
237        # save action cleared the settings above and we have to set them
238        # again
239        self.assertTrue(len(hall.blocks_for_female) == 0)
240        hall.blocks_for_female = ['A','B']
241        hall.beds_for_fresh = ['A']
242        hall.beds_for_returning = ['B']
243        hall.beds_for_final = ['C']
244        hall.beds_for_all = ['D','E']
245        self.browser.getControl("Update all beds").click()
246        expected = '...0 empty beds removed, 10 beds added, 0 occupied beds modified ()...'
247        self.assertMatches(expected,self.browser.contents)
248        cat = queryUtility(ICatalog, name='beds_catalog')
249        results = cat.searchResults(
250            bed_type=('regular_female_all', 'regular_female_all'))
251        results = [(x.bed_id, x.bed_type) for x in results]
252        self.assertEqual(results,
253            [(u'hall-1_A_101_D', u'regular_female_all'),
254             (u'hall-1_A_101_E', u'regular_female_all'),
255             (u'hall-1_B_101_D', u'regular_female_all'),
256             (u'hall-1_B_101_E', u'regular_female_all')])
257
258        # Reserve bed
259        self.browser.getControl("Switch reservation", index=0).click()
260        self.assertTrue('No item selected' in self.browser.contents)
261        ctrl = self.browser.getControl(name='val_id')
262        ctrl.getControl(value='hall-1_A_101_A').selected = True
263        ctrl.getControl(value='hall-1_A_101_B').selected = True
264        ctrl.getControl(value='hall-1_A_101_C').selected = True
265        ctrl.getControl(value='hall-1_A_101_D').selected = True
266        self.browser.getControl("Switch reservation", index=0).click()
267        self.assertTrue('Successfully switched beds: hall-1_A_101_A (reserved)'
268            in self.browser.contents)
269        self.assertEqual(self.app['hostels']['hall-1'][
270            'hall-1_A_101_D'].bed_type, 'regular_female_reserved')
271        self.assertTrue('A_101_A&nbsp;&nbsp;' in self.browser.contents)
272        # The catalog has been updated
273        results = cat.searchResults(
274            bed_type=('regular_female_all', 'regular_female_all'))
275        results = [(x.bed_id, x.bed_type) for x in results]
276        self.assertEqual(results,
277            [(u'hall-1_A_101_E', u'regular_female_all'),
278             (u'hall-1_B_101_D', u'regular_female_all'),
279             (u'hall-1_B_101_E', u'regular_female_all')])
280        results = cat.searchResults(
281            bed_type=('regular_female_reserved', 'regular_female_reserved'))
282        results = [(x.bed_id, x.bed_type) for x in results]
283        self.assertEqual(results,
284            [(u'hall-1_A_101_A', u'regular_female_reserved'),
285             (u'hall-1_A_101_B', u'regular_female_reserved'),
286             (u'hall-1_A_101_C', u'regular_female_reserved'),
287             (u'hall-1_A_101_D', u'regular_female_reserved')])
288
289        # Change hostel configuration with one bed booked
290        hall['hall-1_A_101_E'].owner = u'anyid'
291        notify(grok.ObjectModifiedEvent(hall['hall-1_A_101_E']))
292        hall.beds_for_fresh = ['A', 'E']
293        hall.beds_for_all = ['D']
294        self.browser.getControl("Update all beds").click()
295        expected = '...9 empty beds removed, 9 beds added, 1 occupied beds modified...'
296        self.assertMatches(expected,self.browser.contents)
297        # Updating beds (including booked beds!) does update catalog
298        results = cat.searchResults(
299            bed_type=('regular_female_all', 'regular_female_all'))
300        results = [(x.bed_id, x.bed_type) for x in results]
301        self.assertEqual(results,
302            [(u'hall-1_B_101_D', u'regular_female_all'),])
303        # Unreserve bed
304        ctrl = self.browser.getControl(name='val_id')
305        ctrl.getControl(value='hall-1_A_101_A').selected = True
306        ctrl.getControl(value='hall-1_A_101_B').selected = True
307        ctrl.getControl(value='hall-1_A_101_C').selected = True
308        ctrl.getControl(value='hall-1_A_101_D').selected = True
309        self.browser.getControl("Switch reservation", index=0).click()
310        assert self.app['hostels']['hall-1'][
311            'hall-1_A_101_D'].bed_type == 'regular_female_all'
312        self.assertFalse(expected in self.browser.contents)
313        # Release bed which has previously been booked
314        bedticket = BedTicket()
315        bedticket.booking_session = 2004
316        bedticket.bed_coordinates = u'anything'
317        self.student['accommodation'].addBedTicket(bedticket)
318        self.app['hostels']['hall-1']['hall-1_A_101_D'].owner = self.student_id
319        self.browser.open(self.container_path + '/hall-1/manage')
320        ctrl = self.browser.getControl(name='val_id')
321        self.browser.getControl("Release selected beds", index=0).click()
322        self.assertMatches("...No item selected...", self.browser.contents)
323        ctrl = self.browser.getControl(name='val_id')
324        ctrl.getControl(value='hall-1_A_101_D').selected = True
325        self.browser.getControl("Release selected beds", index=0).click()
326        self.assertMatches(
327          '...Successfully released beds: hall-1_A_101_D (%s)...' % self.student_id,
328          self.browser.contents)
329        self.assertMatches(bedticket.bed_coordinates,
330          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> UTC --')
331        # If we release a free be, nothing will happen
332        ctrl = self.browser.getControl(name='val_id')
333        ctrl.getControl(value='hall-1_A_101_D').selected = True
334        self.browser.getControl("Release selected beds", index=0).click()
335        self.assertMatches(
336          '...No allocated bed selected...', self.browser.contents)
337        # Managers can manually allocate eligible students after cancellation
338        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
339        # 'not occupied' is not accepted
340        self.browser.getControl("Save").click()
341        self.assertMatches(
342            "...No valid student id...",
343            self.browser.contents)
344        # Invalid student ids are not accepted
345        self.browser.getControl(name="form.owner").value = 'nonsense'
346        self.browser.getControl("Save").click()
347        self.assertMatches(
348            "...Either student does not exist or student "
349            "is not in accommodation session...",
350            self.browser.contents)
351        self.browser.getControl(name="form.owner").value = self.student_id
352        self.browser.getControl("Save").click()
353        self.assertMatches("...Form has been saved...", self.browser.contents)
354        # Students can only be allocated once
355        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_B')
356        self.browser.getControl(name="form.owner").value = self.student_id
357        self.browser.getControl("Save").click()
358        self.assertMatches(
359            "...This student resides in bed hall-1_A_101_A...",
360            self.browser.contents)
361        # If we open the same form again, we will be redirected to hostel
362        # manage page. Beds must be released first before they can be
363        # allocated to other students.
364        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
365        self.assertEqual(self.browser.url,
366            self.container_path + '/hall-1/@@manage#tab2')
367        # Updating the beds again will not affect the allocation and also
368        # the bed numbering remains the same
369        old_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
370        old_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
371        self.browser.getControl("Update all beds").click()
372        # 8 beds have been removed and re-added, 2 beds remains untouched
373        # because they are occupied
374        expected = '...8 empty beds removed, 8 beds added, 0 occupied beds modified...'
375        self.assertMatches(expected,self.browser.contents)
376        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
377        new_owner = self.app['hostels']['hall-1']['hall-1_A_101_A'].owner
378        self.assertEqual(new_number, old_number)
379        self.assertEqual(new_owner, old_owner)
380        # If we change the bed type of an allocated bed, the modification will
381        # be indicated
382        hall.blocks_for_female = ['B']
383        hall.blocks_for_male = ['A']
384        self.browser.getControl("Update all beds").click()
385        expected = '...8 empty beds removed, 8 beds added, ' + \
386            '2 occupied beds modified (hall-1_A_101_A, hall-1_A_101_E, )...'
387        self.assertMatches(expected,self.browser.contents)
388        new_number = self.app['hostels']['hall-1']['hall-1_A_101_A'].bed_number
389        # Also the number of the bed has changed.
390        self.assertFalse(new_number == old_number)
391        # The number of occupied beds are displayed on container page.
392        self.browser.open(self.container_path)
393        self.assertTrue('2 of 10' in self.browser.contents)
394        # Remove entire hostel
395        self.browser.open(self.manage_container_path)
396        ctrl = self.browser.getControl(name='val_id')
397        value = ctrl.options[0]
398        ctrl.getControl(value=value).selected = True
399        self.browser.getControl("Remove selected", index=0).click()
400        self.assertTrue('Successfully removed' in self.browser.contents)
401        # Catalog is empty
402        results = cat.searchResults(
403            bed_type=('regular_female_all', 'regular_female_all'))
404        results = [x for x in results]
405        assert len(results) == 0
406        # Actions are logged.
407        logcontent = open(self.logfile).read()
408        self.assertTrue(
409            'hall-1 - 9 empty beds removed, 9 beds added, 1 occupied '
410            'beds modified (hall-1_A_101_E, )'
411            in logcontent)
412
413    def test_clear_hostels(self):
414        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
415        self.browser.open(self.container_path)
416        self.browser.getLink("Manage accommodation").click()
417        self.browser.getControl("Add hostel").click()
418        self.browser.getControl("Create hostel").click()
419        hall = self.app['hostels']['hall-1']
420        hall.blocks_for_female = ['A','B']
421        hall.rooms_per_floor = 1
422        hall.beds_for_fresh = ['A']
423        hall.beds_for_returning = ['B']
424        hall.beds_for_final = ['C']
425        hall.beds_for_all = ['D','E']
426        self.browser.open(self.container_path + '/hall-1/manage')
427        self.browser.getControl("Update all beds").click()
428        cat = queryUtility(ICatalog, name='beds_catalog')
429        results = cat.searchResults(bed_type=(None, None))
430        self.assertEqual(len(results), 11)
431        self.browser.getControl("Clear hostel").click()
432        self.assertEqual(len(self.app['hostels']['hall-1']), 0)
433        # Only the bed in hall-x remains in the catalog.
434        results = cat.searchResults(bed_type=(None, None))
435        self.assertEqual(len(results), 1)
436        # We can clear all hostels at the same time.
437        self.browser.open(self.manage_container_path)
438        self.browser.getControl("Clear all hostels").click()
439        results = cat.searchResults(bed_type=(None, None))
440        self.assertEqual(len(results), 0)
441        # Both actions have been logged.
442        logcontent = open(self.logfile).read()
443        self.assertTrue('INFO - zope.mgr - hostels.browser.HostelManageFormPage'
444                        ' - hall-1 - cleared' in logcontent)
445        self.assertTrue('zope.mgr - hostels.browser.HostelsContainerManagePage'
446                        ' - hostels - all hostels cleared' in logcontent)
447
448class ExportTests(HostelsFullSetup):
449
450    layer = FunctionalLayer
451
452    def setUp(self):
453        super(ExportTests, self).setUp()
454        self.workdir = tempfile.mkdtemp()
455        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
456        return
457
458    def test_export_hostels(self):
459        exporter = HostelExporter()
460        exporter.export_all(self.app, self.outfile)
461        result = open(self.outfile, 'rb').read()
462        self.assertEqual(
463            result,
464            'beds_for_all,beds_for_final,beds_for_fresh,beds_for_pre,'
465            'beds_for_returning,beds_reserved,blocks_for_female,'
466            'blocks_for_male,floors_per_block,hostel_id,hostel_name,maint_fee,'
467            'rooms_per_floor,sort_id,special_handling\r\n,,,,,[],,,1,'
468            'hall-x,Hall 1,0.0,2,10,regular\r\n'
469            )
470        return
471
472    def test_export_beds(self):
473        exporter = BedExporter()
474        exporter.export_all(self.app, self.outfile)
475        result = open(self.outfile, 'rb').read()
476        self.assertEqual(
477            result,
478            'bed_id,bed_number,bed_type,owner,hall,block,room,bed,'
479            'special_handling,sex,bt\r\nhall_block_room_bed,1,a_b_c,,'
480            'hall,block,room,bed,a,b,c\r\n'
481            )
482        return
483
484    def tearDown(self):
485        super(ExportTests, self).tearDown()
486        clearSite()
487        shutil.rmtree(os.path.dirname(self.outfile))
488
489class HostelProcessorTest(HostelsFullSetup):
490
491    layer = FunctionalLayer
492
493    def test_import(self):
494        self.processor = HostelProcessor()
495        self.workdir = tempfile.mkdtemp()
496        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
497        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
498        num, num_warns, fin_file, fail_file = self.processor.doImport(
499            self.csv_file, HOSTEL_HEADER_FIELDS)
500        self.assertEqual(num_warns,0)
501        self.assertEqual(len(self.app['hostels'].keys()), 11) # including hall-x
502        self.assertEqual(self.app['hostels'][
503            'block-a-upper-hostel'].hostel_id,'block-a-upper-hostel')
504        self.assertEqual(self.app['hostels'][
505            'block-a-upper-hostel'].beds_for_final, ['A', 'B'])
506        logcontent = open(self.logfile).read()
507        self.assertTrue(
508            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
509            "updated: "
510            "beds_for_pre=['G'], floors_per_block=1, "
511            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
512            "hostel_id=block-a-upper-hostel, "
513            "sort_id=20, beds_for_returning=['C', 'D'], "
514            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
515            "blocks_for_female=['A']"
516            in logcontent)
517        shutil.rmtree(os.path.dirname(fin_file))
518        shutil.rmtree(self.workdir)
519        return
520
521    def test_import_update(self):
522        self.processor = HostelProcessor()
523        self.workdir = tempfile.mkdtemp()
524        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
525        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
526        self.csv_file = os.path.join(self.workdir, 'sample_hostel_data.csv')
527        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
528        num, num_warns, fin_file, fail_file = self.processor.doImport(
529            self.csv_file, HOSTEL_HEADER_FIELDS)
530        # We import the same file in update mode
531        num, num_warns, fin_file, fail_file = self.processor.doImport(
532            self.csv_file, HOSTEL_HEADER_FIELDS, 'update')
533        self.assertEqual(num_warns,0)
534        logcontent = open(self.logfile).read()
535        self.assertTrue(
536            "Hostel Processor - sample_hostel_data - block-a-upper-hostel - "
537            "updated: "
538            "beds_for_pre=['G'], floors_per_block=1, "
539            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
540            "hostel_id=block-a-upper-hostel, "
541            "sort_id=20, beds_for_returning=['C', 'D'], "
542            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
543            "blocks_for_female=['A']"
544            in logcontent)
545        shutil.rmtree(os.path.dirname(fin_file))
546        shutil.rmtree(self.workdir)
547        return
Note: See TracBrowser for help on using the repository browser.