source: main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_logger.py @ 9855

Last change on this file since 9855 was 9283, checked in by Henrik Bettermann, 12 years ago

Remove temporary dirs in tests.

  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1## $Id: test_logger.py 9283 2012-10-03 21:36:14Z 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
19# Tests for waeup.kofa.utils.logger
20import logging
21import os
22import shutil
23import tempfile
24from zope.component import queryUtility
25from zope.component.hooks import setSite, clearSite
26from zope.interface.verify import verifyClass, verifyObject
27from waeup.kofa.app import University
28from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
29
30from waeup.kofa.utils.logger import (
31    Logger, MAX_BYTES, BACKUP_COUNT, ILoggerCollector, LoggerCollector,
32    ILogger)
33
34class FakeComponent(object):
35    # A component that can use the Logger mixin-class
36    def do_something(self):
37        self.logger.info('msg from do_something')
38
39class LoggingComponent(FakeComponent, Logger):
40    # A component that supports logging by mixing in Logger
41    logger_name = 'sample.${sitename}'
42    logger_filename = 'sample.log'
43
44class LoggersTests(FunctionalTestCase):
45
46    layer = FunctionalLayer
47
48    def setUp(self):
49        super(LoggersTests, self).setUp()
50        # Setup a sample site for each test
51        app = University()
52        self.dc_root = tempfile.mkdtemp()
53        self.dc_root2 = None
54        app['datacenter'].setStoragePath(self.dc_root)
55
56        # Prepopulate the ZODB...
57        self.getRootFolder()['app'] = app
58        self.app = self.getRootFolder()['app']
59        self.workdir = tempfile.mkdtemp()
60        return
61
62    def tearDown(self):
63        super(LoggersTests, self).tearDown()
64        shutil.rmtree(self.workdir)
65        shutil.rmtree(self.dc_root)
66        clearSite()
67        return
68
69    def clear_logger(self, logger):
70        del_list = [x for x in logger.handlers]
71        for handler in del_list:
72            logger.removeHandler(handler)
73        return
74
75    def test_iface(self):
76        setSite(self.app)
77        logger = LoggingComponent()
78        verifyClass(ILogger, Logger)
79        verifyObject(ILogger, logger)
80        return
81
82    def test_logger_prop_no_site(self):
83        # If not in a site, we will get a logger without handlers
84        logger = Logger().logger
85        self.assertTrue(isinstance(logger, logging.Logger))
86        self.assertEqual(len(logger.handlers), 0)
87        return
88
89    def test_site_no_site_name(self):
90        # If a site has not name we will get a logger anyway
91        setSite(self.app)
92        del self.app.__name__
93        logger = Logger().logger
94        self.assertTrue(logger is not None)
95        return
96
97    def test_get_logdir(self):
98        # We can get a logdir
99        setSite(self.app)
100        logger = Logger()
101        logdir = logger.logger_get_logdir()
102        expected_logdir = os.path.join(
103            self.app['datacenter'].storage, 'logs')
104        self.assertEqual(logdir, expected_logdir)
105        return
106
107    def test_get_logdir_no_site(self):
108        # We cannot get a logdir without a site
109        logger = Logger()
110        logdir = logger.logger_get_logdir()
111        self.assertTrue(logdir is None)
112        return
113
114    def test_get_logdir_no_datacenter(self):
115        # Having a site, is not enough. We also need a datacenter in it.
116        setSite(self.app)
117        del self.app['datacenter']
118        logger = Logger()
119        logdir = logger.logger_get_logdir()
120        self.assertTrue(logdir is None)
121        return
122
123    def test_get_logdir_create_dir(self):
124        # If the logdirectory does not exist, we will create it
125        setSite(self.app)
126        logger = Logger()
127        expected_logdir = os.path.join(
128            self.app['datacenter'].storage, 'logs')
129        if os.path.exists(expected_logdir):
130            shutil.rmtree(expected_logdir)
131        logdir = logger.logger_get_logdir()
132        exists_after = os.path.exists(expected_logdir)
133        self.assertEqual(logdir, expected_logdir)
134        self.assertTrue(exists_after is True)
135        return
136
137    def test_get_logfile(self):
138        # We can get a logfile
139        setSite(self.app)
140        logger = Logger()
141        expected_filepath = os.path.join(
142            self.app['datacenter'].storage, 'logs', 'main.log')
143        path = logger.logger_get_logfile_path()
144        self.assertEqual(expected_filepath, path)
145        return
146
147    def test_get_logfile_no_dir(self):
148        # We cannot get a logfilepath if there is no dir for it
149        setSite(self.app)
150        logger = Logger()
151        del self.app['datacenter']
152        path = logger.logger_get_logfile_path()
153        self.assertTrue(path is None)
154        return
155
156    def test_setup(self):
157        # We can setup a logger.
158        mylogger = logging.getLogger('test.sample')
159        setSite(self.app)
160        logger = Logger()
161        result = logger.logger_setup(mylogger)
162        self.assertEqual(len(result.handlers), 1)
163        handler = result.handlers[0]
164        #self.assertEqual(handler.maxBytes, MAX_BYTES)
165        self.assertEqual(handler.backupCount, BACKUP_COUNT)
166        self.assertTrue(result.propagate is False)
167        return
168
169    def test_setup_no_site(self):
170        # Without a site we get no logger from setup
171        mylogger = logging.getLogger('test.sample')
172        logger = Logger()
173        result = logger.logger_setup(mylogger)
174        self.assertTrue(result is None)
175        return
176
177    def test_logfile_change(self):
178        # When the logfile location changes, logger_logfile_changed can react
179        setSite(self.app)
180        logger = Logger()
181        logger.logger.warn('Warning 1')  # Log something to old logfile
182        filename1 = logger.logger.handlers[0].baseFilename
183        content1 = open(filename1, 'r').read()
184        # Now move the logfile
185        self.dc_root2 = tempfile.mkdtemp()
186        self.app['datacenter'].setStoragePath(self.dc_root2)
187        logger.logger_logfile_changed()
188        logger.logger.warn('Warning 2')  # Log something to new logfile
189        filename2 = logger.logger.handlers[0].baseFilename
190        content2 = open(filename2, 'r').read()
191        self.assertTrue('Warning 1' in content1)
192        self.assertTrue('Warning 2' in content2)
193        self.assertTrue('Warning 1' not in content2)
194        self.assertTrue('Warning 2' not in content1)
195        self.assertTrue(filename1 != filename2)
196        shutil.rmtree(self.dc_root2)
197        return
198
199    def test_logger_additional_handlers(self):
200        # When we detect additional handlers in a logger, setup anew.
201        setSite(self.app)
202        logger = Logger()
203        old_py_logger = logger.logger
204        handler = logging.StreamHandler()
205        logger.logger.addHandler(handler)
206        old_handler_num = len(old_py_logger.handlers)
207        new_py_logger = logger.logger  # This should detect new handler
208        new_handler_num = len(new_py_logger.handlers)
209        self.assertEqual(new_handler_num, 1)
210        self.assertTrue(isinstance(
211                new_py_logger.handlers[0],
212                logging.handlers.RotatingFileHandler))
213
214class LoggersFunctionalTests(FunctionalTestCase):
215    # Check loggers with real components using them
216
217    layer = FunctionalLayer
218
219    def setUp(self):
220        super(LoggersFunctionalTests, self).setUp()
221
222        # Setup a sample site for each test
223        app = University()
224        self.dc_root = tempfile.mkdtemp()
225        app['datacenter'].setStoragePath(self.dc_root)
226
227        # Prepopulate the ZODB...
228        self.getRootFolder()['app'] = app
229        self.app = self.getRootFolder()['app']
230        self.workdir = tempfile.mkdtemp()
231
232        self.app['mycomponent'] = LoggingComponent()
233        self.component = self.app['mycomponent']
234        setSite(self.app)
235        return
236
237    def tearDown(self):
238        super(LoggersFunctionalTests, self).tearDown()
239        shutil.rmtree(self.workdir)
240        shutil.rmtree(self.dc_root)
241        clearSite()
242        return
243
244    def test_component_can_get_logger(self):
245        # Components can get a logger
246        logger = self.component.logger
247        self.assertTrue(logger is not None)
248        self.assertEqual(len(logger.handlers), 1)
249        self.assertEqual(logger.name, 'sample.app')
250        return
251
252    def test_component_handler_setup(self):
253        # handlers of components are setup
254        handler = self.component.logger.handlers[0]
255        self.assertTrue(isinstance(
256                handler, logging.handlers.RotatingFileHandler))
257        #self.assertEqual(handler.maxBytes, MAX_BYTES)
258        self.assertEqual(handler.backupCount, BACKUP_COUNT)
259        self.assertTrue(handler.baseFilename.endswith('logs/sample.log'))
260        return
261
262    def test_component_can_log(self):
263        # a method of some 'loggerized' instance can log like this.
264        self.component.logger.setLevel(logging.INFO)
265        self.component.do_something()
266        handler = logging.getLogger('sample.app').handlers[0]
267        logfile = handler.baseFilename
268        content = open(logfile, 'rb').read()
269        self.assertTrue(content.endswith(' - INFO - system - msg from do_something\n'))
270        return
271
272class LoggerCollectorTests(FunctionalTestCase):
273
274    layer = FunctionalLayer
275
276    def setUp(self):
277        super(LoggerCollectorTests, self).setUp()
278        # Setup a sample site for each test
279        app = University()
280        self.dc_root = tempfile.mkdtemp()
281        app['datacenter'].setStoragePath(self.dc_root)
282
283        # Prepopulate the ZODB...
284        self.getRootFolder()['app'] = app
285        self.app = self.getRootFolder()['app']
286        self.workdir = tempfile.mkdtemp()
287
288        self.app['mycomponent'] = LoggingComponent()
289        self.component = self.app['mycomponent']
290        setSite(self.app)
291
292        self.component = LoggingComponent()
293
294
295        return
296
297    def tearDown(self):
298        super(LoggerCollectorTests, self).tearDown()
299        shutil.rmtree(self.workdir)
300        shutil.rmtree(self.dc_root)
301        clearSite()
302        return
303
304    def test_ifaces(self):
305        collector = LoggerCollector()
306        verifyClass(ILoggerCollector, LoggerCollector)
307        verifyObject(ILoggerCollector, collector)
308        return
309
310    def test_get_utility(self):
311        # We can get a logger collector via utility lookup
312        util1 = queryUtility(ILoggerCollector, default=None)
313        util2 = queryUtility(ILoggerCollector, default=None)
314        self.assertTrue(util1 is util2)
315        self.assertTrue(isinstance(util1, LoggerCollector))
316        return
317
318    def test_get_loggers(self):
319        # We can get loggers from a logger collector
320        collector = LoggerCollector()
321        result0 = collector.getLoggers(None)
322        result1 = collector.getLoggers('not-a-site')
323        result2 = collector.getLoggers(self.app)
324        collector.registerLogger(self.app, self.component)
325        result3 = collector.getLoggers(self.app)
326        self.assertEqual(result0, [])
327        self.assertEqual(result1, [])
328        self.assertEqual(result2, [])
329        self.assertEqual(result3, [self.component])
330        self.assertTrue(result3[0] is self.component)
331        return
332
333    def test_register_logger(self):
334        # We can register loggers by name
335        collector = LoggerCollector()
336        collector.registerLogger(None, self.component) # Should have no effect
337        collector.registerLogger(object(), self.component) # Same here
338        collector.registerLogger(self.app, self.component)
339        self.assertEqual(['app'], collector.keys())
340        return
341
342    def test_register_logger_double(self):
343        # Registering the same component twice gives one entry, not two
344        collector = LoggerCollector()
345        collector.registerLogger(self.app, self.component)
346        collector.registerLogger(self.app, self.component)
347        self.assertEqual(len(collector['app']), 1)
348        return
349
350    def test_unregister_logger(self):
351        # We can also unregister loggers
352        collector = LoggerCollector()
353        collector.registerLogger(self.app, self.component)
354        collector.unregisterLogger(self.app, self.component)
355        result = collector.getLoggers(self.app)
356        self.assertEqual(result, [])
357        return
358
359    def test_unregister_logger_invalid(self):
360        # We can cope with unregistration of non-existing entries.
361        collector = LoggerCollector()
362        collector.registerLogger(self.app, self.component)
363        collector.unregisterLogger(None, self.component)
364        collector.unregisterLogger(self.app, 'nonsense')
365        self.assertEqual(len(collector), 1)
366        return
367
368class LogfileChangeTests(FunctionalTestCase):
369
370    layer = FunctionalLayer
371
372    def setUp(self):
373        super(LogfileChangeTests, self).setUp()
374        # Setup a sample site for each test
375        app = University()
376        self.dc_root = tempfile.mkdtemp()
377        self.dc_root_new = None
378        app['datacenter'].setStoragePath(self.dc_root)
379
380        # Prepopulate the ZODB...
381        self.getRootFolder()['app'] = app
382        self.app = self.getRootFolder()['app']
383        self.workdir = tempfile.mkdtemp()
384
385        self.app['mycomponent'] = LoggingComponent()
386        self.component = self.app['mycomponent']
387        setSite(self.app)
388        self.component = LoggingComponent()
389        return
390
391    def tearDown(self):
392        super(LogfileChangeTests, self).tearDown()
393        shutil.rmtree(self.workdir)
394        shutil.rmtree(self.dc_root)
395        if self.dc_root_new is not None:
396            shutil.rmtree(self.dc_root_new)
397        clearSite()
398        return
399
400    def test_storage_move(self):
401        # When a datacenter storage (its path) changes, we have to
402        # move the logfiles as well.
403        filename1 = self.component.logger.handlers[0].baseFilename
404        self.dc_root_new = tempfile.mkdtemp()
405        self.app['datacenter'].setStoragePath(self.dc_root_new)
406        filename2 = self.component.logger.handlers[0].baseFilename
407        self.assertTrue(filename1 != filename2)
408        self.assertTrue(filename2.startswith(self.dc_root_new))
409        return
410
411    def test_storage_deletion(self):
412        # When a site is deleted, the loggers should go away as well
413        self.dc_root_new = tempfile.mkdtemp()
414        logger1 = self.component.logger.handlers # create entry in collector
415        collector = queryUtility(ILoggerCollector)
416        loggers1 = collector.keys()
417        root = self.app.__parent__
418        del root['app']
419        loggers2 = collector.keys()
420        self.assertEqual(loggers1, ['app'])
421        self.assertEqual(loggers2, [])
422        return
Note: See TracBrowser for help on using the repository browser.