Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/batching.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/batching.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/batching.py	(revision 9209)
@@ -0,0 +1,91 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Batch processing components for hostels.
+
+"""
+import grok
+from zope.interface import Interface
+from waeup.kofa.interfaces import IBatchProcessor, IGNORE_MARKER
+from waeup.kofa.utils.batching import BatchProcessor
+from waeup.kofa.hostels.interfaces import IHostel
+
+class HostelProcessor(BatchProcessor):
+    """A batch processor for IUserAccount objects.
+    """
+    grok.implements(IBatchProcessor)
+    grok.provides(IBatchProcessor)
+    grok.context(Interface)
+    util_name = 'hostelprocessor'
+    grok.name(util_name)
+
+    name = u'Hostel Processor'
+    iface = IHostel
+
+    location_fields = ['hostel_id',]
+    factory_name = 'waeup.Hostel'
+
+    mode = None
+
+    def parentsExist(self, row, site):
+        return 'hostels' in site.keys()
+
+    def entryExists(self, row, site):
+        return row['hostel_id'] in site['hostels'].keys()
+
+    def getParent(self, row, site):
+        return site['hostels']
+
+    def getEntry(self, row, site):
+        if not self.entryExists(row, site):
+            return None
+        parent = self.getParent(row, site)
+        return parent.get(row['hostel_id'])
+
+    def addEntry(self, obj, row, site):
+        parent = self.getParent(row, site)
+        parent.addHostel(obj)
+        return
+
+    def updateEntry(self, obj, row, site):
+        """Update obj to the values given in row.
+
+        Returns a string describing the fields changed.
+        """
+        changed = []
+        for key, value in row.items():
+            # Skip fields to be ignored.
+            if value == IGNORE_MARKER:
+                continue
+            if not hasattr(obj, key):
+                continue
+            try:
+                evalvalue = eval(value)
+                if isinstance(evalvalue, list):
+                    value = eval(value)
+            except:
+                pass
+            setattr(obj, key, value)
+            log_value = getattr(value, 'code', value)
+            changed.append('%s=%s' % (key, log_value))
+
+        # Log actions...
+        location_field = self.location_fields[0]
+        items_changed = ', '.join(changed)
+        grok.getSite()['hostels'].logger.info('%s - %s - Record updated: %s'
+            % (self.name, row[location_field], items_changed))
+        return
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/browser.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/browser.py	(revision 9166)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/browser.py	(revision 9209)
@@ -93,5 +93,5 @@
 
     def title(self):
-        co = self.context.getBedCoordinates()
+        co = self.context.coordinates
         return _('Block ${a}, Room ${b}, Bed ${c}',
             mapping = {'a':co[1], 'b':co[2], 'c':co[3]})
@@ -130,5 +130,7 @@
     form_fields = grok.AutoFields(IHostelsContainer)
     taboneactions = [_('Save')]
-    tabtwoactions = [_('Add hostel'), _('Remove selected')]
+    tabtwoactions = [_('Add hostel'),
+        _('Clear all hostels'),
+        _('Remove selected')]
 
     def update(self):
@@ -164,4 +166,12 @@
         return
 
+    @jsaction(_('Clear all hostels'))
+    def clearHostels(self, **data):
+        self.context.clearAllHostels()
+        self.flash(_('All hostels cleared.'))
+        write_log_message(self, 'all hostels cleared')
+        self.redirect(self.url(self.context, '@@manage')+'?tab2')
+        return
+
     @action(_('Save'), style='primary')
     def save(self, **data):
@@ -232,5 +242,6 @@
     tabtwoactions = [_('Update all beds'),
         _('Switch reservation of selected beds'),
-        _('Release selected beds')]
+        _('Release selected beds'),
+        _('Clear hostel')]
     not_occupied = NOT_OCCUPIED
 
@@ -243,4 +254,5 @@
         tabs.need()
         datatable.need()
+        warning.need()
         self.tab1 = self.tab2 = ''
         qs = self.request.get('QUERY_STRING', '')
@@ -327,4 +339,12 @@
         return
 
+    @jsaction(_('Clear hostel'))
+    def clearHostel(self, **data):
+        self.context.clearHostel()
+        self.flash(_('Hostel cleared.'))
+        write_log_message(self, 'cleared')
+        self.redirect(self.url(self.context, '@@manage')+'?tab2')
+        return
+
 class BedManageFormPage(KofaEditFormPage):
     """ View to edit bed data
