1# -*- coding: utf-8 -*- 2 3# Copyright(C) 2010-2011 Romain Bignon, Laurent Bachelier 4# 5# This file is part of weboob. 6# 7# weboob is free software: you can redistribute it and/or modify 8# it under the terms of the GNU Lesser General Public License as published by 9# the Free Software Foundation, either version 3 of the License, or 10# (at your option) any later version. 11# 12# weboob is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public License 18# along with weboob. If not, see <http://www.gnu.org/licenses/>. 19 20from __future__ import print_function 21import sys 22from functools import wraps 23from unittest import TestCase 24 25from weboob.capabilities.base import empty 26from weboob.core import Weboob 27 28# This is what nose does for Python 2.6 and lower compatibility 29# We do the same so nose becomes optional 30try: 31 from unittest.case import SkipTest 32except: 33 from nose.plugins.skip import SkipTest 34 35 36__all__ = ['BackendTest', 'SkipTest', 'skip_without_config'] 37 38 39class BackendTest(TestCase): 40 MODULE = None 41 42 def __init__(self, *args, **kwargs): 43 super(BackendTest, self).__init__(*args, **kwargs) 44 45 self.backends = {} 46 self.backend_instance = None 47 self.backend = None 48 self.weboob = Weboob() 49 50 # Skip tests when passwords are missing 51 self.weboob.requests.register('login', self.login_cb) 52 53 if self.weboob.load_backends(modules=[self.MODULE]): 54 # provide the tests with all available backends 55 self.backends = self.weboob.backend_instances 56 57 def login_cb(self, backend_name, value): 58 raise SkipTest('missing config \'%s\' is required for this test' % value.label) 59 60 def run(self, result): 61 """ 62 Call the parent run() for each backend instance. 63 Skip the test if we have no backends. 64 """ 65 # This is a hack to fix an issue with nosetests running 66 # with many tests. The default is 1000. 67 sys.setrecursionlimit(10000) 68 try: 69 if not len(self.backends): 70 self.backend = self.weboob.build_backend(self.MODULE, nofail=True) 71 TestCase.run(self, result) 72 else: 73 # Run for all backend 74 for backend_instance in self.backends.keys(): 75 print(backend_instance) 76 self.backend = self.backends[backend_instance] 77 TestCase.run(self, result) 78 finally: 79 self.weboob.deinit() 80 81 def shortDescription(self): 82 """ 83 Generate a description with the backend instance name. 84 """ 85 # do not use TestCase.shortDescription as it returns None 86 return '%s [%s]' % (str(self), self.backend_instance) 87 88 def is_backend_configured(self): 89 """ 90 Check if the backend is in the user configuration file 91 """ 92 return self.weboob.backends_config.backend_exists(self.backend.config.instname) 93 94 def assertNotEmpty(self, obj, *args): 95 """ 96 Assert an object is neither `empty` in the BaseObject parlance. 97 98 `obj` should not be `None`, `NotLoaded`, or `NotAvailable`. 99 """ 100 self.assertFalse(empty(obj), *args) 101 102 103def skip_without_config(*keys): 104 """Decorator to skip a test if backend config is missing 105 106 :param keys: if any of these keys is missing in backend config, skip test. Can be empty. 107 """ 108 109 for key in keys: 110 if callable(key): 111 raise TypeError('skip_without_config() must be called with arguments') 112 113 def decorator(func): 114 @wraps(func) 115 def wrapper(self, *args, **kwargs): 116 config = self.backend.config 117 if not self.is_backend_configured(): 118 raise SkipTest('a backend must be declared in configuration for this test') 119 for key in keys: 120 if not config[key].get(): 121 raise SkipTest('config key %r is required for this test' % 122 key) 123 124 return func(self, *args, **kwargs) 125 return wrapper 126 return decorator 127