# HG changeset patch # User Sylvain Thénault # Date 1299605539 -3600 # Node ID bb20805477222db3c941f9e460a8b516f9fa48e4 # Parent 1d65b235549fa9352a26915975344b83b76692a6# Parent f26a1cbddc9143db8df3b433aa5ce4875b533330 backport stable diff -r 1d65b235549f -r bb2080547722 dbapi.py --- a/dbapi.py Fri Feb 18 15:26:00 2011 +0100 +++ b/dbapi.py Tue Mar 08 18:32:19 2011 +0100 @@ -201,21 +201,30 @@ cnx.vreg = vreg return cnx -def in_memory_cnx(config, login, **kwargs): - """usefull method for testing and scripting to get a dbapi.Connection - object connected to an in-memory repository instance - """ +def in_memory_repo(config): + """Return and in_memory Repository object from a config (or vreg)""" if isinstance(config, cwvreg.CubicWebVRegistry): vreg = config config = None else: vreg = None # get local access to the repository - repo = get_repository('inmemory', config=config, vreg=vreg) - # connection to the CubicWeb repository + return get_repository('inmemory', config=config, vreg=vreg) + +def in_memory_cnx(repo, login, **kwargs): + """Establish a In memory connection to a for the user with + + additionel credential might be required""" cnxprops = ConnectionProperties('inmemory') - cnx = repo_connect(repo, login, cnxprops=cnxprops, **kwargs) - return repo, cnx + return repo_connect(repo, login, cnxprops=cnxprops, **kwargs) + +def in_memory_repo_cnx(config, login, **kwargs): + """usefull method for testing and scripting to get a dbapi.Connection + object connected to an in-memory repository instance + """ + # connection to the CubicWeb repository + repo = in_memory_repo(config) + return repo, in_memory_cnx(repo, login, **kwargs) class _NeedAuthAccessMock(object): def __getattribute__(self, attr): diff -r 1d65b235549f -r bb2080547722 devtools/__init__.py --- a/devtools/__init__.py Fri Feb 18 15:26:00 2011 +0100 +++ b/devtools/__init__.py Tue Mar 08 18:32:19 2011 +0100 @@ -217,7 +217,7 @@ def init_test_database(config=None, appid='data', apphome=None): """init a test database for a specific driver""" - from cubicweb.dbapi import in_memory_cnx + from cubicweb.dbapi import in_memory_repo_cnx config = config or TestServerConfiguration(appid, apphome=apphome) sources = config.sources() driver = sources['system']['db-driver'] @@ -229,7 +229,7 @@ else: raise ValueError('no initialization function for driver %r' % driver) config._cubes = None # avoid assertion error - repo, cnx = in_memory_cnx(config, unicode(sources['admin']['login']), + repo, cnx = in_memory_repo_cnx(config, unicode(sources['admin']['login']), password=sources['admin']['password'] or 'xxx') if driver == 'sqlite': install_sqlite_patch(repo.querier) diff -r 1d65b235549f -r bb2080547722 devtools/cwwindmill.py --- a/devtools/cwwindmill.py Fri Feb 18 15:26:00 2011 +0100 +++ b/devtools/cwwindmill.py Tue Mar 08 18:32:19 2011 +0100 @@ -29,120 +29,133 @@ import sys # imported by default to simplify further import statements -from logilab.common.testlib import TestCase, unittest_main +from logilab.common.testlib import TestCase, unittest_main, Tags -import windmill -from windmill.dep import functest -from windmill.bin.admin_lib import configure_global_settings, setup, teardown +try: + import windmill + from windmill.dep import functest + from windmill.bin.admin_lib import configure_global_settings, setup, teardown +except ImportError, ex: + windmill = None from cubicweb.devtools.httptest import CubicWebServerTC, CubicWebServerConfig +if windmill is None: + class CubicWebWindmillUseCase(CubicWebServerTC): + tags = CubicWebServerTC.tags & Tags(('windmill',)) -# Excerpt from :ref:`windmill.authoring.unit` -class UnitTestReporter(functest.reports.FunctestReportInterface): - def summary(self, test_list, totals_dict, stdout_capture): - self.test_list = test_list - -unittestreporter = UnitTestReporter() -functest.reports.register_reporter(unittestreporter) + def testWindmill(self): + self.skipTest("can't import windmill %s" % ex) +else: + # Excerpt from :ref:`windmill.authoring.unit` + class UnitTestReporter(functest.reports.FunctestReportInterface): + def summary(self, test_list, totals_dict, stdout_capture): + self.test_list = test_list -class CubicWebWindmillUseCase(CubicWebServerTC): - """basic class for Windmill use case tests + unittestreporter = UnitTestReporter() + functest.reports.register_reporter(unittestreporter) + + class CubicWebWindmillUseCase(CubicWebServerTC): + """basic class for Windmill use case tests - If you want to change cubicweb test server parameters, define a new - :class:`CubicWebServerConfig` and override the :var:`configcls` - attribute: + If you want to change cubicweb test server parameters, define a new + :class:`CubicWebServerConfig` and override the :var:`configcls` + attribute: - configcls = CubicWebServerConfig + configcls = CubicWebServerConfig - From Windmill configuration: + From Windmill configuration: - .. attribute:: browser - identification string (firefox|ie|safari|chrome) (firefox by default) - .. attribute :: edit_test - load and edit test for debugging (False by default) - .. attribute:: test_dir (optional) - testing file path or directory (windmill directory under your unit case - file by default) + .. attribute:: browser + identification string (firefox|ie|safari|chrome) (firefox by default) + .. attribute :: edit_test + load and edit test for debugging (False by default) + .. attribute:: test_dir (optional) + testing file path or directory (windmill directory under your unit case + file by default) + + Examples: - Examples: + browser = 'firefox' + test_dir = osp.join(__file__, 'windmill') + edit_test = False + If you prefer, you can put here the use cases recorded by windmill GUI + (services transformer) instead of the windmill sub-directory + You can change `test_dir` as following: + + test_dir = __file__ + + Instead of toggle `edit_test` value, try `python -f` + """ browser = 'firefox' - test_dir = osp.join(__file__, 'windmill') - edit_test = False - - If you prefer, you can put here the use cases recorded by windmill GUI - (services transformer) instead of the windmill sub-directory - You can change `test_dir` as following: +<<<<<<< /home/syt/src/fcubicweb/cubicweb/devtools/cwwindmill.py - test_dir = __file__ + edit_test = "-i" in sys.argv # detection for pytest invocation + # Windmill use case are written with no anonymous user + anonymous_logged = False - Instead of toggle `edit_test` value, try `python -f` - """ - browser = 'firefox' - edit_test = "-f" in sys.argv or "-i" in sys.argv # XXX pytest - # Windmill use case are written with no anonymous user - anonymous_logged = False + tags = CubicWebServerTC.tags & Tags(('windmill',)) - def _test_dir(self): - """access to class attribute if possible or make assumption - of expected directory""" - try: - return getattr(self, 'test_dir') - except AttributeError: - if os.path.basename(sys.argv[0]) == "pytest": - test_dir = os.getcwd() - else: - import inspect - test_dir = os.path.dirname(inspect.stack()[-1][1]) - return osp.join(test_dir, 'windmill') + def _test_dir(self): + """access to class attribute if possible or make assumption + of expected directory""" + try: + return getattr(self, 'test_dir') + except AttributeError: + if os.path.basename(sys.argv[0]) == "pytest": + test_dir = os.getcwd() + else: + import inspect + test_dir = os.path.dirname(inspect.stack()[-1][1]) + return osp.join(test_dir, 'windmill') - def setUp(self): - # Start CubicWeb session before running the server to populate self.vreg - super(CubicWebWindmillUseCase, self).setUp() - # XXX reduce log output (should be done in a cleaner way) - # windmill fu** up our logging configuration - for logkey in ('windmill', 'logilab', 'cubicweb'): - getLogger(logkey).setLevel(ERROR) - self.test_dir = self._test_dir() - msg = "provide a valid 'test_dir' as the given test file/dir (current: %s)" - assert os.path.exists(self.test_dir), (msg % self.test_dir) - # windmill setup - windmill.stdout, windmill.stdin = sys.stdout, sys.stdin - configure_global_settings() - windmill.settings['TEST_URL'] = self.config['base-url'] - if hasattr(self,"windmill_settings"): - for (setting,value) in self.windmill_settings.iteritems(): - windmill.settings[setting] = value - self.windmill_shell_objects = setup() + def setUp(self): + # Start CubicWeb session before running the server to populate self.vreg + CubicWebServerTC.setUp(self) + # XXX reduce log output (should be done in a cleaner way) + # windmill fu** up our logging configuration + for logkey in ('windmill', 'logilab', 'cubicweb'): + getLogger(logkey).setLevel(ERROR) + self.test_dir = self._test_dir() + msg = "provide a valid 'test_dir' as the given test file/dir (current: %s)" + assert os.path.exists(self.test_dir), (msg % self.test_dir) + # windmill setup + windmill.stdout, windmill.stdin = sys.stdout, sys.stdin + configure_global_settings() + windmill.settings['TEST_URL'] = self.config['base-url'] + if hasattr(self,"windmill_settings"): + for (setting,value) in self.windmill_settings.iteritems(): + windmill.settings[setting] = value + self.windmill_shell_objects = setup() - def tearDown(self): - teardown(self.windmill_shell_objects) - super(CubicWebWindmillUseCase, self).tearDown() + def tearDown(self): + teardown(self.windmill_shell_objects) + CubicWebServerTC.tearDown(self) - def testWindmill(self): - if self.edit_test: - # see windmill.bin.admin_options.Firebug - windmill.settings['INSTALL_FIREBUG'] = 'firebug' - windmill.settings.setdefault('MOZILLA_PLUGINS', []).extend( - ['/usr/share/mozilla-extensions/', - '/usr/share/xul-ext/']) - controller = self.windmill_shell_objects['start_' + self.browser]() - self.windmill_shell_objects['do_test'](self.test_dir, - load=self.edit_test, - threaded=False) - # set a breakpoint to be able to debug windmill test - if self.edit_test: - import pdb; pdb.set_trace() - return + def testWindmill(self): + if self.edit_test: + # see windmill.bin.admin_options.Firebug + windmill.settings['INSTALL_FIREBUG'] = 'firebug' + windmill.settings.setdefault('MOZILLA_PLUGINS', []).extend( + ['/usr/share/mozilla-extensions/', + '/usr/share/xul-ext/']) + controller = self.windmill_shell_objects['start_' + self.browser]() + self.windmill_shell_objects['do_test'](self.test_dir, + load=self.edit_test, + threaded=False) + # set a breakpoint to be able to debug windmill test + if self.edit_test: + import pdb; pdb.set_trace() + return - # reporter - for test in unittestreporter.test_list: - msg = "" - self._testMethodDoc = getattr(test, "__doc__", None) - self._testMethodName = test.__name__ - # try to display a better message in case of failure - if hasattr(test, "tb"): - msg = '\n'.join(test.tb) - self.assertEqual(test.result, True, msg=msg) + # reporter + for test in unittestreporter.test_list: + msg = "" + self._testMethodDoc = getattr(test, "__doc__", None) + self._testMethodName = test.__name__ + # try to display a better message in case of failure + if hasattr(test, "tb"): + msg = '\n'.join(test.tb) + self.assertEqual(test.result, True, msg=msg) diff -r 1d65b235549f -r bb2080547722 devtools/livetest.py --- a/devtools/livetest.py Fri Feb 18 15:26:00 2011 +0100 +++ b/devtools/livetest.py Tue Mar 08 18:32:19 2011 +0100 @@ -35,7 +35,7 @@ from logilab.common.testlib import TestCase -from cubicweb.dbapi import in_memory_cnx +from cubicweb.dbapi import in_memory_repo_cnx from cubicweb.etwist.server import CubicWebRootResource from cubicweb.devtools import BaseApptestConfiguration, init_test_database @@ -164,7 +164,7 @@ # build a config, and get a connection self.config = LivetestConfiguration(self.cube, self.sourcefile) _, user, passwd, _ = loadconf() - self.repo, self.cnx = in_memory_cnx(self.config, user, password=passwd) + self.repo, self.cnx = in_memory_repo_cnx(self.config, user, password=passwd) self.setup_db(self.cnx) def tearDown(self): diff -r 1d65b235549f -r bb2080547722 devtools/qunit.py --- a/devtools/qunit.py Fri Feb 18 15:26:00 2011 +0100 +++ b/devtools/qunit.py Tue Mar 08 18:32:19 2011 +0100 @@ -8,7 +8,7 @@ from uuid import uuid4 # imported by default to simplify further import statements -from logilab.common.testlib import unittest_main, with_tempdir, InnerTest +from logilab.common.testlib import unittest_main, with_tempdir, InnerTest, Tags from logilab.common.shellutils import getlogin import cubicweb @@ -86,6 +86,8 @@ class QUnitTestCase(CubicWebServerTC): + tags = CubicWebServerTC.tags | Tags(('qunit',)) + # testfile, (dep_a, dep_b) all_js_tests = () diff -r 1d65b235549f -r bb2080547722 devtools/test/unittest_httptest.py --- a/devtools/test/unittest_httptest.py Fri Feb 18 15:26:00 2011 +0100 +++ b/devtools/test/unittest_httptest.py Tue Mar 08 18:32:19 2011 +0100 @@ -19,6 +19,7 @@ import httplib +from logilab.common.testlib import Tags from cubicweb.devtools.httptest import CubicWebServerTC, CubicWebServerConfig @@ -40,7 +41,9 @@ class TwistedCWIdentTC(CubicWebServerTC): + anonymous_logged = False + tags = CubicWebServerTC.tags | Tags(('auth',)) def test_response_denied(self): response = self.web_get() @@ -49,7 +52,7 @@ def test_login(self): response = self.web_get() if response.status != httplib.FORBIDDEN: - self.skipTest('Already authenticated') + self.skipTest('Already authenticated, "test_response_denied" must have failed') # login self.web_login(self.admlogin, self.admpassword) response = self.web_get() diff -r 1d65b235549f -r bb2080547722 devtools/testlib.py --- a/devtools/testlib.py Fri Feb 18 15:26:00 2011 +0100 +++ b/devtools/testlib.py Tue Mar 08 18:32:19 2011 +0100 @@ -854,6 +854,27 @@ raise self.failureException("doctest file '%s' failed" % testfile) + # notifications ############################################################ + + def assertSentEmail(self, subject, recipients=None, nb_msgs=None): + """test recipients in system mailbox for given email subject + + :param subject: email subject to find in mailbox + :param recipients: list of email recipients + :param nb_msgs: expected number of entries + :returns: list of matched emails + """ + messages = [email for email in MAILBOX + if email.message.get('Subject') == subject] + if recipients is not None: + sent_to = set() + for msg in messages: + sent_to.update(msg.recipients) + self.assertSetEqual(set(recipients), sent_to) + if nb_msgs is not None: + self.assertEqual(len(MAILBOX), nb_msgs) + return messages + # deprecated ############################################################### @deprecated('[3.8] use self.execute(...).get_entity(0, 0)') diff -r 1d65b235549f -r bb2080547722 misc/migration/3.10.9_Any.py --- a/misc/migration/3.10.9_Any.py Fri Feb 18 15:26:00 2011 +0100 +++ b/misc/migration/3.10.9_Any.py Tue Mar 08 18:32:19 2011 +0100 @@ -1,4 +1,5 @@ from __future__ import with_statement +import sys # fix some corrupted entities noticed on several instances rql('DELETE CWConstraint X WHERE NOT E constrained_by X') @@ -9,13 +10,17 @@ from logilab.common.shellutils import ProgressBar from cubicweb.server.session import hooks_control rset = rql('Any X, XC WHERE X cwuri XC, X cwuri ~= "%/eid/%"') - pb = ProgressBar(nbops=rset.rowcount, size=70) + if sys.stdout.isatty(): + pb = ProgressBar(nbops=rset.rowcount, size=70) + else: + pb = None with hooks_control(session, session.HOOKS_DENY_ALL, 'integrity'): for i, e in enumerate(rset.entities()): e.set_attributes(cwuri=e.cwuri.replace('/eid', '')) if i % 100: # commit every 100 entities to limit memory consumption commit(ask_confirm=False) - pb.update() + if pb is not None: + pb.update() commit(ask_confirm=False) try: diff -r 1d65b235549f -r bb2080547722 misc/scripts/repair_file_1-9_migration.py --- a/misc/scripts/repair_file_1-9_migration.py Fri Feb 18 15:26:00 2011 +0100 +++ b/misc/scripts/repair_file_1-9_migration.py Tue Mar 08 18:32:19 2011 +0100 @@ -19,9 +19,9 @@ sourcescfg = repo.config.sources() backupcfg = cwconfig.instance_configuration(backupinstance) backupcfg.repairing = True -backuprepo, backupcnx = dbapi.in_memory_cnx(backupcfg, sourcescfg['admin']['login'], - password=sourcescfg['admin']['password'], - host='localhost') +backuprepo, backupcnx = dbapi.in_memory_repo_cnx(backupcfg, sourcescfg['admin']['login'], + password=sourcescfg['admin']['password'], + host='localhost') backupcu = backupcnx.cursor() with hooks_control(session, session.HOOKS_DENY_ALL): diff -r 1d65b235549f -r bb2080547722 server/__init__.py --- a/server/__init__.py Fri Feb 18 15:26:00 2011 +0100 +++ b/server/__init__.py Tue Mar 08 18:32:19 2011 +0100 @@ -121,7 +121,7 @@ with the minimal set of entities (ie at least the schema, base groups and a initial user) """ - from cubicweb.dbapi import in_memory_cnx + from cubicweb.dbapi import in_memory_repo_cnx from cubicweb.server.repository import Repository from cubicweb.server.utils import manager_userpasswd from cubicweb.server.sqlutils import sqlexec, sqlschema, sqldropschema @@ -185,7 +185,7 @@ repo.shutdown() # reloging using the admin user config._cubes = None # avoid assertion error - repo, cnx = in_memory_cnx(config, login, password=pwd) + repo, cnx = in_memory_repo_cnx(config, login, password=pwd) repo.system_source.eid = ssource.eid # redo this manually # trigger vreg initialisation of entity classes config.cubicweb_appobject_path = set(('entities',)) diff -r 1d65b235549f -r bb2080547722 server/serverctl.py --- a/server/serverctl.py Fri Feb 18 15:26:00 2011 +0100 +++ b/server/serverctl.py Tue Mar 08 18:32:19 2011 +0100 @@ -130,7 +130,7 @@ def repo_cnx(config): """return a in-memory repository and a db api connection it""" - from cubicweb.dbapi import in_memory_cnx + from cubicweb.dbapi import in_memory_repo_cnx from cubicweb.server.utils import manager_userpasswd try: login = config.sources()['admin']['login'] @@ -139,7 +139,7 @@ login, pwd = manager_userpasswd() while True: try: - return in_memory_cnx(config, login, password=pwd) + return in_memory_repo_cnx(config, login, password=pwd) except AuthenticationError: print '-> Error: wrong user/password.' # reset cubes else we'll have an assertion error on next retry diff -r 1d65b235549f -r bb2080547722 server/session.py --- a/server/session.py Fri Feb 18 15:26:00 2011 +0100 +++ b/server/session.py Tue Mar 08 18:32:19 2011 +0100 @@ -854,6 +854,10 @@ del self.__threaddata del self._tx_data + @property + def closed(self): + return not hasattr(self, '_tx_data') + # transaction data/operations management ################################## @property diff -r 1d65b235549f -r bb2080547722 server/sources/ldapuser.py --- a/server/sources/ldapuser.py Fri Feb 18 15:26:00 2011 +0100 +++ b/server/sources/ldapuser.py Tue Mar 08 18:32:19 2011 +0100 @@ -196,6 +196,7 @@ self._interval = typedconfig['synchronization-interval'] self._cache_ttl = max(71, typedconfig['cache-life-time']) self.reset_caches() + self._conn = None def reset_caches(self): """method called during test to reset potential source caches""" diff -r 1d65b235549f -r bb2080547722 server/test/unittest_storage.py --- a/server/test/unittest_storage.py Fri Feb 18 15:26:00 2011 +0100 +++ b/server/test/unittest_storage.py Tue Mar 08 18:32:19 2011 +0100 @@ -60,7 +60,7 @@ storages.set_attribute_storage(self.repo, 'File', 'data', bfs_storage) def tearDown(self): - super(CubicWebTC, self).tearDown() + super(StorageTC, self).tearDown() storages.unset_attribute_storage(self.repo, 'File', 'data') shutil.rmtree(self.tempdir) diff -r 1d65b235549f -r bb2080547722 uilib.py --- a/uilib.py Fri Feb 18 15:26:00 2011 +0100 +++ b/uilib.py Tue Mar 08 18:32:19 2011 +0100 @@ -47,9 +47,8 @@ return 'Any X WHERE X eid %s' % eid def eid_param(name, eid): + assert name is not None assert eid is not None - if eid is None: - eid = '' return '%s:%s' % (name, eid) def printable_value(req, attrtype, value, props=None, displaytime=True):