@@ -334,5 +354,5 @@
     grok.require('waeup.manageHostels')
     form_fields = grok.AutoFields(IBedAllocateStudent).omit(
-        'bed_id').omit('bed_number').omit('bed_type')
+        'bed_id', 'bed_number', 'bed_type')
     label = _('Allocate student')
     pnav = 5
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/browser_templates/containerpage.pt
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/browser_templates/containerpage.pt	(revision 9166)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/browser_templates/containerpage.pt	(revision 9209)
@@ -21,12 +21,18 @@
       <th i18n:translate="">Id</th>
       <th i18n:translate="">Name</th>
+      <th i18n:translate="">Booked Beds</th>
     </tr>
   </thead>
   <tbody>
-    <tr tal:repeat="value context/values">
-      <td> <a tal:attributes="href value/__name__">
-          <span tal:content="value/hostel_id">ID</span></a></td>
-      <td tal:content="value/hostel_name">NAME</td>
-    </tr>
+    <tal:tbody repeat="value context/values">
+      <tr tal:define = "stats value/bed_statistics">
+        <td> <a tal:attributes="href value/__name__">
+            <span tal:content="value/hostel_id">ID</span></a></td>
+        <td tal:content="value/hostel_name">NAME</td>
+        <td>
+          <span tal:replace="stats/booked">10</span> of <span tal:replace="stats/total">100</span>
+        </td>
+      </tr>
+    </tal:tbody>
   </tbody>
 </table>
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/container.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/container.py	(revision 9166)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/container.py	(revision 9209)
@@ -51,4 +51,11 @@
         return
 
+    def clearAllHostels(self):
+        """Clear all hostels.
+        """
+        for hostel in self.values():
+            hostel.clearHostel()
+        return
+
     logger_name = 'waeup.kofa.${sitename}.hostels'
     logger_filename = 'hostels.log'
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/export.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/export.py	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/export.py	(revision 9209)
@@ -0,0 +1,75 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Exporters for hostels and beds.
+"""
+import grok
+from zope.securitypolicy.interfaces import IPrincipalRoleMap
+from waeup.kofa.interfaces import ICSVExporter
+from waeup.kofa.interfaces import MessageFactory as _
+from waeup.kofa.utils.batching import ExporterBase
+from waeup.kofa.utils.helpers import iface_names
+from waeup.kofa.hostels.interfaces import IBed, IHostel
+
+class HostelExporter(grok.GlobalUtility, ExporterBase):
+    """Exporter for hostels.
+    """
+    grok.implements(ICSVExporter)
+    grok.name('hostels')
+
+    #: Fieldnames considered by this exporter
+    fields = tuple(sorted(iface_names(IHostel))) 
+
+    #: The title under which this exporter will be displayed
+    title = _(u'Hostels')
+
+    def export_all(self, site, filepath=None):
+        """Export hostels into filepath as CSV data.
+
+        If `filepath` is ``None``, a raw string with CSV data is returned.
+        """
+        writer, outfile = self.get_csv_writer(filepath)
+        hostels = site.get('hostels', {})
+        for hostel in hostels.values():
+            self.write_item(hostel, writer)
+        return self.close_outfile(filepath, outfile)
+
+class BedExporter(grok.GlobalUtility, ExporterBase):
+    """Exporter for courses.
+    """
+    grok.implements(ICSVExporter)
+    grok.name('beds')
+
+    #: Fieldnames considered by this exporter
+    fields = tuple(sorted(iface_names(IBed))) + (
+        'hall', 'block', 'room', 'bed', 'special_handling', 'sex', 'bt')
+
+    #: The title under which this exporter will be displayed
+    title = _(u'Beds')
+
+    def export_all(self, site, filepath=None):
+        """Export beds into filepath as CSV data.
+
+        If `filepath` is ``None``, a raw string with CSV data is returned.
+        """
+        writer, outfile = self.get_csv_writer(filepath)
+        hostels = site.get('hostels', {})
+        for hostel in hostels.values():
+            for bed in hostel.values():
+                self.write_item(bed, writer)
+        return self.close_outfile(filepath, outfile)
+
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/hostel.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/hostel.py	(revision 9166)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/hostel.py	(revision 9209)
@@ -22,4 +22,5 @@
 from zope.event import notify
 from zope.component import getUtility
+from zope.component.interfaces import IFactory
 from datetime import datetime
 from waeup.kofa.utils.helpers import attrs_to_fields
@@ -40,4 +41,21 @@
         target = self.__name__
         return grok.getSite()['hostels'].logger_info(ob_class,target,comment)
+
+    @property
+    def bed_statistics(self):
+        total = len(self.keys())
+        booked = 0
+        for value in self.values():
+            if value.owner != NOT_OCCUPIED:
+                booked += 1
+        return {'booked':booked, 'total':total}
+
+    def clearHostel(self):
+        """Remove all beds
+        """
+        keys = [i for i in self.keys()] # create deep copy
+        for bed in keys:
+            del self[bed]
+        return
 
     def addBed(self, bed):
@@ -128,8 +146,41 @@
     grok.provides(IBed)
 
-    def getBedCoordinates(self):
+    @property
+    def coordinates(self):
         """Determine the coordinates from the bed_id.
         """
         return self.bed_id.split('_')
+
+    # The following property attributes are only needed
+    # for the exporter to ease evaluation with  Excel.
+
+    @property
+    def hall(self):
+        return self.coordinates[0]
+
+    @property
+    def block(self):
+        return self.coordinates[1]
+
+    @property
+    def room(self):
+        return self.coordinates[2]
+
+    @property
+    def bed(self):
+        return self.coordinates[3]
+
+    @property
+    def special_handling(self):
+        return self.bed_type.split('_')[0]
+
+    @property
+    def sex(self):
+        return self.bed_type.split('_')[1]
+
+    @property
+    def bt(self):
+        return self.bed_type.split('_')[2]
+
 
     def bookBed(self, student_id):
@@ -145,5 +196,5 @@
         """
         sh, sex, bt = self.bed_type.split('_')
