def test_instantiate(self): "Test instantiate" def side_effect(*args, **kwargs): self.assertEqual(Transaction().context, {'test': True}) return DEFAULT rpc = RPC(instantiate=0, check_access=True) obj = Mock() obj.return_value = instance = Mock() obj.side_effect = side_effect # Integer self.assertEqual( rpc.convert(obj, 1, {'test': True}), ([instance], {}, {'test': True, '_check_access': True}, None)) obj.assert_called_once_with(1) obj.reset_mock() # Dictionary self.assertEqual( rpc.convert(obj, {'foo': 'bar'}, {'test': True}), ([instance], {}, {'test': True, '_check_access': True}, None)) obj.assert_called_once_with(foo='bar') obj.reset_mock() obj.browse.return_value = instances = Mock() # List self.assertEqual( rpc.convert(obj, [1, 2, 3], {'test': True}), ([instances], {}, {'test': True, '_check_access': True}, None)) obj.browse.assert_called_once_with([1, 2, 3])
def test_missing_context(self): "Test missing context" rpc = RPC() with self.assertRaises(ValueError) as cm: rpc.convert(None) self.assertEqual(str(cm.exception), "Missing context argument")
def test_wrong_context_type(self): "Test wrong context type" rpc = RPC() with self.assertRaises(TypeError) as cm: rpc.convert(None, context=None) self.assertEqual(str(cm.exception), "context must be a dictionary")
def test_check_access(self): "Test check_access" rpc_no_access = RPC(check_access=False) self.assertEqual(rpc_no_access.convert(None, {}), ([], {}, {}, None)) rpc_with_access = RPC(check_access=True) self.assertEqual(rpc_with_access.convert(None, {}), ([], {}, { '_check_access': True }, None))
def test_instantiate_unique(self): "Test instantiate unique" rpc = RPC(instantiate=0, unique=True) obj = Mock() rpc.convert(obj, [1, 2], {}) obj.browse.assert_called_once_with([1, 2]) obj.reset_mock() with self.assertRaises(ValueError): rpc.convert(obj, [1, 1], {})
def __call__(self, *args): from trytond.cache import Cache from trytond.transaction import Transaction from trytond.rpc import RPC if self._name in self._object.__rpc__: rpc = self._object.__rpc__[self._name] elif self._name in getattr(self._object, '_buttons', {}): rpc = RPC(readonly=False, instantiate=0) else: raise TypeError('%s is not callable' % self._name) with Transaction().start(self._config.database_name, self._config.user, readonly=rpc.readonly) as transaction: Cache.clean(self._config.database_name) args, kwargs, transaction.context, transaction.timestamp = \ rpc.convert(self._object, *args) meth = getattr(self._object, self._name) if not hasattr(meth, 'im_self') or meth.im_self: result = rpc.result(meth(*args, **kwargs)) else: assert rpc.instantiate == 0 inst = args.pop(0) if hasattr(inst, self._name): result = rpc.result(meth(inst, *args, **kwargs)) else: result = [rpc.result(meth(i, *args, **kwargs)) for i in inst] if not rpc.readonly: transaction.commit() Cache.resets(self._config.database_name) return result
def test_keyword_argument(self): "Test keyword argument" rpc = RPC(check_access=False) self.assertEqual(rpc.convert(None, 'foo', bar=True, context={}), (['foo'], { 'bar': True }, {}, None))
def __call__(self, *args): from trytond.transaction import Transaction from trytond.rpc import RPC if self._name in self._object.__rpc__: rpc = self._object.__rpc__[self._name] elif self._name in getattr(self._object, '_buttons', {}): rpc = RPC(readonly=False, instantiate=0) else: raise TypeError('%s is not callable' % self._name) with Transaction().start(self._config.database_name, self._config.user, readonly=rpc.readonly) as transaction: args, kwargs, transaction.context, transaction.timestamp = \ rpc.convert(self._object, *args) meth = getattr(self._object, self._name) if not hasattr(meth, 'im_self') or meth.im_self: result = rpc.result(meth(*args, **kwargs)) else: assert rpc.instantiate == 0 inst = args.pop(0) if hasattr(inst, self._name): result = rpc.result(meth(inst, *args, **kwargs)) else: result = [rpc.result(meth(i, *args, **kwargs)) for i in inst] if not rpc.readonly: transaction.commit() return result
def test_clean_context(self): "Test clean context" rpc = RPC(check_access=False) self.assertEqual(rpc.convert(None, { '_foo': True, '_datetime': None }), ([], {}, { '_datetime': None }, None))
def test_instantiate_slice(self): "Test instantiate with slice" rpc = RPC(instantiate=slice(0, 2), check_access=False) obj = Mock() obj.return_value = instance = Mock() self.assertEqual(rpc.convert(obj, 1, 2, {}), ([instance, instance], {}, {}, None)) obj.assert_has_calls([call(1), call(2)])
def __call__(self, *args, **kwargs): from trytond.rpc import RPC from trytond.tools import is_instance_method from trytond.transaction import Transaction from trytond.worker import run_task if self._name in self._object.__rpc__: rpc = self._object.__rpc__[self._name] elif self._name in getattr(self._object, '_buttons', {}): rpc = RPC(readonly=False, instantiate=0) else: raise TypeError('%s is not callable' % self._name) with Transaction().start(self._config.database_name, self._config.user, readonly=rpc.readonly) as transaction: args, kwargs, transaction.context, transaction.timestamp = \ rpc.convert(self._object, *args, **kwargs) meth = getattr(self._object, self._name) if (rpc.instantiate is None or not is_instance_method(self._object, self._name)): result = rpc.result(meth(*args, **kwargs)) else: assert rpc.instantiate == 0 inst = args.pop(0) if hasattr(inst, self._name): result = rpc.result(meth(inst, *args, **kwargs)) else: result = [ rpc.result(meth(i, *args, **kwargs)) for i in inst ] transaction.commit() while transaction.tasks: task_id = transaction.tasks.pop() run_task(self._config.database_name, task_id) return result
def test_timestamp(self): "Test context timestamp" rpc = RPC(check_access=False) self.assertEqual(rpc.convert(None, {'_timestamp': 'test'}), ([], {}, {}, 'test'))
def test_simple(self): "Test simple" rpc = RPC(check_access=False) self.assertEqual(rpc.convert(None, 'foo', {}), (['foo'], {}, {}, None))
def dispatch(host, port, protocol, database_name, user, session, object_type, object_name, method, *args, **kwargs): if object_type == 'common': if method == 'login': try: database = Database(database_name).connect() cursor = database.cursor() cursor.close() except Exception: return False res = security.login(database_name, user, session) Cache.clean(database_name) logger = logging.getLogger('dispatcher') msg = res and 'successful login' or 'bad login or password' logger.info('%s \'%s\' from %s:%d using %s on database \'%s\'' % (msg, user, host, port, protocol, database_name)) Cache.resets(database_name) return res or False elif method == 'logout': name = security.logout(database_name, user, session) logger = logging.getLogger('dispatcher') logger.info(('logout \'%s\' from %s:%d ' 'using %s on database \'%s\'') % (name, host, port, protocol, database_name)) return True elif method == 'version': return VERSION elif method == 'timezone_get': return CONFIG['timezone'] elif method == 'list_lang': return [ ('bg_BG', 'Български'), ('ca_ES', 'Català'), ('cs_CZ', 'Čeština'), ('de_DE', 'Deutsch'), ('en_US', 'English'), ('es_AR', 'Español (Argentina)'), ('es_ES', 'Español (España)'), ('es_CO', 'Español (Colombia)'), ('fr_FR', 'Français'), ('lt_LT', 'Lietuvių'), ('nl_NL', 'Nederlands'), ('ru_RU', 'Russian'), ] elif method == 'db_exist': try: database = Database(*args, **kwargs).connect() cursor = database.cursor() cursor.close(close=True) return True except Exception: return False elif method == 'list': if CONFIG['prevent_dblist']: raise Exception('AccessDenied') database = Database().connect() try: cursor = database.cursor() try: res = database.list(cursor) finally: cursor.close(close=True) except Exception: res = [] return res elif method == 'create': return create(*args, **kwargs) elif method == 'restore': return restore(*args, **kwargs) elif method == 'drop': return drop(*args, **kwargs) elif method == 'dump': return dump(*args, **kwargs) return elif object_type == 'system': database = Database(database_name).connect() database_list = Pool.database_list() pool = Pool(database_name) if not database_name in database_list: pool.init() if method == 'listMethods': res = [] for type in ('model', 'wizard', 'report'): for object_name, obj in pool.iterobject(type=type): for method in obj.__rpc__: res.append(type + '.' + object_name + '.' + method) if hasattr(obj, '_buttons'): for button in obj._buttons: res.append(type + '.' + object_name + '.' + button) return res elif method == 'methodSignature': return 'signatures not supported' elif method == 'methodHelp': res = [] args_list = args[0].split('.') object_type = args_list[0] object_name = '.'.join(args_list[1:-1]) method = args_list[-1] obj = pool.get(object_name, type=object_type) return pydoc.getdoc(getattr(obj, method)) for count in range(int(CONFIG['retry']), -1, -1): try: user = security.check(database_name, user, session) except DatabaseOperationalError: if count: continue raise break Cache.clean(database_name) database_list = Pool.database_list() pool = Pool(database_name) if not database_name in database_list: with Transaction().start(database_name, user, readonly=True) as transaction: pool.init() obj = pool.get(object_name, type=object_type) if method in obj.__rpc__: rpc = obj.__rpc__[method] elif method in getattr(obj, '_buttons', {}): rpc = RPC(readonly=False, instantiate=0) else: raise UserError('Calling method %s on %s %s is not allowed!' % (method, object_type, object_name)) for count in range(int(CONFIG['retry']), -1, -1): with Transaction().start(database_name, user, readonly=rpc.readonly) as transaction: try: args, kwargs, transaction.context, transaction.timestamp = \ rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) if not hasattr(meth, 'im_self') or meth.im_self: result = rpc.result(meth(*args, **kwargs)) else: assert rpc.instantiate == 0 inst = args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *args, **kwargs)) else: result = [rpc.result(meth(i, *args, **kwargs)) for i in inst] if not rpc.readonly: transaction.cursor.commit() except DatabaseOperationalError, exception: transaction.cursor.rollback() if count and not rpc.readonly: continue raise except Exception, exception: if CONFIG['verbose'] and not isinstance(exception, ( NotLogged, ConcurrencyException, UserError, UserWarning)): tb_s = ''.join(traceback.format_exception(*sys.exc_info())) logger = logging.getLogger('dispatcher') logger.error('Exception calling method %s on ' '%s %s from %s@%s:%d/%s:\n' % (method, object_type, object_name, user, host, port, database_name) + tb_s) transaction.cursor.rollback() raise