From a376b8e25ccf9b668f808ab1527026963ee38596 Mon Sep 17 00:00:00 2001 From: "U. Artie Eoff" Date: Wed, 19 Jan 2011 17:25:57 -0800 Subject: Added a simple logging class. Updated Test::doRun to use the new log. Added log.py which includes a simple Logger class that wraps some basic functions from the Python logging module. The log wrapper simplifies setup and will accommodate thread synchronization in the future. Test::doRun now uses the new log facility. NOTE: this changes the format of the 'test progress' previously printed via stdout. Added patterns.py which includes a Singleton class design pattern to support the Logger class. Future design patterns can be added to this file. Tested with Python 2.7 on Linux. All should be compatible with Windows and Mac and most earlier widely-used versions of Python. Signed-off-by: Ian Romanick Reviewed-by: Chad Versace --- framework/core.py | 10 ++++-- framework/log.py | 46 +++++++++++++++++++++++++++ framework/patterns.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 framework/log.py create mode 100644 framework/patterns.py (limited to 'framework') diff --git a/framework/core.py b/framework/core.py index b975cb3c..d363a342 100644 --- a/framework/core.py +++ b/framework/core.py @@ -31,6 +31,7 @@ import subprocess import sys import time import traceback +from log import log from cStringIO import StringIO __all__ = [ @@ -304,10 +305,14 @@ class Test: if len(env.exclude_filter) > 0: if True in map(lambda f: f.search(path) != None, env.exclude_filter): return None + + def status(msg): + log(msg = msg, channel = path) + # Run the test if env.execute: try: - print "Test: %(path)s" % locals() + status("running") time_start = time.time() result = self.run() time_end = time.time() @@ -325,8 +330,7 @@ class Test: result['exception'] = str(sys.exc_info()[0]) + str(sys.exc_info()[1]) result['traceback'] = '@@@' + "".join(traceback.format_tb(sys.exc_info()[2])) - if result['result'] != 'pass': - print " result: %(result)s" % { 'result': result['result'] } + status(result['result']) result.write(env.file, path) if Test.sleep: diff --git a/framework/log.py b/framework/log.py new file mode 100644 index 00000000..c3fbdd77 --- /dev/null +++ b/framework/log.py @@ -0,0 +1,46 @@ +# +# Copyright (c) 2010 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# + +from patterns import Singleton +import logging + +class Logger(Singleton): + def __logMessage(self, logfunc, message, **kwargs): + [logfunc(line, **kwargs) for line in message.split('\n')] + + def getLogger(self, channel = None): + if 0 == len(logging.root.handlers): + logging.basicConfig( + format = "[%(asctime)s] :: %(message)+8s :: %(name)s", + datefmt = "%c", + level = logging.INFO, + ) + if channel is None: + channel = "base" + logger = logging.getLogger(channel) + return logger + + def log(self, type = logging.INFO, msg = "", channel = None): + self.__logMessage(lambda m, **kwargs: self.getLogger(channel).log(type, m, **kwargs), msg) + +log = Logger().log diff --git a/framework/patterns.py b/framework/patterns.py new file mode 100644 index 00000000..653b98ff --- /dev/null +++ b/framework/patterns.py @@ -0,0 +1,87 @@ +# +# Copyright (c) 2010 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# + +import threading + +class Singleton(object): + ''' + Modeled after http://www.python.org/download/releases/2.2.3/descrintro/*__new__ + + A thread-safe (mostly -- see NOTE) Singleton class pattern. + + NOTE: deleting a singleton instance (i.e. Singleton::delInstance) does not guarantee that something + else is currently using it. To reduce this risk, a program should not hold a reference to the + instance. Rather, use the create/construct syntax (see example below) to access the instance. Yet, + this still does not guarantee that this type of usage will result in a desired effect in a + multithreaded program. + You've been warned so use the singleton pattern wisely! + + Example: + + class MySingletonClass(Singleton): + def init(self): + print "in MySingletonClass::init()", self + + def foo(self): + print "in MySingletonClass::foo()", self + + MySingletonClass().foo() + MySingletonClass().foo() + MySingletonClass().foo() + + ---> output will look something like this: + in MySingletonClass::init() <__main__.MySingletonClass object at 0x7ff5b322f3d0> + in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0> + in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0> + in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0> + ''' + + lock = threading.RLock() + + def __new__(cls, *args, **kwargs): + try: + cls.lock.acquire() + it = cls.__dict__.get('__it__') + if it is not None: + return it + cls.__it__ = it = object.__new__(cls) + it.init(*args, **kwargs) + return it + finally: # this always gets called, even when returning from within the try block + cls.lock.release() + + def init(self, *args, **kwargs): + ''' + Derived classes should override this method to do its initializations + The derived class should not implement a '__init__' method. + ''' + pass + + @classmethod + def delInstance(cls): + cls.lock.acquire() + try: + if cls.__dict__.get('__it__') is not None: + del cls.__it__ + finally: + cls.lock.release() -- cgit v1.2.3