-        hostel_id, block, room_nr, bed = self.getBedCoordinates()
+        hostel_id, block, room_nr, bed = self.coordinates
         hostel = self.__parent__
         beds_for_fresh = getattr(hostel,'beds_for_fresh',[])
@@ -221,4 +272,21 @@
 Bed = attrs_to_fields(Bed)
 
+class HostelFactory(grok.GlobalUtility):
+    """A factory for hostels.
+
+    We need this factory for the hostel processor.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.Hostel')
+    title = u"Create a new hostel.",
+    description = u"This factory instantiates new hostel instances."
+
+    def __call__(self, *args, **kw):
+        return Hostel()
+
+    def getInterfaces(self):
+        return implementedBy(Hostel)
+
+
 @grok.subscribe(IBedTicket, grok.IObjectRemovedEvent)
 def handle_bedticket_removed(bedticket, event):
@@ -229,2 +297,3 @@
         bedticket.bed.owner = NOT_OCCUPIED
         notify(grok.ObjectModifiedEvent(bedticket.bed))
+
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/interfaces.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/interfaces.py	(revision 9166)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/interfaces.py	(revision 9209)
@@ -17,5 +17,5 @@
 ##
 from datetime import datetime
-from zope.interface import invariant, Invalid
+from zope.interface import invariant, Invalid, Attribute
 from zope import schema
 from waeup.kofa.interfaces import (
@@ -58,4 +58,8 @@
         )
 
+    def clearAllHostels():
+        """Clear all hostels.
+        """
+
 class IHostel(IKofaObject):
     """A base representation of hostels.
@@ -63,6 +67,12 @@
     """
 
+    bed_statistics = Attribute('Number of booked and total beds')
+
     def loggerInfo(ob_class, comment):
         """Adds an INFO message to the log file
+        """
+
+    def clearHostel():
+        """Remove all beds.
         """
 
@@ -125,4 +135,11 @@
         )
 
+    beds_for_pre= schema.List(
+        title = _(u'Beds for Pre-Study Students'),
+        value_type = schema.Choice(
+            vocabulary = bed_letters
+            ),
+        )
+
     beds_for_fresh = schema.List(
         title = _(u'Beds for Fresh Students'),
@@ -172,4 +189,5 @@
                 hostel.beds_for_returning +
                 hostel.beds_for_final +
+                hostel.beds_for_pre +
                 hostel.beds_for_all)
         if len(beds) != len(set(beds)):
@@ -181,11 +199,10 @@
     """
 
+    coordinates = Attribute('The coordinates of the bed from bed_id')
+
     def loggerInfo(ob_class, comment):
         """Adds an INFO message to the log file
         """
 
