source: main/waeup.sirp/trunk/src/waeup/sirp/utils/tests/test_logger.py @ 6750

Last change on this file since 6750 was 6748, checked in by uli, 14 years ago

Remove manual logfile removal/detection. This should be done by
surrounding test cases automatically.

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