Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id B7B6A200C24 for ; Thu, 23 Feb 2017 08:17:02 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id B6280160B62; Thu, 23 Feb 2017 07:17:02 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id C9D36160B50 for ; Thu, 23 Feb 2017 08:17:00 +0100 (CET) Received: (qmail 34798 invoked by uid 500); 23 Feb 2017 07:16:59 -0000 Mailing-List: contact dev-help@ariatosca.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ariatosca.incubator.apache.org Delivered-To: mailing list dev@ariatosca.incubator.apache.org Received: (qmail 34786 invoked by uid 99); 23 Feb 2017 07:16:59 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 23 Feb 2017 07:16:59 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id 30FC4C0744 for ; Thu, 23 Feb 2017 07:16:59 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -5.22 X-Spam-Level: X-Spam-Status: No, score=-5.22 tagged_above=-999 required=6.31 tests=[HK_RANDOM_FROM=0.999, KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-2.999] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id sgsgUfGrHVax for ; Thu, 23 Feb 2017 07:16:51 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id 1FC9F5FBBD for ; Thu, 23 Feb 2017 07:16:48 +0000 (UTC) Received: (qmail 34755 invoked by uid 99); 23 Feb 2017 07:16:48 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 23 Feb 2017 07:16:48 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 3EBD1DFD9E; Thu, 23 Feb 2017 07:16:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mxmrlv@apache.org To: dev@ariatosca.incubator.apache.org Message-Id: <5ab170098b5844558787da7d8e407462@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: incubator-ariatosca git commit: ARIA-106-Create-sqla-logging-handler Date: Thu, 23 Feb 2017 07:16:48 +0000 (UTC) archived-at: Thu, 23 Feb 2017 07:17:02 -0000 Repository: incubator-ariatosca Updated Branches: refs/heads/master d34721228 -> dc18c1d3c ARIA-106-Create-sqla-logging-handler Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/dc18c1d3 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/dc18c1d3 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/dc18c1d3 Branch: refs/heads/master Commit: dc18c1d3cec79dc5df9de1cfc06fe401a6e2c8d3 Parents: d347212 Author: mxmrlv Authored: Mon Feb 13 12:28:27 2017 +0200 Committer: max-orlov Committed: Thu Feb 23 09:15:43 2017 +0200 ---------------------------------------------------------------------- aria/.pylintrc | 2 +- aria/__init__.py | 25 ++-- aria/logger.py | 47 ++++++- aria/orchestrator/context/common.py | 53 +++++++- aria/orchestrator/context/operation.py | 18 ++- aria/orchestrator/context/workflow.py | 5 + aria/orchestrator/decorators.py | 8 +- aria/orchestrator/runner.py | 4 - aria/orchestrator/workflows/core/engine.py | 1 + aria/orchestrator/workflows/core/task.py | 3 +- aria/orchestrator/workflows/events_logging.py | 7 +- aria/orchestrator/workflows/executor/process.py | 21 ++- aria/orchestrator/workflows/executor/thread.py | 2 +- aria/storage/__init__.py | 10 -- aria/storage/core.py | 16 ++- aria/storage/modeling/model.py | 4 + aria/storage/modeling/orchestrator_elements.py | 13 ++ aria/storage/sql_mapi.py | 1 + aria/storage_initializer.py | 2 +- aria/utils/imports.py | 18 +++ tests/.pylintrc | 2 +- tests/conftest.py | 24 ++++ tests/mock/topology.py | 2 +- tests/orchestrator/context/test_operation.py | 133 ++++++++++++++++--- tests/orchestrator/context/test_serialize.py | 2 +- .../execution_plugin/test_common.py | 2 +- .../orchestrator/execution_plugin/test_local.py | 3 - tests/orchestrator/execution_plugin/test_ssh.py | 9 +- .../workflows/executor/test_executor.py | 2 +- .../workflows/executor/test_process_executor.py | 9 +- tests/storage/__init__.py | 23 ++-- tests/storage/test_instrumentation.py | 6 +- tests/storage/test_structures.py | 2 +- tests/test_logger.py | 3 +- 34 files changed, 381 insertions(+), 101 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/.pylintrc ---------------------------------------------------------------------- diff --git a/aria/.pylintrc b/aria/.pylintrc index b7656a3..589402f 100644 --- a/aria/.pylintrc +++ b/aria/.pylintrc @@ -77,7 +77,7 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating,redefined-builtin,logging-format-interpolation,import-error,redefined-variable-type,broad-except,protected-access,global-statement +disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating,redefined-builtin,logging-format-interpolation,import-error,redefined-variable-type,broad-except,protected-access,global-statement,no-member [REPORTS] http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/__init__.py ---------------------------------------------------------------------- diff --git a/aria/__init__.py b/aria/__init__.py index 18eaa56..6b10501 100644 --- a/aria/__init__.py +++ b/aria/__init__.py @@ -17,12 +17,7 @@ Aria top level package """ -import pkgutil - -try: - import pkg_resources -except ImportError: - pkg_resources = None +import sys from .VERSION import version as __version__ @@ -35,6 +30,19 @@ from . import ( orchestrator, cli ) + +if sys.version_info < (2, 7): + # pkgutil in python2.6 has a bug where it fails to import from protected modules, which causes + # the entire process to fail. In order to overcome this issue we use our custom iter_modules + from .utils.imports import iter_modules +else: + from pkgutil import iter_modules + +try: + import pkg_resources +except ImportError: + pkg_resources = None + __all__ = ( '__version__', 'workflow', @@ -48,7 +56,7 @@ def install_aria_extensions(): :code:`aria_extension` entry points and loads them. It then invokes all registered extension functions. """ - for loader, module_name, _ in pkgutil.iter_modules(): + for loader, module_name, _ in iter_modules(): if module_name.startswith('aria_extension_'): loader.find_module(module_name).load_module(module_name) if pkg_resources: @@ -97,7 +105,8 @@ def application_model_storage(api, api_kwargs=None, initiator=None, initiator_kw storage.modeling.model.ServiceInstanceUpdateStep, storage.modeling.model.ServiceInstanceModification, storage.modeling.model.Plugin, - storage.modeling.model.Task + storage.modeling.model.Task, + storage.modeling.model.Log ] return storage.ModelStorage(api_cls=api, api_kwargs=api_kwargs, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/logger.py ---------------------------------------------------------------------- diff --git a/aria/logger.py b/aria/logger.py index 0002cb5..9fe05ae 100644 --- a/aria/logger.py +++ b/aria/logger.py @@ -18,7 +18,8 @@ Logging related mixins and functions """ import logging -from logging.handlers import RotatingFileHandler +from logging import handlers as logging_handlers +from datetime import datetime _base_logger = logging.getLogger('aria') @@ -97,6 +98,15 @@ def create_console_log_handler(level=logging.DEBUG, formatter=None): return console +def create_sqla_log_handler(session, engine, log_cls, level=logging.DEBUG): + + # This is needed since the engine and session are entirely new we need to reflect the db + # schema of the logging model into the engine and session. + log_cls.__table__.create(bind=engine, checkfirst=True) + + return _SQLAlchemyHandler(session=session, engine=engine, log_cls=log_cls, level=level) + + class _DefaultConsoleFormat(logging.Formatter): """ _DefaultConsoleFormat class @@ -106,10 +116,11 @@ class _DefaultConsoleFormat(logging.Formatter): """ def format(self, record): try: - if record.levelno == logging.INFO: - self._fmt = '%(message)s' + if hasattr(record, 'prefix'): + self._fmt = '<%(asctime)s: [%(levelname)s] @%(prefix)s> %(message)s' else: - self._fmt = '%(levelname)s: %(message)s' + self._fmt = '<%(asctime)s: [%(levelname)s]> %(message)s' + except AttributeError: return record.message return logging.Formatter.format(self, record) @@ -124,7 +135,7 @@ def create_file_log_handler( """ Create a logging.handlers.RotatingFileHandler """ - rotating_file = RotatingFileHandler( + rotating_file = logging_handlers.RotatingFileHandler( filename=file_path, maxBytes=max_bytes, backupCount=backup_count, @@ -135,5 +146,31 @@ def create_file_log_handler( return rotating_file +class _SQLAlchemyHandler(logging.Handler): + + def __init__(self, session, engine, log_cls, **kwargs): + logging.Handler.__init__(self, **kwargs) + self._session = session + self._engine = engine + self._cls = log_cls + + def emit(self, record): + created_at = datetime.strptime(logging.Formatter('%(asctime)s').formatTime(record), + '%Y-%m-%d %H:%M:%S,%f') + log = self._cls( + actor=record.prefix, + level=record.levelname, + msg=record.msg, + created_at=created_at, + ) + self._session.add(log) + + try: + self._session.commit() + except BaseException: + self._session.rollback() + raise + + _default_file_formatter = logging.Formatter( '%(asctime)s [%(name)s:%(levelname)s] %(message)s <%(pathname)s:%(lineno)d>') http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/context/common.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/context/common.py b/aria/orchestrator/context/common.py index 37482cf..b34cd5d 100644 --- a/aria/orchestrator/context/common.py +++ b/aria/orchestrator/context/common.py @@ -15,19 +15,36 @@ """ A common context for both workflow and operation """ +import logging +from contextlib import contextmanager +from functools import partial from uuid import uuid4 import jinja2 -from aria import logger -from aria.storage import exceptions +from aria import logger as aria_logger +from aria.storage import ( + exceptions, + modeling +) -class BaseContext(logger.LoggerMixin): +class BaseContext(object): """ Base context object for workflow and operation """ + class PrefixedLogger(object): + def __init__(self, logger, prefix=''): + self._logger = logger + self._prefix = prefix + + def __getattr__(self, item): + if item.upper() in logging._levelNames: + return partial(getattr(self._logger, item), extra={'prefix': self._prefix}) + else: + return getattr(self._logger, item) + def __init__( self, name, @@ -43,6 +60,21 @@ class BaseContext(logger.LoggerMixin): self._resource = resource_storage self._service_instance_id = service_instance_id self._workdir = workdir + self.logger = None + + def _register_logger(self, logger_name=None, level=None): + self.logger = self.PrefixedLogger(logging.getLogger(logger_name or self.__class__.__name__), + self.logging_id) + self.logger.addHandler(aria_logger.create_console_log_handler()) + self.logger.addHandler(self._get_sqla_handler()) + self.logger.setLevel(level or logging.DEBUG) + + def _get_sqla_handler(self): + api_kwargs = {} + if self._model._initiator: + api_kwargs.update(self._model._initiator(**self._model._initiator_kwargs)) + api_kwargs.update(**self._model._api_kwargs) + return aria_logger.create_sqla_log_handler(log_cls=modeling.model.Log, **api_kwargs) def __repr__(self): return ( @@ -50,6 +82,21 @@ class BaseContext(logger.LoggerMixin): 'deployment_id={self._service_instance_id}, ' .format(name=self.__class__.__name__, self=self)) + @contextmanager + def logging_handlers(self, handlers=None): + handlers = handlers or [] + try: + for handler in handlers: + self.logger.addHandler(handler) + yield self.logger + finally: + for handler in handlers: + self.logger.removeHandler(handler) + + @property + def logging_id(self): + raise NotImplementedError + @property def model(self): """ http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/context/operation.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/context/operation.py b/aria/orchestrator/context/operation.py index c5ac8f0..3fb1786 100644 --- a/aria/orchestrator/context/operation.py +++ b/aria/orchestrator/context/operation.py @@ -44,14 +44,19 @@ class BaseOperationContext(BaseContext): self._task_id = task_id self._actor_id = actor_id self._task = None + self._register_logger() def __repr__(self): - details = 'operation_mapping={task.operation_mapping}; ' \ + details = 'implementation={task.implementation}; ' \ 'operation_inputs={task.inputs}'\ .format(task=self.task) return '{name}({0})'.format(details, name=self.name) @property + def logging_id(self): + raise NotImplementedError + + @property def task(self): """ The task in the model storage @@ -105,6 +110,11 @@ class NodeOperationContext(BaseOperationContext): """ Context for node based operations. """ + + @property + def logging_id(self): + return self.node.name or self.node.id + @property def node_template(self): """ @@ -126,6 +136,12 @@ class RelationshipOperationContext(BaseOperationContext): """ Context for relationship based operations. """ + + @property + def logging_id(self): + return '{0}->{1}'.format(self.source_node.name or self.source_node.id, + self.target_node.name or self.target_node.id) + @property def source_node_template(self): """ http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/context/workflow.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/context/workflow.py b/aria/orchestrator/context/workflow.py index 00ed974..0afaa81 100644 --- a/aria/orchestrator/context/workflow.py +++ b/aria/orchestrator/context/workflow.py @@ -46,6 +46,7 @@ class WorkflowContext(BaseContext): # TODO: execution creation should happen somewhere else # should be moved there, when such logical place exists self._execution_id = self._create_execution() if execution_id is None else execution_id + self._register_logger() def __repr__(self): return ( @@ -65,6 +66,10 @@ class WorkflowContext(BaseContext): return execution.id @property + def logging_id(self): + return '{0}[{1}]'.format(self._workflow_name, self._execution_id) + + @property def execution(self): """ The execution model http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/decorators.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/decorators.py b/aria/orchestrator/decorators.py index bbe43f4..3ced61c 100644 --- a/aria/orchestrator/decorators.py +++ b/aria/orchestrator/decorators.py @@ -54,12 +54,16 @@ def workflow(func=None, suffix_template=''): return _wrapper -def operation(func=None, toolbelt=False, suffix_template=''): +def operation(func=None, toolbelt=False, suffix_template='', logging_handlers=None): """ Operation decorator """ + if func is None: - return partial(operation, suffix_template=suffix_template, toolbelt=toolbelt) + return partial(operation, + suffix_template=suffix_template, + toolbelt=toolbelt, + logging_handlers=logging_handlers) @wraps(func) def _wrapper(**func_kwargs): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/runner.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/runner.py b/aria/orchestrator/runner.py index 8927de9..bb92d1c 100644 --- a/aria/orchestrator/runner.py +++ b/aria/orchestrator/runner.py @@ -33,9 +33,6 @@ from .. import ( ) -SQLITE_IN_MEMORY = 'sqlite:///:memory:' - - class Runner(object): """ Runs workflows on a deployment. By default uses temporary storage (either on disk or in memory) @@ -97,7 +94,6 @@ class Runner(object): task_max_attempts=1, task_retry_interval=1) - def cleanup(self): if (self._is_storage_temporary and (self._storage_path is not None) and os.path.isfile(self._storage_path)): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/workflows/core/engine.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflows/core/engine.py b/aria/orchestrator/workflows/core/engine.py index 55b4159..c6ac2b3 100644 --- a/aria/orchestrator/workflows/core/engine.py +++ b/aria/orchestrator/workflows/core/engine.py @@ -69,6 +69,7 @@ class Engine(logger.LoggerMixin): else: events.on_success_workflow_signal.send(self._workflow_context) except BaseException as e: + events.on_failure_workflow_signal.send(self._workflow_context, exception=e) raise http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/workflows/core/task.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflows/core/task.py b/aria/orchestrator/workflows/core/task.py index d0e1363..f19b1cf 100644 --- a/aria/orchestrator/workflows/core/task.py +++ b/aria/orchestrator/workflows/core/task.py @@ -23,7 +23,6 @@ from functools import ( wraps, ) -from aria import logger from aria.storage.modeling import model from aria.orchestrator.context import operation as operation_context @@ -42,7 +41,7 @@ def _locked(func=None): return _wrapper -class BaseTask(logger.LoggerMixin): +class BaseTask(object): """ Base class for Task objects """ http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/workflows/events_logging.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflows/events_logging.py b/aria/orchestrator/workflows/events_logging.py index 142ef74..73d8994 100644 --- a/aria/orchestrator/workflows/events_logging.py +++ b/aria/orchestrator/workflows/events_logging.py @@ -26,18 +26,19 @@ from .. import events @events.start_task_signal.connect def _start_task_handler(task, **kwargs): - task.logger.debug('Event: Starting task: {task.name}'.format(task=task)) + task.context.logger.debug('Event: Starting task: {task.name}'.format(task=task)) @events.on_success_task_signal.connect def _success_task_handler(task, **kwargs): - task.logger.debug('Event: Task success: {task.name}'.format(task=task)) + task.context.logger.debug('Event: Task success: {task.name}'.format(task=task)) @events.on_failure_task_signal.connect def _failure_operation_handler(task, exception, **kwargs): error = '{0}: {1}'.format(type(exception).__name__, exception) - task.logger.error('Event: Task failure: {task.name} [{error}]'.format(task=task, error=error)) + task.context.logger.error('Event: Task failure: {task.name} [{error}]'.format( + task=task, error=error)) @events.start_workflow_signal.connect http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/workflows/executor/process.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflows/executor/process.py b/aria/orchestrator/workflows/executor/process.py index 75bbbce..d999b37 100644 --- a/aria/orchestrator/workflows/executor/process.py +++ b/aria/orchestrator/workflows/executor/process.py @@ -200,7 +200,8 @@ class ProcessExecutor(base.BaseExecutor): request_handler = self._request_handlers.get(request_type) if not request_handler: raise RuntimeError('Invalid request type: {0}'.format(request_type)) - request_handler(task_id=request['task_id'], request=request, response=response) + task_id = request['task_id'] + request_handler(task_id=task_id, request=request, response=response) except BaseException as e: self.logger.debug('Error in process executor listener: {0}'.format(e)) @@ -251,14 +252,26 @@ class ProcessExecutor(base.BaseExecutor): def _send_message(connection, message): + + # Packing the length of the entire msg using struct.pack. + # This enables later reading of the content. + def _pack(data): + return struct.pack(_INT_FMT, len(data)) + data = jsonpickle.dumps(message) - connection.send(struct.pack(_INT_FMT, len(data))) + msg_metadata = _pack(data) + connection.send(msg_metadata) connection.sendall(data) def _recv_message(connection): - message_len, = struct.unpack(_INT_FMT, _recv_bytes(connection, _INT_SIZE)) - return jsonpickle.loads(_recv_bytes(connection, message_len)) + # Retrieving the length of the msg to come. + def _unpack(conn): + return struct.unpack(_INT_FMT, _recv_bytes(conn, _INT_SIZE))[0] + + msg_metadata_len = _unpack(connection) + msg = _recv_bytes(connection, msg_metadata_len) + return jsonpickle.loads(msg) def _recv_bytes(connection, count): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/orchestrator/workflows/executor/thread.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/workflows/executor/thread.py b/aria/orchestrator/workflows/executor/thread.py index 7ae0217..6c59986 100644 --- a/aria/orchestrator/workflows/executor/thread.py +++ b/aria/orchestrator/workflows/executor/thread.py @@ -63,5 +63,5 @@ class ThreadExecutor(BaseExecutor): except BaseException as e: self._task_failed(task, exception=e) # Daemon threads - except BaseException: + except BaseException as e: pass http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/storage/__init__.py ---------------------------------------------------------------------- diff --git a/aria/storage/__init__.py b/aria/storage/__init__.py index eaadc7e..45af1be 100644 --- a/aria/storage/__init__.py +++ b/aria/storage/__init__.py @@ -42,12 +42,6 @@ from .core import ( ModelStorage, ResourceStorage, ) -from .modeling import ( - structure, - model, - model_base, - type -) from . import ( exceptions, api, @@ -58,14 +52,10 @@ from . import ( __all__ = ( 'exceptions', - 'structure', 'Storage', 'ModelStorage', 'ResourceStorage', 'filesystem_rapi', 'sql_mapi', 'api', - 'model', - 'model_base', - 'type', ) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/storage/core.py ---------------------------------------------------------------------- diff --git a/aria/storage/core.py b/aria/storage/core.py index 0e189e6..883f708 100644 --- a/aria/storage/core.py +++ b/aria/storage/core.py @@ -84,6 +84,12 @@ class Storage(LoggerMixin): self.logger.debug('{name} object is ready: {0!r}'.format( self, name=self.__class__.__name__)) + @property + def _all_api_kwargs(self): + kwargs = self._api_kwargs.copy() + kwargs.update(self._additional_api_kwargs) + return kwargs + def __repr__(self): return '{name}(api={self.api})'.format(name=self.__class__.__name__, self=self) @@ -121,9 +127,7 @@ class ResourceStorage(Storage): :param name: :return: """ - kwargs = self._api_kwargs.copy() - kwargs.update(self._additional_api_kwargs) - self.registered[name] = self.api(name=name, **kwargs) + self.registered[name] = self.api(name=name, **self._all_api_kwargs) self.registered[name].create() self.logger.debug('setup {name} in storage {self!r}'.format(name=name, self=self)) @@ -148,9 +152,9 @@ class ModelStorage(Storage): self.logger.debug('{name} in already storage {self!r}'.format(name=model_name, self=self)) return - kwargs = self._api_kwargs.copy() - kwargs.update(self._additional_api_kwargs) - self.registered[model_name] = self.api(name=model_name, model_cls=model_cls, **kwargs) + self.registered[model_name] = self.api(name=model_name, + model_cls=model_cls, + **self._all_api_kwargs) self.registered[model_name].create() self.logger.debug('setup {name} in storage {self!r}'.format(name=model_name, self=self)) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/storage/modeling/model.py ---------------------------------------------------------------------- diff --git a/aria/storage/modeling/model.py b/aria/storage/modeling/model.py index 62b90b3..cf7d933 100644 --- a/aria/storage/modeling/model.py +++ b/aria/storage/modeling/model.py @@ -216,4 +216,8 @@ class Plugin(aria_declarative_base, orchestrator_elements.PluginBase): class Task(aria_declarative_base, orchestrator_elements.TaskBase): pass + + +class Log(aria_declarative_base, orchestrator_elements.LogBase): + pass # endregion http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/storage/modeling/orchestrator_elements.py ---------------------------------------------------------------------- diff --git a/aria/storage/modeling/orchestrator_elements.py b/aria/storage/modeling/orchestrator_elements.py index 5f7a3f2..854f00b 100644 --- a/aria/storage/modeling/orchestrator_elements.py +++ b/aria/storage/modeling/orchestrator_elements.py @@ -466,3 +466,16 @@ class TaskBase(ModelMixin): @staticmethod def retry(message=None, retry_interval=None): raise TaskRetryException(message, retry_interval=retry_interval) + + +class LogBase(ModelMixin): + __tablename__ = 'log' + + level = Column(String) + msg = Column(String) + created_at = Column(DateTime, index=True) + actor = Column(String) + + def __repr__(self): + return "<{self.created_at}: [{self.level}] @{self.actor}> {msg}".format( + self=self, msg=self.msg[:50]) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/storage/sql_mapi.py ---------------------------------------------------------------------- diff --git a/aria/storage/sql_mapi.py b/aria/storage/sql_mapi.py index 2711aee..8bbec54 100644 --- a/aria/storage/sql_mapi.py +++ b/aria/storage/sql_mapi.py @@ -145,6 +145,7 @@ class SQLAlchemyModelAPI(api.ModelAPI): def create(self, checkfirst=True, create_all=True, **kwargs): self.model_cls.__table__.create(self._engine, checkfirst=checkfirst) + if create_all: # In order to create any models created dynamically (e.g. many-to-many helper tables are # created at runtime). http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/storage_initializer.py ---------------------------------------------------------------------- diff --git a/aria/storage_initializer.py b/aria/storage_initializer.py index 175ec22..8c154df 100644 --- a/aria/storage_initializer.py +++ b/aria/storage_initializer.py @@ -16,7 +16,7 @@ from datetime import datetime from threading import RLock -from .storage import model +from .storage.modeling import model from .orchestrator import operation from .utils.formatting import safe_repr from .utils.console import puts, Colored http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/aria/utils/imports.py ---------------------------------------------------------------------- diff --git a/aria/utils/imports.py b/aria/utils/imports.py index e9c164e..64a48cf 100644 --- a/aria/utils/imports.py +++ b/aria/utils/imports.py @@ -18,6 +18,7 @@ Utility methods for dynamically loading python code """ import importlib +import pkgutil def import_fullname(name, paths=None): @@ -76,3 +77,20 @@ def load_attribute(attribute_path): except AttributeError: # TODO: handle raise + + +def iter_modules(): + # apparently pkgutil had some issues in python 2.6. Accessing any root level directories + # failed. and it got the entire process of importing fail. Since we only need any + # aria_extension related loading, in the meantime we could try to import only those + # (and assume they are not located at the root level. + # [In python 2.7 it does actually ignore any OSError]. + yielded = {} + for importer in pkgutil.iter_importers(): + try: + for module_name, ispkg in pkgutil.iter_importer_modules(importer): + if module_name not in yielded: + yielded[module_name] = True + yield importer, module_name, ispkg + except OSError: + pass http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/.pylintrc ---------------------------------------------------------------------- diff --git a/tests/.pylintrc b/tests/.pylintrc index 5de0691..06409e9 100644 --- a/tests/.pylintrc +++ b/tests/.pylintrc @@ -77,7 +77,7 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating,redefined-builtin,no-self-use,missing-docstring,attribute-defined-outside-init,redefined-outer-name,import-error,redefined-variable-type,broad -except,protected-access,global-statement,too-many-locals,abstract-method +disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating,redefined-builtin,no-self-use,missing-docstring,attribute-defined-outside-init,redefined-outer-name,import-error,redefined-variable-type,broad -except,protected-access,global-statement,too-many-locals,abstract-method,no-member [REPORTS] http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/conftest.py ---------------------------------------------------------------------- diff --git a/tests/conftest.py b/tests/conftest.py index 4b24f18..c501eeb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import logging + import pytest import aria @@ -21,3 +23,25 @@ import aria @pytest.fixture(scope='session', autouse=True) def install_aria_extensions(): aria.install_aria_extensions() + + +@pytest.fixture(autouse=True) +def logging_handler_cleanup(request): + """ + Each time a test runs, the loggers do not clear. we need to manually clear them or we'd have + logging overload. + + Since every type of logger (node/relationship/workflow) share the same name, we should + clear the logger each test. This should not happen in real world use. + :param request: + :return: + """ + def clear_logging_handlers(): + logged_ctx_names = [ + aria.orchestrator.context.workflow.WorkflowContext.__name__, + aria.orchestrator.context.operation.NodeOperationContext.__name__, + aria.orchestrator.context.operation.RelationshipOperationContext.__name__ + ] + for logger_name in logged_ctx_names: + logging.getLogger(logger_name).handlers = [] + request.addfinalizer(clear_logging_handlers) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/mock/topology.py ---------------------------------------------------------------------- diff --git a/tests/mock/topology.py b/tests/mock/topology.py index b04fb46..d3e8b7b 100644 --- a/tests/mock/topology.py +++ b/tests/mock/topology.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from aria.storage import model +from aria.storage.modeling import model from . import models http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/context/test_operation.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/context/test_operation.py b/tests/orchestrator/context/test_operation.py index 3f39979..2b26bb1 100644 --- a/tests/orchestrator/context/test_operation.py +++ b/tests/orchestrator/context/test_operation.py @@ -14,17 +14,20 @@ # limitations under the License. import os +import time import pytest +from aria.orchestrator.workflows.executor import process, thread + from aria import ( workflow, operation, ) from aria.orchestrator import context from aria.orchestrator.workflows import api -from aria.orchestrator.workflows.executor import thread +import tests from tests import mock, storage from . import ( op_path, @@ -38,8 +41,7 @@ global_test_holder = {} @pytest.fixture def ctx(tmpdir): context = mock.context.simple( - str(tmpdir.join('workdir')), - inmemory=True, + str(tmpdir), context_kwargs=dict(workdir=str(tmpdir.join('workdir'))) ) yield context @@ -47,7 +49,7 @@ def ctx(tmpdir): @pytest.fixture -def executor(): +def thread_executor(): result = thread.ThreadExecutor() try: yield result @@ -55,13 +57,13 @@ def executor(): result.close() -def test_node_operation_task_execution(ctx, executor): +def test_node_operation_task_execution(ctx, thread_executor): operation_name = 'aria.interfaces.lifecycle.create' node = ctx.model.node.get_by_name(mock.models.DEPENDENCY_NODE_INSTANCE_NAME) interface = mock.models.get_interface( operation_name, - operation_kwargs=dict(implementation=op_path(my_operation, module_path=__name__)) + operation_kwargs=dict(implementation=op_path(basic_operation, module_path=__name__)) ) node.interfaces = [interface] ctx.model.node.update(node) @@ -77,7 +79,7 @@ def test_node_operation_task_execution(ctx, executor): ) ) - execute(workflow_func=basic_workflow, workflow_context=ctx, executor=executor) + execute(workflow_func=basic_workflow, workflow_context=ctx, executor=thread_executor) operation_context = global_test_holder[op_name(node, operation_name)] @@ -96,13 +98,13 @@ def test_node_operation_task_execution(ctx, executor): assert operation_context.node == node -def test_relationship_operation_task_execution(ctx, executor): +def test_relationship_operation_task_execution(ctx, thread_executor): operation_name = 'aria.interfaces.relationship_lifecycle.post_configure' relationship = ctx.model.relationship.list()[0] interface = mock.models.get_interface( operation_name=operation_name, - operation_kwargs=dict(implementation=op_path(my_operation, module_path=__name__)), + operation_kwargs=dict(implementation=op_path(basic_operation, module_path=__name__)), edge='source' ) @@ -121,7 +123,7 @@ def test_relationship_operation_task_execution(ctx, executor): ) ) - execute(workflow_func=basic_workflow, workflow_context=ctx, executor=executor) + execute(workflow_func=basic_workflow, workflow_context=ctx, executor=thread_executor) operation_context = global_test_holder[op_name(relationship, operation_name)] @@ -148,12 +150,12 @@ def test_relationship_operation_task_execution(ctx, executor): assert operation_context.source_node == dependent_node -def test_invalid_task_operation_id(ctx, executor): +def test_invalid_task_operation_id(ctx, thread_executor): """ Checks that the right id is used. The task created with id == 1, thus running the task on node_instance with id == 2. will check that indeed the node_instance uses the correct id. :param ctx: - :param executor: + :param thread_executor: :return: """ operation_name = 'aria.interfaces.lifecycle.create' @@ -174,14 +176,14 @@ def test_invalid_task_operation_id(ctx, executor): api.task.OperationTask.node(name=operation_name, instance=node) ) - execute(workflow_func=basic_workflow, workflow_context=ctx, executor=executor) + execute(workflow_func=basic_workflow, workflow_context=ctx, executor=thread_executor) op_node_instance_id = global_test_holder[op_name(node, operation_name)] assert op_node_instance_id == node.id assert op_node_instance_id != other_node.id -def test_plugin_workdir(ctx, executor, tmpdir): +def test_plugin_workdir(ctx, thread_executor, tmpdir): op = 'test.op' plugin_name = 'mock_plugin' node = ctx.model.node.get_by_name(mock.models.DEPENDENCY_NODE_INSTANCE_NAME) @@ -203,15 +205,114 @@ def test_plugin_workdir(ctx, executor, tmpdir): graph.add_tasks(api.task.OperationTask.node( name=op, instance=node, inputs=inputs)) - execute(workflow_func=basic_workflow, workflow_context=ctx, executor=executor) + execute(workflow_func=basic_workflow, workflow_context=ctx, executor=thread_executor) expected_file = tmpdir.join('workdir', 'plugins', str(ctx.service_instance.id), plugin_name, filename) assert expected_file.read() == content +@pytest.fixture(params=[ + (thread.ThreadExecutor, dict()), + (process.ProcessExecutor, dict(python_path=tests.ROOT_DIR)) +]) +def executor(request): + ex_cls, kwargs = request.param + ex = ex_cls(**kwargs) + try: + yield ex + finally: + ex.close() + + +def test_node_operation_logging(ctx, executor): + operation_name = mock.operations.NODE_OPERATIONS_INSTALL[0] + + node = ctx.model.node.get_by_name(mock.models.DEPENDENCY_NODE_INSTANCE_NAME) + interface = mock.models.get_interface( + operation_name, + operation_kwargs=dict(implementation=op_path(logged_operation, module_path=__name__)) + ) + node.interfaces = [interface] + ctx.model.node.update(node) + + inputs = { + 'op_start': 'op_start', + 'op_end': 'op_end', + } + + @workflow + def basic_workflow(graph, **_): + graph.add_tasks( + api.task.OperationTask.node( + name=operation_name, + instance=node, + inputs=inputs + ) + ) + + execute(workflow_func=basic_workflow, workflow_context=ctx, executor=executor) + _assert_loggins(ctx.model.log.list(), inputs) + + +def test_relationship_operation_logging(ctx, executor): + operation_name = mock.operations.RELATIONSHIP_OPERATIONS_INSTALL[0].rsplit('_', 1)[0] + + relationship = ctx.model.relationship.list()[0] + relationship.interfaces = [mock.models.get_interface( + operation_name, + operation_kwargs=dict(implementation=op_path(logged_operation, module_path=__name__)), + edge='source' + )] + ctx.model.relationship.update(relationship) + + inputs = { + 'op_start': 'op_start', + 'op_end': 'op_end', + } + + @workflow + def basic_workflow(graph, **_): + graph.add_tasks( + api.task.OperationTask.relationship( + name=operation_name, + instance=relationship, + inputs=inputs, + edge='source', + ) + ) + + execute(workflow_func=basic_workflow, workflow_context=ctx, executor=executor) + _assert_loggins(ctx.model.log.list(), inputs) + + +def _assert_loggins(logs, inputs): + + # The logs should contain the following: Workflow Start, Operation Start, custom operation + # log string (op_start), custom operation log string (op_end), Operation End, Workflow End. + assert len(logs) == 6 + + op_start_log = [l for l in logs if inputs['op_start'] in l.msg and l.level.lower() == 'info'] + assert len(op_start_log) == 1 + op_start_log = op_start_log[0] + + op_end_log = [l for l in logs if inputs['op_end'] in l.msg and l.level.lower() == 'debug'] + assert len(op_end_log) == 1 + op_end_log = op_end_log[0] + + assert op_start_log.created_at < op_end_log.created_at + + +@operation +def logged_operation(ctx, **_): + ctx.logger.info(ctx.task.inputs['op_start']) + # enables to check the relation between the created_at field properly + time.sleep(1) + ctx.logger.debug(ctx.task.inputs['op_end']) + + @operation -def my_operation(ctx, **_): +def basic_operation(ctx, **_): global_test_holder[ctx.name] = ctx http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/context/test_serialize.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/context/test_serialize.py b/tests/orchestrator/context/test_serialize.py index 1fdcb1a..03f9529 100644 --- a/tests/orchestrator/context/test_serialize.py +++ b/tests/orchestrator/context/test_serialize.py @@ -58,7 +58,7 @@ def _mock_workflow(ctx, graph): def _mock_operation(ctx): # We test several things in this operation # ctx.task, ctx.node, etc... tell us that the model storage was properly re-created - # a correct ctx.task.operation_mapping tells us we kept the correct task_id + # a correct ctx.task.implementation tells us we kept the correct task_id assert ctx.task.implementation == _operation_mapping() # a correct ctx.node.name tells us we kept the correct actor_id assert ctx.node.name == mock.models.DEPENDENCY_NODE_INSTANCE_NAME http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/execution_plugin/test_common.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/execution_plugin/test_common.py b/tests/orchestrator/execution_plugin/test_common.py index 1048c27..151b996 100644 --- a/tests/orchestrator/execution_plugin/test_common.py +++ b/tests/orchestrator/execution_plugin/test_common.py @@ -18,7 +18,7 @@ from collections import namedtuple import requests import pytest -from aria.storage import model +from aria.storage.modeling import model from aria.orchestrator import exceptions from aria.orchestrator.execution_plugin import common http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/execution_plugin/test_local.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/execution_plugin/test_local.py b/tests/orchestrator/execution_plugin/test_local.py index 9e9540f..5224496 100644 --- a/tests/orchestrator/execution_plugin/test_local.py +++ b/tests/orchestrator/execution_plugin/test_local.py @@ -483,9 +483,6 @@ if __name__ == '__main__': operations.__name__, operations.run_script_locally.__name__)) )] - # node.operations[op] = { - # 'operation': '{0}.{1}'.format(operations.__name__, - # operations.run_script_locally.__name__)} graph.add_tasks(api.task.OperationTask.node( instance=node, name=op, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/execution_plugin/test_ssh.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/execution_plugin/test_ssh.py b/tests/orchestrator/execution_plugin/test_ssh.py index 2e270bb..ad577f0 100644 --- a/tests/orchestrator/execution_plugin/test_ssh.py +++ b/tests/orchestrator/execution_plugin/test_ssh.py @@ -24,7 +24,7 @@ import fabric.api from fabric.contrib import files from fabric import context_managers -from aria.storage import model +from aria.storage.modeling import model from aria.orchestrator import events from aria.orchestrator import workflow from aria.orchestrator.workflows import api @@ -413,6 +413,13 @@ class TestFabricEnvHideGroupsAndRunCommands(object): task.runs_on = Stub logger = logging.getLogger() + @staticmethod + @contextlib.contextmanager + def _mock_self_logging(*args, **kwargs): + yield + _Ctx.logging_handlers = _mock_self_logging + + @pytest.fixture(autouse=True) def _setup(self, mocker): self.default_fabric_env = { http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/workflows/executor/test_executor.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/workflows/executor/test_executor.py b/tests/orchestrator/workflows/executor/test_executor.py index 580bf8b..8da801e 100644 --- a/tests/orchestrator/workflows/executor/test_executor.py +++ b/tests/orchestrator/workflows/executor/test_executor.py @@ -83,7 +83,7 @@ class MockException(Exception): class MockContext(object): def __init__(self, *args, **kwargs): - pass + self.logger = logging.getLogger() def __getattr__(self, item): if item == 'serialization_dict': http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/orchestrator/workflows/executor/test_process_executor.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/workflows/executor/test_process_executor.py b/tests/orchestrator/workflows/executor/test_process_executor.py index e904eb3..2d43261 100644 --- a/tests/orchestrator/workflows/executor/test_process_executor.py +++ b/tests/orchestrator/workflows/executor/test_process_executor.py @@ -22,10 +22,8 @@ from contextlib import contextmanager import pytest from aria import application_model_storage -from aria.storage import ( - model as aria_model, - sql_mapi -) +from aria.storage import sql_mapi +from aria.storage.modeling import model as aria_model from aria.orchestrator import ( events, plugin @@ -114,7 +112,7 @@ def mock_plugin(plugin_manager, tmpdir): class MockContext(object): def __init__(self, *args, **kwargs): - pass + self.logger = logging.getLogger('mock_logger') def __getattr__(self, item): if item == 'serialization_dict': @@ -126,7 +124,6 @@ class MockContext(object): def deserialize_from_dict(cls, **kwargs): return cls() - class MockTask(object): INFINITE_RETRIES = aria_model.Task.INFINITE_RETRIES http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/storage/__init__.py ---------------------------------------------------------------------- diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py index 4278831..f95bdb2 100644 --- a/tests/storage/__init__.py +++ b/tests/storage/__init__.py @@ -12,8 +12,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import os -import platform + from shutil import rmtree from tempfile import mkdtemp @@ -23,19 +22,19 @@ from sqlalchemy import ( Column, Text, Integer, - pool + pool, + MetaData ) -from aria.storage import ( +from aria.storage.modeling import ( model, - type as aria_type, structure, - modeling + type as aria_type ) -class MockModel(model.aria_declarative_base, structure.ModelMixin): #pylint: disable=abstract-method +class MockModel(structure.ModelMixin, model.aria_declarative_base): #pylint: disable=abstract-method __tablename__ = 'mock_model' model_dict = Column(aria_type.Dict) model_list = Column(aria_type.List) @@ -58,14 +57,8 @@ def release_sqlite_storage(storage): :param storage: :return: """ - mapis = storage.registered.values() - - if mapis: - for session in set(mapi._session for mapi in mapis): - session.rollback() - session.close() - for engine in set(mapi._engine for mapi in mapis): - model.aria_declarative_base.metadata.drop_all(engine) + storage._all_api_kwargs['session'].close() + MetaData(bind=storage._all_api_kwargs['engine']).drop_all() def init_inmemory_model_storage(): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/storage/test_instrumentation.py ---------------------------------------------------------------------- diff --git a/tests/storage/test_instrumentation.py b/tests/storage/test_instrumentation.py index 08d5ae0..7f0eb02 100644 --- a/tests/storage/test_instrumentation.py +++ b/tests/storage/test_instrumentation.py @@ -17,13 +17,15 @@ import pytest from sqlalchemy import Column, Text, Integer, event from aria.storage import ( - structure, ModelStorage, sql_mapi, instrumentation, exceptions, +) +from aria.storage.modeling import ( + model, type as aria_type, - model + structure, ) from ..storage import release_sqlite_storage, init_inmemory_model_storage http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/storage/test_structures.py ---------------------------------------------------------------------- diff --git a/tests/storage/test_structures.py b/tests/storage/test_structures.py index 666256e..27e99d7 100644 --- a/tests/storage/test_structures.py +++ b/tests/storage/test_structures.py @@ -21,9 +21,9 @@ from aria.storage import ( ModelStorage, sql_mapi, exceptions, - type, modeling, ) +from aria.storage.modeling import type from ..storage import release_sqlite_storage, structure, init_inmemory_model_storage from . import MockModel http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/dc18c1d3/tests/test_logger.py ---------------------------------------------------------------------- diff --git a/tests/test_logger.py b/tests/test_logger.py index 70f08bb..6457884 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -53,7 +53,8 @@ def test_create_console_log_handler(capsys): logger.info(info_test_string) logger.debug(debug_test_string) _, err = capsys.readouterr() - assert err.count('DEBUG: {test_string}'.format(test_string=debug_test_string)) == 1 + + assert '[DEBUG]> {test_string}'.format(test_string=debug_test_string) in err assert err.count(info_test_string) == 1 # Custom handler