-    def getBedCoordinates():
-        """Determine the coordinates from bed_id.
-        """
     def bookBed(student_id):
         """Book a bed for a student.
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/sample_hostel_data.csv
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/sample_hostel_data.csv	(revision 9209)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/sample_hostel_data.csv	(revision 9209)
@@ -0,0 +1,11 @@
+beds_for_all,beds_for_final,beds_for_fresh,beds_for_pre,beds_for_returning,beds_reserved,blocks_for_female,blocks_for_male,floors_per_block,hostel_id,hostel_name,rooms_per_floor,sort_id,special_handling
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['A'],[],1,block-a-upper-hostel,Block A Upper Hostel,32,20,regular
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['B'],[],1,block-b-upper-hostel,Block B Upper Hostel,32,30,regular
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['C'],[],1,block-c-upper-hostel,Block C Upper Hostel,32,40,regular
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['D'],[],1,block-d-upper-hostel,Block D Upper Hostel,32,50,regular
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['E'],[],1,block-e-down-hostel,Block E Down Hostel,32,60,regular
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['F'],[],1,block-f-down-hostel,Block F Down Hostel,32,70,regular
+[],"['A', 'B']","['E', 'F']",['G'],"['C', 'D']",[],['G'],[],1,block-g-down-hostel,Block G Down Hostel,32,80,regular
+[],"['A', 'B']","['D', 'E']",['F'],['C'],[],[],"['A', 'B']",1,hall-a,Hall A,44,90,regular
+[],"['A', 'B']","['D', 'E']",['F'],['C'],[],[],"['C', 'D']",1,hall-b,Hall B,44,100,regular
+[],[],[],[],[],[],[],['A'],1,stores-32,Stores 32,16,10,regular
Index: main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/tests.py
===================================================================
--- main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/tests.py	(revision 9166)
+++ main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/hostels/tests.py	(revision 9209)
@@ -19,4 +19,5 @@
 Tests for hostels and their UI components.
 """
+import os
 import shutil
 import tempfile
@@ -36,8 +37,17 @@
 from waeup.kofa.hostels.container import HostelsContainer
 from waeup.kofa.hostels.hostel import Hostel, Bed
+from waeup.kofa.hostels.batching import HostelProcessor
+from waeup.kofa.hostels.export import BedExporter, HostelExporter
 from waeup.kofa.testing import (FunctionalLayer, FunctionalTestCase)
 from waeup.kofa.students.student import Student
 from waeup.kofa.students.accommodation import BedTicket
 from waeup.kofa.university.department import Department
+
+HOSTEL_SAMPLE_DATA = open(
+    os.path.join(os.path.dirname(__file__), 'sample_hostel_data.csv'),
+    'rb').read()
+
+HOSTEL_HEADER_FIELDS = HOSTEL_SAMPLE_DATA.split(
+    '\n')[0].split(',')
 
 class HostelsContainerTestCase(FunctionalTestCase):
@@ -142,7 +152,7 @@
         # Create a bed
         bed = Bed()
-        bed.bed_id = u'xyz'
+        bed.bed_id = u'hall_block_room_bed'
         bed.bed_number = 1
-        bed.bed_type = u'abc'
+        bed.bed_type = u'a_b_c'
         self.app['hostels'][hostel.hostel_id][bed.bed_id] = bed
 
@@ -157,4 +167,7 @@
         self.browser.handleErrors = False
 
+        self.logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'hostels.log')
+
     def tearDown(self):
         super(HostelsFullSetup, self).tearDown()
@@ -174,12 +187,12 @@
         # We can find a certain bed
         cat = queryUtility(ICatalog, name='beds_catalog')
-        results = cat.searchResults(bed_type=(u'abc', u'abc'))
+        results = cat.searchResults(bed_type=(u'a_b_c', u'a_b_c'))
         results = [x for x in results] # Turn results generator into list
         assert len(results) == 1
-        assert results[0] is self.app['hostels']['hall-x']['xyz']
+        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
 
     def test_search_by_owner(self):
         # We can find a certain bed
-        myobj = self.app['hostels']['hall-x']['xyz']
+        myobj = self.app['hostels']['hall-x']['hall_block_room_bed']
         myobj.owner = u'abc'
         notify(grok.ObjectModifiedEvent(myobj))
@@ -188,5 +201,5 @@
         results = [x for x in results] # Turn results generator into list
         assert len(results) == 1
-        assert results[0] is self.app['hostels']['hall-x']['xyz']
+        assert results[0] is self.app['hostels']['hall-x']['hall_block_room_bed']
 
 class HostelsUITests(HostelsFullSetup):
@@ -300,5 +313,5 @@
         self.assertMatches(
           '...No allocated bed selected...', self.browser.contents)
-        # Managers can manually allocate studenst after cancellation
+        # Managers can manually allocate students after cancellation
         self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
         self.browser.getControl(name="form.owner").value = [self.student_id]
@@ -334,4 +347,7 @@
         # Also the number of the bed has changed.
         self.assertFalse(new_number == old_number)
+        # The number of occupied bed are displayed on container page.
+        self.browser.open(self.container_path)
+        self.assertTrue('1 of 8' in self.browser.contents)
         # Remove entire hostel
         self.browser.open(self.manage_container_path)
