source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_customer.py @ 12200

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

Add customer documents exporter.

  • Property svn:keywords set to Id
File size: 8.2 KB
Line 
1## $Id: test_customer.py 12006 2014-11-20 08:32:17Z henrik $
2##
3## Copyright (C) 2014 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"""Tests for customers and related.
19"""
20import os
21import re
22import unittest
23import grok
24from cStringIO import StringIO
25from datetime import tzinfo
26from zope.component import getUtility, queryUtility, createObject
27from zope.catalog.interfaces import ICatalog
28from zope.component.interfaces import IFactory
29from zope.event import notify
30from zope.interface import verify
31from zope.schema.interfaces import RequiredMissing
32from waeup.ikoba.interfaces import IExtFileStore, IFileStoreNameChooser
33from waeup.ikoba.customers.export import EXPORTER_NAMES
34from waeup.ikoba.customers.customer import (
35    Customer, CustomerFactory, handle_customer_removed, path_from_custid)
36from waeup.ikoba.customers.interfaces import (
37    ICustomer, ICustomerNavigation)
38from waeup.ikoba.customers.tests.test_batching import CustomerImportExportSetup
39from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
40
41class HelperTests(unittest.TestCase):
42    # Tests for helper functions in customer module.
43
44    def test_path_from_custid(self):
45        # make sure we get predictable paths from customer ids.
46        self.assertEqual(
47            path_from_custid('K1000000'), u'01000/K1000000')
48        self.assertEqual(
49            path_from_custid('K1234567'), u'01234/K1234567')
50        self.assertEqual(
51            path_from_custid('K12345678'), u'12345/K12345678')
52        # The algorithm works also for overlong numbers, just to be
53        # sure.
54        self.assertEqual(
55            path_from_custid('K123456789'), u'123456/K123456789')
56        # low numbers (< 10**6) are treated special: they get max. of
57        # 10,000 entries. That's mainly because of old customers
58        # migrated into our portal.
59        self.assertEqual(
60            path_from_custid('KM123456'), u'00120/KM123456')
61        return
62
63class CustomerTest(FunctionalTestCase):
64
65    layer = FunctionalLayer
66
67    def setUp(self):
68        super(CustomerTest, self).setUp()
69        self.customer = Customer()
70        self.customer.firstname = u'Anna'
71        self.customer.lastname = u'Tester'
72        return
73
74    def tearDown(self):
75        super(CustomerTest, self).tearDown()
76        return
77
78    def test_interfaces(self):
79        verify.verifyClass(ICustomer, Customer)
80        verify.verifyClass(ICustomerNavigation, Customer)
81        verify.verifyObject(ICustomer, self.customer)
82        verify.verifyObject(ICustomerNavigation, self.customer)
83        return
84
85    #def test_base(self):
86    #    department = Department()
87    #    studycourse = CustomerStudyCourse()
88    #    self.assertRaises(
89    #        TypeError, studycourse.addCustomerStudyLevel, department)
90    #    studylevel = CustomerStudyLevel()
91    #    self.assertRaises(
92    #        TypeError, studylevel.addCourseTicket, department, department)
93
94
95class CustomerRemovalTests(CustomerImportExportSetup):
96    # Test handle_customer_removed
97    #
98    # This is a complex action updating several CSV files and moving
99    # stored files to a backup location.
100    #
101    # These tests make no assumptions about the CSV files except that
102    # they contain a deletion timestamp at end of each data row
103
104    layer = FunctionalLayer
105
106    def setUp(self):
107        super(CustomerRemovalTests, self).setUp()
108        self.setup_for_export()
109        return
110
111    def create_passport_img(self, customer):
112        # create some passport file for `customer`
113        storage = getUtility(IExtFileStore)
114        image_path = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
115        self.image_contents = open(image_path, 'rb').read()
116        file_id = IFileStoreNameChooser(customer).chooseName(
117            attr='passport.jpg')
118        storage.createFile(file_id, StringIO(self.image_contents))
119
120    def test_backup_single_customer_data(self):
121        # when a single customer is removed, the data is backed up.
122        self.setup_customer(self.customer)
123        # Add a fake image
124        self.create_passport_img(self.customer)
125        handle_customer_removed(self.customer, None)
126        del_dir = self.app['datacenter'].deleted_path
127        del_img_path = os.path.join(
128            del_dir, 'media', 'customers', '00110', 'A111111',
129            'passport_A111111.jpg')
130
131        # The image was copied over
132        self.assertTrue(os.path.isfile(del_img_path))
133        self.assertEqual(
134            open(del_img_path, 'rb').read(),
135            self.image_contents)
136
137        # The customer data were put into CSV files
138        for name in EXPORTER_NAMES:
139            csv_path = os.path.join(del_dir, '%s.csv' % name)
140            self.assertTrue(os.path.isfile(csv_path))
141            contents = open(csv_path, 'rb').read().split('\r\n')
142            # We expect 3 lines output including a linebreak at end of file.
143            self.assertEqual(len(contents), 3)
144        return
145
146    def test_backup_append_csv(self):
147        # when several customers are removed, existing CSVs are appended
148        self.setup_customer(self.customer)
149        # Add a fake image
150        self.create_passport_img(self.customer)
151        del_dir = self.app['datacenter'].deleted_path
152        # put fake data into customers.csv with trailing linebreak
153        customers_csv = os.path.join(del_dir, 'customers.csv')
154        open(customers_csv, 'wb').write('line1\r\nline2\r\n')
155        handle_customer_removed(self.customer, None)
156        contents = open(customers_csv, 'rb').read().split('\r\n')
157        # there should be 4 lines in result csv (including trailing linebreak)
158        self.assertEqual(len(contents), 4)
159        return
160
161    def test_old_files_removed(self):
162        # make sure old files are not accessible any more
163        self.setup_customer(self.customer)
164        # Add a fake image
165        self.create_passport_img(self.customer)
166        # make sure we can access the image before removal
167        file_store = getUtility(IExtFileStore)
168        image = file_store.getFileByContext(self.customer, attr='passport.jpg')
169        self.assertTrue(image is not None)
170
171        # remove image (hopefully)
172        handle_customer_removed(self.customer, None)
173
174        # the is not accessible anymore
175        image = file_store.getFileByContext(self.customer, attr='passport.jpg')
176        self.assertEqual(image, None)
177        return
178
179    def test_csv_file_entries_have_timestamp(self):
180        # each row in written csv files has a ``del_date`` column to
181        # tell when the associated customer was deleted
182        self.setup_customer(self.customer)
183        del_dir = self.app['datacenter'].deleted_path
184        customers_csv = os.path.join(del_dir, 'customers.csv')
185        handle_customer_removed(self.customer, None)
186        contents = open(customers_csv, 'rb').read().split('\r\n')
187        # the CSV header ends with a ``del_date`` column
188        self.assertTrue(contents[0].endswith(',del_date'))
189        # each line ends with an UTC timestamp
190        timestamp = contents[1][-23:]
191        self.assertTrue(re.match(
192            '^\d\d-\d\d-\d\d \d\d:\d\d:\d\d\+00:00$', timestamp))
193        return
194
195class CustomerFactoryTest(FunctionalTestCase):
196
197    layer = FunctionalLayer
198
199    def setUp(self):
200        super(CustomerFactoryTest, self).setUp()
201        self.factory = CustomerFactory()
202
203    def tearDown(self):
204        super(CustomerFactoryTest, self).tearDown()
205
206    def test_interfaces(self):
207        verify.verifyClass(IFactory, CustomerFactory)
208        verify.verifyObject(IFactory, self.factory)
209
210    def test_factory(self):
211        obj = self.factory()
212        assert isinstance(obj, Customer)
213
214    def test_getInterfaces(self):
215        implemented_by = self.factory.getInterfaces()
216        assert implemented_by.isOrExtends(ICustomer)
Note: See TracBrowser for help on using the repository browser.