@@ -346,2 +362,103 @@
         results = [x for x in results]
         assert len(results) == 0
+
+    def test_clear_hostels(self):
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.container_path)
+        self.browser.getLink("Manage accommodation").click()
+        self.browser.getControl("Add hostel").click()
+        self.browser.getControl("Create hostel").click()
+        hall = self.app['hostels']['hall-1']
+        hall.blocks_for_female = ['A','B']
+        hall.rooms_per_floor = 1
+        hall.beds_for_fresh = ['A']
+        hall.beds_for_returning = ['B']
+        hall.beds_for_final = ['C']
+        hall.beds_for_all = ['D','E']
+        self.browser.open(self.container_path + '/hall-1/manage')
+        self.browser.getControl("Update all beds").click()
+        cat = queryUtility(ICatalog, name='beds_catalog')
+        results = cat.searchResults(bed_type=(None, None))
+        self.assertEqual(len(results), 11)
+        self.browser.getControl("Clear hostel").click()
+        self.assertEqual(len(self.app['hostels']['hall-1']), 0)
+        # Only the bed in hall-x remains in the catalog.
+        results = cat.searchResults(bed_type=(None, None))
+        self.assertEqual(len(results), 1)
+        # We can clear all hostels at the same time.
+        self.browser.open(self.manage_container_path)
+        self.browser.getControl("Clear all hostels").click()
+        results = cat.searchResults(bed_type=(None, None))
+        self.assertEqual(len(results), 0)
+        # Both actions have been logged.
+        logcontent = open(self.logfile).read()
+        self.assertTrue('INFO - zope.mgr - hostels.browser.HostelManageFormPage'
+                        ' - hall-1 - cleared' in logcontent)
+        self.assertTrue('zope.mgr - hostels.browser.HostelsContainerManagePage'
+                        ' - hostels - all hostels cleared' in logcontent)
+
+class ExportTests(HostelsFullSetup):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(ExportTests, self).setUp()
+        self.workdir = tempfile.mkdtemp()
+        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
+        return
+
+    def test_export_hostels(self):
+        exporter = HostelExporter()
+        exporter.export_all(self.app, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'beds_for_all,beds_for_final,beds_for_fresh,beds_for_pre,'
+            'beds_for_returning,beds_reserved,blocks_for_female,'
+            'blocks_for_male,floors_per_block,hostel_id,hostel_name,'
+            'rooms_per_floor,sort_id,special_handling\r\n,,,,,[],,,1,'
+            'hall-x,Hall 1,2,10,regular\r\n'
+            )
+        return
+
+    def test_export_beds(self):
+        exporter = BedExporter()
+        exporter.export_all(self.app, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'bed_id,bed_number,bed_type,owner,hall,block,room,bed,'
+            'special_handling,sex,bt\r\nhall_block_room_bed,1,a_b_c,,'
+            'hall,block,room,bed,a,b,c\r\n'
+            )
+        return
+
+class HostelProcessorTest(HostelsFullSetup):
+
+    layer = FunctionalLayer
+
+    def test_import(self):
+        self.processor = HostelProcessor()
+        self.workdir = tempfile.mkdtemp()
+        self.csv_file = os.path.join(self.workdir, 'sample_student_data.csv')
+        open(self.csv_file, 'wb').write(HOSTEL_SAMPLE_DATA)
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file, HOSTEL_HEADER_FIELDS)
+        self.assertEqual(num_warns,0)
+        self.assertEqual(len(self.app['hostels'].keys()), 11) # including hall-x
+        self.assertEqual(self.app['hostels'][
+            'block-a-upper-hostel'].hostel_id,'block-a-upper-hostel')
+        self.assertEqual(self.app['hostels'][
+            'block-a-upper-hostel'].beds_for_final, ['A', 'B'])
+        logcontent = open(self.logfile).read()
+        self.assertTrue(
+            "Hostel Processor - block-a-upper-hostel - "
+            "Record updated: beds_for_pre=['G'], floors_per_block=1, "
+            "beds_for_final=['A', 'B'], rooms_per_floor=32, "
+            "blocks_for_male=[], hostel_id=block-a-upper-hostel, "
+            "sort_id=20, beds_for_returning=['C', 'D'], "
+            "hostel_name=Block A Upper Hostel, beds_for_fresh=['E', 'F'], "
+            "blocks_for_female=['A'], beds_for_all=[], beds_reserved=[]"
+            in logcontent)
+        shutil.rmtree(os.path.dirname(fin_file))
+        return
