# HG changeset patch # User Julien Cristau # Date 1405697725 -7200 # Node ID fa44db7da2dc4cca37ec1e4f1197189d9dbb4269 # Parent 928732ec00dd5742987ef7bb5fc4682d9cf7c6c4# Parent 4900a937838b682e0d1e4dea4f9d9ab068b03fb0 merge 3.19.3 into 3.20 branch diff -r 928732ec00dd -r fa44db7da2dc .hgtags --- a/.hgtags Thu Jul 17 11:08:56 2014 +0200 +++ b/.hgtags Fri Jul 18 17:35:25 2014 +0200 @@ -332,6 +332,9 @@ ee413076752b3e606801ef55e48f7e7ccd1f7238 cubicweb-version-3.17.15 ee413076752b3e606801ef55e48f7e7ccd1f7238 cubicweb-debian-version-3.17.15-1 ee413076752b3e606801ef55e48f7e7ccd1f7238 cubicweb-centos-version-3.17.15-1 +a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-version-3.17.16 +a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-debian-version-3.17.16-1 +a979d1594af6501a774fb32eb67cd32fea626655 cubicweb-centos-version-3.17.16-1 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-version-3.18.0 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-debian-version-3.18.0-1 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-centos-version-3.18.0-1 @@ -356,3 +359,9 @@ 1fe4bc4a8ac8831a379e9ebea08d75fbb6fc5c2a cubicweb-version-3.19.1 1fe4bc4a8ac8831a379e9ebea08d75fbb6fc5c2a cubicweb-debian-version-3.19.1-1 1fe4bc4a8ac8831a379e9ebea08d75fbb6fc5c2a cubicweb-centos-version-3.19.1-1 +8ac2202866e747444ce12778ff8789edd9c92eae cubicweb-version-3.19.2 +8ac2202866e747444ce12778ff8789edd9c92eae cubicweb-debian-version-3.19.2-1 +8ac2202866e747444ce12778ff8789edd9c92eae cubicweb-centos-version-3.19.2-1 +37f7c60f89f13dfcf326a4ea0a98ca20d959f7bd cubicweb-version-3.19.3 +37f7c60f89f13dfcf326a4ea0a98ca20d959f7bd cubicweb-debian-version-3.19.3-1 +37f7c60f89f13dfcf326a4ea0a98ca20d959f7bd cubicweb-centos-version-3.19.3-1 diff -r 928732ec00dd -r fa44db7da2dc __pkginfo__.py --- a/__pkginfo__.py Thu Jul 17 11:08:56 2014 +0200 +++ b/__pkginfo__.py Fri Jul 18 17:35:25 2014 +0200 @@ -22,7 +22,7 @@ modname = distname = "cubicweb" -numversion = (3, 19, 1) +numversion = (3, 19, 3) version = '.'.join(str(num) for num in numversion) description = "a repository of entities / relations for knowledge management" @@ -44,8 +44,7 @@ 'rql': '>= 0.31.2', 'yams': '>= 0.39.1', #gettext # for xgettext, msgcat, etc... - # web dependancies - 'simplejson': '>= 2.0.9', + # web dependencies 'lxml': '', 'Twisted': '', # XXX graphviz diff -r 928732ec00dd -r fa44db7da2dc cubicweb.spec --- a/cubicweb.spec Thu Jul 17 11:08:56 2014 +0200 +++ b/cubicweb.spec Fri Jul 18 17:35:25 2014 +0200 @@ -7,7 +7,7 @@ %endif Name: cubicweb -Version: 3.19.1 +Version: 3.19.3 Release: logilab.1%{?dist} Summary: CubicWeb is a semantic web application framework Source0: http://download.logilab.org/pub/cubicweb/cubicweb-%{version}.tar.gz diff -r 928732ec00dd -r fa44db7da2dc cwvreg.py --- a/cwvreg.py Thu Jul 17 11:08:56 2014 +0200 +++ b/cwvreg.py Fri Jul 18 17:35:25 2014 +0200 @@ -241,7 +241,7 @@ class CWRegistry(Registry): def __init__(self, vreg): - super(CWRegistry, self).__init__(vreg.config) + super(CWRegistry, self).__init__(vreg.config.debugmode) self.vreg = vreg @property diff -r 928732ec00dd -r fa44db7da2dc dataimport.py --- a/dataimport.py Thu Jul 17 11:08:56 2014 +0200 +++ b/dataimport.py Fri Jul 18 17:35:25 2014 +0200 @@ -1114,7 +1114,6 @@ def _handle_insert_entity_sql(self, session, sql, attrs): # We have to overwrite the source given in parameters # as here, we directly use the system source - attrs['source'] = 'system' attrs['asource'] = self.system_source.uri self._append_to_entities(sql, attrs) @@ -1137,7 +1136,7 @@ assert isinstance(extid, str) extid = b64encode(extid) attrs = {'type': entity.cw_etype, 'eid': entity.eid, 'extid': extid, - 'source': 'system', 'asource': source.uri} + 'asource': source.uri} self._handle_insert_entity_sql(session, self.sqlgen.insert('entities', attrs), attrs) # insert core relations: is, is_instance_of and cw_source try: diff -r 928732ec00dd -r fa44db7da2dc dbapi.py --- a/dbapi.py Thu Jul 17 11:08:56 2014 +0200 +++ b/dbapi.py Fri Jul 18 17:35:25 2014 +0200 @@ -679,7 +679,16 @@ @check_not_closed def entity_metas(self, eid): """return a tuple (type, sourceuri, extid) for the entity with id """ - return self._repo.entity_metas(self.sessionid, eid, **self._txid()) + try: + return self._repo.entity_metas(self.sessionid, eid, **self._txid()) + except AttributeError: + # talking to pre 3.19 repository + metas = self._repo.describe(self.sessionid, eid, **self._txid()) + if len(metas) == 3: # even older backward compat + metas = list(metas) + metas.append(metas[1]) + return dict(zip(('type', 'source', 'extid', 'asource'), metas)) + @deprecated('[3.19] use .entity_metas(eid) instead') @check_not_closed diff -r 928732ec00dd -r fa44db7da2dc debian/changelog --- a/debian/changelog Thu Jul 17 11:08:56 2014 +0200 +++ b/debian/changelog Fri Jul 18 17:35:25 2014 +0200 @@ -1,3 +1,15 @@ +cubicweb (3.19.3-1) unstable; urgency=low + + * new upstream release + + -- Julien Cristau Fri, 18 Jul 2014 16:16:32 +0200 + +cubicweb (3.19.2-1) unstable; urgency=low + + * new upstream release + + -- Julien Cristau Thu, 03 Jul 2014 09:53:52 +0200 + cubicweb (3.19.1-1) unstable; urgency=low * new upstream release @@ -46,6 +58,12 @@ -- Julien Cristau Fri, 10 Jan 2014 17:14:18 +0100 +cubicweb (3.17.16-1) unstable; urgency=low + + * new upstream value + + -- Aurelien Campeas Mon, 07 Jul 2014 19:26:12 +0200 + cubicweb (3.17.15-1) unstable; urgency=low * new upstream release diff -r 928732ec00dd -r fa44db7da2dc debian/control --- a/debian/control Thu Jul 17 11:08:56 2014 +0200 +++ b/debian/control Fri Jul 18 17:35:25 2014 +0200 @@ -124,7 +124,6 @@ ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), - python-simplejson (>= 2.0.9) Recommends: python-docutils (>= 0.6), python-vobject, diff -r 928732ec00dd -r fa44db7da2dc devtools/__init__.py --- a/devtools/__init__.py Thu Jul 17 11:08:56 2014 +0200 +++ b/devtools/__init__.py Fri Jul 18 17:35:25 2014 +0200 @@ -21,6 +21,7 @@ import os import sys +import errno import logging import shutil import pickle @@ -277,8 +278,9 @@ sourcefile='/path/to/sources') def test_something(self): - rset = self.execute('Any X WHERE X is CWUser') - self.view('foaf', rset) + with self.admin_access.web_request() as req: + rset = req.execute('Any X WHERE X is CWUser') + self.view('foaf', rset, req=req) """ skip_db_create_and_restore = True @@ -544,14 +546,29 @@ super(PostgresTestDataBaseHandler, self).__init__(*args, **kwargs) datadir = join(self.config.apphome, 'pgdb') if not exists(datadir): - subprocess.check_call(['initdb', '-D', datadir, '-E', 'utf-8', '--locale=C']) + try: + subprocess.check_call(['initdb', '-D', datadir, '-E', 'utf-8', '--locale=C']) + + except OSError, err: + if err.errno == errno.ENOENT: + raise OSError('"initdb" could not be found. ' + 'You should add the postgresql bin folder to your PATH ' + '(/usr/lib/postgresql/9.1/bin for example).') + raise port = self.system_source['db-port'] directory = self.system_source['db-host'] env = os.environ.copy() env['PGPORT'] = str(port) env['PGHOST'] = str(directory) - subprocess.check_call(['pg_ctl', 'start', '-w', '-D', datadir, '-o', '-h "" -k %s -p %s' % (directory, port)], - env=env) + try: + subprocess.check_call(['pg_ctl', 'start', '-w', '-D', datadir, '-o', '-h "" -k %s -p %s' % (directory, port)], + env=env) + except OSError, err: + if err.errno == errno.ENOENT: + raise OSError('"pg_ctl" could not be found. ' + 'You should add the postgresql bin folder to your PATH ' + '(/usr/lib/postgresql/9.1/bin for example).') + raise self.__CTL.add(datadir) @property diff -r 928732ec00dd -r fa44db7da2dc devtools/fill.py --- a/devtools/fill.py Thu Jul 17 11:08:56 2014 +0200 +++ b/devtools/fill.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -352,7 +352,7 @@ -def select(constraints, cursor, selectvar='O', objtype=None): +def select(constraints, cnx, selectvar='O', objtype=None): """returns list of eids matching should be either 'O' or 'S' to match schema definitions @@ -361,7 +361,7 @@ rql = 'Any %s WHERE %s' % (selectvar, constraints) if objtype: rql += ', %s is %s' % (selectvar, objtype) - rset = cursor.execute(rql) + rset = cnx.execute(rql) except Exception: print "could restrict eid_list with given constraints (%r)" % constraints return [] @@ -369,7 +369,7 @@ -def make_relations_queries(schema, edict, cursor, ignored_relations=(), +def make_relations_queries(schema, edict, cnx, ignored_relations=(), existingrels=None): """returns a list of generated RQL queries for relations :param schema: The instance schema @@ -379,7 +379,7 @@ :param ignored_relations: list of relations to ignore (i.e. don't try to generate insert queries for these relations) """ - gen = RelationsQueriesGenerator(schema, cursor, existingrels) + gen = RelationsQueriesGenerator(schema, cnx, existingrels) return gen.compute_queries(edict, ignored_relations) def composite_relation(rschema): @@ -393,9 +393,9 @@ class RelationsQueriesGenerator(object): rql_tmpl = 'SET S %s O WHERE S eid %%(subjeid)s, O eid %%(objeid)s' - def __init__(self, schema, cursor, existing=None): + def __init__(self, schema, cnx, existing=None): self.schema = schema - self.cursor = cursor + self.cnx = cnx self.existingrels = existing or {} def compute_queries(self, edict, ignored_relations): @@ -457,7 +457,7 @@ # restrict object eids if possible # XXX the attempt to restrict below in completely wrong # disabling it for now - objeids = select(restrictions, self.cursor, objtype=obj) + objeids = select(restrictions, self.cnx, objtype=obj) else: objeids = oedict.get(obj, frozenset()) if subjcard in '?1' or objcard in '?1': diff -r 928732ec00dd -r fa44db7da2dc devtools/repotest.py --- a/devtools/repotest.py Thu Jul 17 11:08:56 2014 +0200 +++ b/devtools/repotest.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -22,17 +22,12 @@ __docformat__ = "restructuredtext en" -from copy import deepcopy from pprint import pprint -from logilab.common.decorators import clear_cache from logilab.common.testlib import SkipTest -def tuplify(list): - for i in range(len(list)): - if type(list[i]) is not type(()): - list[i] = tuple(list[i]) - return list +def tuplify(mylist): + return [tuple(item) for item in mylist] def snippet_cmp(a, b): a = (a[0], [e.expression for e in a[1]]) @@ -40,17 +35,18 @@ return cmp(a, b) def test_plan(self, rql, expected, kwargs=None): - plan = self._prepare_plan(rql, kwargs) - self.planner.build_plan(plan) - try: - self.assertEqual(len(plan.steps), len(expected), - 'expected %s steps, got %s' % (len(expected), len(plan.steps))) - # step order is important - for i, step in enumerate(plan.steps): - compare_steps(self, step.test_repr(), expected[i]) - except AssertionError: - pprint([step.test_repr() for step in plan.steps]) - raise + with self.session.new_cnx() as cnx: + plan = self._prepare_plan(cnx, rql, kwargs) + self.planner.build_plan(plan) + try: + self.assertEqual(len(plan.steps), len(expected), + 'expected %s steps, got %s' % (len(expected), len(plan.steps))) + # step order is important + for i, step in enumerate(plan.steps): + compare_steps(self, step.test_repr(), expected[i]) + except AssertionError: + pprint([step.test_repr() for step in plan.steps]) + raise def compare_steps(self, step, expected): try: @@ -161,8 +157,9 @@ def setUp(self): self.repo = FakeRepo(self.schema, config=FakeConfig(apphome=self.datadir)) self.repo.system_source = mock_object(dbdriver=self.backend) - self.rqlhelper = RQLHelper(self.schema, special_relations={'eid': 'uid', - 'has_text': 'fti'}, + self.rqlhelper = RQLHelper(self.schema, + special_relations={'eid': 'uid', + 'has_text': 'fti'}, backend=self.backend) self.qhelper = QuerierHelper(self.repo, self.schema) ExecutionPlan._check_permissions = _dummy_check_permissions @@ -204,27 +201,22 @@ self.ueid = self.session.user.eid assert self.ueid != -1 self.repo._type_source_cache = {} # clear cache - self.cnxset = self.session.set_cnxset() self.maxeid = self.get_max_eid() do_monkey_patch() self._dumb_sessions = [] def get_max_eid(self): - return self.session.execute('Any MAX(X)')[0][0] + with self.session.new_cnx() as cnx: + return cnx.execute('Any MAX(X)')[0][0] + def cleanup(self): - self.session.set_cnxset() - self.session.execute('DELETE Any X WHERE X eid > %s' % self.maxeid) + with self.session.new_cnx() as cnx: + cnx.execute('DELETE Any X WHERE X eid > %s' % self.maxeid) + cnx.commit() def tearDown(self): undo_monkey_patch() - self.session.rollback() self.cleanup() - self.commit() - # properly close dumb sessions - for session in self._dumb_sessions: - session.rollback() - session.close() - self.repo._free_cnxset(self.cnxset) assert self.session.user.eid != -1 def set_debug(self, debug): @@ -239,7 +231,7 @@ rqlhelper._analyser.uid_func_mapping = {} return rqlhelper - def _prepare_plan(self, rql, kwargs=None, simplify=True): + def _prepare_plan(self, cnx, rql, kwargs=None, simplify=True): rqlhelper = self._rqlhelper() rqlst = rqlhelper.parse(rql) rqlhelper.compute_solutions(rqlst, kwargs=kwargs) @@ -247,10 +239,10 @@ rqlhelper.simplify(rqlst) for select in rqlst.children: select.solutions.sort() - return self.o.plan_factory(rqlst, kwargs, self.session) + return self.o.plan_factory(rqlst, kwargs, cnx) - def _prepare(self, rql, kwargs=None): - plan = self._prepare_plan(rql, kwargs, simplify=False) + def _prepare(self, cnx, rql, kwargs=None): + plan = self._prepare_plan(cnx, rql, kwargs, simplify=False) plan.preprocess(plan.rqlst) rqlst = plan.rqlst.children[0] rqlst.solutions = remove_unused_solutions(rqlst, rqlst.solutions, {}, self.repo.schema)[0] @@ -259,21 +251,20 @@ def user_groups_session(self, *groups): """lightweight session using the current user with hi-jacked groups""" # use self.session.user.eid to get correct owned_by relation, unless explicit eid - u = self.repo._build_user(self.session, self.session.user.eid) - u._groups = set(groups) - s = Session(u, self.repo) - s._cnx.cnxset = self.cnxset - s._cnx.ctx_count = 1 - # register session to ensure it gets closed - self._dumb_sessions.append(s) - return s + with self.session.new_cnx() as cnx: + u = self.repo._build_user(cnx, self.session.user.eid) + u._groups = set(groups) + s = Session(u, self.repo) + return s - def execute(self, rql, args=None, build_descr=True): - return self.o.execute(self.session, rql, args, build_descr) - - def commit(self): - self.session.commit() - self.session.set_cnxset() + def qexecute(self, rql, args=None, build_descr=True): + with self.session.new_cnx() as cnx: + with cnx.ensure_cnx_set: + try: + return self.o.execute(cnx, rql, args, build_descr) + finally: + if rql.startswith(('INSERT', 'DELETE', 'SET')): + cnx.commit() class BasePlannerTC(BaseQuerierTC): @@ -282,31 +273,24 @@ # XXX source_defs self.o = self.repo.querier self.session = self.repo._sessions.values()[0] - self.cnxset = self.session.set_cnxset() self.schema = self.o.schema self.system = self.repo.system_source do_monkey_patch() - self._dumb_sessions = [] # by hi-jacked parent setup self.repo.vreg.rqlhelper.backend = 'postgres' # so FTIRANK is considered def tearDown(self): undo_monkey_patch() - for session in self._dumb_sessions: - if session._cnx.cnxset is not None: - session._cnx.cnxset = None - session.close() - def _prepare_plan(self, rql, kwargs=None): + def _prepare_plan(self, cnx, rql, kwargs=None): rqlst = self.o.parse(rql, annotate=True) - self.o.solutions(self.session, rqlst, kwargs) + self.o.solutions(cnx, rqlst, kwargs) if rqlst.TYPE == 'select': self.repo.vreg.rqlhelper.annotate(rqlst) for select in rqlst.children: select.solutions.sort() else: rqlst.solutions.sort() - with self.session.ensure_cnx_set: - return self.o.plan_factory(rqlst, kwargs, self.session) + return self.o.plan_factory(rqlst, kwargs, cnx) # monkey patch some methods to get predicatable results ####################### @@ -354,24 +338,6 @@ _sort=lambda rels: sorted(rels, key=sort_key)) -def _merge_input_maps(*args, **kwargs): - return sorted(_orig_merge_input_maps(*args, **kwargs)) - -def _choose_term(self, source, sourceterms): - # predictable order for test purpose - def get_key(x): - try: - # variable - return x.name - except AttributeError: - try: - # relation - return x.r_type - except AttributeError: - # const - return x.value - return _orig_choose_term(self, source, DumbOrderedDict2(sourceterms, get_key)) - def _ordered_iter_relations(stinfo): return sorted(_orig_iter_relations(stinfo), key=lambda x:x.r_type) diff -r 928732ec00dd -r fa44db7da2dc devtools/test/unittest_testlib.py --- a/devtools/test/unittest_testlib.py Thu Jul 17 11:08:56 2014 +0200 +++ b/devtools/test/unittest_testlib.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -39,11 +39,13 @@ class MyWebTest(CubicWebTC): def test_error_view(self): - self.request().create_entity('Bug', title=u"bt") - self.view('raising', self.execute('Bug B'), template=None) + with self.admin_access.web_request() as req: + req.create_entity('Bug', title=u"bt") + self.view('raising', req.execute('Bug B'), template=None, req=req) def test_correct_view(self): - self.view('primary', self.execute('CWUser U'), template=None) + with self.admin_access.web_request() as req: + self.view('primary', req.execute('CWUser U'), template=None, req=req) tests = [MyWebTest('test_error_view'), MyWebTest('test_correct_view')] result = self.runner.run(TestSuite(tests)) @@ -98,6 +100,7 @@ class HTMLPageInfoTC(TestCase): """test cases for PageInfo""" + def setUp(self): parser = htmlparser.HTMLValidator() # disable cleanup that would remove doctype @@ -113,7 +116,6 @@ parser = htmlparser.DTDValidator() self.assertRaises(AssertionError, parser.parse_string, HTML_PAGE_ERROR) - def test_has_title_no_level(self): """tests h? tags information""" self.assertEqual(self.page_info.has_title('Test'), True) @@ -160,6 +162,7 @@ class CWUtilitiesTC(CubicWebTC): + def test_temporary_permissions_eschema(self): eschema = self.schema['CWUser'] with self.temporary_permissions(CWUser={'read': ()}): @@ -175,11 +178,13 @@ self.assertTrue(rdef.permissions['read'], ()) def test_temporary_appobjects_registered(self): + class AnAppobject(object): __registries__ = ('hip',) __regid__ = 'hop' __select__ = yes() registered = None + @classmethod def __registered__(cls, reg): cls.registered = reg @@ -190,10 +195,11 @@ self.assertNotIn(AnAppobject, self.vreg['hip']['hop']) def test_login(self): - """Calling login should not break self.session hook control""" - self.hook_executed = False - babar = self.create_user(self.request(), 'babar') - self.commit() + """Calling login should not break hook control""" + with self.admin_access.repo_cnx() as cnx: + self.hook_executed = False + self.create_user(cnx, 'babar') + cnx.commit() from cubicweb.server import hook from cubicweb.predicates import is_instance @@ -208,31 +214,31 @@ def __call__(self): self.test.hook_executed = True - self.login('babar') - with self.temporary_appobjects(MyHook): - with self.session.allow_all_hooks_but('test-hook'): - req = self.request() - prop = req.create_entity('CWProperty', pkey=u'ui.language', value=u'en') - self.commit() - self.assertFalse(self.hook_executed) + with self.new_access('babar').repo_cnx() as cnx: + with self.temporary_appobjects(MyHook): + with cnx.allow_all_hooks_but('test-hook'): + prop = cnx.create_entity('CWProperty', pkey=u'ui.language', value=u'en') + cnx.commit() + self.assertFalse(self.hook_executed) class RepoAccessTC(CubicWebTC): + def test_repo_connection(self): acc = self.new_access('admin') - with acc.repo_cnx() as cnx: + with acc.repo_cnx() as cnx: rset = cnx.execute('Any X WHERE X is CWUser') self.assertTrue(rset) def test_client_connection(self): acc = self.new_access('admin') - with acc.client_cnx() as cnx: + with acc.client_cnx() as cnx: rset = cnx.execute('Any X WHERE X is CWUser') self.assertTrue(rset) def test_web_request(self): acc = self.new_access('admin') - with acc.web_request(elephant='babar') as req: + with acc.web_request(elephant='babar') as req: rset = req.execute('Any X WHERE X is CWUser') self.assertTrue(rset) self.assertEqual('babar', req.form['elephant']) diff -r 928732ec00dd -r fa44db7da2dc devtools/testlib.py --- a/devtools/testlib.py Thu Jul 17 11:08:56 2014 +0200 +++ b/devtools/testlib.py Fri Jul 18 17:35:25 2014 +0200 @@ -823,12 +823,13 @@ def list_startup_views(self): """returns the list of startup views""" - req = self.request() - for view in self.vreg['views'].possible_views(req, None): - if view.category == 'startupview': - yield view.__regid__ - else: - not_selected(self.vreg, view) + with self.admin_access.web_request() as req: + for view in self.vreg['views'].possible_views(req, None): + if view.category == 'startupview': + yield view.__regid__ + else: + not_selected(self.vreg, view) + # web ui testing utilities ################################################# @@ -842,6 +843,7 @@ publisher.error_handler = raise_error_handler return publisher + @deprecated('[3.19] use the .remote_calling method') def remote_call(self, fname, *args): """remote json call simulation""" dump = json.dumps @@ -850,6 +852,14 @@ ctrl = self.vreg['controllers'].select('ajax', req) return ctrl.publish(), req + @contextmanager + def remote_calling(self, fname, *args): + """remote json call simulation""" + args = [json.dumps(arg) for arg in args] + with self.admin_access.web_request(fname=fname, pageid='123', arg=args) as req: + ctrl = self.vreg['controllers'].select('ajax', req) + yield ctrl.publish(), req + def app_handle_request(self, req, path='view'): return self.app.core_handle(req, path) @@ -1178,7 +1188,7 @@ # XXX cleanup unprotected_entities & all mess -def how_many_dict(schema, cursor, how_many, skip): +def how_many_dict(schema, cnx, how_many, skip): """given a schema, compute how many entities by type we need to be able to satisfy relations cardinality. @@ -1212,7 +1222,7 @@ # step 1, compute a base number of each entity types: number of already # existing entities of this type + `how_many` for etype in unprotected_entities(schema, strict=True): - howmanydict[str(etype)] = cursor.execute('Any COUNT(X) WHERE X is %s' % etype)[0][0] + howmanydict[str(etype)] = cnx.execute('Any COUNT(X) WHERE X is %s' % etype)[0][0] if etype in unprotected: howmanydict[str(etype)] += how_many # step 2, augment nb entity per types to satisfy cardinality constraints, @@ -1246,10 +1256,10 @@ def to_test_etypes(self): return unprotected_entities(self.schema, strict=True) - def custom_populate(self, how_many, cursor): + def custom_populate(self, how_many, cnx): pass - def post_populate(self, cursor): + def post_populate(self, cnx): pass @@ -1258,77 +1268,79 @@ """this method populates the database with `how_many` entities of each possible type. It also inserts random relations between them """ - with self.session.security_enabled(read=False, write=False): - self._auto_populate(how_many) + with self.admin_access.repo_cnx() as cnx: + with cnx.security_enabled(read=False, write=False): + self._auto_populate(cnx, how_many) + cnx.commit() - def _auto_populate(self, how_many): - cu = self.cursor() - self.custom_populate(how_many, cu) + def _auto_populate(self, cnx, how_many): + self.custom_populate(how_many, cnx) vreg = self.vreg - howmanydict = how_many_dict(self.schema, cu, how_many, self.no_auto_populate) + howmanydict = how_many_dict(self.schema, cnx, how_many, self.no_auto_populate) for etype in unprotected_entities(self.schema): if etype in self.no_auto_populate: continue nb = howmanydict.get(etype, how_many) for rql, args in insert_entity_queries(etype, self.schema, vreg, nb): - cu.execute(rql, args) + cnx.execute(rql, args) edict = {} for etype in unprotected_entities(self.schema, strict=True): - rset = cu.execute('%s X' % etype) + rset = cnx.execute('%s X' % etype) edict[str(etype)] = set(row[0] for row in rset.rows) existingrels = {} ignored_relations = SYSTEM_RELATIONS | self.ignored_relations for rschema in self.schema.relations(): if rschema.final or rschema in ignored_relations: continue - rset = cu.execute('DISTINCT Any X,Y WHERE X %s Y' % rschema) + rset = cnx.execute('DISTINCT Any X,Y WHERE X %s Y' % rschema) existingrels.setdefault(rschema.type, set()).update((x, y) for x, y in rset) - q = make_relations_queries(self.schema, edict, cu, ignored_relations, + q = make_relations_queries(self.schema, edict, cnx, ignored_relations, existingrels=existingrels) for rql, args in q: try: - cu.execute(rql, args) + cnx.execute(rql, args) except ValidationError as ex: # failed to satisfy some constraint print 'error in automatic db population', ex - self.session.commit_state = None # reset uncommitable flag - self.post_populate(cu) - self.commit() + cnx.commit_state = None # reset uncommitable flag + self.post_populate(cnx) def iter_individual_rsets(self, etypes=None, limit=None): etypes = etypes or self.to_test_etypes() - for etype in etypes: - if limit: - rql = 'Any X LIMIT %s WHERE X is %s' % (limit, etype) - else: - rql = 'Any X WHERE X is %s' % etype - rset = self.execute(rql) - for row in xrange(len(rset)): - if limit and row > limit: - break - # XXX iirk - rset2 = rset.limit(limit=1, offset=row) - yield rset2 + with self.admin_access.web_request() as req: + for etype in etypes: + if limit: + rql = 'Any X LIMIT %s WHERE X is %s' % (limit, etype) + else: + rql = 'Any X WHERE X is %s' % etype + rset = req.execute(rql) + for row in xrange(len(rset)): + if limit and row > limit: + break + # XXX iirk + rset2 = rset.limit(limit=1, offset=row) + yield rset2 def iter_automatic_rsets(self, limit=10): """generates basic resultsets for each entity type""" etypes = self.to_test_etypes() if not etypes: return - for etype in etypes: - yield self.execute('Any X LIMIT %s WHERE X is %s' % (limit, etype)) - etype1 = etypes.pop() - try: - etype2 = etypes.pop() - except KeyError: - etype2 = etype1 - # test a mixed query (DISTINCT/GROUP to avoid getting duplicate - # X which make muledit view failing for instance (html validation fails - # because of some duplicate "id" attributes) - yield self.execute('DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is %s, Y is %s' % (etype1, etype2)) - # test some application-specific queries if defined - for rql in self.application_rql: - yield self.execute(rql) + with self.admin_access.web_request() as req: + for etype in etypes: + yield req.execute('Any X LIMIT %s WHERE X is %s' % (limit, etype)) + etype1 = etypes.pop() + try: + etype2 = etypes.pop() + except KeyError: + etype2 = etype1 + # test a mixed query (DISTINCT/GROUP to avoid getting duplicate + # X which make muledit view failing for instance (html validation fails + # because of some duplicate "id" attributes) + yield req.execute('DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is %s, Y is %s' % (etype1, etype2)) + # test some application-specific queries if defined + for rql in self.application_rql: + yield req.execute(rql) def _test_everything_for(self, rset): """this method tries to find everything that can be tested @@ -1390,8 +1402,8 @@ ## startup views def test_startup_views(self): for vid in self.list_startup_views(): - req = self.request() - yield self.view, vid, None, req + with self.admin_access.web_request() as req: + yield self.view, vid, None, req # registry instrumentization ################################################### diff -r 928732ec00dd -r fa44db7da2dc doc/book/en/annexes/rql/language.rst --- a/doc/book/en/annexes/rql/language.rst Thu Jul 17 11:08:56 2014 +0200 +++ b/doc/book/en/annexes/rql/language.rst Fri Jul 18 17:35:25 2014 +0200 @@ -350,9 +350,10 @@ matching state of or tagged by the expected tag, * the later will retrieve all versions, state and tags (cartesian product!), - compute join and then exclude each row which are in the matching state of or - tagged by the expected tag. This implies that : you won't get any result if the - in_state or tag + compute join and then exclude each row which are in the matching state or + tagged by the expected tag. This implies that you won't get any result if the + in_state or tag tables are empty (ie there is no such relation in the + application). This is usually NOT what you want. Another common case where you may want to use ``EXISTS`` is when you find yourself using ``DISTINCT`` at the beginning of your query to @@ -562,19 +563,19 @@ Aggregate functions ``````````````````` -+--------------------+----------------------------------------------------------+ -| :func:`COUNT` | return the number of rows | -+--------------------+----------------------------------------------------------+ -| :func:`MIN` | return the minimum value | -+--------------------+----------------------------------------------------------+ -| :func:`MAX` | return the maximum value | -+--------------------+----------------------------------------------------------+ -| :func:`AVG` | return the average value | -+--------------------+----------------------------------------------------------+ -| :func:`SUM` | return the sum of values | -+--------------------+----------------------------------------------------------+ -| :func:`COMMA_JOIN` | return each value separated by a comma (for string only) | -+--------------------+----------------------------------------------------------+ ++------------------------+----------------------------------------------------------+ +| ``COUNT(Any)`` | return the number of rows | ++------------------------+----------------------------------------------------------+ +| ``MIN(Any)`` | return the minimum value | ++------------------------+----------------------------------------------------------+ +| ``MAX(Any)`` | return the maximum value | ++------------------------+----------------------------------------------------------+ +| ``AVG(Any)`` | return the average value | ++------------------------+----------------------------------------------------------+ +| ``SUM(Any)`` | return the sum of values | ++------------------------+----------------------------------------------------------+ +| ``COMMA_JOIN(String)`` | return each value separated by a comma (for string only) | ++------------------------+----------------------------------------------------------+ All aggregate functions above take a single argument. Take care some aggregate functions (e.g. ``MAX``, ``MIN``) may return `None` if there is no @@ -585,67 +586,67 @@ String transformation functions ``````````````````````````````` -+---------------------------------------------------+-----------------------------------------------------------------+ -| :func:`UPPER(String)` | upper case the string | -+---------------------------------------------------+-----------------------------------------------------------------+ -| :func:`LOWER(String)` | lower case the string | -+---------------------------------------------------+-----------------------------------------------------------------+ -| :func:`LENGTH(String)` | return the length of the string | -+---------------------------------------------------+-----------------------------------------------------------------+ -| :func:`SUBSTRING(String, start, length)` | extract from the string a string starting at given index and of | -| | given length | -+---------------------------------------------------+-----------------------------------------------------------------+ -| :func:`LIMIT_SIZE(String, max size)` | if the length of the string is greater than given max size, | -| | strip it and add ellipsis ("..."). The resulting string will | -| | hence have max size + 3 characters | -+---------------------------------------------------+-----------------------------------------------------------------+ -| :func:`TEXT_LIMIT_SIZE(String, format, max size)` | similar to the above, but allow to specify the MIME type of the | -| | text contained by the string. Supported formats are text/html, | -| | text/xhtml and text/xml. All others will be considered as plain | -| | text. For non plain text format, sgml tags will be first removed| -| | before limiting the string. | -+---------------------------------------------------+-----------------------------------------------------------------+ ++-----------------------------------------------+-----------------------------------------------------------------+ +| ``UPPER(String)`` | upper case the string | ++-----------------------------------------------+-----------------------------------------------------------------+ +| ``LOWER(String)`` | lower case the string | ++-----------------------------------------------+-----------------------------------------------------------------+ +| ``LENGTH(String)`` | return the length of the string | ++-----------------------------------------------+-----------------------------------------------------------------+ +| ``SUBSTRING(String, start, length)`` | extract from the string a string starting at given index and of | +| | given length | ++-----------------------------------------------+-----------------------------------------------------------------+ +| ``LIMIT_SIZE(String, max size)`` | if the length of the string is greater than given max size, | +| | strip it and add ellipsis ("..."). The resulting string will | +| | hence have max size + 3 characters | ++-----------------------------------------------+-----------------------------------------------------------------+ +| ``TEXT_LIMIT_SIZE(String, format, max size)`` | similar to the above, but allow to specify the MIME type of the | +| | text contained by the string. Supported formats are text/html, | +| | text/xhtml and text/xml. All others will be considered as plain | +| | text. For non plain text format, sgml tags will be first removed| +| | before limiting the string. | ++-----------------------------------------------+-----------------------------------------------------------------+ .. _RQLDateFunctions: Date extraction functions ````````````````````````` -+--------------------------+----------------------------------------+ -| :func:`YEAR(Date)` | return the year of a date or datetime | -+--------------------------+----------------------------------------+ -| :func:`MONTH(Date)` | return the month of a date or datetime | -+--------------------------+----------------------------------------+ -| :func:`DAY(Date)` | return the day of a date or datetime | -+--------------------------+----------------------------------------+ -| :func:`HOUR(Datetime)` | return the hours of a datetime | -+--------------------------+----------------------------------------+ -| :func:`MINUTE(Datetime)` | return the minutes of a datetime | -+--------------------------+----------------------------------------+ -| :func:`SECOND(Datetime)` | return the seconds of a datetime | -+--------------------------+----------------------------------------+ -| :func:`WEEKDAY(Date)` | return the day of week of a date or | -| | datetime. Sunday == 1, Saturday == 7. | -+--------------------------+----------------------------------------+ ++----------------------+----------------------------------------+ +| ``YEAR(Date)`` | return the year of a date or datetime | ++----------------------+----------------------------------------+ +| ``MONTH(Date)`` | return the month of a date or datetime | ++----------------------+----------------------------------------+ +| ``DAY(Date)`` | return the day of a date or datetime | ++----------------------+----------------------------------------+ +| ``HOUR(Datetime)`` | return the hours of a datetime | ++----------------------+----------------------------------------+ +| ``MINUTE(Datetime)`` | return the minutes of a datetime | ++----------------------+----------------------------------------+ +| ``SECOND(Datetime)`` | return the seconds of a datetime | ++----------------------+----------------------------------------+ +| ``WEEKDAY(Date)`` | return the day of week of a date or | +| | datetime. Sunday == 1, Saturday == 7. | ++----------------------+----------------------------------------+ .. _RQLOtherFunctions: Other functions ``````````````` -+-----------------------+--------------------------------------------------------------------+ -| :func:`ABS(num)` | return the absolute value of a number | -+-----------------------+--------------------------------------------------------------------+ -| :func:`RANDOM()` | return a pseudo-random value from 0.0 to 1.0 | -+-----------------------+--------------------------------------------------------------------+ -| :func:`FSPATH(X)` | expect X to be an attribute whose value is stored in a | -| | :class:`BFSStorage` and return its path on the file system | -+-----------------------+--------------------------------------------------------------------+ -| :func:`FTIRANK(X)` | expect X to be an entity used in a has_text relation, and return a | -| | number corresponding to the rank order of each resulting entity | -+-----------------------+--------------------------------------------------------------------+ -| :func:`CAST(Type, X)` | expect X to be an attribute and return it casted into the given | -| | final type | -+-----------------------+--------------------------------------------------------------------+ ++-------------------+--------------------------------------------------------------------+ +| ``ABS(num)`` | return the absolute value of a number | ++-------------------+--------------------------------------------------------------------+ +| ``RANDOM()`` | return a pseudo-random value from 0.0 to 1.0 | ++-------------------+--------------------------------------------------------------------+ +| ``FSPATH(X)`` | expect X to be an attribute whose value is stored in a | +| | :class:`BFSStorage` and return its path on the file system | ++-------------------+--------------------------------------------------------------------+ +| ``FTIRANK(X)`` | expect X to be an entity used in a has_text relation, and return a | +| | number corresponding to the rank order of each resulting entity | ++-------------------+--------------------------------------------------------------------+ +| ``CAST(Type, X)`` | expect X to be an attribute and return it casted into the given | +| | final type | ++-------------------+--------------------------------------------------------------------+ .. _RQLExamples: @@ -657,7 +658,7 @@ .. sourcecode:: sql - Any WHERE X eid 53 + Any X WHERE X eid 53 - *Search material such as comics, owned by syt and available* @@ -686,7 +687,7 @@ .. sourcecode:: sql - Any P WHERE P is Person, (P interested_by T, T name 'training') OR + Any P WHERE P is Person, EXISTS(P interested_by T, T name 'training') OR (P city 'Paris') - *The surname and firstname of all people* diff -r 928732ec00dd -r fa44db7da2dc doc/book/en/devrepo/testing.rst --- a/doc/book/en/devrepo/testing.rst Thu Jul 17 11:08:56 2014 +0200 +++ b/doc/book/en/devrepo/testing.rst Fri Jul 18 17:35:25 2014 +0200 @@ -25,8 +25,8 @@ http://docs.python.org/library/sqlite3.html) as a backend. The database is stored in the mycube/test/tmpdb, -mycube/test/tmpdb-template files. If it does not (yet) exists, it will -be built automatically when the test suit starts. +mycube/test/tmpdb-template files. If it does not (yet) exist, it will +be built automatically when the test suite starts. .. warning:: @@ -34,8 +34,8 @@ one must delete these two files. Changes concerned only with entity or relation type properties (constraints, cardinalities, permissions) and generally dealt with using the - `sync_schema_props_perms()` fonction of the migration environment - need not a database regeneration step. + `sync_schema_props_perms()` function of the migration environment do + not need a database regeneration step. .. _hook_test: @@ -53,56 +53,58 @@ class ClassificationHooksTC(CubicWebTC): def setup_database(self): - req = self.request() - group_etype = req.find_one_entity('CWEType', name='CWGroup') - c1 = req.create_entity('Classification', name=u'classif1', - classifies=group_etype) - user_etype = req.find_one_entity('CWEType', name='CWUser') - c2 = req.create_entity('Classification', name=u'classif2', - classifies=user_etype) - self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1) - self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2) + with self.admin_access.repo_cnx() as cnx: + group_etype = cnx.find('CWEType', name='CWGroup').one() + c1 = cnx.create_entity('Classification', name=u'classif1', + classifies=group_etype) + user_etype = cnx.find('CWEType', name='CWUser').one() + c2 = cnx.create_entity('Classification', name=u'classif2', + classifies=user_etype) + self.kw1eid = cnx.create_entity('Keyword', name=u'kwgroup', included_in=c1).eid + cnx.commit() def test_cannot_create_cycles(self): - # direct obvious cycle - self.assertRaises(ValidationError, self.kw1.cw_set, - subkeyword_of=self.kw1) - # testing indirect cycles - kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, ' - 'SK subkeyword_of K WHERE C name "classif1", K eid %s' - % self.kw1.eid).get_entity(0,0) - self.kw1.cw_set(subkeyword_of=kw3) - self.assertRaises(ValidationError, self.commit) + with self.admin_access.repo_cnx() as cnx: + kw1 = cnx.entity_from_eid(self.kw1eid) + # direct obvious cycle + with self.assertRaises(ValidationError): + kw1.cw_set(subkeyword_of=kw1) + cnx.rollback() + # testing indirect cycles + kw3 = cnx.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, ' + 'SK subkeyword_of K WHERE C name "classif1", K eid %(k)s' + {'k': kw1}).get_entity(0,0) + kw3.cw_set(reverse_subkeyword_of=kw1) + self.assertRaises(ValidationError, cnx.commit) The test class defines a :meth:`setup_database` method which populates the database with initial data. Each test of the class runs with this -pre-populated database. A commit is done automatically after the -:meth:`setup_database` call. You don't have to call it explicitely. +pre-populated database. -The test case itself checks that an Operation does it job of +The test case itself checks that an Operation does its job of preventing cycles amongst Keyword entities. -`create_entity` is a useful method, which easily allows to create an -entity. You can link this entity to others entities, by specifying as -argument, the relation name, and the entity to link, as value. In the -above example, the `Classification` entity is linked to a `CWEtype` -via the relation `classifies`. Conversely, if you are creating a -`CWEtype` entity, you can link it to a `Classification` entity, by -adding `reverse_classifies` as argument. +The `create_entity` method of connection (or request) objects allows +to create an entity. You can link this entity to other entities, by +specifying as argument, the relation name, and the entity to link, as +value. In the above example, the `Classification` entity is linked to +a `CWEtype` via the relation `classifies`. Conversely, if you are +creating a `CWEtype` entity, you can link it to a `Classification` +entity, by adding `reverse_classifies` as argument. .. note:: - :meth:`commit` method is not called automatically in test_XXX - methods. You have to call it explicitely if needed (notably to test - operations). It is a good practice to call :meth:`clear_all_caches` - on entities after a commit to avoid request cache effects. + the :meth:`commit` method is not called automatically. You have to + call it explicitly if needed (notably to test operations). It is a + good practice to regenerate entities with :meth:`entity_from_eid` + after a commit to avoid request cache effects. You can see an example of security tests in the :ref:`adv_tuto_security`. It is possible to have these tests run continuously using `apycot`_. -.. _apycot: http://www.logilab.org/project/apycot +.. _apycot: http://www.cubicweb.org/project/apycot .. _securitytest: @@ -113,66 +115,50 @@ support multiple connections at a time, you must be careful when simulating security, changing users. -By default, tests run with a user with admin privileges. This -user/connection must never be closed. +By default, tests run with a user with admin privileges. Connections +using these credentials are accessible through the `admin_access` object +of the test classes. -Before a self.login, one has to release the connection pool in use -with a self.commit, self.rollback or self.close. - -The `login` method returns a connection object that can be used as a +The `repo_cnx()` method returns a connection object that can be used as a context manager: .. sourcecode:: python - with self.login('user1') as user: - req = user.req - req.execute(...) - -On exit of the context manager, either a commit or rollback is issued, -which releases the connection. - -When one is logged in as a normal user and wants to switch back to the -admin user without committing, one has to use -self.restore_connection(). - -Usage with restore_connection: - -.. sourcecode:: python + # admin_access is a pre-cooked session wrapping object + # it is built with: + # self.admin_access = self.new_access('admin') + with self.admin_access.repo_cnx() as cnx: + cnx.execute(...) + self.create_user(cnx, login='user1') + cnx.commit() - # execute using default admin connection - self.execute(...) - # I want to login with another user, ensure to free admin connection pool - # (could have used rollback but not close here - # we should never close defaut admin connection) - self.commit() - cnx = self.login('user') - # execute using user connection - self.execute(...) - # I want to login with another user or with admin user - self.commit(); cnx.close() - # restore admin connection, never use cnx = self.login('admin'), it will return - # the default admin connection and one may be tempted to close it - self.restore_connection() + user1access = self.new_access('user1') + with user1access.web_request() as req: + req.execute(...) + req.cnx.commit() + +On exit of the context manager, a rollback is issued, which releases +the connection. Don't forget to issue the `cnx.commit()` calls! .. warning:: - Do not use the references kept to the entities created with a - connection from another ! + Do not use references kept to the entities created with a + connection from another one! Email notifications tests ````````````````````````` -When running tests potentially generated e-mails are not really sent -but is found in the list `MAILBOX` of module +When running tests, potentially generated e-mails are not really sent +but are found in the list `MAILBOX` of module :mod:`cubicweb.devtools.testlib`. You can test your notifications by analyzing the contents of this list, which contains objects with two attributes: * `recipients`, the list of recipients -* `msg`, object email.Message +* `msg`, email.Message object -Let us look at simple example from the ``blog`` cube. +Let us look at a simple example from the ``blog`` cube. .. sourcecode:: python @@ -182,28 +168,28 @@ """test blog specific behaviours""" def test_notifications(self): - req = self.request() - cubicweb_blog = req.create_entity('Blog', title=u'cubicweb', - description=u'cubicweb is beautiful') - blog_entry_1 = req.create_entity('BlogEntry', title=u'hop', - content=u'cubicweb hop') - blog_entry_1.cw_set(entry_of=cubicweb_blog) - blog_entry_2 = req.create_entity('BlogEntry', title=u'yes', - content=u'cubicweb yes') - blog_entry_2.cw_set(entry_of=cubicweb_blog) - self.assertEqual(len(MAILBOX), 0) - self.commit() - self.assertEqual(len(MAILBOX), 2) - mail = MAILBOX[0] - self.assertEqual(mail.subject, '[data] hop') - mail = MAILBOX[1] - self.assertEqual(mail.subject, '[data] yes') + with self.admin_access.web_request() as req: + cubicweb_blog = req.create_entity('Blog', title=u'cubicweb', + description=u'cubicweb is beautiful') + blog_entry_1 = req.create_entity('BlogEntry', title=u'hop', + content=u'cubicweb hop') + blog_entry_1.cw_set(entry_of=cubicweb_blog) + blog_entry_2 = req.create_entity('BlogEntry', title=u'yes', + content=u'cubicweb yes') + blog_entry_2.cw_set(entry_of=cubicweb_blog) + self.assertEqual(len(MAILBOX), 0) + req.cnx.commit() + self.assertEqual(len(MAILBOX), 2) + mail = MAILBOX[0] + self.assertEqual(mail.subject, '[data] hop') + mail = MAILBOX[1] + self.assertEqual(mail.subject, '[data] yes') Visible actions tests ````````````````````` It is easy to write unit tests to test actions which are visible to -user or to a category of users. Let's take an example in the +a user or to a category of users. Let's take an example in the `conference cube`_. .. _`conference cube`: http://www.cubicweb.org/project/cubicweb-conference @@ -212,34 +198,35 @@ class ConferenceActionsTC(CubicWebTC): def setup_database(self): - self.conf = self.create_entity('Conference', - title=u'my conf', - url_id=u'conf', - start_on=date(2010, 1, 27), - end_on = date(2010, 1, 29), - call_open=True, - reverse_is_chair_at=chair, - reverse_is_reviewer_at=reviewer) + with self.admin_access.repo_cnx() as cnx: + self.confeid = cnx.create_entity('Conference', + title=u'my conf', + url_id=u'conf', + start_on=date(2010, 1, 27), + end_on = date(2010, 1, 29), + call_open=True, + reverse_is_chair_at=chair, + reverse_is_reviewer_at=reviewer).eid def test_admin(self): - req = self.request() - rset = req.find_entities('Conference') - self.assertListEqual(self.pactions(req, rset), - [('workflow', workflow.WorkflowActions), - ('edit', confactions.ModifyAction), - ('managepermission', actions.ManagePermissionsAction), - ('addrelated', actions.AddRelatedActions), - ('delete', actions.DeleteAction), - ('generate_badge_action', badges.GenerateBadgeAction), - ('addtalkinconf', confactions.AddTalkInConferenceAction) - ]) - self.assertListEqual(self.action_submenu(req, rset, 'addrelated'), - [(u'add Track in_conf Conference object', - u'http://testing.fr/cubicweb/add/Track' - u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&' - u'__redirectpath=conference%%2Fconf&' - u'__redirectvid=' % {'conf': self.conf.eid}), - ]) + with self.admin_access.web_request() as req: + rset = req.find('Conference').one() + self.assertListEqual(self.pactions(req, rset), + [('workflow', workflow.WorkflowActions), + ('edit', confactions.ModifyAction), + ('managepermission', actions.ManagePermissionsAction), + ('addrelated', actions.AddRelatedActions), + ('delete', actions.DeleteAction), + ('generate_badge_action', badges.GenerateBadgeAction), + ('addtalkinconf', confactions.AddTalkInConferenceAction) + ]) + self.assertListEqual(self.action_submenu(req, rset, 'addrelated'), + [(u'add Track in_conf Conference object', + u'http://testing.fr/cubicweb/add/Track' + u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&' + u'__redirectpath=conference%%2Fconf&' + u'__redirectvid=' % {'conf': self.confeid}), + ]) You just have to execute a rql query corresponding to the view you want to test, and to compare the result of @@ -247,7 +234,7 @@ that must be visible in the interface. This is a list of tuples. The first element is the action's `__regid__`, the second the action's class. -To test actions in submenu, you just have to test the result of +To test actions in a submenu, you just have to test the result of :meth:`~cubicweb.devtools.testlib.CubicWebTC.action_submenu` method. The last parameter of the method is the action's category. The result is a list of tuples. The first element is the action's title, and the second element the @@ -290,23 +277,27 @@ Cache heavy database setup ------------------------------- -Some tests suite require a complex setup of the database that takes seconds (or -event minutes) to complete. Doing the whole setup for all individual tests make -the whole run very slow. The ``CubicWebTC`` class offer a simple way to prepare -specific database once for multiple tests. The `test_db_id` class attribute of -your ``CubicWebTC`` must be set a unique identifier and the -:meth:`pre_setup_database` class method build the cached content. As the -:meth:`pre_setup_database` method is not grantee to be called, you must not set -any class attribut to be used during test there. Databases for each `test_db_id` -are automatically created if not already in cache. Clearing the cache is up to -the user. Cache files are found in the :file:`data/database` subdirectory of your -test directory. +Some test suites require a complex setup of the database that takes +seconds (or even minutes) to complete. Doing the whole setup for each +individual test makes the whole run very slow. The ``CubicWebTC`` +class offer a simple way to prepare a specific database once for +multiple tests. The `test_db_id` class attribute of your +``CubicWebTC`` subclass must be set to a unique identifier and the +:meth:`pre_setup_database` class method must build the cached content. As +the :meth:`pre_setup_database` method is not garanteed to be called +every time a test method is run, you must not set any class attribute +to be used during test *there*. Databases for each `test_db_id` are +automatically created if not already in cache. Clearing the cache is +up to the user. Cache files are found in the :file:`data/database` +subdirectory of your test directory. .. warning:: - Take care to always have the same :meth:`pre_setup_database` function for all - call with a given `test_db_id` otherwise you test will have unpredictable - result given the first encountered one. + Take care to always have the same :meth:`pre_setup_database` + function for all classes with a given `test_db_id` otherwise your + tests will have unpredictable results depending on the first + encountered one. + Testing on a real-life database ------------------------------- @@ -332,10 +323,10 @@ sourcefile='/path/to/realdb_sources') def test_blog_rss(self): - req = self.request() + with self.admin_access.web_request() as req: rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, ' - 'B created_by U, U login "logilab", B creation_date D') - self.view('rss', rset) + 'B created_by U, U login "logilab", B creation_date D') + self.view('rss', rset, req=req) Testing with other cubes @@ -351,7 +342,7 @@ The format is: * possibly several empy lines or lines starting with ``#`` (comment lines) -* one line containing a coma separated list of cube names. +* one line containing a comma-separated list of cube names. It is also possible to add a ``schema.py`` file in ``mycube/test/data``, which will be used by the testing framework, @@ -362,12 +353,12 @@ -------------------- CubicWeb provides some literate programming capabilities. The :ref:`cubicweb-ctl` -`shell` command accepts differents format files. If your file ends with `.txt` -or `.rst`, the file will be parsed by :mod:`doctest.testfile` with CubicWeb +`shell` command accepts different file formats. If your file ends with `.txt` +or `.rst`, the file will be parsed by :mod:`doctest.testfile` with CubicWeb's :ref:`migration` API enabled in it. -Create a `scenario.txt` file into `test/` directory and fill with some content. -Please refer the :mod:`doctest.testfile` `documentation`_. +Create a `scenario.txt` file in the `test/` directory and fill with some content. +Refer to the :mod:`doctest.testfile` `documentation`_. .. _documentation: http://docs.python.org/library/doctest.html @@ -404,7 +395,7 @@ Passing paramaters `````````````````` -Using extra arguments to parametrize your scenario is possible by prepend them +Using extra arguments to parametrize your scenario is possible by prepending them by double dashes. Please refer to the `cubicweb-ctl shell --help` usage. @@ -431,7 +422,7 @@ discover them automatically) * launch `pytest unittest_foo.py` to execute one test file * launch `pytest unittest_foo.py bar` to execute all test methods and - all test cases whose name contain `bar` + all test cases whose name contains `bar` Additionally, the `-x` option tells pytest to exit at the first error or failure. The `-i` option tells pytest to drop into pdb whenever an @@ -460,7 +451,6 @@ What you need to know about request and session ----------------------------------------------- - .. image:: ../images/request_session.png First, remember to think that some code run on a client side, some @@ -474,9 +464,14 @@ The client interacts with the repository through a repoapi connection. +.. note:: + + These distinctions are going to disappear in cubicweb 3.21 (if not + before). + A repoapi connection is tied to a session in the repository. The connection and -request objects are unaccessible from repository code / the session object is -unaccessible from client code (theoretically at least). +request objects are inaccessible from repository code / the session object is +inaccessible from client code (theoretically at least). The web interface provides a request class. That `request` object provides access to all cubicweb resources, eg: @@ -492,7 +487,7 @@ A `session` provides an api similar to a request regarding RQL execution and -access to global resources (registry and all), but also have the following +access to global resources (registry and all), but also has the following responsibilities: * handle transaction data, that will live during the time of a single @@ -529,45 +524,36 @@ The web publisher handles the transaction: * commit / rollback is done automatically -* you should not commit / rollback explicitly -Because a session lives for a long time, and database connections are a limited -resource, we can't bind a session to its own database connection for all its -lifetime. The repository handles a pool of connections (4 by default), and it's -responsible to attribute them as needed. +* you should not commit / rollback explicitly, except if you really + need it Let's detail the process: -1. an incoming RQL query comes from a client to the repository +1. an incoming RQL query comes from a client to the web stack -2. the repository attributes a database connection to the session +2. the web stack opens an authenticated database connection for the + request, which is associated to a user session -3. the repository's querier executes the query +3. the query is executed (through the repository connection) -4. this query may trigger hooks. Hooks and operation may execute some rql queries - through `_cw.execute`. Those queries go directly to the querier, hence don't - touch the database connection, they use the one attributed in 2. +4. this query may trigger hooks. Hooks and operations may execute some rql queries + through `cnx.execute`. 5. the repository gets the result of the query in 1. If it was a RQL read query, the database connection is released. If it was a write query, the connection - is then tied to the session until the transaction is commited or rollbacked. + is then tied to the session until the transaction is commited or rolled back. 6. results are sent back to the client This implies several things: -* when using a request, or code executed in hooks, this database connection - handling is totally transparent +* when using a request, or code executed in hooks, this database + connection handling is totally transparent -* however, take care when writing tests: you are usually faking / testing both the - server and the client side, so you have to decide when to use RepoAccess.client_cnx / - RepoAccess.repo_cnx. Ask yourself "where the code I want to test will be running, - client or repository side ?". The response is usually : use a client connection :) - However, if you really need using a server-side object: - - - commit / rollback will free the database connection (unless explicitly told - not to do so). - - - if you issue a query after that without asking for a database connection - (`session.get_cnxset()`), you will end up with a 'None type has no attribute - source()' error +* however, take care when writing tests: you are usually faking / + testing both the server and the client side, so you have to decide + when to use RepoAccess.client_cnx or RepoAccess.repo_cnx. Ask + yourself "where will the code I want to test be running, client or + repository side?". The response is usually: use a repo (since the + "client connection" concept is going away in a couple of releases). diff -r 928732ec00dd -r fa44db7da2dc doc/book/en/tutorials/advanced/part02_security.rst --- a/doc/book/en/tutorials/advanced/part02_security.rst Thu Jul 17 11:08:56 2014 +0200 +++ b/doc/book/en/tutorials/advanced/part02_security.rst Fri Jul 18 17:35:25 2014 +0200 @@ -142,7 +142,7 @@ * `VISIBILITY_PERMISSIONS` provides read access to managers group, if `visibility` attribute's value is 'public', or if user (designed by the 'U' variable in the expression) is linked to the entity (the 'X' variable) through - the `may_read` permission + the `may_be_read_by` permission * we modify permissions of the entity types we use by importing them and modifying their `__permissions__` attribute @@ -168,7 +168,7 @@ commented entity. This kind of `active` rule will be done using CubicWeb's hook -system. Hooks are triggered on database event such as addition of new +system. Hooks are triggered on database events such as addition of a new entity or relation. The tricky part of the requirement is in *unless explicitly specified*, notably @@ -223,9 +223,9 @@ relation types to which the hook applies. To match a relation type, we use the hook specific `match_rtype` selector. -* usage of `set_operation`: instead of adding an operation for each added entity, - set_operation allows to create a single one and to store entity's eids to be - processed in session's transaction data. This is a good pratice to avoid heavy +* usage of `DataOperationMixIn`: instead of adding an operation for each added entity, + DataOperationMixIn allows to create a single one and to store entity's eids to be + processed in the transaction data. This is a good pratice to avoid heavy operations manipulation cost when creating a lot of entities in the same transaction. @@ -314,51 +314,50 @@ class SecurityTC(CubicWebTC): def test_visibility_propagation(self): - # create a user for later security checks - toto = self.create_user('toto') - # init some data using the default manager connection - req = self.request() - folder = req.create_entity('Folder', - name=u'restricted', - visibility=u'restricted') - photo1 = req.create_entity('File', - data_name=u'photo1.jpg', - data=Binary('xxx'), - filed_under=folder) - self.commit() - photo1.clear_all_caches() # good practice, avoid request cache effects - # visibility propagation - self.assertEquals(photo1.visibility, 'restricted') - # unless explicitly specified - photo2 = req.create_entity('File', - data_name=u'photo2.jpg', - data=Binary('xxx'), - visibility=u'public', - filed_under=folder) - self.commit() - self.assertEquals(photo2.visibility, 'public') - # test security - self.login('toto') - req = self.request() - self.assertEquals(len(req.execute('File X')), 1) # only the public one - self.assertEquals(len(req.execute('Folder X')), 0) # restricted... - # may_be_read_by propagation - self.restore_connection() - folder.cw_set(may_be_read_by=toto) - self.commit() - photo1.clear_all_caches() - self.failUnless(photo1.may_be_read_by) - # test security with permissions - self.login('toto') - req = self.request() - self.assertEquals(len(req.execute('File X')), 2) # now toto has access to photo2 - self.assertEquals(len(req.execute('Folder X')), 1) # and to restricted folder + + with self.admin_access.repo_cnx() as cnx: + # create a user for later security checks + toto = self.create_user(cnx, 'toto') + cnx.commit() + # init some data using the default manager connection + folder = cnx.create_entity('Folder', + name=u'restricted', + visibility=u'restricted') + photo1 = cnx.create_entity('File', + data_name=u'photo1.jpg', + data=Binary('xxx'), + filed_under=folder) + cnx.commit() + # visibility propagation + self.assertEquals(photo1.visibility, 'restricted') + # unless explicitly specified + photo2 = cnx.create_entity('File', + data_name=u'photo2.jpg', + data=Binary('xxx'), + visibility=u'public', + filed_under=folder) + cnx.commit() + self.assertEquals(photo2.visibility, 'public') + + with self.new_access('toto').repo_cnx() as cnx: + # test security + self.assertEqual(1, len(cnx.execute('File X'))) # only the public one + self.assertEqual(0, len(cnx.execute('Folder X'))) # restricted... + # may_be_read_by propagation + folder = cnx.entity_from_eid(folder.eid) + folder.cw_set(may_be_read_by=toto) + cnx.commit() + photo1 = cnx.entity_from_eid(photo1) + self.failUnless(photo1.may_be_read_by) + # test security with permissions + self.assertEquals(2, len(cnx.execute('File X'))) # now toto has access to photo2 + self.assertEquals(1, len(cnx.execute('Folder X'))) # and to restricted folder if __name__ == '__main__': from logilab.common.testlib import unittest_main unittest_main() -It's not complete, but show most things you'll want to do in tests: adding some +It's not complete, but shows most things you'll want to do in tests: adding some content, creating users and connecting as them in the test, etc... To run it type: @@ -394,7 +393,7 @@ If you do some changes in your schema, you'll have to force regeneration of that database. You do that by removing the tmpdb files before running the test: :: - $ rm data/tmpdb* + $ rm data/database/tmpdb* .. Note:: @@ -407,12 +406,12 @@ Step 4: writing the migration script and migrating the instance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Prior to those changes, I created an instance, feeded it with some data, so I +Prior to those changes, I created an instance, fed it with some data, so I don't want to create a new one, but to migrate the existing one. Let's see how to do that. Migration commands should be put in the cube's *migration* directory, in a -file named file:`_Any.py` ('Any' being there mostly for historical reason). +file named file:`_Any.py` ('Any' being there mostly for historical reasons). Here I'll create a *migration/0.2.0_Any.py* file containing the following instructions: @@ -423,11 +422,11 @@ add_relation_type('visibility') sync_schema_props_perms() -Then I update the version number in cube's *__pkginfo__.py* to 0.2.0. And +Then I update the version number in the cube's *__pkginfo__.py* to 0.2.0. And that's it! Those instructions will: * update the instance's schema by adding our two new relations and update the - underlying database tables accordingly (the two first instructions) + underlying database tables accordingly (the first two instructions) * update schema's permissions definition (the last instruction) diff -r 928732ec00dd -r fa44db7da2dc entities/test/unittest_base.py --- a/entities/test/unittest_base.py Thu Jul 17 11:08:56 2014 +0200 +++ b/entities/test/unittest_base.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -21,7 +21,6 @@ from logilab.common.testlib import unittest_main from logilab.common.decorators import clear_cache -from logilab.common.interface import implements from cubicweb.devtools.testlib import CubicWebTC @@ -31,114 +30,135 @@ class BaseEntityTC(CubicWebTC): def setup_database(self): - req = self.request() - self.member = self.create_user(req, 'member') - + with self.admin_access.repo_cnx() as cnx: + self.membereid = self.create_user(cnx, 'member').eid + cnx.commit() class MetadataTC(BaseEntityTC): def test_creator(self): - self.login(u'member') - entity = self.request().create_entity('Bookmark', title=u"hello", path=u'project/cubicweb') - self.commit() - self.assertEqual(entity.creator.eid, self.member.eid) - self.assertEqual(entity.dc_creator(), u'member') + with self.new_access('member').repo_cnx() as cnx: + entity = cnx.create_entity('Bookmark', title=u"hello", path=u'project/cubicweb') + cnx.commit() + self.assertEqual(entity.creator.eid, self.membereid) + self.assertEqual(entity.dc_creator(), u'member') def test_type(self): #dc_type may be translated - self.assertEqual(self.member.dc_type(), 'CWUser') + with self.admin_access.client_cnx() as cnx: + member = cnx.entity_from_eid(self.membereid) + self.assertEqual(member.dc_type(), 'CWUser') def test_cw_etype(self): #cw_etype is never translated - self.assertEqual(self.member.cw_etype, 'CWUser') + with self.admin_access.client_cnx() as cnx: + member = cnx.entity_from_eid(self.membereid) + self.assertEqual(member.cw_etype, 'CWUser') def test_entity_meta_attributes(self): # XXX move to yams self.assertEqual(self.schema['CWUser'].meta_attributes(), {}) - self.assertEqual(dict((str(k), v) for k, v in self.schema['State'].meta_attributes().iteritems()), + self.assertEqual(dict((str(k), v) + for k, v in self.schema['State'].meta_attributes().iteritems()), {'description_format': ('format', 'description')}) def test_fti_rql_method(self): - eclass = self.vreg['etypes'].etype_class('EmailAddress') - self.assertEqual(['Any X, ALIAS, ADDRESS WHERE X is EmailAddress, ' - 'X alias ALIAS, X address ADDRESS'], - eclass.cw_fti_index_rql_queries(self.request())) + with self.admin_access.web_request() as req: + eclass = self.vreg['etypes'].etype_class('EmailAddress') + self.assertEqual(['Any X, ALIAS, ADDRESS WHERE X is EmailAddress, ' + 'X alias ALIAS, X address ADDRESS'], + eclass.cw_fti_index_rql_queries(req)) class EmailAddressTC(BaseEntityTC): + def test_canonical_form(self): - email1 = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0) - email2 = self.execute('INSERT EmailAddress X: X address "maarten@philips.com"').get_entity(0, 0) - email3 = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"').get_entity(0, 0) - email1.cw_set(prefered_form=email2) - self.assertEqual(email1.prefered.eid, email2.eid) - self.assertEqual(email2.prefered.eid, email2.eid) - self.assertEqual(email3.prefered.eid, email3.eid) + with self.admin_access.repo_cnx() as cnx: + email1 = cnx.execute('INSERT EmailAddress X: ' + 'X address "maarten.ter.huurne@philips.com"').get_entity(0, 0) + email2 = cnx.execute('INSERT EmailAddress X: ' + 'X address "maarten@philips.com"').get_entity(0, 0) + email3 = cnx.execute('INSERT EmailAddress X: ' + 'X address "toto@logilab.fr"').get_entity(0, 0) + email1.cw_set(prefered_form=email2) + self.assertEqual(email1.prefered.eid, email2.eid) + self.assertEqual(email2.prefered.eid, email2.eid) + self.assertEqual(email3.prefered.eid, email3.eid) def test_mangling(self): - email = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0) - self.assertEqual(email.display_address(), 'maarten.ter.huurne@philips.com') - self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne@philips.com') - self.vreg.config.global_set_option('mangle-emails', True) - try: - self.assertEqual(email.display_address(), 'maarten.ter.huurne at philips dot com') - self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne at philips dot com') - email = self.execute('INSERT EmailAddress X: X address "syt"').get_entity(0, 0) - self.assertEqual(email.display_address(), 'syt') - self.assertEqual(email.printable_value('address'), 'syt') - finally: - self.vreg.config.global_set_option('mangle-emails', False) + with self.admin_access.repo_cnx() as cnx: + email = cnx.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0) + self.assertEqual(email.display_address(), 'maarten.ter.huurne@philips.com') + self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne@philips.com') + self.vreg.config.global_set_option('mangle-emails', True) + try: + self.assertEqual(email.display_address(), 'maarten.ter.huurne at philips dot com') + self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne at philips dot com') + email = cnx.execute('INSERT EmailAddress X: X address "syt"').get_entity(0, 0) + self.assertEqual(email.display_address(), 'syt') + self.assertEqual(email.printable_value('address'), 'syt') + finally: + self.vreg.config.global_set_option('mangle-emails', False) def test_printable_value_escape(self): - email = self.execute('INSERT EmailAddress X: X address "maarten&ter@philips.com"').get_entity(0, 0) - self.assertEqual(email.printable_value('address'), 'maarten&ter@philips.com') - self.assertEqual(email.printable_value('address', format='text/plain'), 'maarten&ter@philips.com') + with self.admin_access.repo_cnx() as cnx: + email = cnx.execute('INSERT EmailAddress X: ' + 'X address "maarten&ter@philips.com"').get_entity(0, 0) + self.assertEqual(email.printable_value('address'), + 'maarten&ter@philips.com') + self.assertEqual(email.printable_value('address', format='text/plain'), + 'maarten&ter@philips.com') class CWUserTC(BaseEntityTC): def test_complete(self): - e = self.execute('CWUser X WHERE X login "admin"').get_entity(0, 0) - e.complete() + with self.admin_access.repo_cnx() as cnx: + e = cnx.execute('CWUser X WHERE X login "admin"').get_entity(0, 0) + e.complete() def test_matching_groups(self): - e = self.execute('CWUser X WHERE X login "admin"').get_entity(0, 0) - self.assertTrue(e.matching_groups('managers')) - self.assertFalse(e.matching_groups('xyz')) - self.assertTrue(e.matching_groups(('xyz', 'managers'))) - self.assertFalse(e.matching_groups(('xyz', 'abcd'))) + with self.admin_access.repo_cnx() as cnx: + e = cnx.execute('CWUser X WHERE X login "admin"').get_entity(0, 0) + self.assertTrue(e.matching_groups('managers')) + self.assertFalse(e.matching_groups('xyz')) + self.assertTrue(e.matching_groups(('xyz', 'managers'))) + self.assertFalse(e.matching_groups(('xyz', 'abcd'))) def test_dc_title_and_name(self): - e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0) - self.assertEqual(e.dc_title(), 'member') - self.assertEqual(e.name(), 'member') - e.cw_set(firstname=u'bouah') - self.assertEqual(e.dc_title(), 'member') - self.assertEqual(e.name(), u'bouah') - e.cw_set(surname=u'lôt') - self.assertEqual(e.dc_title(), 'member') - self.assertEqual(e.name(), u'bouah lôt') + with self.admin_access.repo_cnx() as cnx: + e = cnx.execute('CWUser U WHERE U login "member"').get_entity(0, 0) + self.assertEqual(e.dc_title(), 'member') + self.assertEqual(e.name(), 'member') + e.cw_set(firstname=u'bouah') + self.assertEqual(e.dc_title(), 'member') + self.assertEqual(e.name(), u'bouah') + e.cw_set(surname=u'lôt') + self.assertEqual(e.dc_title(), 'member') + self.assertEqual(e.name(), u'bouah lôt') def test_allowed_massmail_keys(self): - e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0) - # Bytes/Password attributes should be omited - self.assertEqual(e.cw_adapt_to('IEmailable').allowed_massmail_keys(), - set(('surname', 'firstname', 'login', 'last_login_time', - 'creation_date', 'modification_date', 'cwuri', 'eid')) - ) + with self.admin_access.repo_cnx() as cnx: + e = cnx.execute('CWUser U WHERE U login "member"').get_entity(0, 0) + # Bytes/Password attributes should be omited + self.assertEqual(e.cw_adapt_to('IEmailable').allowed_massmail_keys(), + set(('surname', 'firstname', 'login', 'last_login_time', + 'creation_date', 'modification_date', 'cwuri', 'eid')) + ) def test_cw_instantiate_object_relation(self): """ a weird non regression test """ - e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0) - self.request().create_entity('CWGroup', name=u'logilab', reverse_in_group=e) + with self.admin_access.repo_cnx() as cnx: + e = cnx.execute('CWUser U WHERE U login "member"').get_entity(0, 0) + cnx.create_entity('CWGroup', name=u'logilab', reverse_in_group=e) class HTMLtransformTC(BaseEntityTC): def test_sanitized_html(self): - r = self.request() - c = r.create_entity('Company', name=u'Babar', - description=u""" + with self.admin_access.repo_cnx() as cnx: + c = cnx.create_entity('Company', name=u'Babar', + description=u""" Title ===== @@ -148,10 +168,12 @@ """, description_format=u'text/rest') - self.commit() - c.cw_clear_all_caches() - self.assertIn('alert', c.printable_value('description', format='text/plain')) - self.assertNotIn('alert', c.printable_value('description', format='text/html')) + cnx.commit() + c.cw_clear_all_caches() + self.assertIn('alert', + c.printable_value('description', format='text/plain')) + self.assertNotIn('alert', + c.printable_value('description', format='text/html')) class SpecializedEntityClassesTC(CubicWebTC): diff -r 928732ec00dd -r fa44db7da2dc entity.py --- a/entity.py Thu Jul 17 11:08:56 2014 +0200 +++ b/entity.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -344,7 +344,8 @@ cls.warning('skipping fetch_attr %s defined in %s (not found in schema)', attr, cls.__regid__) continue - rdef = eschema.rdef(attr) + # XXX takefirst=True to remove warning triggered by ambiguous inlined relations + rdef = eschema.rdef(attr, takefirst=True) if not user.matching_groups(rdef.get_groups('read')): continue if rschema.final or rdef.cardinality[0] in '?1': @@ -793,8 +794,9 @@ # skip already defined relations if getattr(self, rschema.type): continue + # XXX takefirst=True to remove warning triggered by ambiguous relations + rdef = self.e_schema.rdef(rschema, takefirst=True) # skip composite relation - rdef = self.e_schema.rdef(rschema) if rdef.composite: continue # skip relation with card in ?1 else we either change the copied @@ -813,7 +815,8 @@ continue if rschema.type in skip_copy_for['object']: continue - rdef = self.e_schema.rdef(rschema, 'object') + # XXX takefirst=True to remove warning triggered by ambiguous relations + rdef = self.e_schema.rdef(rschema, 'object', takefirst=True) # skip composite relation if rdef.composite: continue diff -r 928732ec00dd -r fa44db7da2dc etwist/server.py --- a/etwist/server.py Thu Jul 17 11:08:56 2014 +0200 +++ b/etwist/server.py Fri Jul 18 17:35:25 2014 +0200 @@ -69,6 +69,7 @@ # if pyro is enabled, we have to register to the pyro name # server, create a pyro daemon, and create a task to handle pyro # requests + self.appli.repo.warning('remote repository access through pyro is deprecated') self.pyro_daemon = self.appli.repo.pyro_register() self.pyro_listen_timeout = 0.02 self.appli.repo.looping_task(1, self.pyro_loop_event) diff -r 928732ec00dd -r fa44db7da2dc ext/test/unittest_rest.py --- a/ext/test/unittest_rest.py Thu Jul 17 11:08:56 2014 +0200 +++ b/ext/test/unittest_rest.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -21,18 +21,23 @@ from cubicweb.ext.rest import rest_publish class RestTC(CubicWebTC): - def context(self): - return self.execute('CWUser X WHERE X login "admin"').get_entity(0, 0) + + def context(self, req): + return req.execute('CWUser X WHERE X login "admin"').get_entity(0, 0) def test_eid_role(self): - context = self.context() - self.assertEqual(rest_publish(context, ':eid:`%s`' % context.eid), - '

#%s

\n' % context.eid) - self.assertEqual(rest_publish(context, ':eid:`%s:some text`' % context.eid), - '

some text

\n') + with self.admin_access.web_request() as req: + context = self.context(req) + self.assertEqual(rest_publish(context, ':eid:`%s`' % context.eid), + '

' + '#%s

\n' % context.eid) + self.assertEqual(rest_publish(context, ':eid:`%s:some text`' % context.eid), + '

' + 'some text

\n') def test_bad_rest_no_crash(self): - data = rest_publish(self.context(), ''' + with self.admin_access.web_request() as req: + rest_publish(self.context(req), ''' | card | implication | -------------------------- | 1-1 | N1 = N2 | @@ -55,159 +60,172 @@ def test_rql_role_with_vid(self): - context = self.context() - out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:table`') - self.assertTrue(out.endswith('anon' - '\n

\n')) + with self.admin_access.web_request() as req: + context = self.context(req) + out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:table`') + self.assertTrue(out.endswith('anon\n' + '

\n')) def test_rql_role_with_vid_empty_rset(self): - context = self.context() - out = rest_publish(context, ':rql:`Any X WHERE X is CWUser, X login "nono":table`') - self.assertTrue(out.endswith('

No result matching query
\n

\n')) + with self.admin_access.web_request() as req: + context = self.context(req) + out = rest_publish(context, ':rql:`Any X WHERE X is CWUser, X login "nono":table`') + self.assertTrue(out.endswith('

' + 'No result matching query
\n

\n')) def test_rql_role_with_unknown_vid(self): - context = self.context() - out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`') - self.assertTrue(out.startswith("

an error occurred while interpreting this rql directive: ObjectNotFound(u'toto',)

")) + with self.admin_access.web_request() as req: + context = self.context(req) + out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`') + self.assertTrue(out.startswith("

an error occurred while interpreting this " + "rql directive: ObjectNotFound(u'toto',)

")) def test_rql_role_without_vid(self): - context = self.context() - out = rest_publish(context, ':rql:`Any X WHERE X is CWUser`') - self.assertEqual(out, u'

CWUser_plural

\n') + with self.admin_access.web_request() as req: + context = self.context(req) + out = rest_publish(context, ':rql:`Any X WHERE X is CWUser`') + self.assertEqual(out, u'

CWUser_plural

' + 'admin' + '
' + 'anon' + '

\n') def test_bookmark_role(self): - context = self.context() - rset = self.execute('INSERT Bookmark X: X title "hello", X path "/view?rql=Any X WHERE X is CWUser"') - eid = rset[0][0] - out = rest_publish(context, ':bookmark:`%s`' % eid) - self.assertEqual(out, u'

CWUser_plural

\n') + with self.admin_access.web_request() as req: + context = self.context(req) + rset = req.execute('INSERT Bookmark X: X title "hello", X path ' + '"/view?rql=Any X WHERE X is CWUser"') + eid = rset[0][0] + out = rest_publish(context, ':bookmark:`%s`' % eid) + self.assertEqual(out, u'

CWUser_plural

\n') def test_rqltable_nocontent(self): - context = self.context() - out = rest_publish(context, """.. rql-table::""") - self.assertIn("System Message: ERROR", out) - self.assertIn("Content block expected for the "rql-table" " - "directive; none found" , out) + with self.admin_access.web_request() as req: + context = self.context(req) + out = rest_publish(context, """.. rql-table::""") + self.assertIn("System Message: ERROR", out) + self.assertIn("Content block expected for the "rql-table" " + "directive; none found" , out) def test_rqltable_norset(self): - context = self.context() - rql = "Any X WHERE X is CWUser, X firstname 'franky'" - out = rest_publish( - context, """\ + with self.admin_access.web_request() as req: + context = self.context(req) + rql = "Any X WHERE X is CWUser, X firstname 'franky'" + out = rest_publish( + context, """\ .. rql-table:: - %(rql)s""" % {'rql': rql}) - self.assertIn("System Message: WARNING", out) - self.assertIn("empty result set", out) + %(rql)s""" % {'rql': rql}) + self.assertIn("System Message: WARNING", out) + self.assertIn("empty result set", out) def test_rqltable_nooptions(self): - rql = """Any S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - out = rest_publish( - self.context(), """\ + with self.admin_access.web_request() as req: + rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + out = rest_publish( + self.context(req), """\ .. rql-table:: %(rql)s - """ % {'rql': rql}) - req = self.request() - view = self.vreg['views'].select('table', req, rset=req.execute(rql)) - self.assertEqual(view.render(w=None)[49:], out[49:]) + """ % {'rql': rql}) + view = self.vreg['views'].select('table', req, rset=req.execute(rql)) + self.assertEqual(view.render(w=None)[49:], out[49:]) def test_rqltable_vid(self): - rql = """Any S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - vid = 'mytable' - out = rest_publish( - self.context(), """\ + with self.admin_access.web_request() as req: + rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + vid = 'mytable' + out = rest_publish( + self.context(req), """\ .. rql-table:: :vid: %(vid)s %(rql)s - """ % {'rql': rql, 'vid': vid}) - req = self.request() - view = self.vreg['views'].select(vid, req, rset=req.execute(rql)) - self.assertEqual(view.render(w=None)[49:], out[49:]) - self.assertIn(vid, out[:49]) + """ % {'rql': rql, 'vid': vid}) + view = self.vreg['views'].select(vid, req, rset=req.execute(rql)) + self.assertEqual(view.render(w=None)[49:], out[49:]) + self.assertIn(vid, out[:49]) def test_rqltable_badvid(self): - rql = """Any S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - vid = 'mytabel' - out = rest_publish( - self.context(), """\ + with self.admin_access.web_request() as req: + rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + vid = 'mytabel' + out = rest_publish( + self.context(req), """\ .. rql-table:: :vid: %(vid)s %(rql)s - """ % {'rql': rql, 'vid': vid}) - self.assertIn("fail to select '%s' view" % vid, out) + """ % {'rql': rql, 'vid': vid}) + self.assertIn("fail to select '%s' view" % vid, out) def test_rqltable_headers(self): - rql = """Any S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - headers = ["nom", "prenom", "identifiant"] - out = rest_publish( - self.context(), """\ -.. rql-table:: - :headers: %(headers)s - - %(rql)s - """ % {'rql': rql, 'headers': ', '.join(headers)}) - req = self.request() - view = self.vreg['views'].select('table', req, rset=req.execute(rql)) - view.headers = headers - self.assertEqual(view.render(w=None)[49:], out[49:]) - - def test_rqltable_headers_missing(self): - rql = """Any S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - headers = ["nom", "", "identifiant"] - out = rest_publish( - self.context(), """\ + with self.admin_access.web_request() as req: + rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + headers = ["nom", "prenom", "identifiant"] + out = rest_publish( + self.context(req), """\ .. rql-table:: :headers: %(headers)s %(rql)s - """ % {'rql': rql, 'headers': ', '.join(headers)}) - req = self.request() - view = self.vreg['views'].select('table', req, rset=req.execute(rql)) - view.headers = [headers[0], None, headers[2]] - self.assertEqual(view.render(w=None)[49:], out[49:]) + """ % {'rql': rql, 'headers': ', '.join(headers)}) + view = self.vreg['views'].select('table', req, rset=req.execute(rql)) + view.headers = headers + self.assertEqual(view.render(w=None)[49:], out[49:]) - def test_rqltable_headers_missing_edges(self): - rql = """Any S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - headers = [" ", "prenom", ""] - out = rest_publish( - self.context(), """\ + def test_rqltable_headers_missing(self): + with self.admin_access.web_request() as req: + rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + headers = ["nom", "", "identifiant"] + out = rest_publish( + self.context(req), """\ .. rql-table:: :headers: %(headers)s %(rql)s - """ % {'rql': rql, 'headers': ', '.join(headers)}) - req = self.request() - view = self.vreg['views'].select('table', req, rset=req.execute(rql)) - view.headers = [None, headers[1], None] - self.assertEqual(view.render(w=None)[49:], out[49:]) + """ % {'rql': rql, 'headers': ', '.join(headers)}) + view = self.vreg['views'].select('table', req, rset=req.execute(rql)) + view.headers = [headers[0], None, headers[2]] + self.assertEqual(view.render(w=None)[49:], out[49:]) + + def test_rqltable_headers_missing_edges(self): + with self.admin_access.web_request() as req: + rql = "Any S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + headers = [" ", "prenom", ""] + out = rest_publish( + self.context(req), """\ +.. rql-table:: + :headers: %(headers)s + + %(rql)s + """ % {'rql': rql, 'headers': ', '.join(headers)}) + view = self.vreg['views'].select('table', req, rset=req.execute(rql)) + view.headers = [None, headers[1], None] + self.assertEqual(view.render(w=None)[49:], out[49:]) def test_rqltable_colvids(self): - rql = """Any X,S,F,L WHERE X is CWUser, X surname S, - X firstname F, X login L""" - colvids = {0: "oneline"} - out = rest_publish( - self.context(), """\ + with self.admin_access.web_request() as req: + rql = "Any X,S,F,L WHERE X is CWUser, X surname S, X firstname F, X login L" + colvids = {0: "oneline"} + out = rest_publish( + self.context(req), """\ .. rql-table:: :colvids: %(colvids)s %(rql)s - """ % {'rql': rql, - 'colvids': ', '.join(["%d=%s" % (k, v) - for k, v in colvids.iteritems()]) - }) - req = self.request() - view = self.vreg['views'].select('table', req, rset=req.execute(rql)) - view.cellvids = colvids - self.assertEqual(view.render(w=None)[49:], out[49:]) + """ % {'rql': rql, + 'colvids': ', '.join(["%d=%s" % (k, v) + for k, v in colvids.iteritems()]) + }) + view = self.vreg['views'].select('table', req, rset=req.execute(rql)) + view.cellvids = colvids + self.assertEqual(view.render(w=None)[49:], out[49:]) if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc hooks/syncschema.py --- a/hooks/syncschema.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/syncschema.py Fri Jul 18 17:35:25 2014 +0200 @@ -653,6 +653,9 @@ else: self.critical('constraint %s for rdef %s was missing or already removed', self.oldcstr, rdef) + if cnx.deleted_in_transaction(rdef.eid): + # don't try to alter a table that's going away (or is already gone) + return # then update database: alter the physical schema on size/unique # constraint changes syssource = cnx.repo.system_source diff -r 928732ec00dd -r fa44db7da2dc hooks/test/unittest_bookmarks.py --- a/hooks/test/unittest_bookmarks.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/test/unittest_bookmarks.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -22,16 +22,17 @@ def test_auto_delete_bookmarks(self): - beid = self.execute('INSERT Bookmark X: X title "hop", X path "view", X bookmarked_by U ' - 'WHERE U login "admin"')[0][0] - self.execute('SET X bookmarked_by U WHERE U login "anon"') - self.commit() - self.execute('DELETE X bookmarked_by U WHERE U login "admin"') - self.commit() - self.assertTrue(self.execute('Any X WHERE X eid %(x)s', {'x': beid})) - self.execute('DELETE X bookmarked_by U WHERE U login "anon"') - self.commit() - self.assertFalse(self.execute('Any X WHERE X eid %(x)s', {'x': beid})) + with self.admin_access.repo_cnx() as cnx: + beid = cnx.execute('INSERT Bookmark X: X title "hop", X path "view", X bookmarked_by U ' + 'WHERE U login "admin"')[0][0] + cnx.execute('SET X bookmarked_by U WHERE U login "anon"') + cnx.commit() + cnx.execute('DELETE X bookmarked_by U WHERE U login "admin"') + cnx.commit() + self.assertTrue(cnx.execute('Any X WHERE X eid %(x)s', {'x': beid})) + cnx.execute('DELETE X bookmarked_by U WHERE U login "anon"') + cnx.commit() + self.assertFalse(cnx.execute('Any X WHERE X eid %(x)s', {'x': beid})) if __name__ == '__main__': unittest_main() diff -r 928732ec00dd -r fa44db7da2dc hooks/test/unittest_hooks.py --- a/hooks/test/unittest_hooks.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/test/unittest_hooks.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -30,177 +30,189 @@ class CoreHooksTC(CubicWebTC): def test_inlined(self): - self.assertEqual(self.repo.schema['sender'].inlined, True) - self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') - self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"') - eeid = self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P ' - 'WHERE Y is EmailAddress, P is EmailPart')[0][0] - self.execute('SET X sender Y WHERE X is Email, Y is EmailAddress') - rset = self.execute('Any S WHERE X sender S, X eid %s' % eeid) - self.assertEqual(len(rset), 1) + with self.admin_access.repo_cnx() as cnx: + self.assertEqual(self.repo.schema['sender'].inlined, True) + cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') + cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, ' + 'X content "this is a test"') + eeid = cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", ' + 'X sender Y, X recipients Y, X parts P ' + 'WHERE Y is EmailAddress, P is EmailPart')[0][0] + cnx.execute('SET X sender Y WHERE X is Email, Y is EmailAddress') + rset = cnx.execute('Any S WHERE X sender S, X eid %s' % eeid) + self.assertEqual(len(rset), 1) def test_symmetric(self): - req = self.request() - u1 = self.create_user(req, u'1') - u2 = self.create_user(req, u'2') - u3 = self.create_user(req, u'3') - ga = req.create_entity('CWGroup', name=u'A') - gb = req.create_entity('CWGroup', name=u'B') - u1.cw_set(friend=u2) - u2.cw_set(friend=u3) - ga.cw_set(friend=gb) - ga.cw_set(friend=u1) - self.commit() - req = self.request() - for l1, l2 in ((u'1', u'2'), - (u'2', u'3')): - self.assertTrue(req.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s', - {'l1': l1, 'l2': l2})) - self.assertTrue(req.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s', - {'l1': l1, 'l2': l2})) - self.assertTrue(req.execute('Any GA,GB WHERE GA friend GB, GA name "A", GB name "B"')) - self.assertTrue(req.execute('Any GA,GB WHERE GB friend GA, GA name "A", GB name "B"')) - self.assertTrue(req.execute('Any GA,U1 WHERE GA friend U1, GA name "A", U1 login "1"')) - self.assertTrue(req.execute('Any GA,U1 WHERE U1 friend GA, GA name "A", U1 login "1"')) - self.assertFalse(req.execute('Any GA,U WHERE GA friend U, GA name "A", U login "2"')) - for l1, l2 in ((u'1', u'3'), - (u'3', u'1')): - self.assertFalse(req.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s', - {'l1': l1, 'l2': l2})) - self.assertFalse(req.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s', - {'l1': l1, 'l2': l2})) + with self.admin_access.repo_cnx() as cnx: + u1 = self.create_user(cnx, u'1') + u2 = self.create_user(cnx, u'2') + u3 = self.create_user(cnx, u'3') + ga = cnx.create_entity('CWGroup', name=u'A') + gb = cnx.create_entity('CWGroup', name=u'B') + u1.cw_set(friend=u2) + u2.cw_set(friend=u3) + ga.cw_set(friend=gb) + ga.cw_set(friend=u1) + cnx.commit() + for l1, l2 in ((u'1', u'2'), + (u'2', u'3')): + self.assertTrue(cnx.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s', + {'l1': l1, 'l2': l2})) + self.assertTrue(cnx.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s', + {'l1': l1, 'l2': l2})) + self.assertTrue(cnx.execute('Any GA,GB WHERE GA friend GB, GA name "A", GB name "B"')) + self.assertTrue(cnx.execute('Any GA,GB WHERE GB friend GA, GA name "A", GB name "B"')) + self.assertTrue(cnx.execute('Any GA,U1 WHERE GA friend U1, GA name "A", U1 login "1"')) + self.assertTrue(cnx.execute('Any GA,U1 WHERE U1 friend GA, GA name "A", U1 login "1"')) + self.assertFalse(cnx.execute('Any GA,U WHERE GA friend U, GA name "A", U login "2"')) + for l1, l2 in ((u'1', u'3'), + (u'3', u'1')): + self.assertFalse(cnx.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s', + {'l1': l1, 'l2': l2})) + self.assertFalse(cnx.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s', + {'l1': l1, 'l2': l2})) def test_html_tidy_hook(self): - req = self.request() - entity = req.create_entity('Workflow', name=u'wf1', - description_format=u'text/html', - description=u'yo') - self.assertEqual(entity.description, u'yo') - entity = req.create_entity('Workflow', name=u'wf2', - description_format=u'text/html', - description=u'yo') - self.assertEqual(entity.description, u'yo') - entity = req.create_entity('Workflow', name=u'wf3', - description_format=u'text/html', - description=u'yo') - self.assertEqual(entity.description, u'yo') - entity = req.create_entity('Workflow', name=u'wf4', - description_format=u'text/html', - description=u'R&D') - self.assertEqual(entity.description, u'R&D') - entity = req.create_entity('Workflow', name=u'wf5', - description_format=u'text/html', - description=u"
c'est l'été") - self.assertEqual(entity.description, u"
c'est l'été
") + with self.admin_access.client_cnx() as cnx: + entity = cnx.create_entity('Workflow', name=u'wf1', + description_format=u'text/html', + description=u'yo') + self.assertEqual(entity.description, u'yo') + entity = cnx.create_entity('Workflow', name=u'wf2', + description_format=u'text/html', + description=u'yo') + self.assertEqual(entity.description, u'yo') + entity = cnx.create_entity('Workflow', name=u'wf3', + description_format=u'text/html', + description=u'yo') + self.assertEqual(entity.description, u'yo') + entity = cnx.create_entity('Workflow', name=u'wf4', + description_format=u'text/html', + description=u'R&D') + self.assertEqual(entity.description, u'R&D') + entity = cnx.create_entity('Workflow', name=u'wf5', + description_format=u'text/html', + description=u"
c'est l'été") + self.assertEqual(entity.description, u"
c'est l'été
") def test_nonregr_html_tidy_hook_no_update(self): - entity = self.request().create_entity('Workflow', name=u'wf1', - description_format=u'text/html', - description=u'yo') - entity.cw_set(name=u'wf2') - self.assertEqual(entity.description, u'yo') - entity.cw_set(description=u'R&D

yo') - self.assertEqual(entity.description, u'R&D

yo

') + with self.admin_access.client_cnx() as cnx: + entity = cnx.create_entity('Workflow', name=u'wf1', + description_format=u'text/html', + description=u'yo') + entity.cw_set(name=u'wf2') + self.assertEqual(entity.description, u'yo') + entity.cw_set(description=u'R&D

yo') + self.assertEqual(entity.description, u'R&D

yo

') def test_metadata_cwuri(self): - entity = self.request().create_entity('Workflow', name=u'wf1') - self.assertEqual(entity.cwuri, self.repo.config['base-url'] + str(entity.eid)) + with self.admin_access.repo_cnx() as cnx: + entity = cnx.create_entity('Workflow', name=u'wf1') + self.assertEqual(entity.cwuri, self.repo.config['base-url'] + str(entity.eid)) def test_metadata_creation_modification_date(self): - _now = datetime.now() - entity = self.request().create_entity('Workflow', name=u'wf1') - self.assertEqual((entity.creation_date - _now).seconds, 0) - self.assertEqual((entity.modification_date - _now).seconds, 0) + with self.admin_access.repo_cnx() as cnx: + _now = datetime.now() + entity = cnx.create_entity('Workflow', name=u'wf1') + self.assertEqual((entity.creation_date - _now).seconds, 0) + self.assertEqual((entity.modification_date - _now).seconds, 0) def test_metadata_created_by(self): - entity = self.request().create_entity('Bookmark', title=u'wf1', path=u'/view') - self.commit() # fire operations - self.assertEqual(len(entity.created_by), 1) # make sure we have only one creator - self.assertEqual(entity.created_by[0].eid, self.session.user.eid) + with self.admin_access.repo_cnx() as cnx: + entity = cnx.create_entity('Bookmark', title=u'wf1', path=u'/view') + cnx.commit() # fire operations + self.assertEqual(len(entity.created_by), 1) # make sure we have only one creator + self.assertEqual(entity.created_by[0].eid, self.session.user.eid) def test_metadata_owned_by(self): - entity = self.request().create_entity('Bookmark', title=u'wf1', path=u'/view') - self.commit() # fire operations - self.assertEqual(len(entity.owned_by), 1) # make sure we have only one owner - self.assertEqual(entity.owned_by[0].eid, self.session.user.eid) + with self.admin_access.repo_cnx() as cnx: + entity = cnx.create_entity('Bookmark', title=u'wf1', path=u'/view') + cnx.commit() # fire operations + self.assertEqual(len(entity.owned_by), 1) # make sure we have only one owner + self.assertEqual(entity.owned_by[0].eid, self.session.user.eid) def test_user_login_stripped(self): - req = self.request() - u = self.create_user(req, ' joe ') - tname = self.execute('Any L WHERE E login L, E eid %(e)s', - {'e': u.eid})[0][0] - self.assertEqual(tname, 'joe') - self.execute('SET X login " jijoe " WHERE X eid %(x)s', {'x': u.eid}) - tname = self.execute('Any L WHERE E login L, E eid %(e)s', - {'e': u.eid})[0][0] - self.assertEqual(tname, 'jijoe') + with self.admin_access.repo_cnx() as cnx: + u = self.create_user(cnx, ' joe ') + tname = cnx.execute('Any L WHERE E login L, E eid %(e)s', + {'e': u.eid})[0][0] + self.assertEqual(tname, 'joe') + cnx.execute('SET X login " jijoe " WHERE X eid %(x)s', {'x': u.eid}) + tname = cnx.execute('Any L WHERE E login L, E eid %(e)s', + {'e': u.eid})[0][0] + self.assertEqual(tname, 'jijoe') class UserGroupHooksTC(CubicWebTC): def test_user_synchronization(self): - req = self.request() - self.create_user(req, 'toto', password='hop', commit=False) - self.assertRaises(AuthenticationError, - self.repo.connect, u'toto', password='hop') - self.commit() - cnxid = self.repo.connect(u'toto', password='hop') - self.assertNotEqual(cnxid, self.session.id) - self.execute('DELETE CWUser X WHERE X login "toto"') - self.repo.execute(cnxid, 'State X') - self.commit() - self.assertRaises(BadConnectionId, - self.repo.execute, cnxid, 'State X') + with self.admin_access.repo_cnx() as cnx: + self.create_user(cnx, 'toto', password='hop', commit=False) + self.assertRaises(AuthenticationError, + self.repo.connect, u'toto', password='hop') + cnx.commit() + cnxid = self.repo.connect(u'toto', password='hop') + self.assertNotEqual(cnxid, self.session.id) + cnx.execute('DELETE CWUser X WHERE X login "toto"') + self.repo.execute(cnxid, 'State X') + cnx.commit() + self.assertRaises(BadConnectionId, + self.repo.execute, cnxid, 'State X') def test_user_group_synchronization(self): - user = self.session.user - self.assertEqual(user.groups, set(('managers',))) - self.execute('SET X in_group G WHERE X eid %s, G name "guests"' % user.eid) - self.assertEqual(user.groups, set(('managers',))) - self.commit() - self.assertEqual(user.groups, set(('managers', 'guests'))) - self.execute('DELETE X in_group G WHERE X eid %s, G name "guests"' % user.eid) - self.assertEqual(user.groups, set(('managers', 'guests'))) - self.commit() - self.assertEqual(user.groups, set(('managers',))) + with self.admin_access.repo_cnx() as cnx: + user = cnx.user + self.assertEqual(user.groups, set(('managers',))) + cnx.execute('SET X in_group G WHERE X eid %s, G name "guests"' % user.eid) + self.assertEqual(user.groups, set(('managers',))) + cnx.commit() + self.assertEqual(user.groups, set(('managers', 'guests'))) + cnx.execute('DELETE X in_group G WHERE X eid %s, G name "guests"' % user.eid) + self.assertEqual(user.groups, set(('managers', 'guests'))) + cnx.commit() + self.assertEqual(user.groups, set(('managers',))) def test_user_composite_owner(self): - req = self.request() - ueid = self.create_user(req, 'toto').eid - # composite of euser should be owned by the euser regardless of who created it - self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", U use_email X ' - 'WHERE U login "toto"') - self.commit() - self.assertEqual(self.execute('Any A WHERE X owned_by U, U use_email X,' - 'U login "toto", X address A')[0][0], - 'toto@logilab.fr') + with self.admin_access.repo_cnx() as cnx: + self.create_user(cnx, 'toto').eid + # composite of euser should be owned by the euser regardless of who created it + cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", U use_email X ' + 'WHERE U login "toto"') + cnx.commit() + self.assertEqual(cnx.execute('Any A WHERE X owned_by U, U use_email X,' + 'U login "toto", X address A')[0][0], + 'toto@logilab.fr') def test_no_created_by_on_deleted_entity(self): - eid = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"')[0][0] - self.execute('DELETE EmailAddress X WHERE X eid %s' % eid) - self.commit() - self.assertFalse(self.execute('Any X WHERE X created_by Y, X eid >= %(x)s', {'x': eid})) + with self.admin_access.repo_cnx() as cnx: + eid = cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr"')[0][0] + cnx.execute('DELETE EmailAddress X WHERE X eid %s' % eid) + cnx.commit() + self.assertFalse(cnx.execute('Any X WHERE X created_by Y, X eid >= %(x)s', {'x': eid})) class SchemaHooksTC(CubicWebTC): def test_duplicate_etype_error(self): - # check we can't add a CWEType or CWRType entity if it already exists one - # with the same name - self.assertRaises(ValidationError, - self.execute, 'INSERT CWEType X: X name "CWUser"') - self.assertRaises(ValidationError, - self.execute, 'INSERT CWRType X: X name "in_group"') + with self.admin_access.repo_cnx() as cnx: + # check we can't add a CWEType or CWRType entity if it already exists one + # with the same name + self.assertRaises(ValidationError, + cnx.execute, 'INSERT CWEType X: X name "CWUser"') + cnx.rollback() + self.assertRaises(ValidationError, + cnx.execute, 'INSERT CWRType X: X name "in_group"') def test_validation_unique_constraint(self): - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWUser X: X login "admin"') - ex = cm.exception - ex.translate(unicode) - self.assertIsInstance(ex.entity, int) - self.assertEqual(ex.errors, {'login-subject': 'the value "admin" is already used, use another one'}) + with self.admin_access.repo_cnx() as cnx: + with self.assertRaises(ValidationError) as cm: + cnx.execute('INSERT CWUser X: X login "admin"') + ex = cm.exception + ex.translate(unicode) + self.assertIsInstance(ex.entity, int) + self.assertEqual(ex.errors, {'login-subject': 'the value "admin" is already used, use another one'}) if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc hooks/test/unittest_integrity.py --- a/hooks/test/unittest_integrity.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/test/unittest_integrity.py Fri Jul 18 17:35:25 2014 +0200 @@ -24,126 +24,138 @@ class CoreHooksTC(CubicWebTC): def test_delete_internal_entities(self): - self.assertRaises(ValidationError, self.execute, - 'DELETE CWEType X WHERE X name "CWEType"') - self.assertRaises(ValidationError, self.execute, - 'DELETE CWRType X WHERE X name "relation_type"') - self.assertRaises(ValidationError, self.execute, - 'DELETE CWGroup X WHERE X name "owners"') + with self.admin_access.repo_cnx() as cnx: + self.assertRaises(ValidationError, cnx.execute, + 'DELETE CWEType X WHERE X name "CWEType"') + cnx.rollback() + self.assertRaises(ValidationError, cnx.execute, + 'DELETE CWRType X WHERE X name "relation_type"') + cnx.rollback() + self.assertRaises(ValidationError, cnx.execute, + 'DELETE CWGroup X WHERE X name "owners"') def test_delete_required_relations_subject(self): - self.execute('INSERT CWUser X: X login "toto", X upassword "hop", X in_group Y ' - 'WHERE Y name "users"') - self.commit() - self.execute('DELETE X in_group Y WHERE X login "toto", Y name "users"') - self.assertRaises(ValidationError, self.commit) - self.execute('DELETE X in_group Y WHERE X login "toto"') - self.execute('SET X in_group Y WHERE X login "toto", Y name "guests"') - self.commit() + with self.admin_access.repo_cnx() as cnx: + cnx.execute('INSERT CWUser X: X login "toto", X upassword "hop", X in_group Y ' + 'WHERE Y name "users"') + cnx.commit() + cnx.execute('DELETE X in_group Y WHERE X login "toto", Y name "users"') + self.assertRaises(ValidationError, cnx.commit) + cnx.rollback() + cnx.execute('DELETE X in_group Y WHERE X login "toto"') + cnx.execute('SET X in_group Y WHERE X login "toto", Y name "guests"') + cnx.commit() def test_static_vocabulary_check(self): - self.assertRaises(ValidationError, - self.execute, - 'SET X composite "whatever" WHERE X from_entity FE, FE name "CWUser", X relation_type RT, RT name "in_group"') + with self.admin_access.repo_cnx() as cnx: + self.assertRaises(ValidationError, + cnx.execute, + 'SET X composite "whatever" WHERE X from_entity FE, FE name "CWUser", ' + 'X relation_type RT, RT name "in_group"') def test_missing_required_relations_subject_inline(self): - # missing in_group relation - self.execute('INSERT CWUser X: X login "toto", X upassword "hop"') - self.assertRaises(ValidationError, - self.commit) + with self.admin_access.repo_cnx() as cnx: + # missing in_group relation + cnx.execute('INSERT CWUser X: X login "toto", X upassword "hop"') + self.assertRaises(ValidationError, cnx.commit) def test_composite_1(self): - self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') - self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"') - self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P ' - 'WHERE Y is EmailAddress, P is EmailPart') - self.assertTrue(self.execute('Email X WHERE X sender Y')) - self.commit() - self.execute('DELETE Email X') - rset = self.execute('Any X WHERE X is EmailPart') - self.assertEqual(len(rset), 0) - self.commit() - rset = self.execute('Any X WHERE X is EmailPart') - self.assertEqual(len(rset), 0) + with self.admin_access.repo_cnx() as cnx: + cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') + cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, ' + 'X content "this is a test"') + cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, ' + 'X recipients Y, X parts P ' + 'WHERE Y is EmailAddress, P is EmailPart') + self.assertTrue(cnx.execute('Email X WHERE X sender Y')) + cnx.commit() + cnx.execute('DELETE Email X') + rset = cnx.execute('Any X WHERE X is EmailPart') + self.assertEqual(len(rset), 0) + cnx.commit() + rset = cnx.execute('Any X WHERE X is EmailPart') + self.assertEqual(len(rset), 0) def test_composite_2(self): - self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') - self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"') - self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P ' - 'WHERE Y is EmailAddress, P is EmailPart') - self.commit() - self.execute('DELETE Email X') - self.execute('DELETE EmailPart X') - self.commit() - rset = self.execute('Any X WHERE X is EmailPart') - self.assertEqual(len(rset), 0) + with self.admin_access.repo_cnx() as cnx: + cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') + cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, ' + 'X content "this is a test"') + cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, ' + 'X recipients Y, X parts P ' + 'WHERE Y is EmailAddress, P is EmailPart') + cnx.commit() + cnx.execute('DELETE Email X') + cnx.execute('DELETE EmailPart X') + cnx.commit() + rset = cnx.execute('Any X WHERE X is EmailPart') + self.assertEqual(len(rset), 0) def test_composite_redirection(self): - self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') - self.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, X content "this is a test"') - self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y, X parts P ' - 'WHERE Y is EmailAddress, P is EmailPart') - self.execute('INSERT Email X: X messageid "<2345>", X subject "test2", X sender Y, X recipients Y ' - 'WHERE Y is EmailAddress') - self.commit() - self.execute('DELETE X parts Y WHERE X messageid "<1234>"') - self.execute('SET X parts Y WHERE X messageid "<2345>"') - self.commit() - rset = self.execute('Any X WHERE X is EmailPart') - self.assertEqual(len(rset), 1) - self.assertEqual(rset.get_entity(0, 0).reverse_parts[0].messageid, '<2345>') + with self.admin_access.repo_cnx() as cnx: + cnx.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"') + cnx.execute('INSERT EmailPart X: X content_format "text/plain", X ordernum 1, ' + 'X content "this is a test"') + cnx.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, ' + 'X recipients Y, X parts P ' + 'WHERE Y is EmailAddress, P is EmailPart') + cnx.execute('INSERT Email X: X messageid "<2345>", X subject "test2", X sender Y, ' + 'X recipients Y ' + 'WHERE Y is EmailAddress') + cnx.commit() + cnx.execute('DELETE X parts Y WHERE X messageid "<1234>"') + cnx.execute('SET X parts Y WHERE X messageid "<2345>"') + cnx.commit() + rset = cnx.execute('Any X WHERE X is EmailPart') + self.assertEqual(len(rset), 1) + self.assertEqual(rset.get_entity(0, 0).reverse_parts[0].messageid, '<2345>') def test_composite_object_relation_deletion(self): - req = self.request() - root = req.create_entity('Folder', name=u'root') - a = req.create_entity('Folder', name=u'a', parent=root) - b = req.create_entity('Folder', name=u'b', parent=a) - c = req.create_entity('Folder', name=u'c', parent=root) - self.commit() - req = self.request() - req.execute('DELETE Folder F WHERE F name "a"') - req.execute('DELETE F parent R WHERE R name "root"') - self.commit() - req = self.request() - self.assertEqual([['root'], ['c']], - req.execute('Any NF WHERE F is Folder, F name NF').rows) - self.assertEqual([], - req.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows) + with self.admin_access.repo_cnx() as cnx: + root = cnx.create_entity('Folder', name=u'root') + a = cnx.create_entity('Folder', name=u'a', parent=root) + cnx.create_entity('Folder', name=u'b', parent=a) + cnx.create_entity('Folder', name=u'c', parent=root) + cnx.commit() + cnx.execute('DELETE Folder F WHERE F name "a"') + cnx.execute('DELETE F parent R WHERE R name "root"') + cnx.commit() + self.assertEqual([['root'], ['c']], + cnx.execute('Any NF WHERE F is Folder, F name NF').rows) + self.assertEqual([], cnx.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows) def test_composite_subject_relation_deletion(self): - req = self.request() - root = req.create_entity('Folder', name=u'root') - a = req.create_entity('Folder', name=u'a') - b = req.create_entity('Folder', name=u'b') - c = req.create_entity('Folder', name=u'c') - root.cw_set(children=(a, c)) - a.cw_set(children=b) - self.commit() - req = self.request() - req.execute('DELETE Folder F WHERE F name "a"') - req.execute('DELETE R children F WHERE R name "root"') - self.commit() - req = self.request() - self.assertEqual([['root'], ['c']], - req.execute('Any NF WHERE F is Folder, F name NF').rows) - self.assertEqual([], - req.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows) + with self.admin_access.repo_cnx() as cnx: + root = cnx.create_entity('Folder', name=u'root') + a = cnx.create_entity('Folder', name=u'a') + b = cnx.create_entity('Folder', name=u'b') + c = cnx.create_entity('Folder', name=u'c') + root.cw_set(children=(a, c)) + a.cw_set(children=b) + cnx.commit() + cnx.execute('DELETE Folder F WHERE F name "a"') + cnx.execute('DELETE R children F WHERE R name "root"') + cnx.commit() + self.assertEqual([['root'], ['c']], + cnx.execute('Any NF WHERE F is Folder, F name NF').rows) + self.assertEqual([], cnx.execute('Any NF,NP WHERE F parent P, F name NF, P name NP').rows) def test_unsatisfied_constraints(self): - releid = self.execute('SET U in_group G WHERE G name "owners", U login "admin"')[0][0] - with self.assertRaises(ValidationError) as cm: - self.commit() + with self.admin_access.repo_cnx() as cnx: + cnx.execute('SET U in_group G WHERE G name "owners", U login "admin"')[0][0] + with self.assertRaises(ValidationError) as cm: + cnx.commit() self.assertEqual(cm.exception.errors, - {'in_group-object': u'RQLConstraint NOT O name "owners" failed'}) + {'in_group-object': u'RQLConstraint NOT O name "owners" failed'}) def test_unique_constraint(self): - req = self.request() - entity = req.create_entity('CWGroup', name=u'trout') - self.commit() - self.assertRaises(ValidationError, req.create_entity, 'CWGroup', name=u'trout') - self.rollback() - req.execute('SET X name "trout" WHERE X eid %(x)s', {'x': entity.eid}) - self.commit() + with self.admin_access.repo_cnx() as cnx: + entity = cnx.create_entity('CWGroup', name=u'trout') + cnx.commit() + self.assertRaises(ValidationError, cnx.create_entity, 'CWGroup', name=u'trout') + cnx.rollback() + cnx.execute('SET X name "trout" WHERE X eid %(x)s', {'x': entity.eid}) + cnx.commit() if __name__ == '__main__': from logilab.common.testlib import unittest_main diff -r 928732ec00dd -r fa44db7da2dc hooks/test/unittest_syncschema.py --- a/hooks/test/unittest_syncschema.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/test/unittest_syncschema.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -17,13 +17,13 @@ # with CubicWeb. If not, see . """cubicweb.server.hooks.syncschema unit and functional tests""" -from logilab.common.testlib import TestCase, unittest_main +from logilab.common.testlib import unittest_main from cubicweb import ValidationError, Binary from cubicweb.schema import META_RTYPES from cubicweb.devtools.testlib import CubicWebTC from cubicweb.server.sqlutils import SQL_PREFIX -from cubicweb.devtools.repotest import schema_eids_idx, restore_schema_eids_idx +from cubicweb.devtools.repotest import schema_eids_idx def tearDownModule(*args): @@ -36,320 +36,343 @@ self.repo.set_schema(self.repo.deserialize_schema(), resetvreg=False) self.__class__.schema_eids = schema_eids_idx(self.repo.schema) - def index_exists(self, etype, attr, unique=False): - self.session.set_cnxset() + def index_exists(self, cnx, etype, attr, unique=False): dbhelper = self.repo.system_source.dbhelper - sqlcursor = self.session.cnxset.cu - return dbhelper.index_exists(sqlcursor, SQL_PREFIX + etype, SQL_PREFIX + attr, unique=unique) + with cnx.ensure_cnx_set: + sqlcursor = cnx.cnxset.cu + return dbhelper.index_exists(sqlcursor, + SQL_PREFIX + etype, + SQL_PREFIX + attr, + unique=unique) - def _set_perms(self, eid): - self.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup', - {'x': eid}) - self.execute('SET X add_permission G WHERE X eid %(x)s, G is CWGroup, G name "managers"', - {'x': eid}) - self.execute('SET X delete_permission G WHERE X eid %(x)s, G is CWGroup, G name "owners"', - {'x': eid}) + def _set_perms(self, cnx, eid): + cnx.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup', + {'x': eid}) + cnx.execute('SET X add_permission G WHERE X eid %(x)s, G is CWGroup, ' + 'G name "managers"', {'x': eid}) + cnx.execute('SET X delete_permission G WHERE X eid %(x)s, G is CWGroup, ' + 'G name "owners"', {'x': eid}) - def _set_attr_perms(self, eid): - self.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup', - {'x': eid}) - self.execute('SET X update_permission G WHERE X eid %(x)s, G is CWGroup, G name "managers"', - {'x': eid}) + def _set_attr_perms(self, cnx, eid): + cnx.execute('SET X read_permission G WHERE X eid %(x)s, G is CWGroup', + {'x': eid}) + cnx.execute('SET X update_permission G WHERE X eid %(x)s, G is CWGroup, G name "managers"', + {'x': eid}) def test_base(self): - schema = self.repo.schema - self.session.set_cnxset() - dbhelper = self.repo.system_source.dbhelper - sqlcursor = self.session.cnxset.cu - self.assertFalse(schema.has_entity('Societe2')) - self.assertFalse(schema.has_entity('concerne2')) - # schema should be update on insertion (after commit) - eeid = self.execute('INSERT CWEType X: X name "Societe2", X description "", X final FALSE')[0][0] - self._set_perms(eeid) - self.execute('INSERT CWRType X: X name "concerne2", X description "", X final FALSE, X symmetric FALSE') - self.assertFalse(schema.has_entity('Societe2')) - self.assertFalse(schema.has_entity('concerne2')) - # have to commit before adding definition relations - self.commit() - self.assertTrue(schema.has_entity('Societe2')) - self.assertTrue(schema.has_relation('concerne2')) - attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, ' - ' X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F ' - 'WHERE RT name "name", E name "Societe2", F name "String"', - {'default': Binary.zpickle('noname')})[0][0] - self._set_attr_perms(attreid) - concerne2_rdef_eid = self.execute( - 'INSERT CWRelation X: X cardinality "**", X relation_type RT, X from_entity E, X to_entity E ' - 'WHERE RT name "concerne2", E name "Societe2"')[0][0] - self._set_perms(concerne2_rdef_eid) - self.assertNotIn('name', schema['Societe2'].subject_relations()) - self.assertNotIn('concerne2', schema['Societe2'].subject_relations()) - self.assertFalse(self.index_exists('Societe2', 'name')) - self.commit() - self.assertIn('name', schema['Societe2'].subject_relations()) - self.assertIn('concerne2', schema['Societe2'].subject_relations()) - self.assertTrue(self.index_exists('Societe2', 'name')) - # now we should be able to insert and query Societe2 - s2eid = self.execute('INSERT Societe2 X: X name "logilab"')[0][0] - self.execute('Societe2 X WHERE X name "logilab"') - self.execute('SET X concerne2 X WHERE X name "logilab"') - rset = self.execute('Any X WHERE X concerne2 Y') - self.assertEqual(rset.rows, [[s2eid]]) - # check that when a relation definition is deleted, existing relations are deleted - rdefeid = self.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, ' - ' X from_entity E, X to_entity E ' - 'WHERE RT name "concerne2", E name "CWUser"')[0][0] - self._set_perms(rdefeid) - self.commit() - self.execute('DELETE CWRelation X WHERE X eid %(x)s', {'x': concerne2_rdef_eid}) - self.commit() - self.assertIn('concerne2', schema['CWUser'].subject_relations()) - self.assertNotIn('concerne2', schema['Societe2'].subject_relations()) - self.assertFalse(self.execute('Any X WHERE X concerne2 Y')) - # schema should be cleaned on delete (after commit) - self.execute('DELETE CWEType X WHERE X name "Societe2"') - self.execute('DELETE CWRType X WHERE X name "concerne2"') - self.assertTrue(self.index_exists('Societe2', 'name')) - self.assertTrue(schema.has_entity('Societe2')) - self.assertTrue(schema.has_relation('concerne2')) - self.commit() - self.assertFalse(self.index_exists('Societe2', 'name')) - self.assertFalse(schema.has_entity('Societe2')) - self.assertFalse(schema.has_entity('concerne2')) - self.assertNotIn('concerne2', schema['CWUser'].subject_relations()) + with self.admin_access.repo_cnx() as cnx: + schema = self.repo.schema + self.assertFalse(schema.has_entity('Societe2')) + self.assertFalse(schema.has_entity('concerne2')) + # schema should be update on insertion (after commit) + eeid = cnx.execute('INSERT CWEType X: X name "Societe2", ' + 'X description "", X final FALSE')[0][0] + self._set_perms(cnx, eeid) + cnx.execute('INSERT CWRType X: X name "concerne2", X description "", ' + 'X final FALSE, X symmetric FALSE') + self.assertFalse(schema.has_entity('Societe2')) + self.assertFalse(schema.has_entity('concerne2')) + # have to commit before adding definition relations + cnx.commit() + self.assertTrue(schema.has_entity('Societe2')) + self.assertTrue(schema.has_relation('concerne2')) + attreid = cnx.execute('INSERT CWAttribute X: X cardinality "11", ' + 'X defaultval %(default)s, X indexed TRUE, ' + 'X relation_type RT, X from_entity E, X to_entity F ' + 'WHERE RT name "name", E name "Societe2", ' + 'F name "String"', + {'default': Binary.zpickle('noname')})[0][0] + self._set_attr_perms(cnx, attreid) + concerne2_rdef_eid = cnx.execute( + 'INSERT CWRelation X: X cardinality "**", X relation_type RT, ' + 'X from_entity E, X to_entity E ' + 'WHERE RT name "concerne2", E name "Societe2"')[0][0] + self._set_perms(cnx, concerne2_rdef_eid) + self.assertNotIn('name', schema['Societe2'].subject_relations()) + self.assertNotIn('concerne2', schema['Societe2'].subject_relations()) + self.assertFalse(self.index_exists(cnx, 'Societe2', 'name')) + cnx.commit() + self.assertIn('name', schema['Societe2'].subject_relations()) + self.assertIn('concerne2', schema['Societe2'].subject_relations()) + self.assertTrue(self.index_exists(cnx, 'Societe2', 'name')) + # now we should be able to insert and query Societe2 + s2eid = cnx.execute('INSERT Societe2 X: X name "logilab"')[0][0] + cnx.execute('Societe2 X WHERE X name "logilab"') + cnx.execute('SET X concerne2 X WHERE X name "logilab"') + rset = cnx.execute('Any X WHERE X concerne2 Y') + self.assertEqual(rset.rows, [[s2eid]]) + # check that when a relation definition is deleted, existing relations are deleted + rdefeid = cnx.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, ' + ' X from_entity E, X to_entity E ' + 'WHERE RT name "concerne2", E name "CWUser"')[0][0] + self._set_perms(cnx, rdefeid) + cnx.commit() + cnx.execute('DELETE CWRelation X WHERE X eid %(x)s', {'x': concerne2_rdef_eid}) + cnx.commit() + self.assertIn('concerne2', schema['CWUser'].subject_relations()) + self.assertNotIn('concerne2', schema['Societe2'].subject_relations()) + self.assertFalse(cnx.execute('Any X WHERE X concerne2 Y')) + # schema should be cleaned on delete (after commit) + cnx.execute('DELETE CWEType X WHERE X name "Societe2"') + cnx.execute('DELETE CWRType X WHERE X name "concerne2"') + self.assertTrue(self.index_exists(cnx, 'Societe2', 'name')) + self.assertTrue(schema.has_entity('Societe2')) + self.assertTrue(schema.has_relation('concerne2')) + cnx.commit() + self.assertFalse(self.index_exists(cnx, 'Societe2', 'name')) + self.assertFalse(schema.has_entity('Societe2')) + self.assertFalse(schema.has_entity('concerne2')) + self.assertNotIn('concerne2', schema['CWUser'].subject_relations()) def test_metartype_with_nordefs(self): - META_RTYPES.add('custom_meta') - self.execute('INSERT CWRType X: X name "custom_meta", X description "", ' - 'X final FALSE, X symmetric FALSE') - self.commit() - eeid = self.execute('INSERT CWEType X: X name "NEWEtype", ' - 'X description "", X final FALSE')[0][0] - self._set_perms(eeid) - self.commit() - META_RTYPES.remove('custom_meta') + with self.admin_access.repo_cnx() as cnx: + META_RTYPES.add('custom_meta') + cnx.execute('INSERT CWRType X: X name "custom_meta", X description "", ' + 'X final FALSE, X symmetric FALSE') + cnx.commit() + eeid = cnx.execute('INSERT CWEType X: X name "NEWEtype", ' + 'X description "", X final FALSE')[0][0] + self._set_perms(cnx, eeid) + cnx.commit() + META_RTYPES.remove('custom_meta') def test_metartype_with_somerdefs(self): - META_RTYPES.add('custom_meta') - self.execute('INSERT CWRType X: X name "custom_meta", X description "", ' - 'X final FALSE, X symmetric FALSE') - self.commit() - rdefeid = self.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, ' - ' X from_entity E, X to_entity E ' - 'WHERE RT name "custom_meta", E name "CWUser"')[0][0] - self._set_perms(rdefeid) - self.commit() - eeid = self.execute('INSERT CWEType X: X name "NEWEtype", ' - 'X description "", X final FALSE')[0][0] - self._set_perms(eeid) - self.commit() - META_RTYPES.remove('custom_meta') + with self.admin_access.repo_cnx() as cnx: + META_RTYPES.add('custom_meta') + cnx.execute('INSERT CWRType X: X name "custom_meta", X description "", ' + 'X final FALSE, X symmetric FALSE') + cnx.commit() + rdefeid = cnx.execute('INSERT CWRelation X: X cardinality "**", X relation_type RT, ' + ' X from_entity E, X to_entity E ' + 'WHERE RT name "custom_meta", E name "CWUser"')[0][0] + self._set_perms(cnx, rdefeid) + cnx.commit() + eeid = cnx.execute('INSERT CWEType X: X name "NEWEtype", ' + 'X description "", X final FALSE')[0][0] + self._set_perms(cnx, eeid) + cnx.commit() + META_RTYPES.remove('custom_meta') def test_is_instance_of_insertions(self): - seid = self.execute('INSERT Transition T: T name "subdiv"')[0][0] - is_etypes = [etype for etype, in self.execute('Any ETN WHERE X eid %s, X is ET, ET name ETN' % seid)] - self.assertEqual(is_etypes, ['Transition']) - instanceof_etypes = [etype for etype, in self.execute('Any ETN WHERE X eid %s, X is_instance_of ET, ET name ETN' % seid)] - self.assertEqual(sorted(instanceof_etypes), ['BaseTransition', 'Transition']) - snames = [name for name, in self.execute('Any N WHERE S is BaseTransition, S name N')] - self.assertNotIn('subdiv', snames) - snames = [name for name, in self.execute('Any N WHERE S is_instance_of BaseTransition, S name N')] - self.assertIn('subdiv', snames) + with self.admin_access.repo_cnx() as cnx: + seid = cnx.execute('INSERT Transition T: T name "subdiv"')[0][0] + is_etypes = [etype for etype, in cnx.execute('Any ETN WHERE X eid %s, ' + 'X is ET, ET name ETN' % seid)] + self.assertEqual(is_etypes, ['Transition']) + instanceof_etypes = [etype + for etype, in cnx.execute('Any ETN WHERE X eid %s, ' + 'X is_instance_of ET, ET name ETN' + % seid)] + self.assertEqual(sorted(instanceof_etypes), ['BaseTransition', 'Transition']) + snames = [name for name, in cnx.execute('Any N WHERE S is BaseTransition, S name N')] + self.assertNotIn('subdiv', snames) + snames = [name for name, in cnx.execute('Any N WHERE S is_instance_of BaseTransition, ' + 'S name N')] + self.assertIn('subdiv', snames) def test_perms_synchronization_1(self): - schema = self.repo.schema - self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users'))) - self.assertTrue(self.execute('Any X, Y WHERE X is CWEType, X name "CWUser", Y is CWGroup, Y name "users"')[0]) - self.execute('DELETE X read_permission Y WHERE X is CWEType, X name "CWUser", Y name "users"') - self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users', ))) - self.commit() - self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers',))) - self.execute('SET X read_permission Y WHERE X is CWEType, X name "CWUser", Y name "users"') - self.commit() - self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users',))) + with self.admin_access.repo_cnx() as cnx: + schema = self.repo.schema + self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users'))) + self.assertTrue(cnx.execute('Any X, Y WHERE X is CWEType, X name "CWUser", ' + 'Y is CWGroup, Y name "users"')[0]) + cnx.execute('DELETE X read_permission Y WHERE X is CWEType, X name "CWUser", Y name "users"') + self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers', 'users', ))) + cnx.commit() + self.assertEqual(schema['CWUser'].get_groups('read'), set(('managers',))) + cnx.execute('SET X read_permission Y WHERE X is CWEType, ' + 'X name "CWUser", Y name "users"') + cnx.commit() + self.assertEqual(schema['CWUser'].get_groups('read'), + set(('managers', 'users',))) def test_perms_synchronization_2(self): - schema = self.repo.schema['in_group'].rdefs[('CWUser', 'CWGroup')] - self.assertEqual(schema.get_groups('read'), set(('managers', 'users', 'guests'))) - self.execute('DELETE X read_permission Y WHERE X relation_type RT, RT name "in_group", Y name "guests"') - self.assertEqual(schema.get_groups('read'), set(('managers', 'users', 'guests'))) - self.commit() - self.assertEqual(schema.get_groups('read'), set(('managers', 'users'))) - self.execute('SET X read_permission Y WHERE X relation_type RT, RT name "in_group", Y name "guests"') - self.assertEqual(schema.get_groups('read'), set(('managers', 'users'))) - self.commit() - self.assertEqual(schema.get_groups('read'), set(('managers', 'users', 'guests'))) + with self.admin_access.repo_cnx() as cnx: + schema = self.repo.schema['in_group'].rdefs[('CWUser', 'CWGroup')] + self.assertEqual(schema.get_groups('read'), + set(('managers', 'users', 'guests'))) + cnx.execute('DELETE X read_permission Y WHERE X relation_type RT, ' + 'RT name "in_group", Y name "guests"') + self.assertEqual(schema.get_groups('read'), + set(('managers', 'users', 'guests'))) + cnx.commit() + self.assertEqual(schema.get_groups('read'), + set(('managers', 'users'))) + cnx.execute('SET X read_permission Y WHERE X relation_type RT, ' + 'RT name "in_group", Y name "guests"') + self.assertEqual(schema.get_groups('read'), + set(('managers', 'users'))) + cnx.commit() + self.assertEqual(schema.get_groups('read'), + set(('managers', 'users', 'guests'))) def test_nonregr_user_edit_itself(self): - ueid = self.session.user.eid - groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')] - self.execute('DELETE X in_group Y WHERE X eid %s' % ueid) - self.execute('SET X surname "toto" WHERE X eid %s' % ueid) - self.execute('SET X in_group Y WHERE X eid %s, Y name "managers"' % ueid) - self.commit() - eeid = self.execute('Any X WHERE X is CWEType, X name "CWEType"')[0][0] - self.execute('DELETE X read_permission Y WHERE X eid %s' % eeid) - self.execute('SET X final FALSE WHERE X eid %s' % eeid) - self.execute('SET X read_permission Y WHERE X eid %s, Y eid in (%s, %s)' - % (eeid, groupeids[0], groupeids[1])) - self.commit() - self.execute('Any X WHERE X is CWEType, X name "CWEType"') + with self.admin_access.repo_cnx() as cnx: + ueid = cnx.user.eid + groupeids = [eid for eid, in cnx.execute('CWGroup G WHERE G name ' + 'in ("managers", "users")')] + cnx.execute('DELETE X in_group Y WHERE X eid %s' % ueid) + cnx.execute('SET X surname "toto" WHERE X eid %s' % ueid) + cnx.execute('SET X in_group Y WHERE X eid %s, Y name "managers"' % ueid) + cnx.commit() + eeid = cnx.execute('Any X WHERE X is CWEType, X name "CWEType"')[0][0] + cnx.execute('DELETE X read_permission Y WHERE X eid %s' % eeid) + cnx.execute('SET X final FALSE WHERE X eid %s' % eeid) + cnx.execute('SET X read_permission Y WHERE X eid %s, Y eid in (%s, %s)' + % (eeid, groupeids[0], groupeids[1])) + cnx.commit() + cnx.execute('Any X WHERE X is CWEType, X name "CWEType"') # schema modification hooks tests ######################################### def test_uninline_relation(self): - self.session.set_cnxset() - dbhelper = self.repo.system_source.dbhelper - sqlcursor = self.session.cnxset.cu - self.assertTrue(self.schema['state_of'].inlined) - try: - self.execute('SET X inlined FALSE WHERE X name "state_of"') - self.assertTrue(self.schema['state_of'].inlined) - self.commit() - self.assertFalse(self.schema['state_of'].inlined) - self.assertFalse(self.index_exists('State', 'state_of')) - rset = self.execute('Any X, Y WHERE X state_of Y') - self.assertEqual(len(rset), 2) # user states - except Exception: - import traceback - traceback.print_exc() - finally: - self.execute('SET X inlined TRUE WHERE X name "state_of"') - self.assertFalse(self.schema['state_of'].inlined) - self.commit() - self.assertTrue(self.schema['state_of'].inlined) - self.assertTrue(self.index_exists('State', 'state_of')) - rset = self.execute('Any X, Y WHERE X state_of Y') - self.assertEqual(len(rset), 2) + with self.admin_access.repo_cnx() as cnx: + try: + self.assertTrue(self.schema['state_of'].inlined) + cnx.execute('SET X inlined FALSE WHERE X name "state_of"') + self.assertTrue(self.schema['state_of'].inlined) + cnx.commit() + self.assertFalse(self.schema['state_of'].inlined) + self.assertFalse(self.index_exists(cnx, 'State', 'state_of')) + rset = cnx.execute('Any X, Y WHERE X state_of Y') + self.assertEqual(len(rset), 2) # user states + finally: + cnx.execute('SET X inlined TRUE WHERE X name "state_of"') + self.assertFalse(self.schema['state_of'].inlined) + cnx.commit() + self.assertTrue(self.schema['state_of'].inlined) + self.assertTrue(self.index_exists(cnx, 'State', 'state_of')) + rset = cnx.execute('Any X, Y WHERE X state_of Y') + self.assertEqual(len(rset), 2) def test_indexed_change(self): - self.session.set_cnxset() - dbhelper = self.repo.system_source.dbhelper - sqlcursor = self.session.cnxset.cu - try: - self.execute('SET X indexed FALSE WHERE X relation_type R, R name "name"') - self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed) - self.assertTrue(self.index_exists('Workflow', 'name')) - self.commit() - self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed) - self.assertFalse(self.index_exists('Workflow', 'name')) - finally: - self.execute('SET X indexed TRUE WHERE X relation_type R, R name "name"') - self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed) - self.assertFalse(self.index_exists('Workflow', 'name')) - self.commit() - self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed) - self.assertTrue(self.index_exists('Workflow', 'name')) + with self.admin_access.repo_cnx() as cnx: + try: + cnx.execute('SET X indexed FALSE WHERE X relation_type R, R name "name"') + self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed) + self.assertTrue(self.index_exists(cnx, 'Workflow', 'name')) + cnx.commit() + self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed) + self.assertFalse(self.index_exists(cnx, 'Workflow', 'name')) + finally: + cnx.execute('SET X indexed TRUE WHERE X relation_type R, R name "name"') + self.assertFalse(self.schema['name'].rdef('Workflow', 'String').indexed) + self.assertFalse(self.index_exists(cnx, 'Workflow', 'name')) + cnx.commit() + self.assertTrue(self.schema['name'].rdef('Workflow', 'String').indexed) + self.assertTrue(self.index_exists(cnx, 'Workflow', 'name')) def test_unique_change(self): - self.session.set_cnxset() - dbhelper = self.repo.system_source.dbhelper - sqlcursor = self.session.cnxset.cu - try: - eid = self.execute('INSERT CWConstraint X: X cstrtype CT, DEF constrained_by X ' - 'WHERE CT name "UniqueConstraint", DEF relation_type RT, DEF from_entity E,' - 'RT name "name", E name "Workflow"').rows[0][0] - self.assertFalse(self.schema['Workflow'].has_unique_values('name')) - self.assertFalse(self.index_exists('Workflow', 'name', unique=True)) - self.commit() - self.assertTrue(self.schema['Workflow'].has_unique_values('name')) - self.assertTrue(self.index_exists('Workflow', 'name', unique=True)) - finally: - self.execute('DELETE CWConstraint C WHERE C eid %(eid)s', {'eid': eid}) - self.commit() - self.assertFalse(self.schema['Workflow'].has_unique_values('name')) - self.assertFalse(self.index_exists('Workflow', 'name', unique=True)) + with self.admin_access.repo_cnx() as cnx: + try: + eid = cnx.execute('INSERT CWConstraint X: X cstrtype CT, DEF constrained_by X ' + 'WHERE CT name "UniqueConstraint", DEF relation_type RT, ' + 'DEF from_entity E, RT name "name", ' + 'E name "Workflow"').rows[0][0] + self.assertFalse(self.schema['Workflow'].has_unique_values('name')) + self.assertFalse(self.index_exists(cnx, 'Workflow', 'name', unique=True)) + cnx.commit() + self.assertTrue(self.schema['Workflow'].has_unique_values('name')) + self.assertTrue(self.index_exists(cnx, 'Workflow', 'name', unique=True)) + finally: + cnx.execute('DELETE CWConstraint C WHERE C eid %(eid)s', {'eid': eid}) + cnx.commit() + self.assertFalse(self.schema['Workflow'].has_unique_values('name')) + self.assertFalse(self.index_exists(cnx, 'Workflow', 'name', unique=True)) def test_required_change_1(self): - self.execute('SET DEF cardinality "?1" ' - 'WHERE DEF relation_type RT, DEF from_entity E,' - 'RT name "title", E name "Bookmark"') - self.commit() - # should now be able to add bookmark without title - self.execute('INSERT Bookmark X: X path "/view"') - self.commit() + with self.admin_access.repo_cnx() as cnx: + cnx.execute('SET DEF cardinality "?1" ' + 'WHERE DEF relation_type RT, DEF from_entity E,' + 'RT name "title", E name "Bookmark"') + cnx.commit() + # should now be able to add bookmark without title + cnx.execute('INSERT Bookmark X: X path "/view"') + cnx.commit() def test_required_change_2(self): - self.execute('SET DEF cardinality "11" ' - 'WHERE DEF relation_type RT, DEF from_entity E,' - 'RT name "surname", E name "CWUser"') - self.commit() - # should not be able anymore to add cwuser without surname - req = self.request() - self.assertRaises(ValidationError, self.create_user, req, "toto") - self.rollback() - self.execute('SET DEF cardinality "?1" ' - 'WHERE DEF relation_type RT, DEF from_entity E,' - 'RT name "surname", E name "CWUser"') - self.commit() - + with self.admin_access.repo_cnx() as cnx: + cnx.execute('SET DEF cardinality "11" ' + 'WHERE DEF relation_type RT, DEF from_entity E,' + 'RT name "surname", E name "CWUser"') + cnx.commit() + # should not be able anymore to add cwuser without surname + self.assertRaises(ValidationError, self.create_user, cnx, "toto") + cnx.rollback() + cnx.execute('SET DEF cardinality "?1" ' + 'WHERE DEF relation_type RT, DEF from_entity E,' + 'RT name "surname", E name "CWUser"') + cnx.commit() def test_add_attribute_to_base_class(self): - attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, ' - 'X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F ' - 'WHERE RT name "messageid", E name "BaseTransition", F name "String"', - {'default': Binary.zpickle('noname')})[0][0] - assert self.execute('SET X read_permission Y WHERE X eid %(x)s, Y name "managers"', - {'x': attreid}) - self.commit() - self.schema.rebuild_infered_relations() - self.assertIn('Transition', self.schema['messageid'].subjects()) - self.assertIn('WorkflowTransition', self.schema['messageid'].subjects()) - self.execute('Any X WHERE X is_instance_of BaseTransition, X messageid "hop"') + with self.admin_access.repo_cnx() as cnx: + attreid = cnx.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, ' + 'X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F ' + 'WHERE RT name "messageid", E name "BaseTransition", F name "String"', + {'default': Binary.zpickle('noname')})[0][0] + assert cnx.execute('SET X read_permission Y WHERE X eid %(x)s, Y name "managers"', + {'x': attreid}) + cnx.commit() + self.schema.rebuild_infered_relations() + self.assertIn('Transition', self.schema['messageid'].subjects()) + self.assertIn('WorkflowTransition', self.schema['messageid'].subjects()) + cnx.execute('Any X WHERE X is_instance_of BaseTransition, X messageid "hop"') def test_change_fulltextindexed(self): - req = self.request() - target = req.create_entity(u'Email', messageid=u'1234', - subject=u'rick.roll@dance.com') - self.commit() - rset = req.execute('Any X WHERE X has_text "rick.roll"') - self.assertIn(target.eid, [item[0] for item in rset]) - assert req.execute('SET A fulltextindexed FALSE ' - 'WHERE E is CWEType, E name "Email", A is CWAttribute,' - 'A from_entity E, A relation_type R, R name "subject"') - self.commit() - rset = req.execute('Any X WHERE X has_text "rick.roll"') - self.assertFalse(rset) - assert req.execute('SET A fulltextindexed TRUE ' - 'WHERE A from_entity E, A relation_type R, ' - 'E name "Email", R name "subject"') - self.commit() - rset = req.execute('Any X WHERE X has_text "rick.roll"') - self.assertIn(target.eid, [item[0] for item in rset]) + with self.admin_access.repo_cnx() as cnx: + target = cnx.create_entity(u'Email', messageid=u'1234', + subject=u'rick.roll@dance.com') + cnx.commit() + rset = cnx.execute('Any X WHERE X has_text "rick.roll"') + self.assertIn(target.eid, [item[0] for item in rset]) + assert cnx.execute('SET A fulltextindexed FALSE ' + 'WHERE E is CWEType, E name "Email", A is CWAttribute,' + 'A from_entity E, A relation_type R, R name "subject"') + cnx.commit() + rset = cnx.execute('Any X WHERE X has_text "rick.roll"') + self.assertFalse(rset) + assert cnx.execute('SET A fulltextindexed TRUE ' + 'WHERE A from_entity E, A relation_type R, ' + 'E name "Email", R name "subject"') + cnx.commit() + rset = cnx.execute('Any X WHERE X has_text "rick.roll"') + self.assertIn(target.eid, [item[0] for item in rset]) def test_change_fulltext_container(self): - req = self.request() - target = req.create_entity(u'EmailAddress', address=u'rick.roll@dance.com') - target.cw_set(reverse_use_email=req.user) - self.commit() - rset = req.execute('Any X WHERE X has_text "rick.roll"') - self.assertIn(req.user.eid, [item[0] for item in rset]) - assert self.execute('SET R fulltext_container NULL ' - 'WHERE R name "use_email"') - self.commit() - rset = self.execute('Any X WHERE X has_text "rick.roll"') - self.assertIn(target.eid, [item[0] for item in rset]) - assert self.execute('SET R fulltext_container "subject" ' - 'WHERE R name "use_email"') - self.commit() - rset = req.execute('Any X WHERE X has_text "rick.roll"') - self.assertIn(req.user.eid, [item[0] for item in rset]) + with self.admin_access.repo_cnx() as cnx: + target = cnx.create_entity(u'EmailAddress', address=u'rick.roll@dance.com') + target.cw_set(reverse_use_email=cnx.user) + cnx.commit() + rset = cnx.execute('Any X WHERE X has_text "rick.roll"') + self.assertIn(cnx.user.eid, [item[0] for item in rset]) + assert cnx.execute('SET R fulltext_container NULL ' + 'WHERE R name "use_email"') + cnx.commit() + rset = cnx.execute('Any X WHERE X has_text "rick.roll"') + self.assertIn(target.eid, [item[0] for item in rset]) + assert cnx.execute('SET R fulltext_container "subject" ' + 'WHERE R name "use_email"') + cnx.commit() + rset = cnx.execute('Any X WHERE X has_text "rick.roll"') + self.assertIn(cnx.user.eid, [item[0] for item in rset]) def test_update_constraint(self): - rdef = self.schema['Transition'].rdef('type') - cstr = rdef.constraint_by_type('StaticVocabularyConstraint') - if not getattr(cstr, 'eid', None): - self.skipTest('start me alone') # bug in schema reloading, constraint's eid not restored - self.execute('SET X value %(v)s WHERE X eid %(x)s', - {'x': cstr.eid, 'v': u"u'normal', u'auto', u'new'"}) - self.execute('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X ' - 'WHERE CT name %(ct)s, EDEF eid %(x)s', - {'ct': 'SizeConstraint', 'value': u'max=10', 'x': rdef.eid}) - self.commit() - cstr = rdef.constraint_by_type('StaticVocabularyConstraint') - self.assertEqual(cstr.values, (u'normal', u'auto', u'new')) - self.execute('INSERT Transition T: T name "hop", T type "new"') + with self.admin_access.repo_cnx() as cnx: + rdef = self.schema['Transition'].rdef('type') + cstr = rdef.constraint_by_type('StaticVocabularyConstraint') + if not getattr(cstr, 'eid', None): + # bug in schema reloading, constraint's eid not restored + self.skipTest('start me alone') + cnx.execute('SET X value %(v)s WHERE X eid %(x)s', + {'x': cstr.eid, 'v': u"u'normal', u'auto', u'new'"}) + cnx.execute('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, ' + 'EDEF constrained_by X WHERE CT name %(ct)s, EDEF eid %(x)s', + {'ct': 'SizeConstraint', 'value': u'max=10', 'x': rdef.eid}) + cnx.commit() + cstr = rdef.constraint_by_type('StaticVocabularyConstraint') + self.assertEqual(cstr.values, (u'normal', u'auto', u'new')) + cnx.execute('INSERT Transition T: T name "hop", T type "new"') if __name__ == '__main__': unittest_main() diff -r 928732ec00dd -r fa44db7da2dc hooks/test/unittest_syncsession.py --- a/hooks/test/unittest_syncsession.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/test/unittest_syncsession.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -28,32 +28,46 @@ class CWPropertyHooksTC(CubicWebTC): def test_unexistant_cwproperty(self): - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop", X for_user U') - cm.exception.translate(unicode) - self.assertEqual(cm.exception.errors, {'pkey-subject': 'unknown property key bla.bla'}) - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop"') - cm.exception.translate(unicode) - self.assertEqual(cm.exception.errors, {'pkey-subject': 'unknown property key bla.bla'}) + with self.admin_access.web_request() as req: + with self.assertRaises(ValidationError) as cm: + req.execute('INSERT CWProperty X: X pkey "bla.bla", ' + 'X value "hop", X for_user U') + cm.exception.translate(unicode) + self.assertEqual(cm.exception.errors, + {'pkey-subject': 'unknown property key bla.bla'}) + + with self.assertRaises(ValidationError) as cm: + req.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop"') + cm.exception.translate(unicode) + self.assertEqual(cm.exception.errors, + {'pkey-subject': 'unknown property key bla.bla'}) def test_site_wide_cwproperty(self): - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWProperty X: X pkey "ui.site-title", X value "hop", X for_user U') - self.assertEqual(cm.exception.errors, {'for_user-subject': "site-wide property can't be set for user"}) + with self.admin_access.web_request() as req: + with self.assertRaises(ValidationError) as cm: + req.execute('INSERT CWProperty X: X pkey "ui.site-title", ' + 'X value "hop", X for_user U') + self.assertEqual(cm.exception.errors, + {'for_user-subject': "site-wide property can't be set for user"}) def test_system_cwproperty(self): - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWProperty X: X pkey "system.version.cubicweb", X value "hop", X for_user U') - self.assertEqual(cm.exception.errors, {'for_user-subject': "site-wide property can't be set for user"}) + with self.admin_access.web_request() as req: + with self.assertRaises(ValidationError) as cm: + req.execute('INSERT CWProperty X: X pkey "system.version.cubicweb", ' + 'X value "hop", X for_user U') + self.assertEqual(cm.exception.errors, + {'for_user-subject': "site-wide property can't be set for user"}) def test_bad_type_cwproperty(self): - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWProperty X: X pkey "ui.language", X value "hop", X for_user U') - self.assertEqual(cm.exception.errors, {'value-subject': u'unauthorized value'}) - with self.assertRaises(ValidationError) as cm: - self.execute('INSERT CWProperty X: X pkey "ui.language", X value "hop"') - self.assertEqual(cm.exception.errors, {'value-subject': u'unauthorized value'}) + with self.admin_access.web_request() as req: + with self.assertRaises(ValidationError) as cm: + req.execute('INSERT CWProperty X: X pkey "ui.language", ' + 'X value "hop", X for_user U') + self.assertEqual(cm.exception.errors, + {'value-subject': u'unauthorized value'}) + with self.assertRaises(ValidationError) as cm: + req.execute('INSERT CWProperty X: X pkey "ui.language", X value "hop"') + self.assertEqual(cm.exception.errors, {'value-subject': u'unauthorized value'}) if __name__ == '__main__': from logilab.common.testlib import unittest_main diff -r 928732ec00dd -r fa44db7da2dc hooks/zmq.py --- a/hooks/zmq.py Thu Jul 17 11:08:56 2014 +0200 +++ b/hooks/zmq.py Fri Jul 18 17:35:25 2014 +0200 @@ -71,6 +71,7 @@ address = config.get('zmq-repository-address') if not address: return + self.repo.warning('remote access to the repository via zmq/pickle is deprecated') from cubicweb.server import cwzmq self.repo.zmq_repo_server = server = cwzmq.ZMQRepositoryServer(self.repo) server.connect(address) diff -r 928732ec00dd -r fa44db7da2dc migration.py --- a/migration.py Thu Jul 17 11:08:56 2014 +0200 +++ b/migration.py Fri Jul 18 17:35:25 2014 +0200 @@ -414,7 +414,9 @@ toremove = (cube,) origcubes = self.config._cubes basecubes = [c for c in origcubes if not c in toremove] - self.config._cubes = tuple(self.config.expand_cubes(basecubes)) + # don't fake-add any new ones, or we won't be able to really-add them later + self.config._cubes = tuple(cube for cube in self.config.expand_cubes(basecubes) + if cube in origcubes) removed = [p for p in origcubes if not p in self.config._cubes] if not cube in removed and cube in origcubes: raise ConfigurationError("can't remove cube %s, " diff -r 928732ec00dd -r fa44db7da2dc rset.py --- a/rset.py Thu Jul 17 11:08:56 2014 +0200 +++ b/rset.py Fri Jul 18 17:35:25 2014 +0200 @@ -541,7 +541,8 @@ else: attr_cols[attr] = i else: - rdef = eschema.rdef(attr, role) + # XXX takefirst=True to remove warning triggered by ambiguous relations + rdef = eschema.rdef(attr, role, takefirst=True) # only keep value if it can't be multivalued if rdef.role_cardinality(role) in '1?': rel_cols[(attr, role)] = i diff -r 928732ec00dd -r fa44db7da2dc server/repository.py --- a/server/repository.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/repository.py Fri Jul 18 17:35:25 2014 +0200 @@ -880,7 +880,7 @@ """ mintime = time() - self.cleanup_session_time self.debug('cleaning session unused since %s', - strftime('%T', localtime(mintime))) + strftime('%H:%M:%S', localtime(mintime))) nbclosed = 0 for session in self._sessions.values(): if session.timestamp < mintime: diff -r 928732ec00dd -r fa44db7da2dc server/serverctl.py --- a/server/serverctl.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/serverctl.py Fri Jul 18 17:35:25 2014 +0200 @@ -677,6 +677,7 @@ def run(self, args): from logilab.common.daemon import daemonize, setugid from cubicweb.cwctl import init_cmdline_log_threshold + print 'WARNING: Standalone repository with pyro or zmq access is deprecated' appid = args[0] debug = self['debug'] if sys.platform == 'win32' and not debug: diff -r 928732ec00dd -r fa44db7da2dc server/sources/datafeed.py --- a/server/sources/datafeed.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/sources/datafeed.py Fri Jul 18 17:35:25 2014 +0200 @@ -126,18 +126,18 @@ self.parser_id = source_entity.parser self.load_mapping(source_entity._cw) - def _get_parser(self, session, **kwargs): + def _get_parser(self, cnx, **kwargs): return self.repo.vreg['parsers'].select( - self.parser_id, session, source=self, **kwargs) + self.parser_id, cnx, source=self, **kwargs) - def load_mapping(self, session): + def load_mapping(self, cnx): self.mapping = {} self.mapping_idx = {} try: - parser = self._get_parser(session) + parser = self._get_parser(cnx) except (RegistryNotFound, ObjectNotFound): return # no parser yet, don't go further - self._load_mapping(session, parser=parser) + self._load_mapping(cnx, parser=parser) def add_schema_config(self, schemacfg, checkonly=False, parser=None): """added CWSourceSchemaConfig, modify mapping accordingly""" @@ -159,7 +159,7 @@ def update_latest_retrieval(self, cnx): self.latest_retrieval = datetime.utcnow() cnx.execute('SET X latest_retrieval %(date)s WHERE X eid %(x)s', - {'x': self.eid, 'date': self.latest_retrieval}) + {'x': self.eid, 'date': self.latest_retrieval}) cnx.commit() def acquire_synchronization_lock(self, cnx): @@ -178,7 +178,7 @@ def release_synchronization_lock(self, cnx): cnx.execute('SET X in_synchronization NULL WHERE X eid %(x)s', - {'x': self.eid}) + {'x': self.eid}) cnx.commit() def pull_data(self, cnx, force=False, raise_on_error=False): @@ -238,7 +238,7 @@ error = True return error - def before_entity_insertion(self, session, lid, etype, eid, sourceparams): + def before_entity_insertion(self, cnx, lid, etype, eid, sourceparams): """called by the repository when an eid has been attributed for an entity stored here but the entity has not been inserted in the system table yet. @@ -247,40 +247,40 @@ entity. """ entity = super(DataFeedSource, self).before_entity_insertion( - session, lid, etype, eid, sourceparams) + cnx, lid, etype, eid, sourceparams) entity.cw_edited['cwuri'] = lid.decode('utf-8') entity.cw_edited.set_defaults() sourceparams['parser'].before_entity_copy(entity, sourceparams) return entity - def after_entity_insertion(self, session, lid, entity, sourceparams): + def after_entity_insertion(self, cnx, lid, entity, sourceparams): """called by the repository after an entity stored here has been inserted in the system table. """ - relations = preprocess_inlined_relations(session, entity) - if session.is_hook_category_activated('integrity'): + relations = preprocess_inlined_relations(cnx, entity) + if cnx.is_hook_category_activated('integrity'): entity.cw_edited.check(creation=True) - self.repo.system_source.add_entity(session, entity) + self.repo.system_source.add_entity(cnx, entity) entity.cw_edited.saved = entity._cw_is_saved = True sourceparams['parser'].after_entity_copy(entity, sourceparams) # call hooks for inlined relations call_hooks = self.repo.hm.call_hooks if self.should_call_hooks: for attr, value in relations: - call_hooks('before_add_relation', session, + call_hooks('before_add_relation', cnx, eidfrom=entity.eid, rtype=attr, eidto=value) - call_hooks('after_add_relation', session, + call_hooks('after_add_relation', cnx, eidfrom=entity.eid, rtype=attr, eidto=value) - def source_cwuris(self, session): + def source_cwuris(self, cnx): sql = ('SELECT extid, eid, type FROM entities, cw_source_relation ' 'WHERE entities.eid=cw_source_relation.eid_from ' 'AND cw_source_relation.eid_to=%s' % self.eid) return dict((b64decode(uri), (eid, type)) - for uri, eid, type in session.system_sql(sql).fetchall()) + for uri, eid, type in cnx.system_sql(sql).fetchall()) - def init_import_log(self, session, **kwargs): - dataimport = session.create_entity('CWDataImport', cw_import_of=self, + def init_import_log(self, cnx, **kwargs): + dataimport = cnx.create_entity('CWDataImport', cw_import_of=self, start_timestamp=datetime.utcnow(), **kwargs) dataimport.init() @@ -290,8 +290,8 @@ class DataFeedParser(AppObject): __registry__ = 'parsers' - def __init__(self, session, source, sourceuris=None, import_log=None, **kwargs): - super(DataFeedParser, self).__init__(session, **kwargs) + def __init__(self, cnx, source, sourceuris=None, import_log=None, **kwargs): + super(DataFeedParser, self).__init__(cnx, **kwargs) self.source = source self.sourceuris = sourceuris self.import_log = import_log @@ -345,20 +345,20 @@ """return an entity for the given uri. May return None if it should be skipped """ - session = self._cw + cnx = self._cw # if cwsource is specified and repository has a source with the same # name, call extid2eid on that source so entity will be properly seen as # coming from this source source_uri = sourceparams.pop('cwsource', None) if source_uri is not None and source_uri != 'system': - source = session.repo.sources_by_uri.get(source_uri, self.source) + source = cnx.repo.sources_by_uri.get(source_uri, self.source) else: source = self.source sourceparams['parser'] = self if isinstance(uri, unicode): uri = uri.encode('utf-8') try: - eid = session.repo.extid2eid(source, str(uri), etype, session, + eid = cnx.repo.extid2eid(source, str(uri), etype, cnx, sourceparams=sourceparams) except ValidationError as ex: # XXX use critical so they are seen during tests. Should consider @@ -373,14 +373,14 @@ # Don't give etype to entity_from_eid so we get UnknownEid if the # entity has been removed try: - entity = session.entity_from_eid(-eid) + entity = cnx.entity_from_eid(-eid) except UnknownEid: return None self.notify_updated(entity) # avoid later update from the source's data return entity if self.sourceuris is not None: self.sourceuris.pop(str(uri), None) - return session.entity_from_eid(eid, etype) + return cnx.entity_from_eid(eid, etype) def process(self, url, raise_on_error=False): """main callback: process the url""" @@ -411,7 +411,7 @@ """ return True - def handle_deletion(self, config, session, myuris): + def handle_deletion(self, config, cnx, myuris): if config['delete-entities'] and myuris: byetype = {} for extid, (eid, etype) in myuris.iteritems(): @@ -419,10 +419,9 @@ byetype.setdefault(etype, []).append(str(eid)) for etype, eids in byetype.iteritems(): self.warning('delete %s %s entities', len(eids), etype) - session.set_cnxset() - session.execute('DELETE %s X WHERE X eid IN (%s)' - % (etype, ','.join(eids))) - session.commit() + cnx.execute('DELETE %s X WHERE X eid IN (%s)' + % (etype, ','.join(eids))) + cnx.commit() def update_if_necessary(self, entity, attrs): entity.complete(tuple(attrs)) @@ -450,13 +449,8 @@ self.import_log.record_error(str(ex)) return True error = False - # Check whether self._cw is a session or a connection - if getattr(self._cw, 'commit', None) is not None: - commit = self._cw.commit - rollback = self._cw.rollback - else: - commit = self._cw.cnx.commit - rollback = self._cw.cnx.rollback + commit = self._cw.commit + rollback = self._cw.rollback for args in parsed: try: self.process_item(*args) diff -r 928732ec00dd -r fa44db7da2dc server/test/data/schema.py --- a/server/test/data/schema.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/test/data/schema.py Fri Jul 18 17:35:25 2014 +0200 @@ -202,7 +202,6 @@ name = 'ecrit_par' subject = 'Note' object ='Personne' - constraints = [RQLConstraint('E concerns P, S version_of P')] cardinality = '?*' class ecrit_par_2(RelationDefinition): diff -r 928732ec00dd -r fa44db7da2dc server/test/unittest_datafeed.py --- a/server/test/unittest_datafeed.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/test/unittest_datafeed.py Fri Jul 18 17:35:25 2014 +0200 @@ -104,11 +104,11 @@ self.assertEqual(self.repo._extid_cache['http://www.cubicweb.org/'], entity.eid) - self.assertEqual(dfsource.source_cwuris(self.session), - {'http://www.cubicweb.org/': (entity.eid, 'Card')} - ) - self.assertTrue(dfsource.latest_retrieval) - self.assertTrue(dfsource.fresh()) + self.assertEqual(dfsource.source_cwuris(cnx), + {'http://www.cubicweb.org/': (entity.eid, 'Card')} + ) + self.assertTrue(dfsource.latest_retrieval) + self.assertTrue(dfsource.fresh()) # test_rename_source with self.admin_access.repo_cnx() as cnx: diff -r 928732ec00dd -r fa44db7da2dc server/test/unittest_querier.py --- a/server/test/unittest_querier.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/test/unittest_querier.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -110,167 +110,193 @@ pass def test_preprocess_1(self): - reid = self.execute('Any X WHERE X is CWRType, X name "owned_by"')[0][0] - rqlst = self._prepare('Any COUNT(RDEF) WHERE RDEF relation_type X, X eid %(x)s', {'x': reid}) - self.assertEqual(rqlst.solutions, [{'RDEF': 'CWAttribute'}, {'RDEF': 'CWRelation'}]) + with self.session.new_cnx() as cnx: + reid = cnx.execute('Any X WHERE X is CWRType, X name "owned_by"')[0][0] + rqlst = self._prepare(cnx, 'Any COUNT(RDEF) WHERE RDEF relation_type X, X eid %(x)s', + {'x': reid}) + self.assertEqual([{'RDEF': 'CWAttribute'}, {'RDEF': 'CWRelation'}], + rqlst.solutions) def test_preprocess_2(self): - teid = self.execute("INSERT Tag X: X name 'tag'")[0][0] - #geid = self.execute("CWGroup G WHERE G name 'users'")[0][0] - #self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s", - # {'g': geid, 't': teid}, 'g') - rqlst = self._prepare('Any X WHERE E eid %(x)s, E tags X', {'x': teid}) - # the query may be optimized, should keep only one solution - # (any one, etype will be discarded) - self.assertEqual(len(rqlst.solutions), 1) + with self.session.new_cnx() as cnx: + teid = cnx.execute("INSERT Tag X: X name 'tag'")[0][0] + #geid = self.execute("CWGroup G WHERE G name 'users'")[0][0] + #self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s", + # {'g': geid, 't': teid}, 'g') + rqlst = self._prepare(cnx, 'Any X WHERE E eid %(x)s, E tags X', {'x': teid}) + # the query may be optimized, should keep only one solution + # (any one, etype will be discarded) + self.assertEqual(1, len(rqlst.solutions)) + + def assertRQLEqual(self, expected, got): + from rql import parse + self.assertMultiLineEqual(unicode(parse(expected)), + unicode(parse(got))) def test_preprocess_security(self): - plan = self._prepare_plan('Any ETN,COUNT(X) GROUPBY ETN ' - 'WHERE X is ET, ET name ETN') - plan.cnx = self.user_groups_session('users') - union = plan.rqlst - plan.preprocess(union) - self.assertEqual(len(union.children), 1) - self.assertEqual(len(union.children[0].with_), 1) - subq = union.children[0].with_[0].query - self.assertEqual(len(subq.children), 4) - self.assertEqual([t.as_string() for t in union.children[0].selection], - ['ETN','COUNT(X)']) - self.assertEqual([t.as_string() for t in union.children[0].groupby], - ['ETN']) - partrqls = sorted(((rqlst.as_string(), rqlst.solutions) for rqlst in subq.children)) - rql, solutions = partrqls[0] - self.assertEqual(rql, - 'Any ETN,X WHERE X is ET, ET name ETN, (EXISTS(X owned_by %(B)s))' - ' OR ((((EXISTS(D concerne C?, C owned_by %(B)s, X identity D, C is Division, D is Affaire))' - ' OR (EXISTS(H concerne G?, G owned_by %(B)s, G is SubDivision, X identity H, H is Affaire)))' - ' OR (EXISTS(I concerne F?, F owned_by %(B)s, F is Societe, X identity I, I is Affaire)))' - ' OR (EXISTS(J concerne E?, E owned_by %(B)s, E is Note, X identity J, J is Affaire)))' - ', ET is CWEType, X is Affaire') - self.assertEqual(solutions, [{'C': 'Division', - 'D': 'Affaire', - 'E': 'Note', - 'F': 'Societe', - 'G': 'SubDivision', - 'H': 'Affaire', - 'I': 'Affaire', - 'J': 'Affaire', - 'X': 'Affaire', - 'ET': 'CWEType', 'ETN': 'String'}]) - rql, solutions = partrqls[1] - self.assertEqual(rql, 'Any ETN,X WHERE X is ET, ET name ETN, ET is CWEType, X is IN(BaseTransition, Bookmark, CWAttribute, CWCache, CWConstraint, CWConstraintType, CWEType, CWGroup, CWPermission, CWProperty, CWRType, CWRelation, CWSource, CWUniqueTogetherConstraint, CWUser, Card, Comment, Division, Email, EmailPart, EmailThread, ExternalUri, File, Folder, Note, Old, Personne, RQLExpression, Societe, State, SubDivision, SubWorkflowExitPoint, Tag, TrInfo, Transition, Workflow, WorkflowTransition)') - self.assertListEqual(sorted(solutions), - sorted([{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Bookmark', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Card', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Comment', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Division', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWCache', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWConstraint', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWConstraintType', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWEType', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWAttribute', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWGroup', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWRelation', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWPermission', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWProperty', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWRType', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWSource', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWUniqueTogetherConstraint', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'CWUser', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Email', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'EmailPart', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'EmailThread', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'RQLExpression', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Societe', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'State', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'SubDivision', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'SubWorkflowExitPoint', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Tag', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Transition', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'TrInfo', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'Workflow', 'ETN': 'String', 'ET': 'CWEType'}, - {'X': 'WorkflowTransition', 'ETN': 'String', 'ET': 'CWEType'}])) - rql, solutions = partrqls[2] - self.assertEqual(rql, - 'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(%(D)s use_email X), ' - 'ET is CWEType, X is EmailAddress') - self.assertEqual(solutions, [{'X': 'EmailAddress', 'ET': 'CWEType', 'ETN': 'String'}]) - rql, solutions = partrqls[3] - self.assertEqual(rql, - 'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(X owned_by %(C)s), ' - 'ET is CWEType, X is Basket') - self.assertEqual(solutions, [{'X': 'Basket', 'ET': 'CWEType', 'ETN': 'String'}]) + s = self.user_groups_session('users') + with s.new_cnx() as cnx: + plan = self._prepare_plan(cnx, 'Any ETN,COUNT(X) GROUPBY ETN ' + 'WHERE X is ET, ET name ETN') + union = plan.rqlst + plan.preprocess(union) + self.assertEqual(len(union.children), 1) + self.assertEqual(len(union.children[0].with_), 1) + subq = union.children[0].with_[0].query + self.assertEqual(len(subq.children), 4) + self.assertEqual([t.as_string() for t in union.children[0].selection], + ['ETN','COUNT(X)']) + self.assertEqual([t.as_string() for t in union.children[0].groupby], + ['ETN']) + partrqls = sorted(((rqlst.as_string(), rqlst.solutions) for rqlst in subq.children)) + rql, solutions = partrqls[0] + self.assertRQLEqual(rql, + 'Any ETN,X WHERE X is ET, ET name ETN, (EXISTS(X owned_by %(B)s))' + ' OR ((((EXISTS(D concerne C?, C owned_by %(B)s, ' + ' X identity D, C is Division, D is Affaire))' + ' OR (EXISTS(H concerne G?, G owned_by %(B)s, G is SubDivision, ' + ' X identity H, H is Affaire)))' + ' OR (EXISTS(I concerne F?, F owned_by %(B)s, F is Societe, ' + ' X identity I, I is Affaire)))' + ' OR (EXISTS(J concerne E?, E owned_by %(B)s, E is Note, ' + ' X identity J, J is Affaire)))' + ', ET is CWEType, X is Affaire') + self.assertEqual(solutions, [{'C': 'Division', + 'D': 'Affaire', + 'E': 'Note', + 'F': 'Societe', + 'G': 'SubDivision', + 'H': 'Affaire', + 'I': 'Affaire', + 'J': 'Affaire', + 'X': 'Affaire', + 'ET': 'CWEType', 'ETN': 'String'}]) + rql, solutions = partrqls[1] + self.assertRQLEqual(rql, 'Any ETN,X WHERE X is ET, ET name ETN, ET is CWEType, ' + 'X is IN(BaseTransition, Bookmark, CWAttribute, CWCache, CWConstraint, ' + ' CWConstraintType, CWEType, CWGroup, CWPermission, CWProperty, CWRType, ' + ' CWRelation, CWSource, CWUniqueTogetherConstraint, CWUser, Card, Comment, ' + ' Division, Email, EmailPart, EmailThread, ExternalUri, File, Folder, Note, ' + ' Old, Personne, RQLExpression, Societe, State, SubDivision, ' + ' SubWorkflowExitPoint, Tag, TrInfo, Transition, Workflow, WorkflowTransition)') + self.assertListEqual(sorted(solutions), + sorted([{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Bookmark', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Card', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Comment', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Division', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWCache', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWConstraint', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWConstraintType', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWEType', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWAttribute', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWGroup', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWRelation', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWPermission', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWProperty', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWRType', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWSource', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWUniqueTogetherConstraint', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'CWUser', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Email', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'EmailPart', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'EmailThread', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'RQLExpression', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Societe', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'State', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'SubDivision', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'SubWorkflowExitPoint', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Tag', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Transition', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'TrInfo', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'Workflow', 'ETN': 'String', 'ET': 'CWEType'}, + {'X': 'WorkflowTransition', 'ETN': 'String', 'ET': 'CWEType'}])) + rql, solutions = partrqls[2] + self.assertEqual(rql, + 'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(%(D)s use_email X), ' + 'ET is CWEType, X is EmailAddress') + self.assertEqual(solutions, [{'X': 'EmailAddress', 'ET': 'CWEType', 'ETN': 'String'}]) + rql, solutions = partrqls[3] + self.assertEqual(rql, + 'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(X owned_by %(C)s), ' + 'ET is CWEType, X is Basket') + self.assertEqual(solutions, [{'X': 'Basket', 'ET': 'CWEType', 'ETN': 'String'}]) def test_preprocess_security_aggregat(self): - plan = self._prepare_plan('Any MAX(X)') - plan.cnx = self.user_groups_session('users') - union = plan.rqlst - plan.preprocess(union) - self.assertEqual(len(union.children), 1) - self.assertEqual(len(union.children[0].with_), 1) - subq = union.children[0].with_[0].query - self.assertEqual(len(subq.children), 4) - self.assertEqual([t.as_string() for t in union.children[0].selection], - ['MAX(X)']) + s = self.user_groups_session('users') + with s.new_cnx() as cnx: + plan = self._prepare_plan(cnx, 'Any MAX(X)') + union = plan.rqlst + plan.preprocess(union) + self.assertEqual(len(union.children), 1) + self.assertEqual(len(union.children[0].with_), 1) + subq = union.children[0].with_[0].query + self.assertEqual(len(subq.children), 4) + self.assertEqual([t.as_string() for t in union.children[0].selection], + ['MAX(X)']) def test_preprocess_nonregr(self): - rqlst = self._prepare('Any S ORDERBY SI WHERE NOT S ecrit_par O, S para SI') - self.assertEqual(len(rqlst.solutions), 1) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any S ORDERBY SI WHERE NOT S ecrit_par O, S para SI') + self.assertEqual(len(rqlst.solutions), 1) def test_build_description(self): # should return an empty result set - rset = self.execute('Any X WHERE X eid %(x)s', {'x': self.session.user.eid}) + rset = self.qexecute('Any X WHERE X eid %(x)s', {'x': self.session.user.eid}) self.assertEqual(rset.description[0][0], 'CWUser') - rset = self.execute('Any 1') + rset = self.qexecute('Any 1') self.assertEqual(rset.description[0][0], 'Int') - rset = self.execute('Any TRUE') + rset = self.qexecute('Any TRUE') self.assertEqual(rset.description[0][0], 'Boolean') - rset = self.execute('Any "hop"') + rset = self.qexecute('Any "hop"') self.assertEqual(rset.description[0][0], 'String') - rset = self.execute('Any TODAY') + rset = self.qexecute('Any TODAY') self.assertEqual(rset.description[0][0], 'Date') - rset = self.execute('Any NOW') + rset = self.qexecute('Any NOW') self.assertEqual(rset.description[0][0], 'Datetime') - rset = self.execute('Any %(x)s', {'x': 1}) + rset = self.qexecute('Any %(x)s', {'x': 1}) self.assertEqual(rset.description[0][0], 'Int') - rset = self.execute('Any %(x)s', {'x': 1L}) + rset = self.qexecute('Any %(x)s', {'x': 1L}) self.assertEqual(rset.description[0][0], 'Int') - rset = self.execute('Any %(x)s', {'x': True}) + rset = self.qexecute('Any %(x)s', {'x': True}) self.assertEqual(rset.description[0][0], 'Boolean') - rset = self.execute('Any %(x)s', {'x': 1.0}) + rset = self.qexecute('Any %(x)s', {'x': 1.0}) self.assertEqual(rset.description[0][0], 'Float') - rset = self.execute('Any %(x)s', {'x': datetime.now()}) + rset = self.qexecute('Any %(x)s', {'x': datetime.now()}) self.assertEqual(rset.description[0][0], 'Datetime') - rset = self.execute('Any %(x)s', {'x': 'str'}) + rset = self.qexecute('Any %(x)s', {'x': 'str'}) self.assertEqual(rset.description[0][0], 'String') - rset = self.execute('Any %(x)s', {'x': u'str'}) + rset = self.qexecute('Any %(x)s', {'x': u'str'}) self.assertEqual(rset.description[0][0], 'String') def test_build_descr1(self): - rset = self.execute('(Any U,L WHERE U login L) UNION (Any G,N WHERE G name N, G is CWGroup)') - rset.req = self.session - orig_length = len(rset) - rset.rows[0][0] = 9999999 - description = manual_build_descr(rset.req, rset.syntax_tree(), None, rset.rows) - self.assertEqual(len(description), orig_length - 1) - self.assertEqual(len(rset.rows), orig_length - 1) - self.assertNotEqual(rset.rows[0][0], 9999999) + with self.session.new_cnx() as cnx: + rset = cnx.execute('(Any U,L WHERE U login L) UNION ' + '(Any G,N WHERE G name N, G is CWGroup)') + # rset.req = self.session + orig_length = len(rset) + rset.rows[0][0] = 9999999 + description = manual_build_descr(cnx, rset.syntax_tree(), None, rset.rows) + self.assertEqual(len(description), orig_length - 1) + self.assertEqual(len(rset.rows), orig_length - 1) + self.assertNotEqual(rset.rows[0][0], 9999999) def test_build_descr2(self): - rset = self.execute('Any X,Y WITH X,Y BEING ((Any G,NULL WHERE G is CWGroup) UNION (Any U,G WHERE U in_group G))') + rset = self.qexecute('Any X,Y WITH X,Y BEING ((Any G,NULL WHERE G is CWGroup) UNION ' + '(Any U,G WHERE U in_group G))') for x, y in rset.description: if y is not None: self.assertEqual(y, 'CWGroup') def test_build_descr3(self): - rset = self.execute('(Any G,NULL WHERE G is CWGroup) UNION (Any U,G WHERE U in_group G)') + rset = self.qexecute('(Any G,NULL WHERE G is CWGroup) UNION ' + '(Any U,G WHERE U in_group G)') for x, y in rset.description: if y is not None: self.assertEqual(y, 'CWGroup') @@ -281,284 +307,298 @@ tearDownClass = classmethod(tearDownClass) def test_encoding_pb(self): - self.assertRaises(RQLSyntaxError, self.execute, + self.assertRaises(RQLSyntaxError, self.qexecute, 'Any X WHERE X is CWRType, X name "öwned_by"') def test_unknown_eid(self): # should return an empty result set - self.assertFalse(self.execute('Any X WHERE X eid 99999999')) + self.assertFalse(self.qexecute('Any X WHERE X eid 99999999')) def test_typed_eid(self): # should return an empty result set - rset = self.execute('Any X WHERE X eid %(x)s', {'x': '1'}) + rset = self.qexecute('Any X WHERE X eid %(x)s', {'x': '1'}) self.assertIsInstance(rset[0][0], (int, long)) def test_bytes_storage(self): - feid = self.execute('INSERT File X: X data_name "foo.pdf", X data_format "text/plain", X data %(data)s', + feid = self.qexecute('INSERT File X: X data_name "foo.pdf", ' + 'X data_format "text/plain", X data %(data)s', {'data': Binary("xxx")})[0][0] - fdata = self.execute('Any D WHERE X data D, X eid %(x)s', {'x': feid})[0][0] + fdata = self.qexecute('Any D WHERE X data D, X eid %(x)s', {'x': feid})[0][0] self.assertIsInstance(fdata, Binary) self.assertEqual(fdata.getvalue(), 'xxx') # selection queries tests ################################################# def test_select_1(self): - rset = self.execute('Any X ORDERBY X WHERE X is CWGroup') + rset = self.qexecute('Any X ORDERBY X WHERE X is CWGroup') result, descr = rset.rows, rset.description self.assertEqual(tuplify(result), [(2,), (3,), (4,), (5,)]) self.assertEqual(descr, [('CWGroup',), ('CWGroup',), ('CWGroup',), ('CWGroup',)]) def test_select_2(self): - rset = self.execute('Any X ORDERBY N WHERE X is CWGroup, X name N') + rset = self.qexecute('Any X ORDERBY N WHERE X is CWGroup, X name N') self.assertEqual(tuplify(rset.rows), [(2,), (3,), (4,), (5,)]) self.assertEqual(rset.description, [('CWGroup',), ('CWGroup',), ('CWGroup',), ('CWGroup',)]) - rset = self.execute('Any X ORDERBY N DESC WHERE X is CWGroup, X name N') + rset = self.qexecute('Any X ORDERBY N DESC WHERE X is CWGroup, X name N') self.assertEqual(tuplify(rset.rows), [(5,), (4,), (3,), (2,)]) def test_select_3(self): - rset = self.execute('Any N GROUPBY N WHERE X is CWGroup, X name N') + rset = self.qexecute('Any N GROUPBY N WHERE X is CWGroup, X name N') result, descr = rset.rows, rset.description result.sort() self.assertEqual(tuplify(result), [('guests',), ('managers',), ('owners',), ('users',)]) self.assertEqual(descr, [('String',), ('String',), ('String',), ('String',)]) def test_select_is(self): - rset = self.execute('Any X, TN ORDERBY TN LIMIT 10 WHERE X is T, T name TN') + rset = self.qexecute('Any X, TN ORDERBY TN LIMIT 10 WHERE X is T, T name TN') result, descr = rset.rows, rset.description self.assertEqual(result[0][1], descr[0][0]) def test_select_is_aggr(self): - rset = self.execute('Any TN, COUNT(X) GROUPBY TN ORDERBY 2 DESC WHERE X is T, T name TN') + rset = self.qexecute('Any TN, COUNT(X) GROUPBY TN ORDERBY 2 DESC WHERE X is T, T name TN') result, descr = rset.rows, rset.description self.assertEqual(descr[0][0], 'String') self.assertEqual(descr[0][1], 'Int') self.assertEqual(result[0][0], 'CWRelation') # XXX may change as schema evolve def test_select_groupby_orderby(self): - rset = self.execute('Any N GROUPBY N ORDERBY N WHERE X is CWGroup, X name N') + rset = self.qexecute('Any N GROUPBY N ORDERBY N WHERE X is CWGroup, X name N') self.assertEqual(tuplify(rset.rows), [('guests',), ('managers',), ('owners',), ('users',)]) self.assertEqual(rset.description, [('String',), ('String',), ('String',), ('String',)]) def test_select_complex_groupby(self): - rset = self.execute('Any N GROUPBY N WHERE X name N') - rset = self.execute('Any N,MAX(D) GROUPBY N LIMIT 5 WHERE X name N, X creation_date D') + rset = self.qexecute('Any N GROUPBY N WHERE X name N') + rset = self.qexecute('Any N,MAX(D) GROUPBY N LIMIT 5 WHERE X name N, X creation_date D') def test_select_inlined_groupby(self): - seid = self.execute('State X WHERE X name "deactivated"')[0][0] - rset = self.execute('Any U,L,S GROUPBY U,L,S WHERE X in_state S, U login L, S eid %s' % seid) + seid = self.qexecute('State X WHERE X name "deactivated"')[0][0] + rset = self.qexecute('Any U,L,S GROUPBY U,L,S WHERE X in_state S, U login L, S eid %s' % seid) def test_select_groupby_funccall(self): - rset = self.execute('Any YEAR(CD), COUNT(X) GROUPBY YEAR(CD) WHERE X is CWUser, X creation_date CD') + rset = self.qexecute('Any YEAR(CD), COUNT(X) GROUPBY YEAR(CD) ' + 'WHERE X is CWUser, X creation_date CD') self.assertListEqual(rset.rows, [[date.today().year, 2]]) def test_select_groupby_colnumber(self): - rset = self.execute('Any YEAR(CD), COUNT(X) GROUPBY 1 WHERE X is CWUser, X creation_date CD') + rset = self.qexecute('Any YEAR(CD), COUNT(X) GROUPBY 1 ' + 'WHERE X is CWUser, X creation_date CD') self.assertListEqual(rset.rows, [[date.today().year, 2]]) def test_select_complex_orderby(self): - rset1 = self.execute('Any N ORDERBY N WHERE X name N') + rset1 = self.qexecute('Any N ORDERBY N WHERE X name N') self.assertEqual(sorted(rset1.rows), rset1.rows) - rset = self.execute('Any N ORDERBY N LIMIT 5 OFFSET 1 WHERE X name N') + rset = self.qexecute('Any N ORDERBY N LIMIT 5 OFFSET 1 WHERE X name N') self.assertEqual(rset.rows[0][0], rset1.rows[1][0]) self.assertEqual(len(rset), 5) def test_select_5(self): - rset = self.execute('Any X, TMP ORDERBY TMP WHERE X name TMP, X is CWGroup') - self.assertEqual(tuplify(rset.rows), [(2, 'guests',), (3, 'managers',), (4, 'owners',), (5, 'users',)]) - self.assertEqual(rset.description, [('CWGroup', 'String',), ('CWGroup', 'String',), ('CWGroup', 'String',), ('CWGroup', 'String',)]) + rset = self.qexecute('Any X, TMP ORDERBY TMP WHERE X name TMP, X is CWGroup') + self.assertEqual(tuplify(rset.rows), + [(2, 'guests',), + (3, 'managers',), + (4, 'owners',), + (5, 'users',)]) + self.assertEqual(rset.description, + [('CWGroup', 'String',), + ('CWGroup', 'String',), + ('CWGroup', 'String',), + ('CWGroup', 'String',)]) def test_select_6(self): - self.execute("INSERT Personne X: X nom 'bidule'")[0] - rset = self.execute('Any Y where X name TMP, Y nom in (TMP, "bidule")') + self.qexecute("INSERT Personne X: X nom 'bidule'")[0] + rset = self.qexecute('Any Y where X name TMP, Y nom in (TMP, "bidule")') #self.assertEqual(rset.description, [('Personne',), ('Personne',)]) self.assertIn(('Personne',), rset.description) - rset = self.execute('DISTINCT Any Y where X name TMP, Y nom in (TMP, "bidule")') + rset = self.qexecute('DISTINCT Any Y where X name TMP, Y nom in (TMP, "bidule")') self.assertIn(('Personne',), rset.description) def test_select_not_attr(self): - peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - seid = self.execute("INSERT Societe X: X nom 'chouette'")[0][0] - rset = self.execute('Personne X WHERE NOT X nom "bidule"') + peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + seid = self.qexecute("INSERT Societe X: X nom 'chouette'")[0][0] + rset = self.qexecute('Personne X WHERE NOT X nom "bidule"') self.assertEqual(len(rset.rows), 0, rset.rows) - rset = self.execute('Personne X WHERE NOT X nom "bid"') + rset = self.qexecute('Personne X WHERE NOT X nom "bid"') self.assertEqual(len(rset.rows), 1, rset.rows) - self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'") - rset = self.execute('Personne X WHERE NOT X travaille S') + self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'") + rset = self.qexecute('Personne X WHERE NOT X travaille S') self.assertEqual(len(rset.rows), 0, rset.rows) def test_select_is_in(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Societe X: X nom 'chouette'") - self.assertEqual(len(self.execute("Any X WHERE X is IN (Personne, Societe)")), + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Societe X: X nom 'chouette'") + self.assertEqual(len(self.qexecute("Any X WHERE X is IN (Personne, Societe)")), 2) def test_select_not_rel(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Societe X: X nom 'chouette'") - self.execute("INSERT Personne X: X nom 'autre'") - self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'") - rset = self.execute('Personne X WHERE NOT X travaille S') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Societe X: X nom 'chouette'") + self.qexecute("INSERT Personne X: X nom 'autre'") + self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'") + rset = self.qexecute('Personne X WHERE NOT X travaille S') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('Personne X WHERE NOT X travaille S, S nom "chouette"') + rset = self.qexecute('Personne X WHERE NOT X travaille S, S nom "chouette"') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_nonregr_inlined(self): - self.execute("INSERT Note X: X para 'bidule'") - self.execute("INSERT Personne X: X nom 'chouette'") - self.execute("INSERT Personne X: X nom 'autre'") - self.execute("SET X ecrit_par P WHERE X para 'bidule', P nom 'chouette'") - rset = self.execute('Any U,T ORDERBY T DESC WHERE U is CWUser, ' - 'N ecrit_par U, N type T')#, {'x': self.ueid}) + self.qexecute("INSERT Note X: X para 'bidule'") + self.qexecute("INSERT Personne X: X nom 'chouette'") + self.qexecute("INSERT Personne X: X nom 'autre'") + self.qexecute("SET X ecrit_par P WHERE X para 'bidule', P nom 'chouette'") + rset = self.qexecute('Any U,T ORDERBY T DESC WHERE U is CWUser, ' + 'N ecrit_par U, N type T')#, {'x': self.ueid}) self.assertEqual(len(rset.rows), 0) def test_select_nonregr_edition_not(self): groupeids = set((2, 3, 4)) - groupreadperms = set(r[0] for r in self.execute('Any Y WHERE X name "CWGroup", Y eid IN(2, 3, 4), X read_permission Y')) - rset = self.execute('DISTINCT Any Y WHERE X is CWEType, X name "CWGroup", Y eid IN(2, 3, 4), NOT X read_permission Y') + groupreadperms = set(r[0] for r in self.qexecute('Any Y WHERE X name "CWGroup", ' + 'Y eid IN(2, 3, 4), X read_permission Y')) + rset = self.qexecute('DISTINCT Any Y WHERE X is CWEType, X name "CWGroup", ' + 'Y eid IN(2, 3, 4), NOT X read_permission Y') self.assertEqual(sorted(r[0] for r in rset.rows), sorted(groupeids - groupreadperms)) - rset = self.execute('DISTINCT Any Y WHERE X name "CWGroup", Y eid IN(2, 3, 4), NOT X read_permission Y') + rset = self.qexecute('DISTINCT Any Y WHERE X name "CWGroup", ' + 'Y eid IN(2, 3, 4), NOT X read_permission Y') self.assertEqual(sorted(r[0] for r in rset.rows), sorted(groupeids - groupreadperms)) def test_select_outer_join(self): - peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - peid2 = self.execute("INSERT Personne X: X nom 'autre'")[0][0] - seid1 = self.execute("INSERT Societe X: X nom 'chouette'")[0][0] - seid2 = self.execute("INSERT Societe X: X nom 'chouetos'")[0][0] - rset = self.execute('Any X,S ORDERBY X WHERE X travaille S?') + peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + peid2 = self.qexecute("INSERT Personne X: X nom 'autre'")[0][0] + seid1 = self.qexecute("INSERT Societe X: X nom 'chouette'")[0][0] + seid2 = self.qexecute("INSERT Societe X: X nom 'chouetos'")[0][0] + rset = self.qexecute('Any X,S ORDERBY X WHERE X travaille S?') self.assertEqual(rset.rows, [[peid1, None], [peid2, None]]) - self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'") - rset = self.execute('Any X,S ORDERBY X WHERE X travaille S?') + self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'chouette'") + rset = self.qexecute('Any X,S ORDERBY X WHERE X travaille S?') self.assertEqual(rset.rows, [[peid1, seid1], [peid2, None]]) - rset = self.execute('Any S,X ORDERBY S WHERE X? travaille S') + rset = self.qexecute('Any S,X ORDERBY S WHERE X? travaille S') self.assertEqual(rset.rows, [[seid1, peid1], [seid2, None]]) def test_select_outer_join_optimized(self): - peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - rset = self.execute('Any X WHERE X eid %(x)s, P? connait X', {'x':peid1}) + peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + rset = self.qexecute('Any X WHERE X eid %(x)s, P? connait X', {'x':peid1}) self.assertEqual(rset.rows, [[peid1]]) - rset = self.execute('Any X WHERE X eid %(x)s, X require_permission P?', + rset = self.qexecute('Any X WHERE X eid %(x)s, X require_permission P?', {'x':peid1}) self.assertEqual(rset.rows, [[peid1]]) def test_select_left_outer_join(self): - rset = self.execute('DISTINCT Any G WHERE U? in_group G') + rset = self.qexecute('DISTINCT Any G WHERE U? in_group G') self.assertEqual(len(rset), 4) - rset = self.execute('DISTINCT Any G WHERE U? in_group G, U eid %(x)s', + rset = self.qexecute('DISTINCT Any G WHERE U? in_group G, U eid %(x)s', {'x': self.session.user.eid}) self.assertEqual(len(rset), 4) def test_select_ambigous_outer_join(self): - teid = self.execute("INSERT Tag X: X name 'tag'")[0][0] - self.execute("INSERT Tag X: X name 'tagbis'")[0][0] - geid = self.execute("CWGroup G WHERE G name 'users'")[0][0] - self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s", + teid = self.qexecute("INSERT Tag X: X name 'tag'")[0][0] + self.qexecute("INSERT Tag X: X name 'tagbis'")[0][0] + geid = self.qexecute("CWGroup G WHERE G name 'users'")[0][0] + self.qexecute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s", {'g': geid, 't': teid}) - rset = self.execute("Any GN,TN ORDERBY GN WHERE T? tags G, T name TN, G name GN") + rset = self.qexecute("Any GN,TN ORDERBY GN WHERE T? tags G, T name TN, G name GN") self.assertIn(['users', 'tag'], rset.rows) self.assertIn(['activated', None], rset.rows) - rset = self.execute("Any GN,TN ORDERBY GN WHERE T tags G?, T name TN, G name GN") + rset = self.qexecute("Any GN,TN ORDERBY GN WHERE T tags G?, T name TN, G name GN") self.assertEqual(rset.rows, [[None, 'tagbis'], ['users', 'tag']]) def test_select_not_inline_rel(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Note X: X type 'a'") - self.execute("INSERT Note X: X type 'b'") - self.execute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'") - rset = self.execute('Note X WHERE NOT X ecrit_par P') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Note X: X type 'a'") + self.qexecute("INSERT Note X: X type 'b'") + self.qexecute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'") + rset = self.qexecute('Note X WHERE NOT X ecrit_par P') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_not_unlinked_multiple_solutions(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Note X: X type 'a'") - self.execute("INSERT Note X: X type 'b'") - self.execute("SET Y evaluee X WHERE X type 'a', Y nom 'bidule'") - rset = self.execute('Note X WHERE NOT Y evaluee X') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Note X: X type 'a'") + self.qexecute("INSERT Note X: X type 'b'") + self.qexecute("SET Y evaluee X WHERE X type 'a', Y nom 'bidule'") + rset = self.qexecute('Note X WHERE NOT Y evaluee X') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_date_extraction(self): - self.execute("INSERT Personne X: X nom 'foo', X datenaiss %(d)s", + self.qexecute("INSERT Personne X: X nom 'foo', X datenaiss %(d)s", {'d': datetime(2001, 2,3, 12,13)}) test_data = [('YEAR', 2001), ('MONTH', 2), ('DAY', 3), ('HOUR', 12), ('MINUTE', 13), ('WEEKDAY', 6)] for funcname, result in test_data: - rset = self.execute('Any %s(D) WHERE X is Personne, X datenaiss D' + rset = self.qexecute('Any %s(D) WHERE X is Personne, X datenaiss D' % funcname) self.assertEqual(len(rset.rows), 1) self.assertEqual(rset.rows[0][0], result) self.assertEqual(rset.description, [('Int',)]) def test_regexp_based_pattern_matching(self): - peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - peid2 = self.execute("INSERT Personne X: X nom 'cidule'")[0][0] - rset = self.execute('Any X WHERE X is Personne, X nom REGEXP "^b"') + peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + peid2 = self.qexecute("INSERT Personne X: X nom 'cidule'")[0][0] + rset = self.qexecute('Any X WHERE X is Personne, X nom REGEXP "^b"') self.assertEqual(len(rset.rows), 1, rset.rows) self.assertEqual(rset.rows[0][0], peid1) - rset = self.execute('Any X WHERE X is Personne, X nom REGEXP "idu"') + rset = self.qexecute('Any X WHERE X is Personne, X nom REGEXP "idu"') self.assertEqual(len(rset.rows), 2, rset.rows) def test_select_aggregat_count(self): - rset = self.execute('Any COUNT(X)') + rset = self.qexecute('Any COUNT(X)') self.assertEqual(len(rset.rows), 1) self.assertEqual(len(rset.rows[0]), 1) self.assertEqual(rset.description, [('Int',)]) def test_select_aggregat_sum(self): - rset = self.execute('Any SUM(O) WHERE X ordernum O') + rset = self.qexecute('Any SUM(O) WHERE X ordernum O') self.assertEqual(len(rset.rows), 1) self.assertEqual(len(rset.rows[0]), 1) self.assertEqual(rset.description, [('Int',)]) def test_select_aggregat_min(self): - rset = self.execute('Any MIN(X) WHERE X is Personne') + rset = self.qexecute('Any MIN(X) WHERE X is Personne') self.assertEqual(len(rset.rows), 1) self.assertEqual(len(rset.rows[0]), 1) self.assertEqual(rset.description, [('Personne',)]) - rset = self.execute('Any MIN(O) WHERE X ordernum O') + rset = self.qexecute('Any MIN(O) WHERE X ordernum O') self.assertEqual(len(rset.rows), 1) self.assertEqual(len(rset.rows[0]), 1) self.assertEqual(rset.description, [('Int',)]) def test_select_aggregat_max(self): - rset = self.execute('Any MAX(X) WHERE X is Personne') + rset = self.qexecute('Any MAX(X) WHERE X is Personne') self.assertEqual(len(rset.rows), 1) self.assertEqual(len(rset.rows[0]), 1) self.assertEqual(rset.description, [('Personne',)]) - rset = self.execute('Any MAX(O) WHERE X ordernum O') + rset = self.qexecute('Any MAX(O) WHERE X ordernum O') self.assertEqual(len(rset.rows), 1) self.assertEqual(len(rset.rows[0]), 1) self.assertEqual(rset.description, [('Int',)]) def test_select_custom_aggregat_concat_string(self): - rset = self.execute('Any GROUP_CONCAT(N) WHERE X is CWGroup, X name N') + rset = self.qexecute('Any GROUP_CONCAT(N) WHERE X is CWGroup, X name N') self.assertTrue(rset) self.assertEqual(sorted(rset[0][0].split(', ')), ['guests', 'managers', 'owners', 'users']) def test_select_custom_regproc_limit_size(self): - rset = self.execute('Any TEXT_LIMIT_SIZE(N, 3) WHERE X is CWGroup, X name N, X name "managers"') + rset = self.qexecute('Any TEXT_LIMIT_SIZE(N, 3) WHERE X is CWGroup, X name N, X name "managers"') self.assertTrue(rset) self.assertEqual(rset[0][0], 'man...') - self.execute("INSERT Basket X: X name 'bidule', X description 'hop hop', X description_format 'text/html'") - rset = self.execute('Any LIMIT_SIZE(D, DF, 3) WHERE X is Basket, X description D, X description_format DF') + self.qexecute("INSERT Basket X: X name 'bidule', X description 'hop hop', X description_format 'text/html'") + rset = self.qexecute('Any LIMIT_SIZE(D, DF, 3) WHERE X is Basket, X description D, X description_format DF') self.assertTrue(rset) self.assertEqual(rset[0][0], 'hop...') def test_select_regproc_orderby(self): - rset = self.execute('DISTINCT Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, X name "managers"') + rset = self.qexecute('DISTINCT Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, X name "managers"') self.assertEqual(len(rset), 1) self.assertEqual(rset[0][1], 'managers') - rset = self.execute('Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, NOT U in_group X, U login "admin"') + rset = self.qexecute('Any X,N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N, NOT U in_group X, U login "admin"') self.assertEqual(len(rset), 3) self.assertEqual(rset[0][1], 'owners') def test_select_aggregat_sort(self): - rset = self.execute('Any G, COUNT(U) GROUPBY G ORDERBY 2 WHERE U in_group G') + rset = self.qexecute('Any G, COUNT(U) GROUPBY G ORDERBY 2 WHERE U in_group G') self.assertEqual(len(rset.rows), 2) self.assertEqual(len(rset.rows[0]), 2) self.assertEqual(rset.description[0], ('CWGroup', 'Int',)) def test_select_aggregat_having(self): - rset = self.execute('Any N,COUNT(RDEF) GROUPBY N ORDERBY 2,N ' + rset = self.qexecute('Any N,COUNT(RDEF) GROUPBY N ORDERBY 2,N ' 'WHERE RT name N, RDEF relation_type RT ' 'HAVING COUNT(RDEF) > 10') self.assertListEqual(rset.rows, @@ -577,21 +617,21 @@ def test_select_aggregat_having_dumb(self): # dumb but should not raise an error - rset = self.execute('Any U,COUNT(X) GROUPBY U ' + rset = self.qexecute('Any U,COUNT(X) GROUPBY U ' 'WHERE U eid %(x)s, X owned_by U ' 'HAVING COUNT(X) > 10', {'x': self.ueid}) self.assertEqual(len(rset.rows), 1) self.assertEqual(rset.rows[0][0], self.ueid) def test_select_having_non_aggregat_1(self): - rset = self.execute('Any L WHERE X login L, X creation_date CD ' + rset = self.qexecute('Any L WHERE X login L, X creation_date CD ' 'HAVING YEAR(CD) = %s' % date.today().year) self.assertListEqual(rset.rows, [[u'admin'], [u'anon']]) def test_select_having_non_aggregat_2(self): - rset = self.execute('Any L GROUPBY L WHERE X login L, X in_group G, ' + rset = self.qexecute('Any L GROUPBY L WHERE X login L, X in_group G, ' 'X creation_date CD HAVING YEAR(CD) = %s OR COUNT(G) > 1' % date.today().year) self.assertListEqual(rset.rows, @@ -600,226 +640,225 @@ def test_select_complex_sort(self): """need sqlite including http://www.sqlite.org/cvstrac/tktview?tn=3773 fix""" - rset = self.execute('Any X ORDERBY X,D LIMIT 5 WHERE X creation_date D') + rset = self.qexecute('Any X ORDERBY X,D LIMIT 5 WHERE X creation_date D') result = rset.rows result.sort() self.assertEqual(tuplify(result), [(1,), (2,), (3,), (4,), (5,)]) def test_select_upper(self): - rset = self.execute('Any X, UPPER(L) ORDERBY L WHERE X is CWUser, X login L') + rset = self.qexecute('Any X, UPPER(L) ORDERBY L WHERE X is CWUser, X login L') self.assertEqual(len(rset.rows), 2) self.assertEqual(rset.rows[0][1], 'ADMIN') self.assertEqual(rset.description[0], ('CWUser', 'String',)) self.assertEqual(rset.rows[1][1], 'ANON') self.assertEqual(rset.description[1], ('CWUser', 'String',)) eid = rset.rows[0][0] - rset = self.execute('Any UPPER(L) WHERE X eid %s, X login L'%eid) + rset = self.qexecute('Any UPPER(L) WHERE X eid %s, X login L'%eid) self.assertEqual(rset.rows[0][0], 'ADMIN') self.assertEqual(rset.description, [('String',)]) def test_select_float_abs(self): # test positive number - eid = self.execute('INSERT Affaire A: A invoiced %(i)s', {'i': 1.2})[0][0] - rset = self.execute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid}) + eid = self.qexecute('INSERT Affaire A: A invoiced %(i)s', {'i': 1.2})[0][0] + rset = self.qexecute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid}) self.assertEqual(rset.rows[0][0], 1.2) # test negative number - eid = self.execute('INSERT Affaire A: A invoiced %(i)s', {'i': -1.2})[0][0] - rset = self.execute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid}) + eid = self.qexecute('INSERT Affaire A: A invoiced %(i)s', {'i': -1.2})[0][0] + rset = self.qexecute('Any ABS(I) WHERE X eid %(x)s, X invoiced I', {'x': eid}) self.assertEqual(rset.rows[0][0], 1.2) def test_select_int_abs(self): # test positive number - eid = self.execute('INSERT Affaire A: A duration %(d)s', {'d': 12})[0][0] - rset = self.execute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid}) + eid = self.qexecute('INSERT Affaire A: A duration %(d)s', {'d': 12})[0][0] + rset = self.qexecute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid}) self.assertEqual(rset.rows[0][0], 12) # test negative number - eid = self.execute('INSERT Affaire A: A duration %(d)s', {'d': -12})[0][0] - rset = self.execute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid}) + eid = self.qexecute('INSERT Affaire A: A duration %(d)s', {'d': -12})[0][0] + rset = self.qexecute('Any ABS(D) WHERE X eid %(x)s, X duration D', {'x': eid}) self.assertEqual(rset.rows[0][0], 12) ## def test_select_simplified(self): ## ueid = self.session.user.eid -## rset = self.execute('Any L WHERE %s login L'%ueid) +## rset = self.qexecute('Any L WHERE %s login L'%ueid) ## self.assertEqual(rset.rows[0][0], 'admin') -## rset = self.execute('Any L WHERE %(x)s login L', {'x':ueid}) +## rset = self.qexecute('Any L WHERE %(x)s login L', {'x':ueid}) ## self.assertEqual(rset.rows[0][0], 'admin') def test_select_searchable_text_1(self): - rset = self.execute(u"INSERT Personne X: X nom 'bidüle'") - rset = self.execute(u"INSERT Societe X: X nom 'bidüle'") - rset = self.execute("INSERT Societe X: X nom 'chouette'") - self.commit() - rset = self.execute('Any X where X has_text %(text)s', {'text': u'bidüle'}) + rset = self.qexecute(u"INSERT Personne X: X nom 'bidüle'") + rset = self.qexecute(u"INSERT Societe X: X nom 'bidüle'") + rset = self.qexecute("INSERT Societe X: X nom 'chouette'") + rset = self.qexecute('Any X where X has_text %(text)s', {'text': u'bidüle'}) self.assertEqual(len(rset.rows), 2, rset.rows) - rset = self.execute(u'Any N where N has_text "bidüle"') + rset = self.qexecute(u'Any N where N has_text "bidüle"') self.assertEqual(len(rset.rows), 2, rset.rows) biduleeids = [r[0] for r in rset.rows] - rset = self.execute(u'Any N where NOT N has_text "bidüle"') + rset = self.qexecute(u'Any N where NOT N has_text "bidüle"') self.assertFalse([r[0] for r in rset.rows if r[0] in biduleeids]) # duh? - rset = self.execute('Any X WHERE X has_text %(text)s', {'text': u'ça'}) + rset = self.qexecute('Any X WHERE X has_text %(text)s', {'text': u'ça'}) def test_select_searchable_text_2(self): - rset = self.execute("INSERT Personne X: X nom 'bidule'") - rset = self.execute("INSERT Personne X: X nom 'chouette'") - rset = self.execute("INSERT Societe X: X nom 'bidule'") - self.commit() - rset = self.execute('Personne N where N has_text "bidule"') + rset = self.qexecute("INSERT Personne X: X nom 'bidule'") + rset = self.qexecute("INSERT Personne X: X nom 'chouette'") + rset = self.qexecute("INSERT Societe X: X nom 'bidule'") + rset = self.qexecute('Personne N where N has_text "bidule"') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_searchable_text_3(self): - rset = self.execute("INSERT Personne X: X nom 'bidule', X sexe 'M'") - rset = self.execute("INSERT Personne X: X nom 'bidule', X sexe 'F'") - rset = self.execute("INSERT Societe X: X nom 'bidule'") - self.commit() - rset = self.execute('Any X where X has_text "bidule" and X sexe "M"') + rset = self.qexecute("INSERT Personne X: X nom 'bidule', X sexe 'M'") + rset = self.qexecute("INSERT Personne X: X nom 'bidule', X sexe 'F'") + rset = self.qexecute("INSERT Societe X: X nom 'bidule'") + rset = self.qexecute('Any X where X has_text "bidule" and X sexe "M"') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_multiple_searchable_text(self): - self.execute(u"INSERT Personne X: X nom 'bidüle'") - self.execute("INSERT Societe X: X nom 'chouette', S travaille X") - self.execute(u"INSERT Personne X: X nom 'bidüle'") - self.commit() - rset = self.execute('Personne X WHERE X has_text %(text)s, X travaille S, S has_text %(text2)s', + self.qexecute(u"INSERT Personne X: X nom 'bidüle'") + self.qexecute("INSERT Societe X: X nom 'chouette', S travaille X") + self.qexecute(u"INSERT Personne X: X nom 'bidüle'") + rset = self.qexecute('Personne X WHERE X has_text %(text)s, X travaille S, S has_text %(text2)s', {'text': u'bidüle', 'text2': u'chouette',} ) self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_no_descr(self): - rset = self.execute('Any X WHERE X is CWGroup', build_descr=0) + rset = self.qexecute('Any X WHERE X is CWGroup', build_descr=0) rset.rows.sort() self.assertEqual(tuplify(rset.rows), [(2,), (3,), (4,), (5,)]) self.assertEqual(rset.description, ()) def test_select_limit_offset(self): - rset = self.execute('CWGroup X ORDERBY N LIMIT 2 WHERE X name N') + rset = self.qexecute('CWGroup X ORDERBY N LIMIT 2 WHERE X name N') self.assertEqual(tuplify(rset.rows), [(2,), (3,)]) self.assertEqual(rset.description, [('CWGroup',), ('CWGroup',)]) - rset = self.execute('CWGroup X ORDERBY N LIMIT 2 OFFSET 2 WHERE X name N') + rset = self.qexecute('CWGroup X ORDERBY N LIMIT 2 OFFSET 2 WHERE X name N') self.assertEqual(tuplify(rset.rows), [(4,), (5,)]) def test_select_symmetric(self): - self.execute("INSERT Personne X: X nom 'machin'") - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Personne X: X nom 'chouette'") - self.execute("INSERT Personne X: X nom 'trucmuche'") - self.execute("SET X connait Y WHERE X nom 'chouette', Y nom 'bidule'") - self.execute("SET X connait Y WHERE X nom 'machin', Y nom 'chouette'") - rset = self.execute('Any P WHERE P connait P2') + self.qexecute("INSERT Personne X: X nom 'machin'") + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Personne X: X nom 'chouette'") + self.qexecute("INSERT Personne X: X nom 'trucmuche'") + self.qexecute("SET X connait Y WHERE X nom 'chouette', Y nom 'bidule'") + self.qexecute("SET X connait Y WHERE X nom 'machin', Y nom 'chouette'") + rset = self.qexecute('Any P WHERE P connait P2') self.assertEqual(len(rset.rows), 4, rset.rows) - rset = self.execute('Any P WHERE NOT P connait P2') + rset = self.qexecute('Any P WHERE NOT P connait P2') self.assertEqual(len(rset.rows), 1, rset.rows) # trucmuche - rset = self.execute('Any P WHERE P connait P2, P2 nom "bidule"') + rset = self.qexecute('Any P WHERE P connait P2, P2 nom "bidule"') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('Any P WHERE P2 connait P, P2 nom "bidule"') + rset = self.qexecute('Any P WHERE P2 connait P, P2 nom "bidule"') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('Any P WHERE P connait P2, P2 nom "chouette"') + rset = self.qexecute('Any P WHERE P connait P2, P2 nom "chouette"') self.assertEqual(len(rset.rows), 2, rset.rows) - rset = self.execute('Any P WHERE P2 connait P, P2 nom "chouette"') + rset = self.qexecute('Any P WHERE P2 connait P, P2 nom "chouette"') self.assertEqual(len(rset.rows), 2, rset.rows) def test_select_inline(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Note X: X type 'a'") - self.execute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'") - rset = self.execute('Any N where N ecrit_par X, X nom "bidule"') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Note X: X type 'a'") + self.qexecute("SET X ecrit_par Y WHERE X type 'a', Y nom 'bidule'") + rset = self.qexecute('Any N where N ecrit_par X, X nom "bidule"') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_creation_date(self): - self.execute("INSERT Personne X: X nom 'bidule'") - rset = self.execute('Any D WHERE X nom "bidule", X creation_date D') + self.qexecute("INSERT Personne X: X nom 'bidule'") + rset = self.qexecute('Any D WHERE X nom "bidule", X creation_date D') self.assertEqual(len(rset.rows), 1) def test_select_or_relation(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Personne X: X nom 'chouette'") - self.execute("INSERT Societe X: X nom 'logilab'") - self.execute("INSERT Societe X: X nom 'caesium'") - self.execute("SET P travaille S WHERE P nom 'bidule', S nom 'logilab'") - rset = self.execute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, S1 nom "logilab", S2 nom "caesium"') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Personne X: X nom 'chouette'") + self.qexecute("INSERT Societe X: X nom 'logilab'") + self.qexecute("INSERT Societe X: X nom 'caesium'") + self.qexecute("SET P travaille S WHERE P nom 'bidule', S nom 'logilab'") + rset = self.qexecute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, ' + 'S1 nom "logilab", S2 nom "caesium"') self.assertEqual(len(rset.rows), 1) - self.execute("SET P travaille S WHERE P nom 'chouette', S nom 'caesium'") - rset = self.execute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, S1 nom "logilab", S2 nom "caesium"') + self.qexecute("SET P travaille S WHERE P nom 'chouette', S nom 'caesium'") + rset = self.qexecute('DISTINCT Any P WHERE P travaille S1 OR P travaille S2, ' + 'S1 nom "logilab", S2 nom "caesium"') self.assertEqual(len(rset.rows), 2) def test_select_or_sym_relation(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Personne X: X nom 'chouette'") - self.execute("INSERT Personne X: X nom 'truc'") - self.execute("SET P connait S WHERE P nom 'bidule', S nom 'chouette'") - rset = self.execute('DISTINCT Any P WHERE S connait P, S nom "chouette"') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Personne X: X nom 'chouette'") + self.qexecute("INSERT Personne X: X nom 'truc'") + self.qexecute("SET P connait S WHERE P nom 'bidule', S nom 'chouette'") + rset = self.qexecute('DISTINCT Any P WHERE S connait P, S nom "chouette"') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('DISTINCT Any P WHERE P connait S or S connait P, S nom "chouette"') + rset = self.qexecute('DISTINCT Any P WHERE P connait S or S connait P, S nom "chouette"') self.assertEqual(len(rset.rows), 1, rset.rows) - self.execute("SET P connait S WHERE P nom 'chouette', S nom 'truc'") - rset = self.execute('DISTINCT Any P WHERE S connait P, S nom "chouette"') + self.qexecute("SET P connait S WHERE P nom 'chouette', S nom 'truc'") + rset = self.qexecute('DISTINCT Any P WHERE S connait P, S nom "chouette"') self.assertEqual(len(rset.rows), 2, rset.rows) - rset = self.execute('DISTINCT Any P WHERE P connait S OR S connait P, S nom "chouette"') + rset = self.qexecute('DISTINCT Any P WHERE P connait S OR S connait P, S nom "chouette"') self.assertEqual(len(rset.rows), 2, rset.rows) def test_select_follow_relation(self): - self.execute("INSERT Affaire X: X sujet 'cool'") - self.execute("INSERT Societe X: X nom 'chouette'") - self.execute("SET A concerne S WHERE A is Affaire, S is Societe") - self.execute("INSERT Note X: X para 'truc'") - self.execute("SET S evaluee N WHERE S is Societe, N is Note") - self.execute("INSERT Societe X: X nom 'bidule'") - self.execute("INSERT Note X: X para 'troc'") - self.execute("SET S evaluee N WHERE S nom 'bidule', N para 'troc'") - rset = self.execute('DISTINCT Any A,N WHERE A concerne S, S evaluee N') + self.qexecute("INSERT Affaire X: X sujet 'cool'") + self.qexecute("INSERT Societe X: X nom 'chouette'") + self.qexecute("SET A concerne S WHERE A is Affaire, S is Societe") + self.qexecute("INSERT Note X: X para 'truc'") + self.qexecute("SET S evaluee N WHERE S is Societe, N is Note") + self.qexecute("INSERT Societe X: X nom 'bidule'") + self.qexecute("INSERT Note X: X para 'troc'") + self.qexecute("SET S evaluee N WHERE S nom 'bidule', N para 'troc'") + rset = self.qexecute('DISTINCT Any A,N WHERE A concerne S, S evaluee N') self.assertEqual(len(rset.rows), 1, rset.rows) def test_select_ordered_distinct_1(self): self.assertRaises(BadRQLQuery, - self.execute, 'DISTINCT Any S ORDERBY R WHERE A is Affaire, A sujet S, A ref R') + self.qexecute, 'DISTINCT Any S ORDERBY R WHERE A is Affaire, A sujet S, A ref R') def test_select_ordered_distinct_2(self): - self.execute("INSERT Affaire X: X sujet 'minor'") - self.execute("INSERT Affaire X: X sujet 'zou'") - self.execute("INSERT Affaire X: X sujet 'abcd'") - rset = self.execute('DISTINCT Any S ORDERBY S WHERE A is Affaire, A sujet S') + self.qexecute("INSERT Affaire X: X sujet 'minor'") + self.qexecute("INSERT Affaire X: X sujet 'zou'") + self.qexecute("INSERT Affaire X: X sujet 'abcd'") + rset = self.qexecute('DISTINCT Any S ORDERBY S WHERE A is Affaire, A sujet S') self.assertEqual(rset.rows, [['abcd'], ['minor'], ['zou']]) def test_select_ordered_distinct_3(self): - rset = self.execute('DISTINCT Any N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N') + rset = self.qexecute('DISTINCT Any N ORDERBY GROUP_SORT_VALUE(N) WHERE X is CWGroup, X name N') self.assertEqual(rset.rows, [['owners'], ['guests'], ['users'], ['managers']]) def test_select_or_value(self): - rset = self.execute('Any U WHERE U in_group G, G name "owners" OR G name "users"') + rset = self.qexecute('Any U WHERE U in_group G, G name "owners" OR G name "users"') self.assertEqual(len(rset.rows), 0) - rset = self.execute('Any U WHERE U in_group G, G name "guests" OR G name "managers"') + rset = self.qexecute('Any U WHERE U in_group G, G name "guests" OR G name "managers"') self.assertEqual(len(rset.rows), 2) def test_select_explicit_eid(self): - rset = self.execute('Any X,E WHERE X owned_by U, X eid E, U eid %(u)s', {'u': self.session.user.eid}) + rset = self.qexecute('Any X,E WHERE X owned_by U, X eid E, U eid %(u)s', + {'u': self.session.user.eid}) self.assertTrue(rset) self.assertEqual(rset.description[0][1], 'Int') # def test_select_rewritten_optional(self): -# eid = self.execute("INSERT Affaire X: X sujet 'cool'")[0][0] -# rset = self.execute('Any X WHERE X eid %(x)s, EXISTS(X owned_by U) OR EXISTS(X concerne S?, S owned_by U)', +# eid = self.qexecute("INSERT Affaire X: X sujet 'cool'")[0][0] +# rset = self.qexecute('Any X WHERE X eid %(x)s, EXISTS(X owned_by U) OR EXISTS(X concerne S?, S owned_by U)', # {'x': eid}, 'x') # self.assertEqual(rset.rows, [[eid]]) def test_today_bug(self): - self.execute("INSERT Tag X: X name 'bidule', X creation_date NOW") - self.execute("INSERT Tag Y: Y name 'toto'") - rset = self.execute("Any D WHERE X name in ('bidule', 'toto') , X creation_date D") + self.qexecute("INSERT Tag X: X name 'bidule', X creation_date NOW") + self.qexecute("INSERT Tag Y: Y name 'toto'") + rset = self.qexecute("Any D WHERE X name in ('bidule', 'toto') , X creation_date D") self.assertIsInstance(rset.rows[0][0], datetime) - rset = self.execute('Tag X WHERE X creation_date TODAY') + rset = self.qexecute('Tag X WHERE X creation_date TODAY') self.assertEqual(len(rset.rows), 2) - rset = self.execute('Any MAX(D) WHERE X is Tag, X creation_date D') + rset = self.qexecute('Any MAX(D) WHERE X is Tag, X creation_date D') self.assertIsInstance(rset[0][0], datetime) def test_today(self): - self.execute("INSERT Tag X: X name 'bidule', X creation_date TODAY") - self.execute("INSERT Tag Y: Y name 'toto'") - rset = self.execute('Tag X WHERE X creation_date TODAY') + self.qexecute("INSERT Tag X: X name 'bidule', X creation_date TODAY") + self.qexecute("INSERT Tag Y: Y name 'toto'") + rset = self.qexecute('Tag X WHERE X creation_date TODAY') self.assertEqual(len(rset.rows), 2) def test_select_boolean(self): - rset = self.execute('Any N WHERE X is CWEType, X name N, X final %(val)s', + rset = self.qexecute('Any N WHERE X is CWEType, X name N, X final %(val)s', {'val': True}) self.assertEqual(sorted(r[0] for r in rset.rows), ['BigInt', 'Boolean', 'Bytes', 'Date', 'Datetime', @@ -828,7 +867,7 @@ 'Password', 'String', 'TZDatetime', 'TZTime', 'Time']) - rset = self.execute('Any N WHERE X is CWEType, X name N, X final TRUE') + rset = self.qexecute('Any N WHERE X is CWEType, X name N, X final TRUE') self.assertEqual(sorted(r[0] for r in rset.rows), ['BigInt', 'Boolean', 'Bytes', 'Date', 'Datetime', 'Decimal', 'Float', @@ -836,32 +875,33 @@ 'Password', 'String', 'TZDatetime', 'TZTime', 'Time']) - req = self.session - req.create_entity('Personne', nom=u'louis', test=True) - self.assertEqual(len(req.execute('Any X WHERE X test %(val)s', {'val': True})), 1) - self.assertEqual(len(req.execute('Any X WHERE X test TRUE')), 1) - self.assertEqual(len(req.execute('Any X WHERE X test %(val)s', {'val': False})), 0) - self.assertEqual(len(req.execute('Any X WHERE X test FALSE')), 0) + with self.session.new_cnx() as cnx: + cnx.create_entity('Personne', nom=u'louis', test=True) + self.assertEqual(len(cnx.execute('Any X WHERE X test %(val)s', {'val': True})), 1) + self.assertEqual(len(cnx.execute('Any X WHERE X test TRUE')), 1) + self.assertEqual(len(cnx.execute('Any X WHERE X test %(val)s', {'val': False})), 0) + self.assertEqual(len(cnx.execute('Any X WHERE X test FALSE')), 0) def test_select_constant(self): - rset = self.execute('Any X, "toto" ORDERBY X WHERE X is CWGroup') + rset = self.qexecute('Any X, "toto" ORDERBY X WHERE X is CWGroup') self.assertEqual(rset.rows, map(list, zip((2,3,4,5), ('toto','toto','toto','toto',)))) self.assertIsInstance(rset[0][1], unicode) self.assertEqual(rset.description, zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'), ('String', 'String', 'String', 'String',))) - rset = self.execute('Any X, %(value)s ORDERBY X WHERE X is CWGroup', {'value': 'toto'}) + rset = self.qexecute('Any X, %(value)s ORDERBY X WHERE X is CWGroup', {'value': 'toto'}) self.assertEqual(rset.rows, map(list, zip((2,3,4,5), ('toto','toto','toto','toto',)))) self.assertIsInstance(rset[0][1], unicode) self.assertEqual(rset.description, zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'), ('String', 'String', 'String', 'String',))) - rset = self.execute('Any X,GN WHERE X is CWUser, G is CWGroup, X login "syt", X in_group G, G name GN') + rset = self.qexecute('Any X,GN WHERE X is CWUser, G is CWGroup, X login "syt", ' + 'X in_group G, G name GN') def test_select_union(self): - rset = self.execute('Any X,N ORDERBY N WITH X,N BEING ' + rset = self.qexecute('Any X,N ORDERBY N WITH X,N BEING ' '((Any X,N WHERE X name N, X transition_of WF, WF workflow_of E, E name %(name)s)' ' UNION ' '(Any X,N WHERE X name N, X state_of WF, WF workflow_of E, E name %(name)s))', @@ -875,23 +915,26 @@ def test_select_union_aggregat(self): # meaningless, the goal in to have group by done on different attribute # for each sub-query - self.execute('(Any N,COUNT(X) GROUPBY N WHERE X name N, X is State)' + self.qexecute('(Any N,COUNT(X) GROUPBY N WHERE X name N, X is State)' ' UNION ' '(Any N,COUNT(X) GROUPBY N ORDERBY 2 WHERE X login N)') def test_select_union_aggregat_independant_group(self): - self.execute('INSERT State X: X name "hop"') - self.execute('INSERT State X: X name "hop"') - self.execute('INSERT Transition X: X name "hop"') - self.execute('INSERT Transition X: X name "hop"') - rset = self.execute('Any N,NX ORDERBY 2 WITH N,NX BEING ' - '((Any N,COUNT(X) GROUPBY N WHERE X name N, X is State HAVING COUNT(X)>1)' - ' UNION ' - '(Any N,COUNT(X) GROUPBY N WHERE X name N, X is Transition HAVING COUNT(X)>1))') - self.assertEqual(rset.rows, [[u'hop', 2], [u'hop', 2]]) + with self.session.new_cnx() as cnx: + cnx.execute('INSERT State X: X name "hop"') + cnx.execute('INSERT State X: X name "hop"') + cnx.execute('INSERT Transition X: X name "hop"') + cnx.execute('INSERT Transition X: X name "hop"') + rset = cnx.execute('Any N,NX ORDERBY 2 WITH N,NX BEING ' + '((Any N,COUNT(X) GROUPBY N WHERE X name N, ' + ' X is State HAVING COUNT(X)>1)' + ' UNION ' + '(Any N,COUNT(X) GROUPBY N WHERE X name N, ' + ' X is Transition HAVING COUNT(X)>1))') + self.assertEqual(rset.rows, [[u'hop', 2], [u'hop', 2]]) def test_select_union_selection_with_diff_variables(self): - rset = self.execute('(Any N WHERE X name N, X is State)' + rset = self.qexecute('(Any N WHERE X name N, X is State)' ' UNION ' '(Any NN WHERE XX name NN, XX is Transition)') self.assertEqual(sorted(r[0] for r in rset.rows), @@ -901,51 +944,51 @@ 'start', 'todo']) def test_select_union_description_diff_var(self): - eid1 = self.execute('CWGroup X WHERE X name "managers"')[0][0] - eid2 = self.execute('CWUser X WHERE X login "admin"')[0][0] - rset = self.execute('(Any X WHERE X eid %(x)s)' + eid1 = self.qexecute('CWGroup X WHERE X name "managers"')[0][0] + eid2 = self.qexecute('CWUser X WHERE X login "admin"')[0][0] + rset = self.qexecute('(Any X WHERE X eid %(x)s)' ' UNION ' '(Any Y WHERE Y eid %(y)s)', {'x': eid1, 'y': eid2}) self.assertEqual(rset.description[:], [('CWGroup',), ('CWUser',)]) def test_exists(self): - geid = self.execute("INSERT CWGroup X: X name 'lulufanclub'")[0][0] - self.execute("SET U in_group G WHERE G name 'lulufanclub'") - peid = self.execute("INSERT Personne X: X prenom 'lulu', X nom 'petit'")[0][0] - rset = self.execute("Any X WHERE X prenom 'lulu'," + geid = self.qexecute("INSERT CWGroup X: X name 'lulufanclub'")[0][0] + self.qexecute("SET U in_group G WHERE G name 'lulufanclub'") + peid = self.qexecute("INSERT Personne X: X prenom 'lulu', X nom 'petit'")[0][0] + rset = self.qexecute("Any X WHERE X prenom 'lulu'," "EXISTS (U in_group G, G name 'lulufanclub' OR G name 'managers');") self.assertEqual(rset.rows, [[peid]]) def test_identity(self): - eid = self.execute('Any X WHERE X identity Y, Y eid 1')[0][0] + eid = self.qexecute('Any X WHERE X identity Y, Y eid 1')[0][0] self.assertEqual(eid, 1) - eid = self.execute('Any X WHERE Y identity X, Y eid 1')[0][0] + eid = self.qexecute('Any X WHERE Y identity X, Y eid 1')[0][0] self.assertEqual(eid, 1) - login = self.execute('Any L WHERE X login "admin", X identity Y, Y login L')[0][0] + login = self.qexecute('Any L WHERE X login "admin", X identity Y, Y login L')[0][0] self.assertEqual(login, 'admin') def test_select_date_mathexp(self): - rset = self.execute('Any X, TODAY - CD WHERE X is CWUser, X creation_date CD') + rset = self.qexecute('Any X, TODAY - CD WHERE X is CWUser, X creation_date CD') self.assertTrue(rset) self.assertEqual(rset.description[0][1], 'Interval') - eid, = self.execute("INSERT Personne X: X nom 'bidule'")[0] - rset = self.execute('Any X, NOW - CD WHERE X is Personne, X creation_date CD') + eid, = self.qexecute("INSERT Personne X: X nom 'bidule'")[0] + rset = self.qexecute('Any X, NOW - CD WHERE X is Personne, X creation_date CD') self.assertEqual(rset.description[0][1], 'Interval') def test_select_subquery_aggregat_1(self): # percent users by groups - self.execute('SET X in_group G WHERE G name "users"') - rset = self.execute('Any GN, COUNT(X)*100/T GROUPBY GN ORDERBY 2,1' + self.qexecute('SET X in_group G WHERE G name "users"') + rset = self.qexecute('Any GN, COUNT(X)*100/T GROUPBY GN ORDERBY 2,1' ' WHERE G name GN, X in_group G' ' WITH T BEING (Any COUNT(U) WHERE U is CWUser)') self.assertEqual(rset.rows, [[u'guests', 50], [u'managers', 50], [u'users', 100]]) self.assertEqual(rset.description, [('String', 'Int'), ('String', 'Int'), ('String', 'Int')]) def test_select_subquery_aggregat_2(self): - expected = self.execute('Any X, 0, COUNT(T) GROUPBY X ' + expected = self.qexecute('Any X, 0, COUNT(T) GROUPBY X ' 'WHERE X is Workflow, T transition_of X').rows - rset = self.execute(''' + rset = self.qexecute(''' Any P1,B,E WHERE P1 identity P2 WITH P1,B BEING (Any P,COUNT(T) GROUPBY P WHERE P is Workflow, T is Transition, T? transition_of P, T type "auto"), @@ -954,116 +997,120 @@ self.assertEqual(sorted(rset.rows), sorted(expected)) def test_select_subquery_const(self): - rset = self.execute('Any X WITH X BEING ((Any NULL) UNION (Any "toto"))') + rset = self.qexecute('Any X WITH X BEING ((Any NULL) UNION (Any "toto"))') self.assertEqual(rset.rows, [[None], ['toto']]) self.assertEqual(rset.description, [(None,), ('String',)]) # insertion queries tests ################################################# def test_insert_is(self): - eid, = self.execute("INSERT Personne X: X nom 'bidule'")[0] - etype, = self.execute("Any TN WHERE X is T, X eid %s, T name TN" % eid)[0] + eid, = self.qexecute("INSERT Personne X: X nom 'bidule'")[0] + etype, = self.qexecute("Any TN WHERE X is T, X eid %s, T name TN" % eid)[0] self.assertEqual(etype, 'Personne') - self.execute("INSERT Personne X: X nom 'managers'") + self.qexecute("INSERT Personne X: X nom 'managers'") def test_insert_1(self): - rset = self.execute("INSERT Personne X: X nom 'bidule'") + rset = self.qexecute("INSERT Personne X: X nom 'bidule'") self.assertEqual(len(rset.rows), 1) self.assertEqual(rset.description, [('Personne',)]) - rset = self.execute('Personne X WHERE X nom "bidule"') + rset = self.qexecute('Personne X WHERE X nom "bidule"') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne',)]) def test_insert_1_multiple(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Personne X: X nom 'chouette'") - rset = self.execute("INSERT Societe Y: Y nom N, P travaille Y WHERE P nom N") + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Personne X: X nom 'chouette'") + rset = self.qexecute("INSERT Societe Y: Y nom N, P travaille Y WHERE P nom N") self.assertEqual(len(rset.rows), 2) self.assertEqual(rset.description, [('Societe',), ('Societe',)]) def test_insert_2(self): - rset = self.execute("INSERT Personne X, Personne Y: X nom 'bidule', Y nom 'tutu'") + rset = self.qexecute("INSERT Personne X, Personne Y: X nom 'bidule', Y nom 'tutu'") self.assertEqual(rset.description, [('Personne', 'Personne')]) - rset = self.execute('Personne X WHERE X nom "bidule" or X nom "tutu"') + rset = self.qexecute('Personne X WHERE X nom "bidule" or X nom "tutu"') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne',), ('Personne',)]) def test_insert_3(self): - self.execute("INSERT Personne X: X nom Y WHERE U login 'admin', U login Y") - rset = self.execute('Personne X WHERE X nom "admin"') + self.qexecute("INSERT Personne X: X nom Y WHERE U login 'admin', U login Y") + rset = self.qexecute('Personne X WHERE X nom "admin"') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne',)]) def test_insert_4(self): - self.execute("INSERT Societe Y: Y nom 'toto'") - self.execute("INSERT Personne X: X nom 'bidule', X travaille Y WHERE Y nom 'toto'") - rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') + self.qexecute("INSERT Societe Y: Y nom 'toto'") + self.qexecute("INSERT Personne X: X nom 'bidule', X travaille Y WHERE Y nom 'toto'") + rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne', 'Societe',)]) def test_insert_4bis(self): - peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - seid = self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", + peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + seid = self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", {'x': str(peid)})[0][0] - self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 1) - self.execute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s", + self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 1) + self.qexecute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s", {'x': str(seid)}) - self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 2) + self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 2) def test_insert_4ter(self): - peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - seid = self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", + peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + seid = self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", {'x': unicode(peid)})[0][0] - self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 1) - self.execute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s", + self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 1) + self.qexecute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s", {'x': unicode(seid)}) - self.assertEqual(len(self.execute('Any X, Y WHERE X travaille Y')), 2) + self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 2) def test_insert_5(self): - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X nom 'bidule'") - rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X nom 'bidule'") + rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne', 'Societe',)]) def test_insert_5bis(self): - peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - self.execute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", + peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", {'x': peid}) - rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') + rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne', 'Societe',)]) def test_insert_6(self): - self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto', X travaille Y") - rset = self.execute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') + self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto', X travaille Y") + rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne', 'Societe',)]) def test_insert_7(self): - self.execute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y WHERE U login 'admin', U login N") - rset = self.execute('Any X, Y WHERE X nom "admin", Y nom "toto", X travaille Y') + self.qexecute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', " + "X travaille Y WHERE U login 'admin', U login N") + rset = self.qexecute('Any X, Y WHERE X nom "admin", Y nom "toto", X travaille Y') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne', 'Societe',)]) def test_insert_7_2(self): - self.execute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y WHERE U login N") - rset = self.execute('Any X, Y WHERE Y nom "toto", X travaille Y') + self.qexecute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', " + "X travaille Y WHERE U login N") + rset = self.qexecute('Any X, Y WHERE Y nom "toto", X travaille Y') self.assertEqual(len(rset), 2) self.assertEqual(rset.description, [('Personne', 'Societe',), ('Personne', 'Societe',)]) def test_insert_8(self): - self.execute("INSERT Societe Y, Personne X: Y nom N, X nom 'toto', X travaille Y WHERE U login 'admin', U login N") - rset = self.execute('Any X, Y WHERE X nom "toto", Y nom "admin", X travaille Y') + self.qexecute("INSERT Societe Y, Personne X: Y nom N, X nom 'toto', X travaille Y " + "WHERE U login 'admin', U login N") + rset = self.qexecute('Any X, Y WHERE X nom "toto", Y nom "admin", X travaille Y') self.assert_(rset.rows) self.assertEqual(rset.description, [('Personne', 'Societe',)]) def test_insert_9(self): - self.execute("INSERT Societe X: X nom 'Lo'") - self.execute("INSERT Societe X: X nom 'Gi'") - self.execute("INSERT SubDivision X: X nom 'Lab'") - rset = self.execute("INSERT Personne X: X nom N, X travaille Y, X travaille_subdivision Z WHERE Y is Societe, Z is SubDivision, Y nom N") + self.qexecute("INSERT Societe X: X nom 'Lo'") + self.qexecute("INSERT Societe X: X nom 'Gi'") + self.qexecute("INSERT SubDivision X: X nom 'Lab'") + rset = self.qexecute("INSERT Personne X: X nom N, X travaille Y, X travaille_subdivision Z " + "WHERE Y is Societe, Z is SubDivision, Y nom N") self.assertEqual(len(rset), 2) self.assertEqual(rset.description, [('Personne',), ('Personne',)]) # self.assertSetEqual(set(x.nom for x in rset.entities()), @@ -1075,21 +1122,21 @@ def test_insert_query_error(self): self.assertRaises(Exception, - self.execute, + self.qexecute, "INSERT Personne X: X nom 'toto', X is Personne") self.assertRaises(Exception, - self.execute, + self.qexecute, "INSERT Personne X: X nom 'toto', X is_instance_of Personne") self.assertRaises(QueryError, - self.execute, + self.qexecute, "INSERT Personne X: X nom 'toto', X has_text 'tutu'") self.assertRaises(QueryError, - self.execute, + self.qexecute, "INSERT CWUser X: X login 'toto', X eid %s" % cnx.user(self.session).eid) def test_insertion_description_with_where(self): - rset = self.execute('INSERT CWUser E, EmailAddress EM: E login "X", E upassword "X", ' + rset = self.qexecute('INSERT CWUser E, EmailAddress EM: E login "X", E upassword "X", ' 'E primary_email EM, EM address "X", E in_group G ' 'WHERE G name "managers"') self.assertEqual(list(rset.description[0]), ['CWUser', 'EmailAddress']) @@ -1097,54 +1144,58 @@ # deletion queries tests ################################################## def test_delete_1(self): - self.execute("INSERT Personne Y: Y nom 'toto'") - rset = self.execute('Personne X WHERE X nom "toto"') + self.qexecute("INSERT Personne Y: Y nom 'toto'") + rset = self.qexecute('Personne X WHERE X nom "toto"') self.assertEqual(len(rset.rows), 1) - drset = self.execute("DELETE Personne Y WHERE Y nom 'toto'") + drset = self.qexecute("DELETE Personne Y WHERE Y nom 'toto'") self.assertEqual(drset.rows, rset.rows) - rset = self.execute('Personne X WHERE X nom "toto"') + rset = self.qexecute('Personne X WHERE X nom "toto"') self.assertEqual(len(rset.rows), 0) def test_delete_2(self): - rset = self.execute("INSERT Personne X, Personne Y, Societe Z : X nom 'syt', Y nom 'adim', Z nom 'Logilab', X travaille Z, Y travaille Z") + rset = self.qexecute("INSERT Personne X, Personne Y, Societe Z : " + "X nom 'syt', Y nom 'adim', Z nom 'Logilab', X travaille Z, Y travaille Z") self.assertEqual(len(rset), 1) self.assertEqual(len(rset[0]), 3) self.assertEqual(rset.description[0], ('Personne', 'Personne', 'Societe')) - self.assertEqual(self.execute('Any N WHERE X nom N, X eid %s'% rset[0][0])[0][0], 'syt') - rset = self.execute('Personne X WHERE X travaille Y, Y nom "Logilab"') + self.assertEqual(self.qexecute('Any N WHERE X nom N, X eid %s'% rset[0][0])[0][0], 'syt') + rset = self.qexecute('Personne X WHERE X travaille Y, Y nom "Logilab"') self.assertEqual(len(rset.rows), 2, rset.rows) - self.execute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilabo'") - rset = self.execute('Personne X WHERE X travaille Y, Y nom "Logilab"') + self.qexecute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilabo'") + rset = self.qexecute('Personne X WHERE X travaille Y, Y nom "Logilab"') self.assertEqual(len(rset.rows), 2, rset.rows) - self.execute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilab'") - rset = self.execute('Personne X WHERE X travaille Y, Y nom "Logilab"') + self.qexecute("DELETE X travaille Y WHERE X is Personne, Y nom 'Logilab'") + rset = self.qexecute('Personne X WHERE X travaille Y, Y nom "Logilab"') self.assertEqual(len(rset.rows), 0, rset.rows) def test_delete_3(self): s = self.user_groups_session('users') - peid, = self.o.execute(s, "INSERT Personne P: P nom 'toto'")[0] - seid, = self.o.execute(s, "INSERT Societe S: S nom 'logilab'")[0] - self.o.execute(s, "SET P travaille S") - rset = self.execute('Personne P WHERE P travaille S') + with s.new_cnx() as cnx: + with cnx.ensure_cnx_set: + peid, = self.o.execute(cnx, "INSERT Personne P: P nom 'toto'")[0] + seid, = self.o.execute(cnx, "INSERT Societe S: S nom 'logilab'")[0] + self.o.execute(cnx, "SET P travaille S") + cnx.commit() + rset = self.qexecute('Personne P WHERE P travaille S') self.assertEqual(len(rset.rows), 1) - self.execute("DELETE X travaille Y WHERE X eid %s, Y eid %s" % (peid, seid)) - rset = self.execute('Personne P WHERE P travaille S') + self.qexecute("DELETE X travaille Y WHERE X eid %s, Y eid %s" % (peid, seid)) + rset = self.qexecute('Personne P WHERE P travaille S') self.assertEqual(len(rset.rows), 0) def test_delete_symmetric(self): - teid1 = self.execute("INSERT Folder T: T name 'toto'")[0][0] - teid2 = self.execute("INSERT Folder T: T name 'tutu'")[0][0] - self.execute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2)) - rset = self.execute('Any X,Y WHERE X see_also Y') + teid1 = self.qexecute("INSERT Folder T: T name 'toto'")[0][0] + teid2 = self.qexecute("INSERT Folder T: T name 'tutu'")[0][0] + self.qexecute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2)) + rset = self.qexecute('Any X,Y WHERE X see_also Y') self.assertEqual(len(rset) , 2, rset.rows) - self.execute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2)) - rset = self.execute('Any X,Y WHERE X see_also Y') + self.qexecute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2)) + rset = self.qexecute('Any X,Y WHERE X see_also Y') self.assertEqual(len(rset) , 0) - self.execute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2)) - rset = self.execute('Any X,Y WHERE X see_also Y') + self.qexecute('SET X see_also Y WHERE X eid %s, Y eid %s' % (teid1, teid2)) + rset = self.qexecute('Any X,Y WHERE X see_also Y') self.assertEqual(len(rset) , 2) - self.execute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid2, teid1)) - rset = self.execute('Any X,Y WHERE X see_also Y') + self.qexecute('DELETE X see_also Y WHERE X eid %s, Y eid %s' % (teid2, teid1)) + rset = self.qexecute('Any X,Y WHERE X see_also Y') self.assertEqual(len(rset) , 0) def test_nonregr_delete_cache(self): @@ -1152,204 +1203,221 @@ (using cachekey on sql generation returned always the same query for an eid, whatever the relation) """ - aeid, = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')[0] + aeid, = self.qexecute('INSERT EmailAddress X: X address "toto@logilab.fr", X alias "hop"')[0] # XXX would be nice if the rql below was enough... #'INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y' - eeid, = self.execute('INSERT Email X: X messageid "<1234>", X subject "test", X sender Y, X recipients Y WHERE Y is EmailAddress')[0] - self.execute("DELETE Email X") - sqlc = self.session.cnxset.cu - sqlc.execute('SELECT * FROM recipients_relation') - self.assertEqual(len(sqlc.fetchall()), 0) - sqlc.execute('SELECT * FROM owned_by_relation WHERE eid_from=%s'%eeid) - self.assertEqual(len(sqlc.fetchall()), 0) + eeid, = self.qexecute('INSERT Email X: X messageid "<1234>", X subject "test", ' + 'X sender Y, X recipients Y WHERE Y is EmailAddress')[0] + self.qexecute("DELETE Email X") + with self.session.new_cnx() as cnx: + with cnx.ensure_cnx_set: + sqlc = cnx.cnxset.cu + sqlc.execute('SELECT * FROM recipients_relation') + self.assertEqual(len(sqlc.fetchall()), 0) + sqlc.execute('SELECT * FROM owned_by_relation WHERE eid_from=%s'%eeid) + self.assertEqual(len(sqlc.fetchall()), 0) def test_nonregr_delete_cache2(self): - eid = self.execute("INSERT Folder T: T name 'toto'")[0][0] - self.commit() + eid = self.qexecute("INSERT Folder T: T name 'toto'")[0][0] # fill the cache - self.execute("Any X WHERE X eid %(x)s", {'x': eid}) - self.execute("Any X WHERE X eid %s" % eid) - self.execute("Folder X WHERE X eid %(x)s", {'x': eid}) - self.execute("Folder X WHERE X eid %s" % eid) - self.execute("DELETE Folder T WHERE T eid %s" % eid) - self.commit() - rset = self.execute("Any X WHERE X eid %(x)s", {'x': eid}) + self.qexecute("Any X WHERE X eid %(x)s", {'x': eid}) + self.qexecute("Any X WHERE X eid %s" % eid) + self.qexecute("Folder X WHERE X eid %(x)s", {'x': eid}) + self.qexecute("Folder X WHERE X eid %s" % eid) + self.qexecute("DELETE Folder T WHERE T eid %s" % eid) + rset = self.qexecute("Any X WHERE X eid %(x)s", {'x': eid}) self.assertEqual(rset.rows, []) - rset = self.execute("Any X WHERE X eid %s" % eid) + rset = self.qexecute("Any X WHERE X eid %s" % eid) self.assertEqual(rset.rows, []) - rset = self.execute("Folder X WHERE X eid %(x)s", {'x': eid}) + rset = self.qexecute("Folder X WHERE X eid %(x)s", {'x': eid}) self.assertEqual(rset.rows, []) - rset = self.execute("Folder X WHERE X eid %s" %eid) + rset = self.qexecute("Folder X WHERE X eid %s" %eid) self.assertEqual(rset.rows, []) # update queries tests #################################################### def test_update_1(self): - peid = self.execute("INSERT Personne Y: Y nom 'toto'")[0][0] - rset = self.execute('Personne X WHERE X nom "toto"') + peid = self.qexecute("INSERT Personne Y: Y nom 'toto'")[0][0] + rset = self.qexecute('Personne X WHERE X nom "toto"') self.assertEqual(len(rset.rows), 1) - rset = self.execute("SET X nom 'tutu', X prenom 'original' WHERE X is Personne, X nom 'toto'") + rset = self.qexecute("SET X nom 'tutu', X prenom 'original' WHERE X is Personne, X nom 'toto'") self.assertEqual(tuplify(rset.rows), [(peid, 'tutu', 'original')]) - rset = self.execute('Any Y, Z WHERE X is Personne, X nom Y, X prenom Z') + rset = self.qexecute('Any Y, Z WHERE X is Personne, X nom Y, X prenom Z') self.assertEqual(tuplify(rset.rows), [('tutu', 'original')]) def test_update_2(self): - peid, seid = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")[0] - rset = self.execute("SET X travaille Y WHERE X nom 'bidule', Y nom 'toto'") + peid, seid = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")[0] + rset = self.qexecute("SET X travaille Y WHERE X nom 'bidule', Y nom 'toto'") self.assertEqual(tuplify(rset.rows), [(peid, seid)]) - rset = self.execute('Any X, Y WHERE X travaille Y') + rset = self.qexecute('Any X, Y WHERE X travaille Y') self.assertEqual(len(rset.rows), 1) def test_update_2bis(self): - rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") + rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") eid1, eid2 = rset[0][0], rset[0][1] - self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s", + self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s", {'x': str(eid1), 'y': str(eid2)}) - rset = self.execute('Any X, Y WHERE X travaille Y') + rset = self.qexecute('Any X, Y WHERE X travaille Y') self.assertEqual(len(rset.rows), 1) # test add of an existant relation but with NOT X rel Y protection - self.assertFalse(self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s," + self.assertFalse(self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s," "NOT X travaille Y", {'x': str(eid1), 'y': str(eid2)})) def test_update_2ter(self): - rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") + rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") eid1, eid2 = rset[0][0], rset[0][1] - self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s", + self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s", {'x': unicode(eid1), 'y': unicode(eid2)}) - rset = self.execute('Any X, Y WHERE X travaille Y') + rset = self.qexecute('Any X, Y WHERE X travaille Y') self.assertEqual(len(rset.rows), 1) def test_update_multiple1(self): - peid1 = self.execute("INSERT Personne Y: Y nom 'tutu'")[0][0] - peid2 = self.execute("INSERT Personne Y: Y nom 'toto'")[0][0] - self.execute("SET X nom 'tutu', Y nom 'toto' WHERE X nom 'toto', Y nom 'tutu'") - self.assertEqual(self.execute('Any X WHERE X nom "toto"').rows, [[peid1]]) - self.assertEqual(self.execute('Any X WHERE X nom "tutu"').rows, [[peid2]]) + peid1 = self.qexecute("INSERT Personne Y: Y nom 'tutu'")[0][0] + peid2 = self.qexecute("INSERT Personne Y: Y nom 'toto'")[0][0] + self.qexecute("SET X nom 'tutu', Y nom 'toto' WHERE X nom 'toto', Y nom 'tutu'") + self.assertEqual(self.qexecute('Any X WHERE X nom "toto"').rows, [[peid1]]) + self.assertEqual(self.qexecute('Any X WHERE X nom "tutu"').rows, [[peid2]]) def test_update_multiple2(self): - ueid = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")[0][0] - peid1 = self.execute("INSERT Personne Y: Y nom 'turlu'")[0][0] - peid2 = self.execute("INSERT Personne Y: Y nom 'tutu'")[0][0] - self.execute('SET P1 owned_by U, P2 owned_by U ' - 'WHERE P1 eid %s, P2 eid %s, U eid %s' % (peid1, peid2, ueid)) - self.assertTrue(self.execute('Any X WHERE X eid %s, X owned_by U, U eid %s' - % (peid1, ueid))) - self.assertTrue(self.execute('Any X WHERE X eid %s, X owned_by U, U eid %s' - % (peid2, ueid))) + with self.session.new_cnx() as cnx: + ueid = cnx.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")[0][0] + peid1 = cnx.execute("INSERT Personne Y: Y nom 'turlu'")[0][0] + peid2 = cnx.execute("INSERT Personne Y: Y nom 'tutu'")[0][0] + cnx.execute('SET P1 owned_by U, P2 owned_by U ' + 'WHERE P1 eid %s, P2 eid %s, U eid %s' % (peid1, peid2, ueid)) + self.assertTrue(cnx.execute('Any X WHERE X eid %s, X owned_by U, U eid %s' + % (peid1, ueid))) + self.assertTrue(cnx.execute('Any X WHERE X eid %s, X owned_by U, U eid %s' + % (peid2, ueid))) def test_update_math_expr(self): - orders = [r[0] for r in self.execute('Any O ORDERBY O WHERE ST name "Personne", X from_entity ST, X ordernum O')] + orders = [r[0] for r in self.qexecute('Any O ORDERBY O WHERE ST name "Personne", ' + 'X from_entity ST, X ordernum O')] for i,v in enumerate(orders): if v != orders[0]: splitidx = i break - self.execute('SET X ordernum Y+1 WHERE X from_entity SE, SE name "Personne", X ordernum Y, X ordernum >= %(order)s', + self.qexecute('SET X ordernum Y+1 WHERE X from_entity SE, SE name "Personne", ' + 'X ordernum Y, X ordernum >= %(order)s', {'order': orders[splitidx]}) - orders2 = [r[0] for r in self.execute('Any O ORDERBY O WHERE ST name "Personne", X from_entity ST, X ordernum O')] + orders2 = [r[0] for r in self.qexecute('Any O ORDERBY O WHERE ST name "Personne", ' + 'X from_entity ST, X ordernum O')] orders = orders[:splitidx] + [o+1 for o in orders[splitidx:]] self.assertEqual(orders2, orders) def test_update_string_concat(self): - beid = self.execute("INSERT Bookmark Y: Y title 'toto', Y path '/view'")[0][0] - self.execute('SET X title XN + %(suffix)s WHERE X is Bookmark, X title XN', {'suffix': u'-moved'}) - newname = self.execute('Any XN WHERE X eid %(x)s, X title XN', {'x': beid})[0][0] + beid = self.qexecute("INSERT Bookmark Y: Y title 'toto', Y path '/view'")[0][0] + self.qexecute('SET X title XN + %(suffix)s WHERE X is Bookmark, X title XN', + {'suffix': u'-moved'}) + newname = self.qexecute('Any XN WHERE X eid %(x)s, X title XN', {'x': beid})[0][0] self.assertEqual(newname, 'toto-moved') def test_update_not_exists(self): - rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") + rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") eid1, eid2 = rset[0][0], rset[0][1] - rset = self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, " + rset = self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, " "NOT EXISTS(Z ecrit_par X)", {'x': unicode(eid1), 'y': unicode(eid2)}) self.assertEqual(tuplify(rset.rows), [(eid1, eid2)]) def test_update_query_error(self): - self.execute("INSERT Personne Y: Y nom 'toto'") - self.assertRaises(Exception, self.execute, "SET X nom 'toto', X is Personne") - self.assertRaises(QueryError, self.execute, "SET X nom 'toto', X has_text 'tutu' WHERE X is Personne") - self.assertRaises(QueryError, self.execute, "SET X login 'tutu', X eid %s" % cnx.user(self.session).eid) + self.qexecute("INSERT Personne Y: Y nom 'toto'") + self.assertRaises(Exception, self.qexecute, "SET X nom 'toto', X is Personne") + self.assertRaises(QueryError, self.qexecute, "SET X nom 'toto', X has_text 'tutu' " + "WHERE X is Personne") + self.assertRaises(QueryError, + self.qexecute, + "SET X login 'tutu', X eid %s" % cnx.user(self.session).eid) # HAVING on write queries test ############################################# def test_update_having(self): - peid1 = self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0] - peid2 = self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2")[0][0] - rset = self.execute("SET X tel 3 WHERE X tel TEL HAVING TEL&1=1") + peid1 = self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0] + peid2 = self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 2")[0][0] + rset = self.qexecute("SET X tel 3 WHERE X tel TEL HAVING TEL&1=1") self.assertEqual(tuplify(rset.rows), [(peid1, 3)]) def test_insert_having(self): self.skipTest('unsupported yet') - self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0] - self.assertFalse(self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2 WHERE X tel XT HAVING XT&2=2")) - self.assertTrue(self.execute("INSERT Personne Y: Y nom 'hop', Y tel 2 WHERE X tel XT HAVING XT&1=1")) + self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0] + self.assertFalse(self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 2 " + "WHERE X tel XT HAVING XT&2=2")) + self.assertTrue(self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 2 " + "WHERE X tel XT HAVING XT&1=1")) def test_delete_having(self): - self.execute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0] - self.assertFalse(self.execute("DELETE Personne Y WHERE X tel XT HAVING XT&2=2")) - self.assertTrue(self.execute("DELETE Personne Y WHERE X tel XT HAVING XT&1=1")) + self.qexecute("INSERT Personne Y: Y nom 'hop', Y tel 1")[0][0] + self.assertFalse(self.qexecute("DELETE Personne Y WHERE X tel XT HAVING XT&2=2")) + self.assertTrue(self.qexecute("DELETE Personne Y WHERE X tel XT HAVING XT&1=1")) # upassword encryption tests ################################################# def test_insert_upassword(self): - rset = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'") + rset = self.qexecute("INSERT CWUser X: X login 'bob', X upassword 'toto', " + "X in_group G WHERE G name 'users'") self.assertEqual(len(rset.rows), 1) self.assertEqual(rset.description, [('CWUser',)]) self.assertRaises(Unauthorized, - self.execute, "Any P WHERE X is CWUser, X login 'bob', X upassword P") - cursor = self.cnxset.cu - cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" - % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) - passwd = str(cursor.fetchone()[0]) - self.assertEqual(passwd, crypt_password('toto', passwd)) - rset = self.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", + self.qexecute, "Any P WHERE X is CWUser, X login 'bob', X upassword P") + with self.session.new_cnx() as cnx: + with cnx.ensure_cnx_set: + cursor = cnx.cnxset.cu + cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" + % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) + passwd = str(cursor.fetchone()[0]) + self.assertEqual(passwd, crypt_password('toto', passwd)) + rset = self.qexecute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", {'pwd': Binary(passwd)}) self.assertEqual(len(rset.rows), 1) self.assertEqual(rset.description, [('CWUser',)]) def test_update_upassword(self): - rset = self.execute("INSERT CWUser X: X login 'bob', X upassword %(pwd)s", {'pwd': 'toto'}) - self.assertEqual(rset.description[0][0], 'CWUser') - rset = self.execute("SET X upassword %(pwd)s WHERE X is CWUser, X login 'bob'", - {'pwd': 'tutu'}) - cursor = self.cnxset.cu - cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" - % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) - passwd = str(cursor.fetchone()[0]) - self.assertEqual(passwd, crypt_password('tutu', passwd)) - rset = self.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", - {'pwd': Binary(passwd)}) - self.assertEqual(len(rset.rows), 1) - self.assertEqual(rset.description, [('CWUser',)]) + with self.session.new_cnx() as cnx: + with cnx.ensure_cnx_set: + rset = cnx.execute("INSERT CWUser X: X login 'bob', X upassword %(pwd)s", + {'pwd': 'toto'}) + self.assertEqual(rset.description[0][0], 'CWUser') + rset = cnx.execute("SET X upassword %(pwd)s WHERE X is CWUser, X login 'bob'", + {'pwd': 'tutu'}) + cursor = cnx.cnxset.cu + cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" + % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) + passwd = str(cursor.fetchone()[0]) + self.assertEqual(passwd, crypt_password('tutu', passwd)) + rset = cnx.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", + {'pwd': Binary(passwd)}) + self.assertEqual(len(rset.rows), 1) + self.assertEqual(rset.description, [('CWUser',)]) # ZT datetime tests ######################################################## def test_tz_datetime(self): - self.execute("INSERT Personne X: X nom 'bob', X tzdatenaiss %(date)s", + self.qexecute("INSERT Personne X: X nom 'bob', X tzdatenaiss %(date)s", {'date': datetime(1977, 6, 7, 2, 0, tzinfo=FixedOffset(1))}) - datenaiss = self.execute("Any XD WHERE X nom 'bob', X tzdatenaiss XD")[0][0] + datenaiss = self.qexecute("Any XD WHERE X nom 'bob', X tzdatenaiss XD")[0][0] self.assertEqual(datenaiss.tzinfo, None) self.assertEqual(datenaiss.utctimetuple()[:5], (1977, 6, 7, 1, 0)) # non regression tests ##################################################### def test_nonregr_1(self): - teid = self.execute("INSERT Tag X: X name 'tag'")[0][0] - self.execute("SET X tags Y WHERE X name 'tag', Y is State, Y name 'activated'") - rset = self.execute('Any X WHERE T tags X') + teid = self.qexecute("INSERT Tag X: X name 'tag'")[0][0] + self.qexecute("SET X tags Y WHERE X name 'tag', Y is State, Y name 'activated'") + rset = self.qexecute('Any X WHERE T tags X') self.assertEqual(len(rset.rows), 1, rset.rows) - rset = self.execute('Any T WHERE T tags X, X is State') + rset = self.qexecute('Any T WHERE T tags X, X is State') self.assertEqual(rset.rows, [[teid]]) - rset = self.execute('Any T WHERE T tags X') + rset = self.qexecute('Any T WHERE T tags X') self.assertEqual(rset.rows, [[teid]]) def test_nonregr_2(self): - teid = self.execute("INSERT Tag X: X name 'tag'")[0][0] - geid = self.execute("CWGroup G WHERE G name 'users'")[0][0] - self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s", + teid = self.qexecute("INSERT Tag X: X name 'tag'")[0][0] + geid = self.qexecute("CWGroup G WHERE G name 'users'")[0][0] + self.qexecute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s", {'g': geid, 't': teid}) - rset = self.execute('Any X WHERE E eid %(x)s, E tags X', + rset = self.qexecute('Any X WHERE E eid %(x)s, E tags X', {'x': teid}) self.assertEqual(rset.rows, [[geid]]) @@ -1357,7 +1425,7 @@ """bad sql generated on the second query (destination_state is not detected as an inlined relation) """ - rset = self.execute('Any S,ES,T WHERE S state_of WF, WF workflow_of ET, ET name "CWUser",' + rset = self.qexecute('Any S,ES,T WHERE S state_of WF, WF workflow_of ET, ET name "CWUser",' 'ES allowed_transition T, T destination_state S') self.assertEqual(len(rset.rows), 2) @@ -1365,26 +1433,28 @@ # fix variables'type, else we get (nb of entity types with a 'name' attribute)**3 # union queries and that make for instance a 266Ko sql query which is refused # by the server (or client lib) - rset = self.execute('Any ER,SE,OE WHERE SE name "Comment", ER name "comments", OE name "Comment",' + rset = self.qexecute('Any ER,SE,OE WHERE SE name "Comment", ER name "comments", OE name "Comment",' 'ER is CWRType, SE is CWEType, OE is CWEType') self.assertEqual(len(rset), 1) def test_nonregr_5(self): # jpl #15505: equivalent queries returning different result sets - teid1 = self.execute("INSERT Folder X: X name 'hop'")[0][0] - teid2 = self.execute("INSERT Folder X: X name 'hip'")[0][0] - neid = self.execute("INSERT Note X: X todo_by U, X filed_under T WHERE U login 'admin', T name 'hop'")[0][0] - weid = self.execute("INSERT Affaire X: X concerne N, X filed_under T WHERE N is Note, T name 'hip'")[0][0] - rset1 = self.execute('Any N,U WHERE N filed_under T, T eid %s,' + teid1 = self.qexecute("INSERT Folder X: X name 'hop'")[0][0] + teid2 = self.qexecute("INSERT Folder X: X name 'hip'")[0][0] + neid = self.qexecute("INSERT Note X: X todo_by U, X filed_under T " + "WHERE U login 'admin', T name 'hop'")[0][0] + weid = self.qexecute("INSERT Affaire X: X concerne N, X filed_under T " + "WHERE N is Note, T name 'hip'")[0][0] + rset1 = self.qexecute('Any N,U WHERE N filed_under T, T eid %s,' 'N todo_by U, W concerne N,' 'W is Affaire, W filed_under A, A eid %s' % (teid1, teid2)) - rset2 = self.execute('Any N,U WHERE N filed_under T, T eid %s,' + rset2 = self.qexecute('Any N,U WHERE N filed_under T, T eid %s,' 'N todo_by U, W concerne N,' 'W filed_under A, A eid %s' % (teid1, teid2)) - rset3 = self.execute('Any N,U WHERE N todo_by U, T eid %s,' + rset3 = self.qexecute('Any N,U WHERE N todo_by U, T eid %s,' 'N filed_under T, W concerne N,' 'W is Affaire, W filed_under A, A eid %s' % (teid1, teid2)) - rset4 = self.execute('Any N,U WHERE N todo_by U, T eid %s,' + rset4 = self.qexecute('Any N,U WHERE N todo_by U, T eid %s,' 'N filed_under T, W concerne N,' 'W filed_under A, A eid %s' % (teid1, teid2)) self.assertEqual(rset1.rows, rset2.rows) @@ -1392,19 +1462,19 @@ self.assertEqual(rset1.rows, rset4.rows) def test_nonregr_6(self): - self.execute('Any N,COUNT(S) GROUPBY N ORDERBY COUNT(N) WHERE S name N, S is State') + self.qexecute('Any N,COUNT(S) GROUPBY N ORDERBY COUNT(N) WHERE S name N, S is State') def test_sqlite_encoding(self): """XXX this test was trying to show a bug on use of lower which only occurs with non ascii string and misconfigured locale """ - self.execute("INSERT Tag X: X name %(name)s," + self.qexecute("INSERT Tag X: X name %(name)s," "X modification_date %(modification_date)s," "X creation_date %(creation_date)s", {'name': u'éname0', 'modification_date': '2003/03/12 11:00', 'creation_date': '2000/07/03 11:00'}) - rset = self.execute('Any lower(N) ORDERBY LOWER(N) WHERE X is Tag, X name N,' + rset = self.qexecute('Any lower(N) ORDERBY LOWER(N) WHERE X is Tag, X name N,' 'X owned_by U, U eid %(x)s', {'x':self.session.user.eid}) self.assertEqual(rset.rows, [[u'\xe9name0']]) @@ -1415,35 +1485,34 @@ solutions may be "fusionned" into one by the querier while all solutions are needed to build the result's description """ - self.execute("INSERT Personne X: X nom 'bidule'") - self.execute("INSERT Societe Y: Y nom 'toto'") - beid = self.execute("INSERT Basket B: B name 'mybasket'")[0][0] - self.execute("SET X in_basket B WHERE X is Personne") - self.execute("SET X in_basket B WHERE X is Societe") - rset = self.execute('Any X WHERE X in_basket B, B eid %s' % beid) + self.qexecute("INSERT Personne X: X nom 'bidule'") + self.qexecute("INSERT Societe Y: Y nom 'toto'") + beid = self.qexecute("INSERT Basket B: B name 'mybasket'")[0][0] + self.qexecute("SET X in_basket B WHERE X is Personne") + self.qexecute("SET X in_basket B WHERE X is Societe") + rset = self.qexecute('Any X WHERE X in_basket B, B eid %s' % beid) self.assertEqual(len(rset), 2) self.assertEqual(rset.description, [('Personne',), ('Societe',)]) def test_nonregr_cache_1(self): - peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - beid = self.execute("INSERT Basket X: X name 'tag'")[0][0] - self.execute("SET X in_basket Y WHERE X is Personne, Y eid %(y)s", + peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + beid = self.qexecute("INSERT Basket X: X name 'tag'")[0][0] + self.qexecute("SET X in_basket Y WHERE X is Personne, Y eid %(y)s", {'y': beid}) - rset = self.execute("Any X WHERE X in_basket B, B eid %(x)s", + rset = self.qexecute("Any X WHERE X in_basket B, B eid %(x)s", {'x': beid}) self.assertEqual(rset.rows, [[peid]]) - rset = self.execute("Any X WHERE X in_basket B, B eid %(x)s", + rset = self.qexecute("Any X WHERE X in_basket B, B eid %(x)s", {'x': beid}) self.assertEqual(rset.rows, [[peid]]) def test_nonregr_has_text_cache(self): - eid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - eid2 = self.execute("INSERT Personne X: X nom 'tag'")[0][0] - self.commit() - rset = self.execute("Any X WHERE X has_text %(text)s", {'text': 'bidule'}) + eid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + eid2 = self.qexecute("INSERT Personne X: X nom 'tag'")[0][0] + rset = self.qexecute("Any X WHERE X has_text %(text)s", {'text': 'bidule'}) self.assertEqual(rset.rows, [[eid1]]) - rset = self.execute("Any X WHERE X has_text %(text)s", {'text': 'tag'}) + rset = self.qexecute("Any X WHERE X has_text %(text)s", {'text': 'tag'}) self.assertEqual(rset.rows, [[eid2]]) def test_nonregr_sortterm_management(self): @@ -1454,133 +1523,133 @@ need sqlite including http://www.sqlite.org/cvstrac/tktview?tn=3773 fix """ - self.execute('Any X ORDERBY D DESC WHERE X creation_date D') + self.qexecute('Any X ORDERBY D DESC WHERE X creation_date D') def test_nonregr_extra_joins(self): ueid = self.session.user.eid - teid1 = self.execute("INSERT Folder X: X name 'folder1'")[0][0] - teid2 = self.execute("INSERT Folder X: X name 'folder2'")[0][0] - neid1 = self.execute("INSERT Note X: X para 'note1'")[0][0] - neid2 = self.execute("INSERT Note X: X para 'note2'")[0][0] - self.execute("SET X filed_under Y WHERE X eid %s, Y eid %s" + teid1 = self.qexecute("INSERT Folder X: X name 'folder1'")[0][0] + teid2 = self.qexecute("INSERT Folder X: X name 'folder2'")[0][0] + neid1 = self.qexecute("INSERT Note X: X para 'note1'")[0][0] + neid2 = self.qexecute("INSERT Note X: X para 'note2'")[0][0] + self.qexecute("SET X filed_under Y WHERE X eid %s, Y eid %s" % (neid1, teid1)) - self.execute("SET X filed_under Y WHERE X eid %s, Y eid %s" + self.qexecute("SET X filed_under Y WHERE X eid %s, Y eid %s" % (neid2, teid2)) - self.execute("SET X todo_by Y WHERE X is Note, Y eid %s" % ueid) - rset = self.execute('Any N WHERE N todo_by U, N is Note, U eid %s, N filed_under T, T eid %s' + self.qexecute("SET X todo_by Y WHERE X is Note, Y eid %s" % ueid) + rset = self.qexecute('Any N WHERE N todo_by U, N is Note, U eid %s, N filed_under T, T eid %s' % (ueid, teid1)) self.assertEqual(len(rset), 1) def test_nonregr_XXX(self): - teid = self.execute('Transition S WHERE S name "deactivate"')[0][0] - rset = self.execute('Any O WHERE O is State, ' + teid = self.qexecute('Transition S WHERE S name "deactivate"')[0][0] + rset = self.qexecute('Any O WHERE O is State, ' 'S eid %(x)s, S transition_of ET, O state_of ET', {'x': teid}) self.assertEqual(len(rset), 2) - rset = self.execute('Any O WHERE O is State, NOT S destination_state O, ' + rset = self.qexecute('Any O WHERE O is State, NOT S destination_state O, ' 'S eid %(x)s, S transition_of ET, O state_of ET', {'x': teid}) self.assertEqual(len(rset), 1) def test_nonregr_set_datetime(self): # huum, psycopg specific - self.execute('SET X creation_date %(date)s WHERE X eid 1', {'date': date.today()}) - - def test_nonregr_set_query(self): - ueid = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto'")[0][0] - self.execute("SET E in_group G, E firstname %(firstname)s, E surname %(surname)s " - "WHERE E eid %(x)s, G name 'users'", - {'x':ueid, 'firstname': u'jean', 'surname': u'paul'}) + self.qexecute('SET X creation_date %(date)s WHERE X eid 1', {'date': date.today()}) def test_nonregr_u_owned_by_u(self): - ueid = self.execute("INSERT CWUser X: X login 'bob', X upassword 'toto', X in_group G " + ueid = self.qexecute("INSERT CWUser X: X login 'bob', X upassword 'toto', X in_group G " "WHERE G name 'users'")[0][0] - rset = self.execute("CWUser U") + rset = self.qexecute("CWUser U") self.assertEqual(len(rset), 3) # bob + admin + anon - rset = self.execute("Any U WHERE NOT U owned_by U") - self.assertEqual(len(rset), 0) # even admin created at repo initialization time should belong to itself + rset = self.qexecute("Any U WHERE NOT U owned_by U") + # even admin created at repo initialization time should belong to itself + self.assertEqual(len(rset), 0) def test_nonreg_update_index(self): # this is the kind of queries generated by "cubicweb-ctl db-check -ry" - self.execute("SET X description D WHERE X is State, X description D") + self.qexecute("SET X description D WHERE X is State, X description D") def test_nonregr_is(self): - uteid = self.execute('Any ET WHERE ET name "CWUser"')[0][0] - self.execute('Any X, ET WHERE X is ET, ET eid %s' % uteid) + uteid = self.qexecute('Any ET WHERE ET name "CWUser"')[0][0] + self.qexecute('Any X, ET WHERE X is ET, ET eid %s' % uteid) def test_nonregr_orderby(self): - seid = self.execute('Any X WHERE X name "activated"')[0][0] - self.execute('Any X,S, MAX(T) GROUPBY X,S ORDERBY S WHERE X is CWUser, T tags X, S eid IN(%s), X in_state S' % seid) + seid = self.qexecute('Any X WHERE X name "activated"')[0][0] + self.qexecute('Any X,S, MAX(T) GROUPBY X,S ORDERBY S ' + 'WHERE X is CWUser, T tags X, S eid IN(%s), X in_state S' % seid) def test_nonregr_solution_cache(self): self.skipTest('XXX should be fixed or documented') # (doesn't occur if cache key is provided.) - rset = self.execute('Any X WHERE X is CWUser, X eid %(x)s', {'x':self.ueid}) + rset = self.qexecute('Any X WHERE X is CWUser, X eid %(x)s', {'x':self.ueid}) self.assertEqual(len(rset), 1) - rset = self.execute('Any X WHERE X is CWUser, X eid %(x)s', {'x':12345}) + rset = self.qexecute('Any X WHERE X is CWUser, X eid %(x)s', {'x':12345}) self.assertEqual(len(rset), 0) def test_nonregr_final_norestr(self): - self.assertRaises(BadRQLQuery, self.execute, 'Date X') + self.assertRaises(BadRQLQuery, self.qexecute, 'Date X') def test_nonregr_eid_cmp(self): - peid1 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - peid2 = self.execute("INSERT Personne X: X nom 'bidule'")[0][0] - rset = self.execute('Any X,Y WHERE X is Personne, Y is Personne, X nom XD, Y nom XD, X eid Z, Y eid > Z') + peid1 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + peid2 = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] + rset = self.qexecute('Any X,Y WHERE X is Personne, Y is Personne, ' + 'X nom XD, Y nom XD, X eid Z, Y eid > Z') self.assertEqual(rset.rows, [[peid1, peid2]]) - rset = self.execute('Any X,Y WHERE X nom XD, Y nom XD, X eid Z, Y eid > Z') + rset = self.qexecute('Any X,Y WHERE X nom XD, Y nom XD, X eid Z, Y eid > Z') self.assertEqual(rset.rows, [[peid1, peid2]]) def test_nonregr_has_text_ambiguity_1(self): - peid = self.execute("INSERT CWUser X: X login 'bidule', X upassword 'bidule', X in_group G WHERE G name 'users'")[0][0] - aeid = self.execute("INSERT Affaire X: X ref 'bidule'")[0][0] - self.commit() - rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule"') + peid = self.qexecute("INSERT CWUser X: X login 'bidule', X upassword 'bidule', " + "X in_group G WHERE G name 'users'")[0][0] + aeid = self.qexecute("INSERT Affaire X: X ref 'bidule'")[0][0] + rset = self.qexecute('Any X WHERE X is CWUser, X has_text "bidule"') self.assertEqual(rset.rows, [[peid]]) - rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule", X in_state S, S name SN') + rset = self.qexecute('Any X WHERE X is CWUser, X has_text "bidule", ' + 'X in_state S, S name SN') self.assertEqual(rset.rows, [[peid]]) def test_nonregr_sql_cache(self): # different SQL generated when 'name' is None or not (IS NULL). - self.assertFalse(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': None})) - self.assertTrue(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': 'CWEType'})) + self.assertFalse(self.qexecute('Any X WHERE X is CWEType, X name %(name)s', + {'name': None})) + self.assertTrue(self.qexecute('Any X WHERE X is CWEType, X name %(name)s', + {'name': 'CWEType'})) class NonRegressionTC(CubicWebTC): def test_has_text_security_cache_bug(self): - req = self.request() - self.create_user(req, 'user', ('users',)) - aff1 = req.create_entity('Societe', nom=u'aff1') - aff2 = req.create_entity('Societe', nom=u'aff2') - self.commit() - with self.login('user', password='user'): - res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff1'}) + with self.admin_access.repo_cnx() as cnx: + self.create_user(cnx, 'user', ('users',)) + aff1 = cnx.create_entity('Societe', nom=u'aff1') + aff2 = cnx.create_entity('Societe', nom=u'aff2') + cnx.commit() + with self.new_access('user').repo_cnx() as cnx: + res = cnx.execute('Any X WHERE X has_text %(text)s', {'text': 'aff1'}) self.assertEqual(res.rows, [[aff1.eid]]) - res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'}) + res = cnx.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'}) self.assertEqual(res.rows, [[aff2.eid]]) def test_set_relations_eid(self): - req = self.request() - # create 3 email addresses - a1 = req.create_entity('EmailAddress', address=u'a1') - a2 = req.create_entity('EmailAddress', address=u'a2') - a3 = req.create_entity('EmailAddress', address=u'a3') - # SET relations using '>=' operator on eids - req.execute('SET U use_email A WHERE U login "admin", A eid >= %s' % a2.eid) - self.assertEqual( - [[a2.eid], [a3.eid]], - req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows) - # DELETE - req.execute('DELETE U use_email A WHERE U login "admin", A eid > %s' % a2.eid) - self.assertEqual( - [[a2.eid]], - req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows) - req.execute('DELETE U use_email A WHERE U login "admin"') - # SET relations using '<' operator on eids - req.execute('SET U use_email A WHERE U login "admin", A eid < %s' % a2.eid) - self.assertEqual( - [[a1.eid]], - req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows) + with self.admin_access.repo_cnx() as cnx: + # create 3 email addresses + a1 = cnx.create_entity('EmailAddress', address=u'a1') + a2 = cnx.create_entity('EmailAddress', address=u'a2') + a3 = cnx.create_entity('EmailAddress', address=u'a3') + # SET relations using '>=' operator on eids + cnx.execute('SET U use_email A WHERE U login "admin", A eid >= %s' % a2.eid) + self.assertEqual( + [[a2.eid], [a3.eid]], + cnx.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows) + # DELETE + cnx.execute('DELETE U use_email A WHERE U login "admin", A eid > %s' % a2.eid) + self.assertEqual( + [[a2.eid]], + cnx.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows) + cnx.execute('DELETE U use_email A WHERE U login "admin"') + # SET relations using '<' operator on eids + cnx.execute('SET U use_email A WHERE U login "admin", A eid < %s' % a2.eid) + self.assertEqual( + [[a1.eid]], + cnx.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows) if __name__ == '__main__': unittest_main() diff -r 928732ec00dd -r fa44db7da2dc server/test/unittest_rqlannotation.py --- a/server/test/unittest_rqlannotation.py Thu Jul 17 11:08:56 2014 +0200 +++ b/server/test/unittest_rqlannotation.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -21,340 +21,424 @@ from cubicweb.devtools import TestServerConfiguration, get_test_db_handler from cubicweb.devtools.repotest import BaseQuerierTC - -def setUpModule(*args): - handler = get_test_db_handler(TestServerConfiguration( - 'data2', apphome=SQLGenAnnotatorTC.datadir)) - handler.build_db_cache() - global repo, cnx - repo, cnx = handler.get_repo_and_cnx() - -def tearDownModule(*args): - global repo, cnx - del repo, cnx - - class SQLGenAnnotatorTC(BaseQuerierTC): def setUp(self): + handler = get_test_db_handler(TestServerConfiguration( + 'data2', apphome=SQLGenAnnotatorTC.datadir)) + handler.build_db_cache() + repo, _cnx = handler.get_repo_and_cnx() self.__class__.repo = repo super(SQLGenAnnotatorTC, self).setUp() def get_max_eid(self): # no need for cleanup here return None + def cleanup(self): # no need for cleanup here pass def test_0_1(self): - rqlst = self._prepare('Any SEN,RN,OEN WHERE X from_entity SE, SE eid 44, X relation_type R, R eid 139, X to_entity OE, OE eid 42, R name RN, SE name SEN, OE name OEN') - self.assertEqual(rqlst.defined_vars['SE']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['OE']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['R']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['SE'].stinfo['attrvar'], None) - self.assertEqual(rqlst.defined_vars['OE'].stinfo['attrvar'], None) - self.assertEqual(rqlst.defined_vars['R'].stinfo['attrvar'], None) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any SEN,RN,OEN WHERE X from_entity SE, ' + 'SE eid 44, X relation_type R, R eid 139, ' + 'X to_entity OE, OE eid 42, R name RN, SE name SEN, ' + 'OE name OEN') + self.assertEqual(rqlst.defined_vars['SE']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['OE']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['R']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['SE'].stinfo['attrvar'], None) + self.assertEqual(rqlst.defined_vars['OE'].stinfo['attrvar'], None) + self.assertEqual(rqlst.defined_vars['R'].stinfo['attrvar'], None) def test_0_2(self): - rqlst = self._prepare('Any O WHERE NOT S ecrit_par O, S eid 1, S inline1 P, O inline2 P') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['O'].stinfo['attrvar'], None) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any O WHERE NOT S ecrit_par O, S eid 1, ' + 'S inline1 P, O inline2 P') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['O'].stinfo['attrvar'], None) def test_0_4(self): - rqlst = self._prepare('Any A,B,C WHERE A eid 12,A comment B, A ?wf_info_for C') - self.assertEqual(rqlst.defined_vars['A']._q_invariant, False) - self.assert_(rqlst.defined_vars['B'].stinfo['attrvar']) - self.assertEqual(rqlst.defined_vars['C']._q_invariant, False) - self.assertEqual(rqlst.solutions, [{'A': 'TrInfo', 'B': 'String', 'C': 'Affaire'}, - {'A': 'TrInfo', 'B': 'String', 'C': 'CWUser'}, - {'A': 'TrInfo', 'B': 'String', 'C': 'Note'}]) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any A,B,C WHERE A eid 12,A comment B, ' + 'A ?wf_info_for C') + self.assertEqual(rqlst.defined_vars['A']._q_invariant, False) + self.assert_(rqlst.defined_vars['B'].stinfo['attrvar']) + self.assertEqual(rqlst.defined_vars['C']._q_invariant, False) + self.assertEqual(rqlst.solutions, [{'A': 'TrInfo', 'B': 'String', 'C': 'Affaire'}, + {'A': 'TrInfo', 'B': 'String', 'C': 'CWUser'}, + {'A': 'TrInfo', 'B': 'String', 'C': 'Note'}]) def test_0_5(self): - rqlst = self._prepare('Any P WHERE N ecrit_par P, N eid 0') - self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['P']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any P WHERE N ecrit_par P, N eid 0') + self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['P']._q_invariant, True) def test_0_6(self): - rqlst = self._prepare('Any P WHERE NOT N ecrit_par P, N eid 512') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any P WHERE NOT N ecrit_par P, N eid 512') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) def test_0_7(self): - rqlst = self._prepare('Personne X,Y where X nom NX, Y nom NX, X eid XE, not Y eid XE') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) - self.assert_(rqlst.defined_vars['XE'].stinfo['attrvar']) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Personne X,Y where X nom NX, ' + 'Y nom NX, X eid XE, not Y eid XE') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + self.assert_(rqlst.defined_vars['XE'].stinfo['attrvar']) def test_0_8(self): - rqlst = self._prepare('Any P WHERE X eid 0, NOT X connait P') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) - #self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) - self.assertEqual(len(rqlst.solutions), 1, rqlst.solutions) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any P WHERE X eid 0, NOT X connait P') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) + #self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + self.assertEqual(len(rqlst.solutions), 1, rqlst.solutions) def test_0_10(self): - rqlst = self._prepare('Any X WHERE X concerne Y, Y is Note') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X concerne Y, Y is Note') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_0_11(self): - rqlst = self._prepare('Any X WHERE X todo_by Y, X is Affaire') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X todo_by Y, X is Affaire') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_0_12(self): - rqlst = self._prepare('Personne P WHERE P concerne A, A concerne S, S nom "Logilab"') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['A']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Personne P WHERE P concerne A, ' + 'A concerne S, S nom "Logilab"') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['A']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) def test_1_0(self): - rqlst = self._prepare('Any X,Y WHERE X created_by Y, X eid 5, NOT Y eid 6') - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,Y WHERE X created_by Y, ' + 'X eid 5, NOT Y eid 6') + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_1_1(self): - rqlst = self._prepare('Any X,Y WHERE X created_by Y, X eid 5, NOT Y eid IN (6,7)') - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,Y WHERE X created_by Y, X eid 5, ' + 'NOT Y eid IN (6,7)') + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_2(self): - rqlst = self._prepare('Any X WHERE X identity Y, Y eid 1') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X identity Y, Y eid 1') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) def test_7(self): - rqlst = self._prepare('Personne X,Y where X nom NX, Y nom NX, X eid XE, not Y eid XE') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Personne X,Y where X nom NX, Y nom NX, ' + 'X eid XE, not Y eid XE') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_8(self): - # DISTINCT Any P WHERE P require_group %(g)s, NOT %(u)s has_group_permission P, P is CWPermission - rqlst = self._prepare('DISTINCT Any X WHERE A concerne X, NOT N migrated_from X, ' - 'X is Note, N eid 1') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + with self.session.new_cnx() as cnx: + # DISTINCT Any P WHERE P require_group %(g)s, + # NOT %(u)s has_group_permission P, P is CWPermission + rqlst = self._prepare(cnx, 'DISTINCT Any X WHERE A concerne X, ' + 'NOT N migrated_from X, ' + 'X is Note, N eid 1') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) def test_diff_scope_identity_deamb(self): - rqlst = self._prepare('Any X WHERE X concerne Y, Y is Note, EXISTS(Y identity Z, Z migrated_from N)') - self.assertEqual(rqlst.defined_vars['Z']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X concerne Y, Y is Note, ' + 'EXISTS(Y identity Z, Z migrated_from N)') + self.assertEqual(rqlst.defined_vars['Z']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_optional_inlined(self): - rqlst = self._prepare('Any X,S where X from_state S?') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,S where X from_state S?') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) def test_optional_inlined_2(self): - rqlst = self._prepare('Any N,A WHERE N? inline1 A') - self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['A']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any N,A WHERE N? inline1 A') + self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['A']._q_invariant, False) def test_optional_1(self): - rqlst = self._prepare('Any X,S WHERE X travaille S?') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,S WHERE X travaille S?') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) def test_greater_eid(self): - rqlst = self._prepare('Any X WHERE X eid > 5') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X eid > 5') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_greater_eid_typed(self): - rqlst = self._prepare('Any X WHERE X eid > 5, X is Note') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X eid > 5, X is Note') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_max_eid(self): - rqlst = self._prepare('Any MAX(X)') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any MAX(X)') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_max_eid_typed(self): - rqlst = self._prepare('Any MAX(X) WHERE X is Note') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any MAX(X) WHERE X is Note') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) def test_all_entities(self): - rqlst = self._prepare('Any X') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_all_typed_entity(self): - rqlst = self._prepare('Any X WHERE X is Note') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X is Note') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) def test_has_text_1(self): - rqlst = self._prepare('Any X WHERE X has_text "toto tata"') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'has_text') + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X has_text "toto tata"') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, + 'has_text') def test_has_text_2(self): - rqlst = self._prepare('Any X WHERE X is Personne, X has_text "coucou"') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'has_text') + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X is Personne, ' + 'X has_text "coucou"') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, + 'has_text') def test_not_relation_1(self): - # P can't be invariant since deambiguification caused by "NOT X require_permission P" - # is not considered by generated sql (NOT EXISTS(...)) - rqlst = self._prepare('Any P,G WHERE P require_group G, NOT X require_permission P') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['G']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + # P can't be invariant since deambiguification caused by "NOT X require_permission P" + # is not considered by generated sql (NOT EXISTS(...)) + rqlst = self._prepare(cnx, 'Any P,G WHERE P require_group G, ' + 'NOT X require_permission P') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['G']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_not_relation_2(self): - rqlst = self._prepare('TrInfo X WHERE X eid 2, NOT X from_state Y, Y is State') - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'TrInfo X WHERE X eid 2, ' + 'NOT X from_state Y, Y is State') + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) def test_not_relation_3(self): - rqlst = self._prepare('Any X, Y WHERE X eid 1, Y eid in (2, 3)') - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X, Y WHERE X eid 1, Y eid in (2, 3)') + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_not_relation_4_1(self): - rqlst = self._prepare('Note X WHERE NOT Y evaluee X') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Note X WHERE NOT Y evaluee X') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_not_relation_4_2(self): - rqlst = self._prepare('Any X WHERE NOT Y evaluee X') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE NOT Y evaluee X') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_not_relation_4_3(self): - rqlst = self._prepare('Any Y WHERE NOT Y evaluee X') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any Y WHERE NOT Y evaluee X') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_not_relation_4_4(self): - rqlst = self._prepare('Any X WHERE NOT Y evaluee X, Y is CWUser') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE NOT Y evaluee X, Y is CWUser') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_not_relation_4_5(self): - rqlst = self._prepare('Any X WHERE NOT Y evaluee X, Y eid %s, X is Note' % self.ueid) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.solutions, [{'X': 'Note'}]) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE NOT Y evaluee X, ' + 'Y eid %s, X is Note' % self.ueid) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.solutions, [{'X': 'Note'}]) def test_not_relation_5_1(self): - rqlst = self._prepare('Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT X read_permission Y') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,Y WHERE X name "CWGroup", ' + 'Y eid IN(1, 2, 3), NOT X read_permission Y') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_not_relation_5_2(self): - rqlst = self._prepare('DISTINCT Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT X read_permission Y') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'DISTINCT Any X,Y WHERE X name "CWGroup", ' + 'Y eid IN(1, 2, 3), NOT X read_permission Y') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_not_relation_6(self): - rqlst = self._prepare('Personne P where NOT P concerne A') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['A']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Personne P where NOT P concerne A') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['A']._q_invariant, True) def test_not_relation_7(self): - rqlst = self._prepare('Any K,V WHERE P is CWProperty, P pkey K, P value V, NOT P for_user U') - self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['U']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any K,V WHERE P is CWProperty, ' + 'P pkey K, P value V, NOT P for_user U') + self.assertEqual(rqlst.defined_vars['P']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['U']._q_invariant, True) def test_exists_1(self): - rqlst = self._prepare('Any U WHERE U eid IN (1,2), EXISTS(X owned_by U)') - self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any U WHERE U eid IN (1,2), EXISTS(X owned_by U)') + self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_exists_2(self): - rqlst = self._prepare('Any U WHERE EXISTS(U eid IN (1,2), X owned_by U)') - self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any U WHERE EXISTS(U eid IN (1,2), X owned_by U)') + self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_exists_3(self): - rqlst = self._prepare('Any U WHERE EXISTS(X owned_by U, X bookmarked_by U)') - self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any U WHERE EXISTS(X owned_by U, X bookmarked_by U)') + self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_exists_4(self): - rqlst = self._prepare('Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), EXISTS(X read_permission Y)') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,Y WHERE X name "CWGroup", ' + 'Y eid IN(1, 2, 3), EXISTS(X read_permission Y)') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_exists_5(self): - rqlst = self._prepare('DISTINCT Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), EXISTS(X read_permission Y)') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'DISTINCT Any X,Y WHERE X name "CWGroup", ' + 'Y eid IN(1, 2, 3), EXISTS(X read_permission Y)') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_not_exists_1(self): - rqlst = self._prepare('Any U WHERE NOT EXISTS(X owned_by U, X bookmarked_by U)') - self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any U WHERE NOT EXISTS(X owned_by U, ' + 'X bookmarked_by U)') + self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_not_exists_2(self): - rqlst = self._prepare('Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)') - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X,Y WHERE X name "CWGroup", ' + 'Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)') + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_not_exists_distinct_1(self): - rqlst = self._prepare('DISTINCT Any X,Y WHERE X name "CWGroup", Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)') - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'DISTINCT Any X,Y WHERE X name "CWGroup", ' + 'Y eid IN(1, 2, 3), NOT EXISTS(X read_permission Y)') + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False) def test_or_1(self): - rqlst = self._prepare('Any X WHERE X concerne B OR C concerne X, B eid 12, C eid 13') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X concerne B OR ' + 'C concerne X, B eid 12, C eid 13') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) def test_or_2(self): - rqlst = self._prepare('Any X WHERE X created_by U, X concerne B OR C concerne X, B eid 12, C eid 13') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['U']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'created_by') + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X created_by U, X concerne B OR ' + 'C concerne X, B eid 12, C eid 13') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['U']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['X'].stinfo['principal'].r_type, 'created_by') def test_or_3(self): - rqlst = self._prepare('Any N WHERE A evaluee N or EXISTS(N todo_by U)') - self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['A']._q_invariant, True) - self.assertEqual(rqlst.defined_vars['U']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any N WHERE A evaluee N or EXISTS(N todo_by U)') + self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['A']._q_invariant, True) + self.assertEqual(rqlst.defined_vars['U']._q_invariant, True) def test_or_exists_1(self): - # query generated by security rewriting - rqlst = self._prepare('DISTINCT Any A,S WHERE A is Affaire, S nom "chouette", S is IN(Division, Societe, SubDivision),' - '(EXISTS(A owned_by D)) ' - 'OR ((((EXISTS(E concerne C?, C owned_by D, A identity E, C is Note, E is Affaire)) ' - 'OR (EXISTS(I concerne H?, H owned_by D, H is Societe, A identity I, I is Affaire))) ' - 'OR (EXISTS(J concerne G?, G owned_by D, G is SubDivision, A identity J, J is Affaire))) ' - 'OR (EXISTS(K concerne F?, F owned_by D, F is Division, A identity K, K is Affaire)))') - self.assertEqual(rqlst.defined_vars['A']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) + with self.session.new_cnx() as cnx: + # query generated by security rewriting + rqlst = self._prepare(cnx, 'DISTINCT Any A,S WHERE A is Affaire, S nom "chouette", ' + 'S is IN(Division, Societe, SubDivision),' + '(EXISTS(A owned_by D)) ' + 'OR ((((EXISTS(E concerne C?, C owned_by D, A identity E, ' + ' C is Note, E is Affaire)) ' + 'OR (EXISTS(I concerne H?, H owned_by D, H is Societe, ' + ' A identity I, I is Affaire))) ' + 'OR (EXISTS(J concerne G?, G owned_by D, G is SubDivision, ' + ' A identity J, J is Affaire))) ' + 'OR (EXISTS(K concerne F?, F owned_by D, F is Division, ' + ' A identity K, K is Affaire)))') + self.assertEqual(rqlst.defined_vars['A']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) def test_or_exists_2(self): - rqlst = self._prepare('Any U WHERE EXISTS(U in_group G, G name "managers") OR EXISTS(X owned_by U, X bookmarked_by U)') - self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['G']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any U WHERE EXISTS(U in_group G, G name "managers") OR ' + 'EXISTS(X owned_by U, X bookmarked_by U)') + self.assertEqual(rqlst.defined_vars['U']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['G']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['X']._q_invariant, True) def test_or_exists_3(self): - rqlst = self._prepare('Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 ' - 'WHERE C is Societe, S concerne C, C nom CS, ' - '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))') - self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) - rqlst = self._prepare('Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 ' - 'WHERE S is Affaire, C is Societe, S concerne C, C nom CS, ' - '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))') - self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 ' + 'WHERE C is Societe, S concerne C, C nom CS, ' + '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))') + self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) + rqlst = self._prepare(cnx, 'Any COUNT(S),CS GROUPBY CS ORDERBY 1 DESC LIMIT 10 ' + 'WHERE S is Affaire, C is Societe, S concerne C, C nom CS, ' + '(EXISTS(S owned_by D)) OR (EXISTS(S documented_by N, N title "published"))') + self.assertEqual(rqlst.defined_vars['S']._q_invariant, True) def test_nonregr_ambiguity(self): - rqlst = self._prepare('Note N WHERE N attachment F') - # N may be an image as well, not invariant - self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['F']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Note N WHERE N attachment F') + # N may be an image as well, not invariant + self.assertEqual(rqlst.defined_vars['N']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['F']._q_invariant, True) def test_nonregr_ambiguity_2(self): - rqlst = self._prepare('Any S,SN WHERE X has_text "tot", X in_state S, S name SN, X is CWUser') - # X use has_text but should not be invariant as ambiguous, and has_text - # may not be its principal - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any S,SN WHERE X has_text "tot", X in_state S, S name SN, X is CWUser') + # X use has_text but should not be invariant as ambiguous, and has_text + # may not be its principal + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['S']._q_invariant, False) def test_remove_from_deleted_source_1(self): - rqlst = self._prepare('Note X WHERE X eid 999998, NOT X cw_source Y') - self.assertNotIn('X', rqlst.defined_vars) # simplified - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Note X WHERE X eid 999998, NOT X cw_source Y') + self.assertNotIn('X', rqlst.defined_vars) # simplified + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_remove_from_deleted_source_2(self): - rqlst = self._prepare('Note X WHERE X eid IN (999998, 999999), NOT X cw_source Y') - self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) - self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) - + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Note X WHERE X eid IN (999998, 999999), NOT X cw_source Y') + self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) + self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) def test_has_text_security_cache_bug(self): - rqlst = self._prepare('Any X WHERE X has_text "toto" WITH X BEING ' - '(Any C WHERE C is Societe, C nom CS)') - self.assertTrue(rqlst.parent.has_text_query) + with self.session.new_cnx() as cnx: + rqlst = self._prepare(cnx, 'Any X WHERE X has_text "toto" WITH X BEING ' + '(Any C WHERE C is Societe, C nom CS)') + self.assertTrue(rqlst.parent.has_text_query) if __name__ == '__main__': from logilab.common.testlib import unittest_main diff -r 928732ec00dd -r fa44db7da2dc sobjects/ldapparser.py --- a/sobjects/ldapparser.py Thu Jul 17 11:08:56 2014 +0200 +++ b/sobjects/ldapparser.py Fri Jul 18 17:35:25 2014 +0200 @@ -92,9 +92,9 @@ for groupdict in self.group_source_entities_by_extid.itervalues(): self._process('CWGroup', groupdict) - def handle_deletion(self, config, session, myuris): + def handle_deletion(self, config, cnx, myuris): if config['delete-entities']: - super(DataFeedLDAPAdapter, self).handle_deletion(config, session, myuris) + super(DataFeedLDAPAdapter, self).handle_deletion(config, cnx, myuris) return if myuris: byetype = {} @@ -107,9 +107,9 @@ continue self.info('deactivate %s %s entities', len(eids), etype) for eid in eids: - wf = session.entity_from_eid(eid).cw_adapt_to('IWorkflowable') + wf = cnx.entity_from_eid(eid).cw_adapt_to('IWorkflowable') wf.fire_transition_if_possible('deactivate') - session.commit(free_cnxset=False) + cnx.commit() def update_if_necessary(self, entity, attrs): # disable read security to allow password selection diff -r 928732ec00dd -r fa44db7da2dc sobjects/test/unittest_cwxmlparser.py --- a/sobjects/test/unittest_cwxmlparser.py Thu Jul 17 11:08:56 2014 +0200 +++ b/sobjects/test/unittest_cwxmlparser.py Fri Jul 18 17:35:25 2014 +0200 @@ -132,13 +132,14 @@ REMOVE THE DATABASE TEMPLATE else it won't be considered """ test_db_id = 'xmlparser' + @classmethod - def pre_setup_database(cls, session, config): - myfeed = session.create_entity('CWSource', name=u'myfeed', type=u'datafeed', + def pre_setup_database(cls, cnx, config): + myfeed = cnx.create_entity('CWSource', name=u'myfeed', type=u'datafeed', parser=u'cw.entityxml', url=BASEXML) - myotherfeed = session.create_entity('CWSource', name=u'myotherfeed', type=u'datafeed', - parser=u'cw.entityxml', url=OTHERXML) - session.commit() + myotherfeed = cnx.create_entity('CWSource', name=u'myotherfeed', type=u'datafeed', + parser=u'cw.entityxml', url=OTHERXML) + cnx.commit() myfeed.init_mapping([(('CWUser', 'use_email', '*'), u'role=subject\naction=copy'), (('CWUser', 'in_group', '*'), @@ -153,7 +154,8 @@ (('CWUser', 'in_state', '*'), u'role=subject\naction=link\nlinkattr=name'), ]) - session.create_entity('Tag', name=u'hop') + cnx.create_entity('Tag', name=u'hop') + cnx.commit() def test_complete_url(self): dfsource = self.repo.sources_by_uri['myfeed'] diff -r 928732ec00dd -r fa44db7da2dc test/unittest_entity.py --- a/test/unittest_entity.py Thu Jul 17 11:08:56 2014 +0200 +++ b/test/unittest_entity.py Fri Jul 18 17:35:25 2014 +0200 @@ -23,13 +23,13 @@ from logilab.common import tempattr from logilab.common.decorators import clear_cache -from cubicweb import Binary, Unauthorized +from cubicweb import Binary from cubicweb.devtools.testlib import CubicWebTC from cubicweb.mttransforms import HAS_TAL from cubicweb.entity import can_use_rest_path from cubicweb.entities import fetch_config from cubicweb.uilib import soup2xhtml -from cubicweb.schema import RQLVocabularyConstraint, RRQLExpression +from cubicweb.schema import RRQLExpression class EntityTC(CubicWebTC): @@ -45,16 +45,16 @@ cls.fetch_attrs, cls.cw_fetch_order = self.backup_dict[cls] def test_no_prefill_related_cache_bug(self): - session = self.session - usine = session.create_entity('Usine', lieu=u'Montbeliard') - produit = session.create_entity('Produit') - # usine was prefilled in glob_add_entity - # let's simulate produit creation without prefill - produit._cw_related_cache.clear() - # use add_relations - session.add_relations([('fabrique_par', [(produit.eid, usine.eid)])]) - self.assertEqual(1, len(usine.reverse_fabrique_par)) - self.assertEqual(1, len(produit.fabrique_par)) + with self.admin_access.repo_cnx() as cnx: + usine = cnx.create_entity('Usine', lieu=u'Montbeliard') + produit = cnx.create_entity('Produit') + # usine was prefilled in glob_add_entity + # let's simulate produit creation without prefill + produit._cw_related_cache.clear() + # use add_relations + cnx.add_relations([('fabrique_par', [(produit.eid, usine.eid)])]) + self.assertEqual(1, len(usine.reverse_fabrique_par)) + self.assertEqual(1, len(produit.fabrique_par)) def test_boolean_value(self): with self.admin_access.web_request() as req: @@ -717,11 +717,11 @@ self.assertFalse(p1.reverse_evaluee) def test_complete_relation(self): - with self.admin_access.repo_cnx() as session: - eid = session.execute( + with self.admin_access.repo_cnx() as cnx: + eid = cnx.execute( 'INSERT TrInfo X: X comment "zou", X wf_info_for U, X from_state S1, X to_state S2 ' 'WHERE U login "admin", S1 name "activated", S2 name "deactivated"')[0][0] - trinfo = session.execute('Any X WHERE X eid %(x)s', {'x': eid}).get_entity(0, 0) + trinfo = cnx.execute('Any X WHERE X eid %(x)s', {'x': eid}).get_entity(0, 0) trinfo.complete() self.assertIsInstance(trinfo.cw_attr_cache['creation_date'], datetime) self.assertTrue(trinfo.cw_relation_cached('from_state', 'subject')) diff -r 928732ec00dd -r fa44db7da2dc web/application.py --- a/web/application.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/application.py Fri Jul 18 17:35:25 2014 +0200 @@ -35,7 +35,7 @@ from cubicweb import ( ValidationError, Unauthorized, Forbidden, AuthenticationError, NoSelectableObject, - BadConnectionId, CW_EVENT_MANAGER) + CW_EVENT_MANAGER) from cubicweb.repoapi import anonymous_cnx from cubicweb.web import LOGGER, component, cors from cubicweb.web import ( @@ -88,22 +88,15 @@ closed, total = 0, 0 for session in self.current_sessions(): total += 1 - try: - last_usage_time = session.cnx.check() - except AttributeError: - last_usage_time = session.mtime - except BadConnectionId: + last_usage_time = session.mtime + no_use_time = (time() - last_usage_time) + if session.anonymous_session: + if no_use_time >= self.cleanup_anon_session_time: + self.close_session(session) + closed += 1 + elif session_time is not None and no_use_time >= session_time: self.close_session(session) closed += 1 - else: - no_use_time = (time() - last_usage_time) - if session.anonymous_session: - if no_use_time >= self.cleanup_anon_session_time: - self.close_session(session) - closed += 1 - elif session_time is not None and no_use_time >= session_time: - self.close_session(session) - closed += 1 return closed, total - closed def current_sessions(self): @@ -300,6 +293,21 @@ """wrapper around _publish to log all queries executed for a given accessed path """ + def wrap_set_cnx(func): + def wrap_execute(cnx): + orig_execute = cnx.execute + def execute(rql, kwargs=None, build_descr=True): + tstart, cstart = time(), clock() + rset = orig_execute(rql, kwargs, build_descr=build_descr) + cnx.executed_queries.append((rql, kwargs, time() - tstart, clock() - cstart)) + return rset + return execute + def set_cnx(cnx): + func(cnx) + cnx.execute = wrap_execute(cnx) + cnx.executed_queries = [] + return set_cnx + req.set_cnx = wrap_set_cnx(req.set_cnx) try: return self.main_handle_request(req, path) finally: diff -r 928732ec00dd -r fa44db7da2dc web/data/cubicweb.css --- a/web/data/cubicweb.css Thu Jul 17 11:08:56 2014 +0200 +++ b/web/data/cubicweb.css Fri Jul 18 17:35:25 2014 +0200 @@ -200,9 +200,15 @@ visibility: hidden; } -li.invisible { - background: none; - padding: 0px 0px 1px 1px; +/* copied verbatim from bootstrap 3.0 */ +.invisible { + visibility: hidden; +} + +/* copied verbatim from bootstrap 3.0 */ +.list-unstyled { + padding-left: 0; + list-style: none; } .caption { diff -r 928732ec00dd -r fa44db7da2dc web/data/cubicweb.edition.js --- a/web/data/cubicweb.edition.js Thu Jul 17 11:08:56 2014 +0200 +++ b/web/data/cubicweb.edition.js Fri Jul 18 17:35:25 2014 +0200 @@ -328,7 +328,7 @@ _postAjaxLoad(dom); }); d.addErrback(function(xxx) { - log('xxx =', xxx); + cw.log('xxx =', xxx); }); } diff -r 928732ec00dd -r fa44db7da2dc web/data/cubicweb.old.css --- a/web/data/cubicweb.old.css Thu Jul 17 11:08:56 2014 +0200 +++ b/web/data/cubicweb.old.css Fri Jul 18 17:35:25 2014 +0200 @@ -219,10 +219,15 @@ visibility: hidden; } -li.invisible { +/* copied verbatim from bootstrap 3.0 */ +.invisible { + visibility: hidden; +} + +/* copied verbatim from bootstrap 3.0 */ +.list-unstyled { + padding-left: 0; list-style: none; - background: none; - padding: 0px 0px 1px 1px; } .caption { diff -r 928732ec00dd -r fa44db7da2dc web/request.py --- a/web/request.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/request.py Fri Jul 18 17:35:25 2014 +0200 @@ -30,7 +30,6 @@ from datetime import date, datetime from urlparse import urlsplit import httplib -from itertools import count from warnings import warn from rql.utils import rqlvar_maker @@ -82,6 +81,24 @@ return [v for v in value if v != INTERNAL_FIELD_VALUE] +class Counter(object): + """A picklable counter object, usable for e.g. page tab index count""" + __slots__ = ('value',) + + def __init__(self, initialvalue=0): + self.value = initialvalue + + def __call__(self): + value = self.value + self.value += 1 + return value + + def __getstate__(self): + return {'value': self.value} + + def __setstate__(self, state): + self.value = state['value'] + class _CubicWebRequestBase(RequestSessionBase): """abstract HTTP request, should be extended according to the HTTP backend @@ -201,7 +218,7 @@ def next_tabindex(self): nextfunc = self.get_page_data('nexttabfunc') if nextfunc is None: - nextfunc = count(1).next + nextfunc = Counter(1) self.set_page_data('nexttabfunc', nextfunc) return nextfunc() diff -r 928732ec00dd -r fa44db7da2dc web/test/test_views.py --- a/web/test/test_views.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/test_views.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -16,8 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """automatic tests""" -from cubicweb.devtools import htmlparser -from cubicweb.devtools.testlib import CubicWebTC, AutoPopulateTest, AutomaticWebTest +from cubicweb.devtools.testlib import AutoPopulateTest, AutomaticWebTest from cubicweb.view import AnyRsetView class AutomaticWebTest(AutomaticWebTest): @@ -28,8 +27,8 @@ ] def to_test_etypes(self): - # We do not really want to test cube views here. So we can drop testing - # some EntityType. The two Blog types below require the sioc cube that + # We do not really want to test cube views here. So we can drop testing + # some EntityType. The two Blog types below require the sioc cube that # we do not want to add as a dependency. etypes = super(AutomaticWebTest, self).to_test_etypes() etypes -= set(('Blog', 'BlogEntry')) @@ -50,29 +49,34 @@ """regression test: make sure we can ask a copy of a composite entity """ - rset = self.execute('CWUser X WHERE X login "admin"') - self.view('copy', rset) + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X WHERE X login "admin"') + self.view('copy', rset, req=req) def test_sortable_js_added(self): - rset = self.execute('CWUser X') - # sortable.js should not be included by default - self.assertFalse('jquery.tablesorter.js' in self.view('oneline', rset)) - # but should be included by the tableview - rset = self.execute('Any P,F,S LIMIT 1 WHERE P is CWUser, P firstname F, P surname S') - self.assertIn('jquery.tablesorter.js', self.view('table', rset).source) + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X') + # sortable.js should not be included by default + self.assertFalse('jquery.tablesorter.js' in self.view('oneline', rset, req=req)) + # but should be included by the tableview + rset = req.execute('Any P,F,S LIMIT 1 WHERE P is CWUser, P firstname F, P surname S') + self.assertIn('jquery.tablesorter.js', self.view('table', rset, req=req).source) def test_js_added_only_once(self): - self.vreg._loadedmods[__name__] = {} - self.vreg.register(SomeView) - rset = self.execute('CWUser X') - source = self.view('someview', rset).source - self.assertEqual(source.count('spam.js'), 1) + with self.admin_access.web_request() as req: + self.vreg._loadedmods[__name__] = {} + self.vreg.register(SomeView) + rset = req.execute('CWUser X') + source = self.view('someview', rset, req=req).source + self.assertEqual(source.count('spam.js'), 1) def test_unrelateddivs(self): - rset = self.execute('Any X WHERE X is CWUser, X login "admin"') - group = self.request().create_entity('CWGroup', name=u'R&D') - req = self.request(relation='in_group_subject') - self.view('unrelateddivs', rset, req) + with self.admin_access.client_cnx() as cnx: + group = cnx.create_entity('CWGroup', name=u'R&D') + cnx.commit() + with self.admin_access.web_request(relation='in_group_subject') as req: + rset = req.execute('Any X WHERE X is CWUser, X login "admin"') + self.view('unrelateddivs', rset, req=req) if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_application.py --- a/web/test/unittest_application.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_application.py Fri Jul 18 17:35:25 2014 +0200 @@ -18,14 +18,12 @@ """unit tests for cubicweb.web.application""" import base64, Cookie -import sys import httplib -from urllib import unquote from logilab.common.testlib import TestCase, unittest_main from logilab.common.decorators import clear_cache, classproperty -from cubicweb import AuthenticationError, Unauthorized +from cubicweb import AuthenticationError from cubicweb import view from cubicweb.devtools.testlib import CubicWebTC, real_error_handling from cubicweb.devtools.fake import FakeRequest @@ -182,7 +180,7 @@ def test_publish_validation_error(self): with self.admin_access.web_request() as req: - user = self.user() + user = self.user(req) eid = unicode(user.eid) req.form = { 'eid': eid, diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_breadcrumbs.py --- a/web/test/unittest_breadcrumbs.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_breadcrumbs.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -29,14 +29,19 @@ {'f1' : f1.eid, 'f2' : f2.eid}) req.cnx.commit() self.assertEqual(f2.view('breadcrumbs'), - 'chi&ld' % f2.eid) + '' + 'chi&ld' % f2.eid) childrset = f2.as_rset() ibc = self.vreg['ctxcomponents'].select('breadcrumbs', req, rset=childrset) l = [] ibc.render(l.append) - self.assertEqual(''.join(l), - """ > Folder_plural > par&ent >  -chi&ld""" % (f1.eid, f2.eid)) + self.assertMultiLineEqual(' > ' + 'Folder_plural' + ' > par&ent > \n' + '' + 'chi&ld' % (f1.eid, f2.eid), + ''.join(l)) if __name__ == '__main__': from logilab.common.testlib import unittest_main diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_propertysheet.py --- a/web/test/unittest_propertysheet.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_propertysheet.py Fri Jul 18 17:35:25 2014 +0200 @@ -4,7 +4,7 @@ from logilab.common.testlib import TestCase, unittest_main -from cubicweb.web.propertysheet import * +from cubicweb.web.propertysheet import PropertySheet, lazystr DATADIR = join(dirname(__file__), 'data') CACHEDIR = join(DATADIR, 'uicache') diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_reledit.py --- a/web/test/unittest_reledit.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_reledit.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -34,9 +34,9 @@ class ClickAndEditFormTC(ReleditMixinTC, CubicWebTC): def test_default_config(self): - reledit = {'title': '''
cubicweb-world-domination
''', - 'long_desc': '''
<not specified>
''', - 'manager': '''
<not specified>
''', + reledit = {'title': '''
cubicweb-world-domination
''', + 'long_desc': '''
<not specified>
''', + 'manager': '''
<not specified>
''', 'composite_card11_2ttypes': """<not specified>""", 'concerns': """<not specified>"""} @@ -53,7 +53,7 @@ def test_default_forms(self): self.skipTest('Need to check if this test should still run post reledit/doreledit merge') - doreledit = {'title': """
cubicweb-world-domination
+ doreledit = {'title': """
cubicweb-world-domination
@@ -82,12 +82,12 @@
-
""", +
""", - 'long_desc': """
<not specified>
+ 'long_desc': """
<not specified>
- - + + @@ -126,9 +126,9 @@
-
""", +
""", - 'manager': """
<not specified>
+ 'manager': """
<not specified>
@@ -162,7 +162,7 @@
-
""", +
""", 'composite_card11_2ttypes': """<not specified>""", 'concerns': """<not specified>""" } @@ -198,11 +198,11 @@ reledit_ctrl.tag_object_of(('Ticket', 'concerns', 'Project'), {'edit_target': 'rtype'}) reledit = { - 'title': """
cubicweb-world-domination
""", - 'long_desc': """
<long_desc is required>
""", - 'manager': """""", + 'title': """
cubicweb-world-domination
""", + 'long_desc': """
<long_desc is required>
""", + 'manager': """""", 'composite_card11_2ttypes': """<not specified>""", - 'concerns': """""" + 'concerns': """""" } with self.admin_access.web_request() as req: proj = req.entity_from_eid(self.proj) diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_urlpublisher.py --- a/web/test/unittest_urlpublisher.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_urlpublisher.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -33,106 +33,135 @@ """test suite for QSPreProcessor""" def setup_database(self): - req = self.request() - self.create_user(req, u'ÿsaÿe') - b = req.create_entity('BlogEntry', title=u'hell\'o', content=u'blabla') - c = req.create_entity('Tag', name=u'yo') # take care: Tag's name normalized to lower case - self.execute('SET C tags B WHERE C eid %(c)s, B eid %(b)s', {'c':c.eid, 'b':b.eid}) + with self.admin_access.repo_cnx() as cnx: + self.create_user(cnx, u'ÿsaÿe') + b = cnx.create_entity('BlogEntry', title=u'hell\'o', content=u'blabla') + # take care: Tag's name normalized to lower case + c = cnx.create_entity('Tag', name=u'yo') + cnx.execute('SET C tags B WHERE C eid %(c)s, B eid %(b)s', + {'c':c.eid, 'b':b.eid}) + cnx.commit() - def process(self, url): - req = self.req = self.request() + def process(self, req, url): return self.app.url_resolver.process(req, url) def test_raw_path(self): """tests raw path resolution'""" - self.assertEqual(self.process('view'), ('view', None)) - self.assertEqual(self.process('edit'), ('edit', None)) - self.assertRaises(NotFound, self.process, 'whatever') + with self.admin_access.web_request() as req: + self.assertEqual(self.process(req, 'view'), ('view', None)) + self.assertEqual(self.process(req, 'edit'), ('edit', None)) + self.assertRaises(NotFound, self.process, req, 'whatever') def test_eid_path(self): """tests eid path resolution""" - self.assertIsInstance(self.process('123')[1], ResultSet) - self.assertEqual(len(self.process('123')[1]), 1) - self.assertRaises(NotFound, self.process, '123/345') - self.assertRaises(NotFound, self.process, 'not_eid') + with self.admin_access.web_request() as req: + self.assertIsInstance(self.process(req, '123')[1], ResultSet) + self.assertEqual(len(self.process(req, '123')[1]), 1) + self.assertRaises(NotFound, self.process, req, '123/345') + self.assertRaises(NotFound, self.process, req, 'not_eid') def test_rest_path_etype(self): """tests the rest path resolution""" - ctrl, rset = self.process('CWEType') - self.assertEqual(ctrl, 'view') - self.assertEqual(rset.description[0][0], 'CWEType') - self.assertEqual(rset.printable_rql(), - "Any X,AA,AB ORDERBY AA WHERE X is_instance_of CWEType, X name AA, X modification_date AB") + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'CWEType') + self.assertEqual(ctrl, 'view') + self.assertEqual(rset.description[0][0], 'CWEType') + self.assertEqual("Any X,AA,AB ORDERBY AA WHERE X is_instance_of CWEType, " + "X name AA, X modification_date AB", + rset.printable_rql()) def test_rest_path_by_attr(self): - ctrl, rset = self.process('CWUser/login/admin') - self.assertEqual(ctrl, 'view') - self.assertEqual(len(rset), 1) - self.assertEqual(rset.description[0][0], 'CWUser') - self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"') + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'CWUser/login/admin') + self.assertEqual(ctrl, 'view') + self.assertEqual(len(rset), 1) + self.assertEqual(rset.description[0][0], 'CWUser') + self.assertEqual('Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, ' + 'X login AA, X firstname AB, X surname AC, ' + 'X modification_date AD, X login "admin"', + rset.printable_rql()) def test_rest_path_unique_attr(self): - ctrl, rset = self.process('cwuser/admin') - self.assertEqual(ctrl, 'view') - self.assertEqual(len(rset), 1) - self.assertEqual(rset.description[0][0], 'CWUser') - self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"') + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'cwuser/admin') + self.assertEqual(ctrl, 'view') + self.assertEqual(len(rset), 1) + self.assertEqual(rset.description[0][0], 'CWUser') + self.assertEqual('Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, ' + 'X login AA, X firstname AB, X surname AC, ' + 'X modification_date AD, X login "admin"', + rset.printable_rql()) def test_rest_path_eid(self): - ctrl, rset = self.process('cwuser/eid/%s' % self.user().eid) - self.assertEqual(ctrl, 'view') - self.assertEqual(len(rset), 1) - self.assertEqual(rset.description[0][0], 'CWUser') - self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X eid %s' % rset[0][0]) + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'cwuser/eid/%s' % self.user(req).eid) + self.assertEqual(ctrl, 'view') + self.assertEqual(len(rset), 1) + self.assertEqual(rset.description[0][0], 'CWUser') + self.assertEqual('Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, ' + 'X login AA, X firstname AB, X surname AC, ' + 'X modification_date AD, X eid %s' % rset[0][0], + rset.printable_rql()) def test_rest_path_non_ascii_paths(self): - ctrl, rset = self.process('CWUser/login/%C3%BFsa%C3%BFe') - self.assertEqual(ctrl, 'view') - self.assertEqual(len(rset), 1) - self.assertEqual(rset.description[0][0], 'CWUser') - self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "\xffsa\xffe"') + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'CWUser/login/%C3%BFsa%C3%BFe') + self.assertEqual(ctrl, 'view') + self.assertEqual(len(rset), 1) + self.assertEqual(rset.description[0][0], 'CWUser') + self.assertEqual(u'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, ' + u'X login AA, X firstname AB, X surname AC, ' + u'X modification_date AD, X login "\xffsa\xffe"', + rset.printable_rql()) def test_rest_path_quoted_paths(self): - ctrl, rset = self.process('BlogEntry/title/hell%27o') - self.assertEqual(ctrl, 'view') - self.assertEqual(len(rset), 1) - self.assertEqual(rset.description[0][0], 'BlogEntry') - self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC WHERE X is_instance_of BlogEntry, X creation_date AA, X title AB, X modification_date AC, X title "hell\'o"') + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'BlogEntry/title/hell%27o') + self.assertEqual(ctrl, 'view') + self.assertEqual(len(rset), 1) + self.assertEqual(rset.description[0][0], 'BlogEntry') + self.assertEqual(u'Any X,AA,AB,AC WHERE X is_instance_of BlogEntry, ' + 'X creation_date AA, X title AB, X modification_date AC, ' + 'X title "hell\'o"', + rset.printable_rql()) def test_rest_path_errors(self): - self.assertRaises(NotFound, self.process, 'CWUser/eid/30000') - self.assertRaises(NotFound, self.process, 'Workcases') - self.assertRaises(NotFound, self.process, 'CWUser/inexistant_attribute/joe') + with self.admin_access.web_request() as req: + self.assertRaises(NotFound, self.process, req, 'CWUser/eid/30000') + self.assertRaises(NotFound, self.process, req, 'Workcases') + self.assertRaises(NotFound, self.process, req, 'CWUser/inexistant_attribute/joe') def test_action_path(self): """tests the action path resolution""" - self.assertRaises(Redirect, self.process, '1/edit') - self.assertRaises(Redirect, self.process, 'Tag/name/yo/edit') - self.assertRaises(Redirect, self.process, 'Tag/yo/edit') - self.assertRaises(NotFound, self.process, 'view/edit') - self.assertRaises(NotFound, self.process, '1/non_action') - self.assertRaises(NotFound, self.process, 'CWUser/login/admin/non_action') + with self.admin_access.web_request() as req: + self.assertRaises(Redirect, self.process, req, '1/edit') + self.assertRaises(Redirect, self.process, req, 'Tag/name/yo/edit') + self.assertRaises(Redirect, self.process, req, 'Tag/yo/edit') + self.assertRaises(NotFound, self.process, req, 'view/edit') + self.assertRaises(NotFound, self.process, req, '1/non_action') + self.assertRaises(NotFound, self.process, req, 'CWUser/login/admin/non_action') def test_regexp_path(self): """tests the regexp path resolution""" - ctrl, rset = self.process('add/Task') - self.assertEqual(ctrl, 'view') - self.assertEqual(rset, None) - self.assertEqual(self.req.form, {'etype' : "Task", 'vid' : "creation"}) - self.assertRaises(NotFound, self.process, 'add/foo/bar') - + with self.admin_access.web_request() as req: + ctrl, rset = self.process(req, 'add/Task') + self.assertEqual(ctrl, 'view') + self.assertEqual(rset, None) + self.assertEqual(req.form, {'etype' : "Task", 'vid' : "creation"}) + self.assertRaises(NotFound, self.process, req, 'add/foo/bar') def test_nonascii_path(self): oldrules = SimpleReqRewriter.rules SimpleReqRewriter.rules = [(re.compile('/\w+', re.U), dict(vid='foo')),] - try: - path = str(FakeRequest().url_quote(u'été')) - ctrl, rset = self.process(path) - self.assertEqual(rset, None) - self.assertEqual(self.req.form, {'vid' : "foo"}) - finally: - SimpleReqRewriter.rules = oldrules + with self.admin_access.web_request() as req: + try: + path = str(FakeRequest().url_quote(u'été')) + ctrl, rset = self.process(req, path) + self.assertEqual(rset, None) + self.assertEqual(req.form, {'vid' : "foo"}) + finally: + SimpleReqRewriter.rules = oldrules if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_urlrewrite.py --- a/web/test/unittest_urlrewrite.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_urlrewrite.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -21,7 +21,8 @@ from cubicweb.devtools.testlib import CubicWebTC from cubicweb.devtools.fake import FakeRequest -from cubicweb.web.views.urlrewrite import SimpleReqRewriter, SchemaBasedRewriter, rgx, rgx_action +from cubicweb.web.views.urlrewrite import (SimpleReqRewriter, SchemaBasedRewriter, + rgx, rgx_action) class UrlRewriteTC(CubicWebTC): @@ -99,47 +100,51 @@ def test_inheritance(self): BaseTransition = self.vreg['etypes'].etype_class('BaseTransition') - req = self.request() - x = req.create_entity('WorkflowTransition', name=u'test') - ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.eid) - self.assertEqual(ctrlid, 'view') - self.assertEqual(x.eid, rset[0][0]) - # cw_rest_attr_info is cached but clear_cache doesn't like cached class - # method - del BaseTransition._cw_rest_attr_info_cache_ - try: - with tempattr(BaseTransition, 'rest_attr', 'name'): + with self.admin_access.web_request() as req: + x = req.create_entity('WorkflowTransition', name=u'test') + ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.eid) + self.assertEqual(ctrlid, 'view') + self.assertEqual(x.eid, rset[0][0]) + # cw_rest_attr_info is cached but clear_cache doesn't like cached class + # method + del BaseTransition._cw_rest_attr_info_cache_ + try: + with tempattr(BaseTransition, 'rest_attr', 'name'): - ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.name) - self.assertEqual(ctrlid, 'view') - self.assertEqual(x.eid, rset[0][0]) - finally: - del BaseTransition._cw_rest_attr_info_cache_ + ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.name) + self.assertEqual(ctrlid, 'view') + self.assertEqual(x.eid, rset[0][0]) + finally: + del BaseTransition._cw_rest_attr_info_cache_ class RgxActionRewriteTC(CubicWebTC): def setup_database(self): - req = self.request() - self.p1 = self.create_user(req, u'user1') - self.p1.cw_set(firstname=u'joe', surname=u'Dalton') - self.p2 = self.create_user(req, u'user2') - self.p2.cw_set(firstname=u'jack', surname=u'Dalton') + with self.admin_access.repo_cnx() as cnx: + p1 = self.create_user(cnx, u'user1') + p1.cw_set(firstname=u'joe', surname=u'Dalton') + p2 = self.create_user(cnx, u'user2') + p2.cw_set(firstname=u'jack', surname=u'Dalton') + self.p1eid = p1.eid + cnx.commit() def test_rgx_action_with_transforms(self): class TestSchemaBasedRewriter(SchemaBasedRewriter): rules = [ - (rgx('/(?P\w+)/(?P\w+)'), rgx_action(r'Any X WHERE X surname %(sn)s, X firstname %(fn)s', - argsgroups=('sn', 'fn'), - transforms={'sn' : unicode.capitalize, - 'fn' : unicode.lower,})), + (rgx('/(?P\w+)/(?P\w+)'), + rgx_action(r'Any X WHERE X surname %(sn)s, ' + 'X firstname %(fn)s', + argsgroups=('sn', 'fn'), + transforms={'sn' : unicode.capitalize, + 'fn' : unicode.lower,})), ] - req = self.request() - rewriter = TestSchemaBasedRewriter(req) - pmid, rset = rewriter.rewrite(req, u'/DaLToN/JoE') - self.assertEqual(len(rset), 1) - self.assertEqual(rset[0][0], self.p1.eid) + with self.admin_access.web_request() as req: + rewriter = TestSchemaBasedRewriter(req) + _pmid, rset = rewriter.rewrite(req, u'/DaLToN/JoE') + self.assertEqual(len(rset), 1) + self.assertEqual(rset[0][0], self.p1eid) def test_inheritance_precedence(self): RQL1 = 'Any C WHERE C is CWEType' @@ -160,20 +165,20 @@ ), ] - req = self.request() - rewriter = Rewriter(req) - pmid, rset = rewriter.rewrite(req, '/collector') - self.assertEqual(rset.rql, RQL1) - self.assertEqual(req.form, {'vid' : "baseindex"}) - pmid, rset = rewriter.rewrite(req, '/collector/something') - self.assertEqual(rset.rql, RQL2) - self.assertEqual(req.form, {'vid' : "index"}) - pmid, rset = rewriter.rewrite(req, '/collector/something/') - self.assertEqual(req.form, {'vid' : "index"}) - self.assertEqual(rset.rql, RQL2) - pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/') - self.assertEqual(rset.rql, RQL1) - self.assertEqual(req.form, {'vid' : "baseindex"}) + with self.admin_access.web_request() as req: + rewriter = Rewriter(req) + _pmid, rset = rewriter.rewrite(req, '/collector') + self.assertEqual(rset.rql, RQL1) + self.assertEqual(req.form, {'vid' : "baseindex"}) + _pmid, rset = rewriter.rewrite(req, '/collector/something') + self.assertEqual(rset.rql, RQL2) + self.assertEqual(req.form, {'vid' : "index"}) + _pmid, rset = rewriter.rewrite(req, '/collector/something/') + self.assertEqual(req.form, {'vid' : "index"}) + self.assertEqual(rset.rql, RQL2) + _pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/') + self.assertEqual(rset.rql, RQL1) + self.assertEqual(req.form, {'vid' : "baseindex"}) def test_inheritance_precedence_same_rgx(self): RQL1 = 'Any C WHERE C is CWEType' @@ -194,20 +199,20 @@ ), ] - req = self.request() - rewriter = Rewriter(req) - pmid, rset = rewriter.rewrite(req, '/collector') - self.assertEqual(rset.rql, RQL2) - self.assertEqual(req.form, {'vid' : "index"}) - pmid, rset = rewriter.rewrite(req, '/collector/something') - self.assertEqual(rset.rql, RQL2) - self.assertEqual(req.form, {'vid' : "index"}) - pmid, rset = rewriter.rewrite(req, '/collector/something/') - self.assertEqual(req.form, {'vid' : "index"}) - self.assertEqual(rset.rql, RQL2) - pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/') - self.assertEqual(rset.rql, RQL2) - self.assertEqual(req.form, {'vid' : "index"}) + with self.admin_access.web_request() as req: + rewriter = Rewriter(req) + _pmid, rset = rewriter.rewrite(req, '/collector') + self.assertEqual(rset.rql, RQL2) + self.assertEqual(req.form, {'vid' : "index"}) + _pmid, rset = rewriter.rewrite(req, '/collector/something') + self.assertEqual(rset.rql, RQL2) + self.assertEqual(req.form, {'vid' : "index"}) + _pmid, rset = rewriter.rewrite(req, '/collector/something/') + self.assertEqual(req.form, {'vid' : "index"}) + self.assertEqual(rset.rql, RQL2) + _pmid, rset = rewriter.rewrite(req, '/collector/somethingelse/') + self.assertEqual(rset.rql, RQL2) + self.assertEqual(req.form, {'vid' : "index"}) if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_basecontrollers.py --- a/web/test/unittest_views_basecontrollers.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_basecontrollers.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -23,18 +23,16 @@ from urlparse import parse_qs as url_parse_query except ImportError: from cgi import parse_qs as url_parse_query -from logilab.common.testlib import unittest_main, mock_object +from logilab.common.testlib import unittest_main from logilab.common.decorators import monkeypatch from cubicweb import Binary, NoSelectableObject, ValidationError -from cubicweb.view import STRICT_DOCTYPE from cubicweb.devtools.testlib import CubicWebTC from cubicweb.utils import json_dumps from cubicweb.uilib import rql_for_eid -from cubicweb.web import INTERNAL_FIELD_VALUE, Redirect, RequestError, RemoteCallFailed +from cubicweb.web import Redirect, RemoteCallFailed import cubicweb.server.session from cubicweb.server.session import Connection as OldConnection -from cubicweb.entities.authobjs import CWUser from cubicweb.web.views.autoform import get_pending_inserts, get_pending_deletes from cubicweb.web.views.basecontrollers import JSonController, xhtmlize, jsonize from cubicweb.web.views.ajaxcontroller import ajaxfunc, AjaxFunction @@ -42,15 +40,15 @@ from cubicweb.server.hook import Hook, Operation from cubicweb.predicates import is_instance -u = unicode - def req_form(user): return {'eid': [str(user.eid)], '_cw_entity_fields:%s' % user.eid: '_cw_generic_field', '__type:%s' % user.eid: user.__regid__ } + class EditControllerTC(CubicWebTC): + def setUp(self): CubicWebTC.setUp(self) self.assertIn('users', self.schema.eschema('CWGroup').get_groups('read')) @@ -62,611 +60,146 @@ def test_noparam_edit(self): """check behaviour of this controller without any form parameter """ - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(self.request()) - self.assertEqual(cm.exception.errors, {None: u'no selected entities'}) + with self.admin_access.web_request() as req: + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + self.assertEqual(cm.exception.errors, {None: u'no selected entities'}) def test_validation_unique(self): """test creation of two linked entities """ - user = self.user() - req = self.request() - req.form = {'eid': 'X', '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,upassword-subject', - 'login-subject:X': u'admin', - 'upassword-subject:X': u'toto', - 'upassword-subject-confirm:X': u'toto', + with self.admin_access.web_request() as req: + req.form = {'eid': 'X', '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,upassword-subject', + 'login-subject:X': u'admin', + 'upassword-subject:X': u'toto', + 'upassword-subject-confirm:X': u'toto', } - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(req) - cm.exception.translate(unicode) - self.assertEqual(cm.exception.errors, {'login-subject': 'the value "admin" is already used, use another one'}) + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + cm.exception.translate(unicode) + self.assertEqual({'login-subject': 'the value "admin" is already used, use another one'}, + cm.exception.errors) def test_user_editing_itself(self): """checking that a manager user can edit itself """ - user = self.user() - basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X in_group G, X eid %(x)s', {'x': user.eid})] - groupeids = [eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')] - groups = [u(eid) for eid in groupeids] - req = self.request() - eid = u(user.eid) - req.form = { - 'eid': eid, '__type:'+eid: 'CWUser', - '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject', - 'login-subject:'+eid: u(user.login), - 'surname-subject:'+eid: u'Th\xe9nault', - 'firstname-subject:'+eid: u'Sylvain', - 'in_group-subject:'+eid: groups, - } - path, params = self.expect_redirect_handle_request(req, 'edit') - e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0) - self.assertEqual(e.firstname, u'Sylvain') - self.assertEqual(e.surname, u'Th\xe9nault') - self.assertEqual(e.login, user.login) - self.assertEqual([g.eid for g in e.in_group], groupeids) + with self.admin_access.web_request() as req: + user = req.user + groupeids = [eid for eid, in req.execute('CWGroup G WHERE G name ' + 'in ("managers", "users")')] + groups = [unicode(eid) for eid in groupeids] + eid = unicode(user.eid) + req.form = { + 'eid': eid, '__type:'+eid: 'CWUser', + '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject', + 'login-subject:'+eid: unicode(user.login), + 'surname-subject:'+eid: u'Th\xe9nault', + 'firstname-subject:'+eid: u'Sylvain', + 'in_group-subject:'+eid: groups, + } + self.expect_redirect_handle_request(req, 'edit') + e = req.execute('Any X WHERE X eid %(x)s', + {'x': user.eid}).get_entity(0, 0) + self.assertEqual(e.firstname, u'Sylvain') + self.assertEqual(e.surname, u'Th\xe9nault') + self.assertEqual(e.login, user.login) + self.assertEqual([g.eid for g in e.in_group], groupeids) def test_user_can_change_its_password(self): - req = self.request() - user = self.create_user(req, 'user') - cnx = self.login('user') - eid = u(user.eid) - req.form = { - 'eid': eid, '__maineid' : eid, - '__type:'+eid: 'CWUser', - '_cw_entity_fields:'+eid: 'upassword-subject', - 'upassword-subject:'+eid: 'tournicoton', - 'upassword-subject-confirm:'+eid: 'tournicoton', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - cnx.commit() # commit to check we don't get late validation error for instance - self.assertEqual(path, 'cwuser/user') - self.assertNotIn('vid', params) + with self.admin_access.repo_cnx() as cnx: + self.create_user(cnx, 'user') + cnx.commit() + with self.new_access('user').web_request() as req: + eid = unicode(req.user.eid) + req.form = { + 'eid': eid, '__maineid' : eid, + '__type:'+eid: 'CWUser', + '_cw_entity_fields:'+eid: 'upassword-subject', + 'upassword-subject:'+eid: 'tournicoton', + 'upassword-subject-confirm:'+eid: 'tournicoton', + } + path, params = self.expect_redirect_handle_request(req, 'edit') + req.cnx.commit() # commit to check we don't get late validation error for instance + self.assertEqual(path, 'cwuser/user') + self.assertNotIn('vid', params) def test_user_editing_itself_no_relation(self): """checking we can edit an entity without specifying some required relations (meaning no changes) """ - user = self.user() - groupeids = [g.eid for g in user.in_group] - req = self.request() - eid = u(user.eid) - req.form = { - 'eid': eid, - '__type:'+eid: 'CWUser', - '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject', - 'login-subject:'+eid: u(user.login), - 'firstname-subject:'+eid: u'Th\xe9nault', - 'surname-subject:'+eid: u'Sylvain', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - e = self.execute('Any X WHERE X eid %(x)s', {'x': user.eid}).get_entity(0, 0) - self.assertEqual(e.login, user.login) - self.assertEqual(e.firstname, u'Th\xe9nault') - self.assertEqual(e.surname, u'Sylvain') - self.assertEqual([g.eid for g in e.in_group], groupeids) - self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated') + with self.admin_access.web_request() as req: + user = req.user + groupeids = [g.eid for g in user.in_group] + eid = unicode(user.eid) + req.form = { + 'eid': eid, + '__type:'+eid: 'CWUser', + '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject', + 'login-subject:'+eid: unicode(user.login), + 'firstname-subject:'+eid: u'Th\xe9nault', + 'surname-subject:'+eid: u'Sylvain', + } + self.expect_redirect_handle_request(req, 'edit') + e = req.execute('Any X WHERE X eid %(x)s', + {'x': user.eid}).get_entity(0, 0) + self.assertEqual(e.login, user.login) + self.assertEqual(e.firstname, u'Th\xe9nault') + self.assertEqual(e.surname, u'Sylvain') + self.assertEqual([g.eid for g in e.in_group], groupeids) + self.assertEqual(e.cw_adapt_to('IWorkflowable').state, 'activated') def test_create_multiple_linked(self): - gueid = self.execute('CWGroup G WHERE G name "users"')[0][0] - req = self.request() - req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', - - '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject', - 'login-subject:X': u'adim', - 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', - 'surname-subject:X': u'Di Mascio', - 'in_group-subject:X': u(gueid), + with self.admin_access.web_request() as req: + gueid = req.execute('CWGroup G WHERE G name "users"')[0][0] + req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', + '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,upassword-subject,surname-subject,in_group-subject', + 'login-subject:X': u'adim', + 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', + 'surname-subject:X': u'Di Mascio', + 'in_group-subject:X': unicode(gueid), - '__type:Y': 'EmailAddress', - '_cw_entity_fields:Y': 'address-subject,use_email-object', - 'address-subject:Y': u'dima@logilab.fr', - 'use_email-object:Y': 'X', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - # should be redirected on the created person - self.assertEqual(path, 'cwuser/adim') - e = self.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0) - self.assertEqual(e.surname, 'Di Mascio') - email = e.use_email[0] - self.assertEqual(email.address, 'dima@logilab.fr') + '__type:Y': 'EmailAddress', + '_cw_entity_fields:Y': 'address-subject,use_email-object', + 'address-subject:Y': u'dima@logilab.fr', + 'use_email-object:Y': 'X', + } + path, _params = self.expect_redirect_handle_request(req, 'edit') + # should be redirected on the created person + self.assertEqual(path, 'cwuser/adim') + e = req.execute('Any P WHERE P surname "Di Mascio"').get_entity(0, 0) + self.assertEqual(e.surname, 'Di Mascio') + email = e.use_email[0] + self.assertEqual(email.address, 'dima@logilab.fr') def test_create_mandatory_inlined(self): - req = self.request() - req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', + with self.admin_access.web_request() as req: + req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', - '__type:X': 'Salesterm', - '_cw_entity_fields:X': '', + '__type:X': 'Salesterm', + '_cw_entity_fields:X': '', - '__type:Y': 'File', - '_cw_entity_fields:Y': 'data-subject,described_by_test-object', - 'data-subject:Y': (u'coucou.txt', Binary('coucou')), - 'described_by_test-object:Y': 'X', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertTrue(path.startswith('salesterm/'), path) - eid = path.split('/')[1] - salesterm = req.entity_from_eid(eid) - # The NOT NULL constraint of mandatory relation implies that the File - # must be created before the Salesterm, otherwise Salesterm insertion - # will fail. - # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the - # insertion does not fail and we have to check dumbly that File is - # created before. - self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid) + '__type:Y': 'File', + '_cw_entity_fields:Y': 'data-subject,described_by_test-object', + 'data-subject:Y': (u'coucou.txt', Binary('coucou')), + 'described_by_test-object:Y': 'X', + } + path, _params = self.expect_redirect_handle_request(req, 'edit') + self.assertTrue(path.startswith('salesterm/'), path) + eid = path.split('/')[1] + salesterm = req.entity_from_eid(eid) + # The NOT NULL constraint of mandatory relation implies that the File + # must be created before the Salesterm, otherwise Salesterm insertion + # will fail. + # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the + # insertion does not fail and we have to check dumbly that File is + # created before. + self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid) def test_create_mandatory_inlined2(self): - req = self.request() - req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', - - '__type:X': 'Salesterm', - '_cw_entity_fields:X': 'described_by_test-subject', - 'described_by_test-subject:X': 'Y', - - '__type:Y': 'File', - '_cw_entity_fields:Y': 'data-subject', - 'data-subject:Y': (u'coucou.txt', Binary('coucou')), - } - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertTrue(path.startswith('salesterm/'), path) - eid = path.split('/')[1] - salesterm = req.entity_from_eid(eid) - # The NOT NULL constraint of mandatory relation implies that the File - # must be created before the Salesterm, otherwise Salesterm insertion - # will fail. - # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the - # insertion does not fail and we have to check dumbly that File is - # created before. - self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid) - - def test_edit_mandatory_inlined3_object(self): - # non regression test for #3120495. Without the fix, leads to - # "unhashable type: 'list'" error - req = self.request() - cwrelation = u(req.execute('CWEType X WHERE X name "CWSource"')[0][0]) - req.form = {'eid': [cwrelation], '__maineid' : cwrelation, - - '__type:'+cwrelation: 'CWEType', - '_cw_entity_fields:'+cwrelation: 'to_entity-object', - 'to_entity-object:'+cwrelation: [9999, 9998], - } - with self.session.deny_all_hooks_but(): - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertTrue(path.startswith('cwetype/CWSource'), path) - - def test_edit_multiple_linked(self): - req = self.request() - peid = u(self.create_user(req, 'adim').eid) - req.form = {'eid': [peid, 'Y'], '__maineid': peid, - - '__type:'+peid: u'CWUser', - '_cw_entity_fields:'+peid: u'surname-subject', - 'surname-subject:'+peid: u'Di Masci', - - '__type:Y': u'EmailAddress', - '_cw_entity_fields:Y': u'address-subject,use_email-object', - 'address-subject:Y': u'dima@logilab.fr', - 'use_email-object:Y': peid, - } - path, params = self.expect_redirect_handle_request(req, 'edit') - # should be redirected on the created person - self.assertEqual(path, 'cwuser/adim') - e = self.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0) - email = e.use_email[0] - self.assertEqual(email.address, 'dima@logilab.fr') - - emaileid = u(email.eid) - req = self.request() - req.form = {'eid': [peid, emaileid], - - '__type:'+peid: u'CWUser', - '_cw_entity_fields:'+peid: u'surname-subject', - 'surname-subject:'+peid: u'Di Masci', - - '__type:'+emaileid: u'EmailAddress', - '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object', - 'address-subject:'+emaileid: u'adim@logilab.fr', - 'use_email-object:'+emaileid: peid, - } - path, params = self.expect_redirect_handle_request(req, 'edit') - email.cw_clear_all_caches() - self.assertEqual(email.address, 'adim@logilab.fr') - - - def test_password_confirm(self): - """test creation of two linked entities - """ - user = self.user() - req = self.request() - req.form = {'eid': 'X', - '__cloned_eid:X': u(user.eid), '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,upassword-subject', - 'login-subject:X': u'toto', - 'upassword-subject:X': u'toto', - } - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(req) - self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'}) - req = self.request() - req.form = {'__cloned_eid:X': u(user.eid), - 'eid': 'X', '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,upassword-subject', - 'login-subject:X': u'toto', - 'upassword-subject:X': u'toto', - 'upassword-subject-confirm:X': u'tutu', - } - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(req) - self.assertEqual(cm.exception.errors, {'upassword-subject': u'password and confirmation don\'t match'}) - - - def test_interval_bound_constraint_success(self): - feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s', - {'data': Binary('yo')})[0][0] - self.commit() - req = self.request(rollbackfirst=True) - req.form = {'eid': ['X'], - '__type:X': 'Salesterm', - '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', - 'amount-subject:X': u'-10', - 'described_by_test-subject:X': u(feid), - } - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(req) - cm.exception.translate(unicode) - self.assertEqual(cm.exception.errors, {'amount-subject': 'value -10 must be >= 0'}) - req = self.request(rollbackfirst=True) - req.form = {'eid': ['X'], - '__type:X': 'Salesterm', - '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', - 'amount-subject:X': u'110', - 'described_by_test-subject:X': u(feid), - } - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(req) - cm.exception.translate(unicode) - self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'}) - - req = self.request(rollbackfirst=True) - req.form = {'eid': ['X'], - '__type:X': 'Salesterm', - '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', - 'amount-subject:X': u'10', - 'described_by_test-subject:X': u(feid), - } - self.expect_redirect_handle_request(req, 'edit') - # should be redirected on the created - #eid = params['rql'].split()[-1] - e = self.execute('Salesterm X').get_entity(0, 0) - self.assertEqual(e.amount, 10) - - def test_interval_bound_constraint_validateform(self): - """Test the FormValidatorController controller on entity with - constrained attributes""" - feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s', - {'data': Binary('yo')})[0][0] - seid = self.request().create_entity('Salesterm', amount=0, described_by_test=feid).eid - self.commit() - - # ensure a value that violate a constraint is properly detected - req = self.request(rollbackfirst=True) - req.form = {'eid': [unicode(seid)], - '__type:%s'%seid: 'Salesterm', - '_cw_entity_fields:%s'%seid: 'amount-subject', - 'amount-subject:%s'%seid: u'-10', - } - self.assertEqual(''''''%seid, self.ctrl_publish(req, 'validateform')) - - # ensure a value that comply a constraint is properly processed - req = self.request(rollbackfirst=True) - req.form = {'eid': [unicode(seid)], - '__type:%s'%seid: 'Salesterm', - '_cw_entity_fields:%s'%seid: 'amount-subject', - 'amount-subject:%s'%seid: u'20', - } - self.assertEqual('''''', self.ctrl_publish(req, 'validateform')) - self.assertEqual(20, self.execute('Any V WHERE X amount V, X eid %(eid)s', {'eid': seid})[0][0]) - - req = self.request(rollbackfirst=True) - req.form = {'eid': ['X'], - '__type:X': 'Salesterm', - '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', - 'amount-subject:X': u'0', - 'described_by_test-subject:X': u(feid), - } - - # ensure a value that is modified in an operation on a modify - # hook works as it should (see - # https://www.cubicweb.org/ticket/2509729 ) - class MyOperation(Operation): - def precommit_event(self): - self.entity.cw_set(amount=-10) - class ValidationErrorInOpAfterHook(Hook): - __regid__ = 'valerror-op-after-hook' - __select__ = Hook.__select__ & is_instance('Salesterm') - events = ('after_add_entity',) - def __call__(self): - MyOperation(self._cw, entity=self.entity) - - with self.temporary_appobjects(ValidationErrorInOpAfterHook): - self.assertEqual('''''', self.ctrl_publish(req, 'validateform')) - - self.assertEqual('''''', self.ctrl_publish(req, 'validateform')) - - def test_req_pending_insert(self): - """make sure req's pending insertions are taken into account""" - tmpgroup = self.request().create_entity('CWGroup', name=u"test") - user = self.user() - req = self.request(**req_form(user)) - req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)]) - path, params = self.expect_redirect_handle_request(req, 'edit') - usergroups = [gname for gname, in - self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})] - self.assertCountEqual(usergroups, ['managers', 'test']) - self.assertEqual(get_pending_inserts(req), []) - - def test_req_pending_delete(self): - """make sure req's pending deletions are taken into account""" - user = self.user() - groupeid = self.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s', - {'x': user.eid})[0][0] - usergroups = [gname for gname, in - self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})] - # just make sure everything was set correctly - self.assertCountEqual(usergroups, ['managers', 'test']) - # now try to delete the relation - req = self.request(**req_form(user)) - req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)]) - path, params = self.expect_redirect_handle_request(req, 'edit') - usergroups = [gname for gname, in - self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})] - self.assertCountEqual(usergroups, ['managers']) - self.assertEqual(get_pending_deletes(req), []) - - def test_redirect_apply_button(self): - redirectrql = rql_for_eid(4012) # whatever - req = self.request() - req.form = { - 'eid': 'A', '__maineid' : 'A', - '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject', - 'content-subject:A': u'"13:03:43"', - 'title-subject:A': u'huuu', - '__redirectrql': redirectrql, - '__redirectvid': 'primary', - '__redirectparams': 'toto=tutu&tata=titi', - '__form_id': 'edition', - '__action_apply': '', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertTrue(path.startswith('blogentry/')) - eid = path.split('/')[1] - self.assertEqual(params['vid'], 'edition') - self.assertNotEqual(int(eid), 4012) - self.assertEqual(params['__redirectrql'], redirectrql) - self.assertEqual(params['__redirectvid'], 'primary') - self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi') - - def test_redirect_ok_button(self): - redirectrql = rql_for_eid(4012) # whatever - req = self.request() - req.form = { - 'eid': 'A', '__maineid' : 'A', - '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject', - 'content-subject:A': u'"13:03:43"', - 'title-subject:A': u'huuu', - '__redirectrql': redirectrql, - '__redirectvid': 'primary', - '__redirectparams': 'toto=tutu&tata=titi', - '__form_id': 'edition', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertEqual(path, 'view') - self.assertEqual(params['rql'], redirectrql) - self.assertEqual(params['vid'], 'primary') - self.assertEqual(params['tata'], 'titi') - self.assertEqual(params['toto'], 'tutu') - - def test_redirect_delete_button(self): - req = self.request() - eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid - req.form = {'eid': u(eid), '__type:%s'%eid: 'BlogEntry', - '__action_delete': ''} - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertEqual(path, 'blogentry') - self.assertIn('_cwmsgid', params) - eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid - self.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s', - {'x': self.session.user.eid, 'e': eid}) - self.commit() - req = req - req.form = {'eid': u(eid), '__type:%s'%eid: 'EmailAddress', - '__action_delete': ''} - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertEqual(path, 'cwuser/admin') - self.assertIn('_cwmsgid', params) - eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid - eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid - req = self.request() - req.form = {'eid': [u(eid1), u(eid2)], - '__type:%s'%eid1: 'BlogEntry', - '__type:%s'%eid2: 'EmailAddress', - '__action_delete': ''} - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertEqual(path, 'view') - self.assertIn('_cwmsgid', params) - - def test_simple_copy(self): - req = self.request() - blog = req.create_entity('Blog', title=u'my-blog') - blogentry = req.create_entity('BlogEntry', title=u'entry1', - content=u'content1', entry_of=blog) - req = self.request() - req.form = {'__maineid' : 'X', 'eid': 'X', - '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry', - '_cw_entity_fields:X': 'title-subject,content-subject', - 'title-subject:X': u'entry1-copy', - 'content-subject:X': u'content1', - } - self.expect_redirect_handle_request(req, 'edit') - blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy') - self.assertEqual(blogentry2.entry_of[0].eid, blog.eid) - - def test_skip_copy_for(self): - req = self.request() - blog = req.create_entity('Blog', title=u'my-blog') - blogentry = req.create_entity('BlogEntry', title=u'entry1', - content=u'content1', entry_of=blog) - blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')] - try: - req = self.request() - req.form = {'__maineid' : 'X', 'eid': 'X', - '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry', - '_cw_entity_fields:X': 'title-subject,content-subject', - 'title-subject:X': u'entry1-copy', - 'content-subject:X': u'content1', - } - self.expect_redirect_handle_request(req, 'edit') - blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy') - # entry_of should not be copied - self.assertEqual(len(blogentry2.entry_of), 0) - finally: - blogentry.__class__.cw_skip_copy_for = [] - - def test_nonregr_eetype_etype_editing(self): - """non-regression test checking that a manager user can edit a CWEType entity - """ - groupeids = sorted(eid for eid, in self.execute('CWGroup G WHERE G name in ("managers", "users")')) - groups = [u(eid) for eid in groupeids] - cwetypeeid = self.execute('CWEType X WHERE X name "CWEType"')[0][0] - basegroups = [u(eid) for eid, in self.execute('CWGroup G WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})] - cwetypeeid = u(cwetypeeid) - req = self.request() - req.form = { - 'eid': cwetypeeid, - '__type:'+cwetypeeid: 'CWEType', - '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject', - 'name-subject:'+cwetypeeid: u'CWEType', - 'final-subject:'+cwetypeeid: '', - 'description-subject:'+cwetypeeid: u'users group', - 'read_permission-subject:'+cwetypeeid: groups, - } - try: - path, params = self.expect_redirect_handle_request(req, 'edit') - e = self.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0) - self.assertEqual(e.name, 'CWEType') - self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids) - finally: - # restore - self.execute('SET X read_permission Y WHERE X name "CWEType", Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups))) - self.commit() - - def test_nonregr_strange_text_input(self): - """non-regression test checking text input containing "13:03:43" - - this seems to be postgres (tsearch?) specific - """ - req = self.request() - req.form = { - 'eid': 'A', '__maineid' : 'A', - '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject', - 'title-subject:A': u'"13:03:40"', - 'content-subject:A': u'"13:03:43"',} - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertTrue(path.startswith('blogentry/')) - eid = path.split('/')[1] - e = self.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0) - self.assertEqual(e.title, '"13:03:40"') - self.assertEqual(e.content, '"13:03:43"') - - - def test_nonregr_multiple_empty_email_addr(self): - gueid = self.execute('CWGroup G WHERE G name "users"')[0][0] - req = self.request() - req.form = {'eid': ['X', 'Y'], - - '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject', - 'login-subject:X': u'adim', - 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', - 'in_group-subject:X': `gueid`, - - '__type:Y': 'EmailAddress', - '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object', - 'address-subject:Y': u'', - 'alias-subject:Y': u'', - 'use_email-object:Y': 'X', - } - with self.assertRaises(ValidationError) as cm: - self.ctrl_publish(req) - self.assertEqual(cm.exception.errors, {'address-subject': u'required field'}) - - def test_nonregr_copy(self): - user = self.user() - req = self.request() - req.form = {'__maineid' : 'X', 'eid': 'X', - '__cloned_eid:X': user.eid, '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,upassword-subject', - 'login-subject:X': u'toto', - 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', - } - path, params = self.expect_redirect_handle_request(req, 'edit') - self.assertEqual(path, 'cwuser/toto') - e = self.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0) - self.assertEqual(e.login, 'toto') - self.assertEqual(e.in_group[0].name, 'managers') - - - def test_nonregr_rollback_on_validation_error(self): - req = self.request() - p = self.create_user(req, "doe") - # do not try to skip 'primary_email' for this test - old_skips = p.__class__.skip_copy_for - p.__class__.skip_copy_for = () - try: - e = self.request().create_entity('EmailAddress', address=u'doe@doe.com') - self.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s', - {'p' : p.eid, 'e' : e.eid}) - req = self.request() - req.form = {'eid': 'X', - '__cloned_eid:X': p.eid, '__type:X': 'CWUser', - '_cw_entity_fields:X': 'login-subject,surname-subject', - 'login-subject': u'dodo', - 'surname-subject:X': u'Boom', - '__errorurl' : "whatever but required", - } - # try to emulate what really happens in the web application - # 1/ validate form => EditController.publish raises a ValidationError - # which fires a Redirect - # 2/ When re-publishing the copy form, the publisher implicitly commits - try: - self.app_handle_request(req, 'edit') - except Redirect: - req = self.request() - req.form['rql'] = 'Any X WHERE X eid %s' % p.eid - req.form['vid'] = 'copy' - self.app_handle_request(req, 'view') - rset = self.execute('CWUser P WHERE P surname "Boom"') - self.assertEqual(len(rset), 0) - finally: - p.__class__.skip_copy_for = old_skips - - def test_regr_inlined_forms(self): - self.schema['described_by_test'].inlined = False - try: - req = self.request() - req.data['eidmap'] = {} - req.data['pending_others'] = set() - req.data['pending_inlined'] = {} + with self.admin_access.web_request() as req: req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', '__type:X': 'Salesterm', @@ -677,25 +210,507 @@ '_cw_entity_fields:Y': 'data-subject', 'data-subject:Y': (u'coucou.txt', Binary('coucou')), } - values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2)) - for eid in req.edited_eids()) - editctrl = self.vreg['controllers'].select('edit', req) - # don't call publish to enforce select order - editctrl.errors = [] - editctrl._to_create = {} - editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError - editctrl.edit_entity(values_by_eid['Y']) - finally: + path, _params = self.expect_redirect_handle_request(req, 'edit') + self.assertTrue(path.startswith('salesterm/'), path) + eid = path.split('/')[1] + salesterm = req.entity_from_eid(eid) + # The NOT NULL constraint of mandatory relation implies that the File + # must be created before the Salesterm, otherwise Salesterm insertion + # will fail. + # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the + # insertion does not fail and we have to check dumbly that File is + # created before. + self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid) + + def test_edit_mandatory_inlined3_object(self): + # non regression test for #3120495. Without the fix, leads to + # "unhashable type: 'list'" error + with self.admin_access.web_request() as req: + cwrelation = unicode(req.execute('CWEType X WHERE X name "CWSource"')[0][0]) + req.form = {'eid': [cwrelation], '__maineid' : cwrelation, + + '__type:'+cwrelation: 'CWEType', + '_cw_entity_fields:'+cwrelation: 'to_entity-object', + 'to_entity-object:'+cwrelation: [9999, 9998], + } + with req.cnx.deny_all_hooks_but(): + path, _params = self.expect_redirect_handle_request(req, 'edit') + self.assertTrue(path.startswith('cwetype/CWSource'), path) + + def test_edit_multiple_linked(self): + with self.admin_access.web_request() as req: + peid = unicode(self.create_user(req, 'adim').eid) + req.form = {'eid': [peid, 'Y'], '__maineid': peid, + + '__type:'+peid: u'CWUser', + '_cw_entity_fields:'+peid: u'surname-subject', + 'surname-subject:'+peid: u'Di Masci', + + '__type:Y': u'EmailAddress', + '_cw_entity_fields:Y': u'address-subject,use_email-object', + 'address-subject:Y': u'dima@logilab.fr', + 'use_email-object:Y': peid, + } + path, _params = self.expect_redirect_handle_request(req, 'edit') + # should be redirected on the created person + self.assertEqual(path, 'cwuser/adim') + e = req.execute('Any P WHERE P surname "Di Masci"').get_entity(0, 0) + email = e.use_email[0] + self.assertEqual(email.address, 'dima@logilab.fr') + + # with self.admin_access.web_request() as req: + emaileid = unicode(email.eid) + req.form = {'eid': [peid, emaileid], + + '__type:'+peid: u'CWUser', + '_cw_entity_fields:'+peid: u'surname-subject', + 'surname-subject:'+peid: u'Di Masci', + + '__type:'+emaileid: u'EmailAddress', + '_cw_entity_fields:'+emaileid: u'address-subject,use_email-object', + 'address-subject:'+emaileid: u'adim@logilab.fr', + 'use_email-object:'+emaileid: peid, + } + self.expect_redirect_handle_request(req, 'edit') + email.cw_clear_all_caches() + self.assertEqual(email.address, 'adim@logilab.fr') + + def test_password_confirm(self): + """test creation of two linked entities + """ + with self.admin_access.web_request() as req: + user = req.user + req.form = {'eid': 'X', + '__cloned_eid:X': unicode(user.eid), '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,upassword-subject', + 'login-subject:X': u'toto', + 'upassword-subject:X': u'toto', + } + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'}, + cm.exception.errors) + req.form = {'__cloned_eid:X': unicode(user.eid), + 'eid': 'X', '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,upassword-subject', + 'login-subject:X': u'toto', + 'upassword-subject:X': u'toto', + 'upassword-subject-confirm:X': u'tutu', + } + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'}, + cm.exception.errors) + + + def test_interval_bound_constraint_success(self): + with self.admin_access.repo_cnx() as cnx: + feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s', + {'data': Binary('yo')})[0][0] + cnx.commit() + + with self.admin_access.web_request(rollbackfirst=True) as req: + req.form = {'eid': ['X'], + '__type:X': 'Salesterm', + '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', + 'amount-subject:X': u'-10', + 'described_by_test-subject:X': unicode(feid), + } + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + cm.exception.translate(unicode) + self.assertEqual({'amount-subject': 'value -10 must be >= 0'}, + cm.exception.errors) + + with self.admin_access.web_request(rollbackfirst=True) as req: + req.form = {'eid': ['X'], + '__type:X': 'Salesterm', + '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', + 'amount-subject:X': u'110', + 'described_by_test-subject:X': unicode(feid), + } + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + cm.exception.translate(unicode) + self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'}) + + with self.admin_access.web_request(rollbackfirst=True) as req: + req.form = {'eid': ['X'], + '__type:X': 'Salesterm', + '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', + 'amount-subject:X': u'10', + 'described_by_test-subject:X': unicode(feid), + } + self.expect_redirect_handle_request(req, 'edit') + # should be redirected on the created + #eid = params['rql'].split()[-1] + e = req.execute('Salesterm X').get_entity(0, 0) + self.assertEqual(e.amount, 10) + + def test_interval_bound_constraint_validateform(self): + """Test the FormValidatorController controller on entity with + constrained attributes""" + with self.admin_access.repo_cnx() as cnx: + feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s', + {'data': Binary('yo')})[0][0] + seid = cnx.create_entity('Salesterm', amount=0, described_by_test=feid).eid + cnx.commit() + + # ensure a value that violate a constraint is properly detected + with self.admin_access.web_request(rollbackfirst=True) as req: + req.form = {'eid': [unicode(seid)], + '__type:%s'%seid: 'Salesterm', + '_cw_entity_fields:%s'%seid: 'amount-subject', + 'amount-subject:%s'%seid: u'-10', + } + self.assertMultiLineEqual(''''''%seid, self.ctrl_publish(req, 'validateform')) + + # ensure a value that comply a constraint is properly processed + with self.admin_access.web_request(rollbackfirst=True) as req: + req.form = {'eid': [unicode(seid)], + '__type:%s'%seid: 'Salesterm', + '_cw_entity_fields:%s'%seid: 'amount-subject', + 'amount-subject:%s'%seid: u'20', + } + self.assertMultiLineEqual('''''', self.ctrl_publish(req, 'validateform')) + self.assertEqual(20, req.execute('Any V WHERE X amount V, X eid %(eid)s', + {'eid': seid})[0][0]) + + with self.admin_access.web_request(rollbackfirst=True) as req: + req.form = {'eid': ['X'], + '__type:X': 'Salesterm', + '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', + 'amount-subject:X': u'0', + 'described_by_test-subject:X': unicode(feid), + } + + # ensure a value that is modified in an operation on a modify + # hook works as it should (see + # https://www.cubicweb.org/ticket/2509729 ) + class MyOperation(Operation): + def precommit_event(self): + self.entity.cw_set(amount=-10) + class ValidationErrorInOpAfterHook(Hook): + __regid__ = 'valerror-op-after-hook' + __select__ = Hook.__select__ & is_instance('Salesterm') + events = ('after_add_entity',) + def __call__(self): + MyOperation(self._cw, entity=self.entity) + + with self.temporary_appobjects(ValidationErrorInOpAfterHook): + self.assertMultiLineEqual('''''', self.ctrl_publish(req, 'validateform')) + + self.assertMultiLineEqual('''''', self.ctrl_publish(req, 'validateform')) + + def test_req_pending_insert(self): + """make sure req's pending insertions are taken into account""" + with self.admin_access.web_request() as req: + tmpgroup = req.create_entity('CWGroup', name=u"test") + user = req.user + req.cnx.commit() + with self.admin_access.web_request(**req_form(user)) as req: + req.session.data['pending_insert'] = set([(user.eid, 'in_group', tmpgroup.eid)]) + self.expect_redirect_handle_request(req, 'edit') + usergroups = [gname for gname, in + req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', + {'u': user.eid})] + self.assertCountEqual(usergroups, ['managers', 'test']) + self.assertEqual(get_pending_inserts(req), []) + + def test_req_pending_delete(self): + """make sure req's pending deletions are taken into account""" + with self.admin_access.web_request() as req: + user = req.user + groupeid = req.execute('INSERT CWGroup G: G name "test", U in_group G WHERE U eid %(x)s', + {'x': user.eid})[0][0] + usergroups = [gname for gname, in + req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', + {'u': user.eid})] + # just make sure everything was set correctly + self.assertCountEqual(usergroups, ['managers', 'test']) + req.cnx.commit() + # now try to delete the relation + with self.admin_access.web_request(**req_form(user)) as req: + req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)]) + self.expect_redirect_handle_request(req, 'edit') + usergroups = [gname for gname, in + req.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', + {'u': user.eid})] + self.assertCountEqual(usergroups, ['managers']) + self.assertEqual(get_pending_deletes(req), []) + + def test_redirect_apply_button(self): + with self.admin_access.web_request() as req: + redirectrql = rql_for_eid(4012) # whatever + req.form = { + 'eid': 'A', '__maineid' : 'A', + '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject', + 'content-subject:A': u'"13:03:43"', + 'title-subject:A': u'huuu', + '__redirectrql': redirectrql, + '__redirectvid': 'primary', + '__redirectparams': 'toto=tutu&tata=titi', + '__form_id': 'edition', + '__action_apply': '', + } + path, params = self.expect_redirect_handle_request(req, 'edit') + self.assertTrue(path.startswith('blogentry/')) + eid = path.split('/')[1] + self.assertEqual(params['vid'], 'edition') + self.assertNotEqual(int(eid), 4012) + self.assertEqual(params['__redirectrql'], redirectrql) + self.assertEqual(params['__redirectvid'], 'primary') + self.assertEqual(params['__redirectparams'], 'toto=tutu&tata=titi') + + def test_redirect_ok_button(self): + with self.admin_access.web_request() as req: + redirectrql = rql_for_eid(4012) # whatever + req.form = { + 'eid': 'A', '__maineid' : 'A', + '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'content-subject,title-subject', + 'content-subject:A': u'"13:03:43"', + 'title-subject:A': u'huuu', + '__redirectrql': redirectrql, + '__redirectvid': 'primary', + '__redirectparams': 'toto=tutu&tata=titi', + '__form_id': 'edition', + } + path, params = self.expect_redirect_handle_request(req, 'edit') + self.assertEqual(path, 'view') + self.assertEqual(params['rql'], redirectrql) + self.assertEqual(params['vid'], 'primary') + self.assertEqual(params['tata'], 'titi') + self.assertEqual(params['toto'], 'tutu') + + def test_redirect_delete_button(self): + with self.admin_access.web_request() as req: + eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid + req.form = {'eid': unicode(eid), '__type:%s'%eid: 'BlogEntry', + '__action_delete': ''} + path, params = self.expect_redirect_handle_request(req, 'edit') + self.assertEqual(path, 'blogentry') + self.assertIn('_cwmsgid', params) + eid = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid + req.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s', + {'x': self.session.user.eid, 'e': eid}) + req.cnx.commit() + req.form = {'eid': unicode(eid), '__type:%s'%eid: 'EmailAddress', + '__action_delete': ''} + path, params = self.expect_redirect_handle_request(req, 'edit') + self.assertEqual(path, 'cwuser/admin') + self.assertIn('_cwmsgid', params) + eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid + eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid + req.form = {'eid': [unicode(eid1), unicode(eid2)], + '__type:%s'%eid1: 'BlogEntry', + '__type:%s'%eid2: 'EmailAddress', + '__action_delete': ''} + path, params = self.expect_redirect_handle_request(req, 'edit') + self.assertEqual(path, 'view') + self.assertIn('_cwmsgid', params) + + def test_simple_copy(self): + with self.admin_access.web_request() as req: + blog = req.create_entity('Blog', title=u'my-blog') + blogentry = req.create_entity('BlogEntry', title=u'entry1', + content=u'content1', entry_of=blog) + req.form = {'__maineid' : 'X', 'eid': 'X', + '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry', + '_cw_entity_fields:X': 'title-subject,content-subject', + 'title-subject:X': u'entry1-copy', + 'content-subject:X': u'content1', + } + self.expect_redirect_handle_request(req, 'edit') + blogentry2 = req.find('BlogEntry', title=u'entry1-copy').one() + self.assertEqual(blogentry2.entry_of[0].eid, blog.eid) + + def test_skip_copy_for(self): + with self.admin_access.web_request() as req: + blog = req.create_entity('Blog', title=u'my-blog') + blogentry = req.create_entity('BlogEntry', title=u'entry1', + content=u'content1', entry_of=blog) + blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')] + try: + req.form = {'__maineid' : 'X', 'eid': 'X', + '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry', + '_cw_entity_fields:X': 'title-subject,content-subject', + 'title-subject:X': u'entry1-copy', + 'content-subject:X': u'content1', + } + self.expect_redirect_handle_request(req, 'edit') + blogentry2 = req.find('BlogEntry', title=u'entry1-copy').one() + # entry_of should not be copied + self.assertEqual(len(blogentry2.entry_of), 0) + finally: + blogentry.__class__.cw_skip_copy_for = [] + + def test_nonregr_eetype_etype_editing(self): + """non-regression test checking that a manager user can edit a CWEType entity + """ + with self.admin_access.web_request() as req: + groupeids = sorted(eid + for eid, in req.execute('CWGroup G ' + 'WHERE G name in ("managers", "users")')) + groups = [unicode(eid) for eid in groupeids] + cwetypeeid = req.execute('CWEType X WHERE X name "CWEType"')[0][0] + basegroups = [unicode(eid) + for eid, in req.execute('CWGroup G ' + 'WHERE X read_permission G, X eid %(x)s', + {'x': cwetypeeid})] + cwetypeeid = unicode(cwetypeeid) + req.form = { + 'eid': cwetypeeid, + '__type:'+cwetypeeid: 'CWEType', + '_cw_entity_fields:'+cwetypeeid: 'name-subject,final-subject,description-subject,read_permission-subject', + 'name-subject:'+cwetypeeid: u'CWEType', + 'final-subject:'+cwetypeeid: '', + 'description-subject:'+cwetypeeid: u'users group', + 'read_permission-subject:'+cwetypeeid: groups, + } + try: + self.expect_redirect_handle_request(req, 'edit') + e = req.execute('Any X WHERE X eid %(x)s', {'x': cwetypeeid}).get_entity(0, 0) + self.assertEqual(e.name, 'CWEType') + self.assertEqual(sorted(g.eid for g in e.read_permission), groupeids) + finally: + # restore + req.execute('SET X read_permission Y WHERE X name "CWEType", ' + 'Y eid IN (%s), NOT X read_permission Y' % (','.join(basegroups))) + req.cnx.commit() + + def test_nonregr_strange_text_input(self): + """non-regression test checking text input containing "13:03:43" + + this seems to be postgres (tsearch?) specific + """ + with self.admin_access.web_request() as req: + req.form = { + 'eid': 'A', '__maineid' : 'A', + '__type:A': 'BlogEntry', '_cw_entity_fields:A': 'title-subject,content-subject', + 'title-subject:A': u'"13:03:40"', + 'content-subject:A': u'"13:03:43"',} + path, _params = self.expect_redirect_handle_request(req, 'edit') + self.assertTrue(path.startswith('blogentry/')) + eid = path.split('/')[1] + e = req.execute('Any C, T WHERE C eid %(x)s, C content T', {'x': eid}).get_entity(0, 0) + self.assertEqual(e.title, '"13:03:40"') + self.assertEqual(e.content, '"13:03:43"') + + + def test_nonregr_multiple_empty_email_addr(self): + with self.admin_access.web_request() as req: + gueid = req.execute('CWGroup G WHERE G name "users"')[0][0] + req.form = {'eid': ['X', 'Y'], + + '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject', + 'login-subject:X': u'adim', + 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', + 'in_group-subject:X': `gueid`, + + '__type:Y': 'EmailAddress', + '_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object', + 'address-subject:Y': u'', + 'alias-subject:Y': u'', + 'use_email-object:Y': 'X', + } + with self.assertRaises(ValidationError) as cm: + self.ctrl_publish(req) + self.assertEqual(cm.exception.errors, {'address-subject': u'required field'}) + + def test_nonregr_copy(self): + with self.admin_access.web_request() as req: + user = req.user + req.form = {'__maineid' : 'X', 'eid': 'X', + '__cloned_eid:X': user.eid, '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,upassword-subject', + 'login-subject:X': u'toto', + 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', + } + path, _params = self.expect_redirect_handle_request(req, 'edit') + self.assertEqual(path, 'cwuser/toto') + e = req.execute('Any X WHERE X is CWUser, X login "toto"').get_entity(0, 0) + self.assertEqual(e.login, 'toto') + self.assertEqual(e.in_group[0].name, 'managers') + + + def test_nonregr_rollback_on_validation_error(self): + with self.admin_access.web_request() as req: + p = self.create_user(req, "doe") + # do not try to skip 'primary_email' for this test + old_skips = p.__class__.skip_copy_for + p.__class__.skip_copy_for = () + try: + e = req.create_entity('EmailAddress', address=u'doe@doe.com') + req.execute('SET P use_email E, P primary_email E WHERE P eid %(p)s, E eid %(e)s', + {'p' : p.eid, 'e' : e.eid}) + req.form = {'eid': 'X', + '__cloned_eid:X': p.eid, '__type:X': 'CWUser', + '_cw_entity_fields:X': 'login-subject,surname-subject', + 'login-subject': u'dodo', + 'surname-subject:X': u'Boom', + '__errorurl' : "whatever but required", + } + # try to emulate what really happens in the web application + # 1/ validate form => EditController.publish raises a ValidationError + # which fires a Redirect + # 2/ When re-publishing the copy form, the publisher implicitly commits + try: + self.app_handle_request(req, 'edit') + except Redirect: + req.form['rql'] = 'Any X WHERE X eid %s' % p.eid + req.form['vid'] = 'copy' + self.app_handle_request(req, 'view') + rset = req.execute('CWUser P WHERE P surname "Boom"') + self.assertEqual(len(rset), 0) + finally: + p.__class__.skip_copy_for = old_skips + + def test_regr_inlined_forms(self): + with self.admin_access.web_request() as req: self.schema['described_by_test'].inlined = False + try: + req.data['eidmap'] = {} + req.data['pending_others'] = set() + req.data['pending_inlined'] = {} + req.form = {'eid': ['X', 'Y'], '__maineid' : 'X', + + '__type:X': 'Salesterm', + '_cw_entity_fields:X': 'described_by_test-subject', + 'described_by_test-subject:X': 'Y', + + '__type:Y': 'File', + '_cw_entity_fields:Y': 'data-subject', + 'data-subject:Y': (u'coucou.txt', Binary('coucou')), + } + values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2)) + for eid in req.edited_eids()) + editctrl = self.vreg['controllers'].select('edit', req) + # don't call publish to enforce select order + editctrl.errors = [] + editctrl._to_create = {} + editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError + editctrl.edit_entity(values_by_eid['Y']) + finally: + self.schema['described_by_test'].inlined = False class ReportBugControllerTC(CubicWebTC): def test_usable_by_guest(self): - self.login('anon') - self.assertRaises(NoSelectableObject, - self.vreg['controllers'].select, 'reportbug', self.request()) - self.vreg['controllers'].select('reportbug', self.request(description='hop')) + with self.new_access('anon').web_request() as req: + self.assertRaises(NoSelectableObject, + self.vreg['controllers'].select, 'reportbug', req) + with self.new_access('anon').web_request(description='hop') as req: + self.vreg['controllers'].select('reportbug', req) class AjaxControllerTC(CubicWebTC): @@ -706,21 +721,21 @@ return self.vreg['controllers'].select(self.tested_controller, req) def setup_database(self): - req = self.request() - self.pytag = req.create_entity('Tag', name=u'python') - self.cubicwebtag = req.create_entity('Tag', name=u'cubicweb') - self.john = self.create_user(req, u'John') - + with self.admin_access.repo_cnx() as cnx: + self.pytag = cnx.create_entity('Tag', name=u'python') + self.cubicwebtag = cnx.create_entity('Tag', name=u'cubicweb') + self.john = self.create_user(cnx, u'John') + cnx.commit() ## tests ################################################################## def test_simple_exec(self): - req = self.request(rql='CWUser P WHERE P login "John"', - pageid='123', fname='view') - ctrl = self.ctrl(req) - rset = self.john.as_rset() - rset.req = req - source = ctrl.publish() - self.assertTrue(source.startswith('
')) + with self.admin_access.web_request(rql='CWUser P WHERE P login "John"', + pageid='123', fname='view') as req: + ctrl = self.ctrl(req) + rset = self.john.as_rset() + rset.req = req + source = ctrl.publish() + self.assertTrue(source.startswith('
')) # def test_json_exec(self): # rql = 'Any T,N WHERE T is Tag, T name N' @@ -729,92 +744,94 @@ # json_dumps(self.execute(rql).rows)) def test_remote_add_existing_tag(self): - self.remote_call('tag_entity', self.john.eid, ['python']) - self.assertCountEqual( - [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')], - ['python', 'cubicweb']) - self.assertEqual( - self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows, - [['python']]) + with self.remote_calling('tag_entity', self.john.eid, ['python']) as (_, req): + self.assertCountEqual( + [tname for tname, in req.execute('Any N WHERE T is Tag, T name N')], + ['python', 'cubicweb']) + self.assertEqual( + req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows, + [['python']]) def test_remote_add_new_tag(self): - self.remote_call('tag_entity', self.john.eid, ['javascript']) - self.assertCountEqual( - [tname for tname, in self.execute('Any N WHERE T is Tag, T name N')], - ['python', 'cubicweb', 'javascript']) - self.assertEqual( - self.execute('Any N WHERE T tags P, P is CWUser, T name N').rows, - [['javascript']]) + with self.remote_calling('tag_entity', self.john.eid, ['javascript']) as (_, req): + self.assertCountEqual( + [tname for tname, in req.execute('Any N WHERE T is Tag, T name N')], + ['python', 'cubicweb', 'javascript']) + self.assertEqual( + req.execute('Any N WHERE T tags P, P is CWUser, T name N').rows, + [['javascript']]) def test_pending_insertion(self): - res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '13']]) - deletes = get_pending_deletes(req) - self.assertEqual(deletes, []) - inserts = get_pending_inserts(req) - self.assertEqual(inserts, ['12:tags:13']) - res, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']]) - deletes = get_pending_deletes(req) - self.assertEqual(deletes, []) - inserts = get_pending_inserts(req) - self.assertEqual(inserts, ['12:tags:13', '12:tags:14']) - inserts = get_pending_inserts(req, 12) - self.assertEqual(inserts, ['12:tags:13', '12:tags:14']) - inserts = get_pending_inserts(req, 13) - self.assertEqual(inserts, ['12:tags:13']) - inserts = get_pending_inserts(req, 14) - self.assertEqual(inserts, ['12:tags:14']) - req.remove_pending_operations() + with self.remote_calling('add_pending_inserts', [['12', 'tags', '13']]) as (_, req): + deletes = get_pending_deletes(req) + self.assertEqual(deletes, []) + inserts = get_pending_inserts(req) + self.assertEqual(inserts, ['12:tags:13']) + with self.remote_calling('add_pending_inserts', [['12', 'tags', '14']]) as (_, req): + deletes = get_pending_deletes(req) + self.assertEqual(deletes, []) + inserts = get_pending_inserts(req) + self.assertEqual(inserts, ['12:tags:13', '12:tags:14']) + inserts = get_pending_inserts(req, 12) + self.assertEqual(inserts, ['12:tags:13', '12:tags:14']) + inserts = get_pending_inserts(req, 13) + self.assertEqual(inserts, ['12:tags:13']) + inserts = get_pending_inserts(req, 14) + self.assertEqual(inserts, ['12:tags:14']) + req.remove_pending_operations() def test_pending_deletion(self): - res, req = self.remote_call('add_pending_delete', ['12', 'tags', '13']) - inserts = get_pending_inserts(req) - self.assertEqual(inserts, []) - deletes = get_pending_deletes(req) - self.assertEqual(deletes, ['12:tags:13']) - res, req = self.remote_call('add_pending_delete', ['12', 'tags', '14']) - inserts = get_pending_inserts(req) - self.assertEqual(inserts, []) - deletes = get_pending_deletes(req) - self.assertEqual(deletes, ['12:tags:13', '12:tags:14']) - deletes = get_pending_deletes(req, 12) - self.assertEqual(deletes, ['12:tags:13', '12:tags:14']) - deletes = get_pending_deletes(req, 13) - self.assertEqual(deletes, ['12:tags:13']) - deletes = get_pending_deletes(req, 14) - self.assertEqual(deletes, ['12:tags:14']) - req.remove_pending_operations() + with self.remote_calling('add_pending_delete', ['12', 'tags', '13']) as (_, req): + inserts = get_pending_inserts(req) + self.assertEqual(inserts, []) + deletes = get_pending_deletes(req) + self.assertEqual(deletes, ['12:tags:13']) + with self.remote_calling('add_pending_delete', ['12', 'tags', '14']) as (_, req): + inserts = get_pending_inserts(req) + self.assertEqual(inserts, []) + deletes = get_pending_deletes(req) + self.assertEqual(deletes, ['12:tags:13', '12:tags:14']) + deletes = get_pending_deletes(req, 12) + self.assertEqual(deletes, ['12:tags:13', '12:tags:14']) + deletes = get_pending_deletes(req, 13) + self.assertEqual(deletes, ['12:tags:13']) + deletes = get_pending_deletes(req, 14) + self.assertEqual(deletes, ['12:tags:14']) + req.remove_pending_operations() def test_remove_pending_operations(self): - self.remote_call('add_pending_delete', ['12', 'tags', '13']) - _, req = self.remote_call('add_pending_inserts', [['12', 'tags', '14']]) - inserts = get_pending_inserts(req) - self.assertEqual(inserts, ['12:tags:14']) - deletes = get_pending_deletes(req) - self.assertEqual(deletes, ['12:tags:13']) - req.remove_pending_operations() - self.assertEqual(get_pending_deletes(req), []) - self.assertEqual(get_pending_inserts(req), []) - + with self.remote_calling('add_pending_delete', ['12', 'tags', '13']): + pass + with self.remote_calling('add_pending_inserts', [['12', 'tags', '14']]) as (_, req): + inserts = get_pending_inserts(req) + self.assertEqual(inserts, ['12:tags:14']) + deletes = get_pending_deletes(req) + self.assertEqual(deletes, ['12:tags:13']) + req.remove_pending_operations() + self.assertEqual(get_pending_deletes(req), []) + self.assertEqual(get_pending_inserts(req), []) def test_add_inserts(self): - res, req = self.remote_call('add_pending_inserts', - [('12', 'tags', '13'), ('12', 'tags', '14')]) - inserts = get_pending_inserts(req) - self.assertEqual(inserts, ['12:tags:13', '12:tags:14']) - req.remove_pending_operations() + with self.remote_calling('add_pending_inserts', + [('12', 'tags', '13'), ('12', 'tags', '14')]) as (_, req): + inserts = get_pending_inserts(req) + self.assertEqual(inserts, ['12:tags:13', '12:tags:14']) + req.remove_pending_operations() # silly tests def test_external_resource(self): - self.assertEqual(self.remote_call('external_resource', 'RSS_LOGO')[0], - json_dumps(self.config.uiprops['RSS_LOGO'])) + with self.remote_calling('external_resource', 'RSS_LOGO') as (res, _): + self.assertEqual(json_dumps(self.config.uiprops['RSS_LOGO']), + res) + def test_i18n(self): - self.assertEqual(self.remote_call('i18n', ['bimboom'])[0], - json_dumps(['bimboom'])) + with self.remote_calling('i18n', ['bimboom']) as (res, _): + self.assertEqual(json_dumps(['bimboom']), res) def test_format_date(self): - self.assertEqual(self.remote_call('format_date', '2007-01-01 12:00:00')[0], - json_dumps('2007/01/01')) + with self.remote_calling('format_date', '2007-01-01 12:00:00') as (res, _): + self.assertEqual(json_dumps('2007/01/01'), res) def test_ajaxfunc_noparameter(self): @ajaxfunc @@ -826,9 +843,9 @@ self.assertEqual(appobject.__regid__, 'foo') self.assertEqual(appobject.check_pageid, False) self.assertEqual(appobject.output_type, None) - req = self.request() - f = appobject(req) - self.assertEqual(f(12, 13), 'hello') + with self.admin_access.web_request() as req: + f = appobject(req) + self.assertEqual(f(12, 13), 'hello') def test_ajaxfunc_checkpageid(self): @ajaxfunc(check_pageid=True) @@ -841,9 +858,9 @@ self.assertEqual(appobject.check_pageid, True) self.assertEqual(appobject.output_type, None) # no pageid - req = self.request() - f = appobject(req) - self.assertRaises(RemoteCallFailed, f, 12, 13) + with self.admin_access.web_request() as req: + f = appobject(req) + self.assertRaises(RemoteCallFailed, f, 12, 13) def test_ajaxfunc_json(self): @ajaxfunc(output_type='json') @@ -856,9 +873,9 @@ self.assertEqual(appobject.check_pageid, False) self.assertEqual(appobject.output_type, 'json') # no pageid - req = self.request() - f = appobject(req) - self.assertEqual(f(12, 13), '25') + with self.admin_access.web_request() as req: + f = appobject(req) + self.assertEqual(f(12, 13), '25') class JSonControllerTC(AjaxControllerTC): @@ -879,38 +896,44 @@ delattr(JSonController, funcname) def test_monkeypatch_jsoncontroller(self): - self.assertRaises(RemoteCallFailed, self.remote_call, 'foo') + with self.assertRaises(RemoteCallFailed): + with self.remote_calling('foo'): + pass @monkeypatch(JSonController) def js_foo(self): return u'hello' - res, req = self.remote_call('foo') - self.assertEqual(res, u'hello') + with self.remote_calling('foo') as (res, _): + self.assertEqual(res, u'hello') def test_monkeypatch_jsoncontroller_xhtmlize(self): - self.assertRaises(RemoteCallFailed, self.remote_call, 'foo') + with self.assertRaises(RemoteCallFailed): + with self.remote_calling('foo'): + pass @monkeypatch(JSonController) @xhtmlize def js_foo(self): return u'hello' - res, req = self.remote_call('foo') - self.assertEqual(u'
hello
', res) + with self.remote_calling('foo') as (res, _): + self.assertEqual(u'
hello
', res) def test_monkeypatch_jsoncontroller_jsonize(self): - self.assertRaises(RemoteCallFailed, self.remote_call, 'foo') + with self.assertRaises(RemoteCallFailed): + with self.remote_calling('foo'): + pass @monkeypatch(JSonController) @jsonize def js_foo(self): return 12 - res, req = self.remote_call('foo') - self.assertEqual(res, '12') + with self.remote_calling('foo') as (res, _): + self.assertEqual(res, '12') def test_monkeypatch_jsoncontroller_stdfunc(self): @monkeypatch(JSonController) @jsonize def js_reledit_form(self): return 12 - res, req = self.remote_call('reledit_form') - self.assertEqual(res, '12') + with self.remote_calling('reledit_form') as (res, _): + self.assertEqual(res, '12') class UndoControllerTC(CubicWebTC): @@ -926,75 +949,76 @@ super(UndoControllerTC, self).tearDown() cubicweb.server.session.Connection = OldConnection - def setup_database(self): - req = self.request() - self.toto = self.create_user(req, 'toto', password='toto', groups=('users',), - commit=False) - self.txuuid_toto = self.commit() - self.toto_email = self.session.create_entity('EmailAddress', - address=u'toto@logilab.org', - reverse_use_email=self.toto) - self.txuuid_toto_email = self.commit() + with self.admin_access.repo_cnx() as cnx: + self.toto = self.create_user(cnx, 'toto', + password='toto', + groups=('users',), + commit=False) + self.txuuid_toto = cnx.commit() + self.toto_email = cnx.create_entity('EmailAddress', + address=u'toto@logilab.org', + reverse_use_email=self.toto) + self.txuuid_toto_email = cnx.commit() def test_no_such_transaction(self): - req = self.request() - txuuid = u"12345acbd" - req.form['txuuid'] = txuuid - controller = self.vreg['controllers'].select('undo', req) - with self.assertRaises(tx.NoSuchTransaction) as cm: - result = controller.publish(rset=None) - self.assertEqual(cm.exception.txuuid, txuuid) + with self.admin_access.web_request() as req: + txuuid = u"12345acbd" + req.form['txuuid'] = txuuid + controller = self.vreg['controllers'].select('undo', req) + with self.assertRaises(tx.NoSuchTransaction) as cm: + result = controller.publish(rset=None) + self.assertEqual(cm.exception.txuuid, txuuid) def assertURLPath(self, url, expected_path, expected_params=None): """ This assert that the path part of `url` matches expected path TODO : implement assertion on the expected_params too """ - req = self.request() - scheme, netloc, path, query, fragment = urlsplit(url) - query_dict = url_parse_query(query) - expected_url = urljoin(req.base_url(), expected_path) - self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url) + with self.admin_access.web_request() as req: + scheme, netloc, path, query, fragment = urlsplit(url) + query_dict = url_parse_query(query) + expected_url = urljoin(req.base_url(), expected_path) + self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url) def test_redirect_redirectpath(self): "Check that the potential __redirectpath is honored" - req = self.request() - txuuid = self.txuuid_toto_email - req.form['txuuid'] = txuuid - rpath = "toto" - req.form['__redirectpath'] = rpath - controller = self.vreg['controllers'].select('undo', req) - with self.assertRaises(Redirect) as cm: - result = controller.publish(rset=None) - self.assertURLPath(cm.exception.location, rpath) + with self.admin_access.web_request() as req: + txuuid = self.txuuid_toto_email + req.form['txuuid'] = txuuid + rpath = "toto" + req.form['__redirectpath'] = rpath + controller = self.vreg['controllers'].select('undo', req) + with self.assertRaises(Redirect) as cm: + result = controller.publish(rset=None) + self.assertURLPath(cm.exception.location, rpath) def test_redirect_default(self): - req = self.request() - txuuid = self.txuuid_toto_email - req.form['txuuid'] = txuuid - req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path) - for path in ('tata', 'toto',)] - controller = self.vreg['controllers'].select('undo', req) - with self.assertRaises(Redirect) as cm: - result = controller.publish(rset=None) - self.assertURLPath(cm.exception.location, 'toto') + with self.admin_access.web_request() as req: + txuuid = self.txuuid_toto_email + req.form['txuuid'] = txuuid + req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path) + for path in ('tata', 'toto',)] + controller = self.vreg['controllers'].select('undo', req) + with self.assertRaises(Redirect) as cm: + result = controller.publish(rset=None) + self.assertURLPath(cm.exception.location, 'toto') class LoginControllerTC(CubicWebTC): def test_login_with_dest(self): - req = self.request() - req.form = {'postlogin_path': 'elephants/babar'} - with self.assertRaises(Redirect) as cm: - self.ctrl_publish(req, ctrl='login') - self.assertEqual(req.build_url('elephants/babar'), cm.exception.location) + with self.admin_access.web_request() as req: + req.form = {'postlogin_path': 'elephants/babar'} + with self.assertRaises(Redirect) as cm: + self.ctrl_publish(req, ctrl='login') + self.assertEqual(req.build_url('elephants/babar'), cm.exception.location) def test_login_no_dest(self): - req = self.request() - with self.assertRaises(Redirect) as cm: - self.ctrl_publish(req, ctrl='login') - self.assertEqual(req.base_url(), cm.exception.location) + with self.admin_access.web_request() as req: + with self.assertRaises(Redirect) as cm: + self.ctrl_publish(req, ctrl='login') + self.assertEqual(req.base_url(), cm.exception.location) if __name__ == '__main__': unittest_main() diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_basetemplates.py --- a/web/test/unittest_views_basetemplates.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_basetemplates.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -18,7 +18,6 @@ from cubicweb.devtools.testlib import CubicWebTC from cubicweb.devtools.htmlparser import XMLValidator -from cubicweb.dbapi import DBAPISession class LogFormTemplateTC(CubicWebTC): @@ -39,7 +38,8 @@ class MainNoTopTemplateTC(CubicWebTC): def test_valid_xhtml(self): - self.view('index', template='main-no-top') + with self.admin_access.web_request() as req: + self.view('index', template='main-no-top', req=req) if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_baseviews.py --- a/web/test/unittest_views_baseviews.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_baseviews.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -22,7 +22,6 @@ from cubicweb.devtools.testlib import CubicWebTC from cubicweb.utils import json from cubicweb.view import StartupView, TRANSITIONAL_DOCTYPE -from cubicweb.web.htmlwidgets import TableWidget from cubicweb.web.views import vid_from_rset def loadjson(value): @@ -31,90 +30,85 @@ class VidFromRsetTC(CubicWebTC): def test_no_rset(self): - req = self.request() - self.assertEqual(vid_from_rset(req, None, self.schema), 'index') + with self.admin_access.web_request() as req: + self.assertEqual(vid_from_rset(req, None, self.schema), 'index') def test_no_entity(self): - req = self.request() - rset = self.execute('Any X WHERE X login "blabla"') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'noresult') + with self.admin_access.web_request() as req: + rset = req.execute('Any X WHERE X login "blabla"') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'noresult') def test_one_entity(self): - req = self.request() - rset = self.execute('Any X WHERE X login "admin"') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary') - rset = self.execute('Any X, L WHERE X login "admin", X login L') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary') - req.search_state = ('pasnormal',) - rset = self.execute('Any X WHERE X login "admin"') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'outofcontext-search') + with self.admin_access.web_request() as req: + rset = req.execute('Any X WHERE X login "admin"') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary') + rset = req.execute('Any X, L WHERE X login "admin", X login L') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary') + req.search_state = ('pasnormal',) + rset = req.execute('Any X WHERE X login "admin"') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'outofcontext-search') def test_one_entity_eid(self): - req = self.request() - rset = self.execute('Any X WHERE X eid 1') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary') + with self.admin_access.web_request() as req: + rset = req.execute('Any X WHERE X eid 1') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'primary') def test_more_than_one_entity_same_type(self): - req = self.request() - rset = self.execute('Any X WHERE X is CWUser') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist') - rset = self.execute('Any X, L WHERE X login L') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist') + with self.admin_access.web_request() as req: + rset = req.execute('Any X WHERE X is CWUser') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist') + rset = req.execute('Any X, L WHERE X login L') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'sameetypelist') def test_more_than_one_entity_diff_type(self): - req = self.request() - rset = self.execute('Any X WHERE X is IN (CWUser, CWGroup)') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'list') + with self.admin_access.web_request() as req: + rset = req.execute('Any X WHERE X is IN (CWUser, CWGroup)') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'list') def test_more_than_one_entity_by_row(self): - req = self.request() - rset = self.execute('Any X, G WHERE X in_group G') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') + with self.admin_access.web_request() as req: + rset = req.execute('Any X, G WHERE X in_group G') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') def test_more_than_one_entity_by_row_2(self): - req = self.request() - rset = self.execute('Any X, GN WHERE X in_group G, G name GN') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') + with self.admin_access.web_request() as req: + rset = req.execute('Any X, GN WHERE X in_group G, G name GN') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') def test_aggregat(self): - req = self.request() - rset = self.execute('Any X, COUNT(T) GROUPBY X WHERE X is T') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') - rset = self.execute('Any MAX(X) WHERE X is CWUser') - self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') + with self.admin_access.web_request() as req: + rset = req.execute('Any X, COUNT(T) GROUPBY X WHERE X is T') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') + rset = req.execute('Any MAX(X) WHERE X is CWUser') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') def test_subquery(self): - rset = self.execute( + with self.admin_access.web_request() as req: + rset = req.execute( 'DISTINCT Any X,N ORDERBY N ' 'WITH X,N BEING (' ' (DISTINCT Any P,N WHERE P is CWUser, P login N)' ' UNION' ' (DISTINCT Any W,N WHERE W is CWGroup, W name N))') - req = self.request() - self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') + self.assertEqual(vid_from_rset(req, rset, self.schema), 'table') class TableViewTC(CubicWebTC): - def _prepare_entity(self): - req = self.request() + def _prepare_entity(self, req): e = req.create_entity("State", name=u'', description=u'loo"ong blabla') - rset = req.execute('Any X, D, CD, NOW - CD WHERE X is State, X description D, X creation_date CD, X eid %(x)s', + rset = req.execute('Any X, D, CD, NOW - CD WHERE X is State, ' + 'X description D, X creation_date CD, X eid %(x)s', {'x': e.eid}) view = self.vreg['views'].select('table', req, rset=rset) return e, rset, view - def test_headers(self): - self.skipTest('implement me') - def test_sortvalue(self): - e, _, view = self._prepare_entity() - colrenderers = view.build_column_renderers()[:3] - self.assertListEqual([renderer.sortvalue(0) for renderer in colrenderers], - [u'', u'loo"ong blabla', e.creation_date]) - # XXX sqlite does not handle Interval correctly - # value = loadjson(view.sortvalue(0, 3)) - # self.assertAlmostEquals(value, rset.rows[0][3].seconds) + with self.admin_access.web_request() as req: + e, _, view = self._prepare_entity(req) + colrenderers = view.build_column_renderers()[:3] + self.assertListEqual([renderer.sortvalue(0) for renderer in colrenderers], + [u'', u'loo"ong blabla', e.creation_date]) class HTMLStreamTests(CubicWebTC): @@ -129,11 +123,15 @@ def call(self): self._cw.set_doctype('') - with self.temporary_appobjects(MyView): - html_source = self.view('my-view').source - source_lines = [line.strip() for line in html_source.splitlines(False) - if line.strip()] - self.assertListEqual(['', ''], source_lines[:2]) + with self.admin_access.web_request() as req: + with self.temporary_appobjects(MyView): + html_source = self.view('my-view', req=req).source + source_lines = [line.strip() + for line in html_source.splitlines(False) + if line.strip()] + self.assertListEqual(['', + ''], + source_lines[:2]) def test_set_doctype_no_reset_xmldecl(self): """ @@ -147,12 +145,16 @@ self._cw.set_doctype(html_doctype) self._cw.main_stream.set_htmlattrs([('lang', 'cz')]) - with self.temporary_appobjects(MyView): - html_source = self.view('my-view').source - source_lines = [line.strip() for line in html_source.splitlines(False) - if line.strip()] - self.assertListEqual([html_doctype, '', ''], - source_lines[:3]) + with self.admin_access.web_request() as req: + with self.temporary_appobjects(MyView): + html_source = self.view('my-view', req=req).source + source_lines = [line.strip() + for line in html_source.splitlines(False) + if line.strip()] + self.assertListEqual([html_doctype, + '', + ''], + source_lines[:3]) if __name__ == '__main__': unittest_main() diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_editforms.py --- a/web/test/unittest_views_editforms.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_editforms.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -15,9 +15,6 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -""" - -""" from logilab.common.testlib import unittest_main, mock_object from cubicweb.devtools.testlib import CubicWebTC @@ -32,154 +29,171 @@ permission = 'update' else: permission = 'add' - return [(rschema.type, x) for rschema, tschemas, x in AFS.relations_by_section(entity, formtype, section, permission)] + return [(rschema.type, x) + for rschema, tschemas, x in AFS.relations_by_section(entity, + formtype, + section, + permission)] class AutomaticEntityFormTC(CubicWebTC): def test_custom_widget(self): - AFFK.tag_subject_of(('CWUser', 'login', '*'), - {'widget': AutoCompletionWidget(autocomplete_initfunc='get_logins')}) - form = self.vreg['forms'].select('edition', self.request(), - entity=self.user()) - field = form.field_by_name('login', 'subject') - self.assertIsInstance(field.widget, AutoCompletionWidget) - AFFK.del_rtag('CWUser', 'login', '*', 'subject') + with self.admin_access.web_request() as req: + AFFK.tag_subject_of(('CWUser', 'login', '*'), + {'widget': AutoCompletionWidget(autocomplete_initfunc='get_logins')}) + form = self.vreg['forms'].select('edition', req, entity=self.user(req)) + field = form.field_by_name('login', 'subject') + self.assertIsInstance(field.widget, AutoCompletionWidget) + AFFK.del_rtag('CWUser', 'login', '*', 'subject') def test_cwuser_relations_by_category(self): - e = self.vreg['etypes'].etype_class('CWUser')(self.request()) - # see custom configuration in views.cwuser - self.assertEqual(rbc(e, 'main', 'attributes'), - [('login', 'subject'), - ('upassword', 'subject'), - ('firstname', 'subject'), - ('surname', 'subject'), - ('in_group', 'subject'), - ]) - self.assertListEqual(rbc(e, 'muledit', 'attributes'), + with self.admin_access.web_request() as req: + e = self.vreg['etypes'].etype_class('CWUser')(req) + # see custom configuration in views.cwuser + self.assertEqual(rbc(e, 'main', 'attributes'), [('login', 'subject'), ('upassword', 'subject'), + ('firstname', 'subject'), + ('surname', 'subject'), ('in_group', 'subject'), ]) - self.assertListEqual(rbc(e, 'main', 'metadata'), - [('last_login_time', 'subject'), - ('cw_source', 'subject'), - ('creation_date', 'subject'), - ('cwuri', 'subject'), - ('modification_date', 'subject'), - ('created_by', 'subject'), - ('owned_by', 'subject'), - ('bookmarked_by', 'object'), - ]) - # XXX skip 'tags' relation here and in the hidden category because - # of some test interdependancy when pytest is launched on whole cw - # (appears here while expected in hidden - self.assertListEqual([x for x in rbc(e, 'main', 'relations') - if x != ('tags', 'object')], - [('connait', 'subject'), - ('custom_workflow', 'subject'), - ('primary_email', 'subject'), - ('checked_by', 'object'), - ]) - self.assertListEqual(rbc(e, 'main', 'inlined'), - [('use_email', 'subject'), - ]) - # owned_by is defined both as subject and object relations on CWUser - self.assertListEqual(sorted(x for x in rbc(e, 'main', 'hidden') - if x != ('tags', 'object')), - sorted([('for_user', 'object'), - ('created_by', 'object'), - ('wf_info_for', 'object'), - ('owned_by', 'object'), - ])) + self.assertListEqual(rbc(e, 'muledit', 'attributes'), + [('login', 'subject'), + ('upassword', 'subject'), + ('in_group', 'subject'), + ]) + self.assertListEqual(rbc(e, 'main', 'metadata'), + [('last_login_time', 'subject'), + ('cw_source', 'subject'), + ('creation_date', 'subject'), + ('cwuri', 'subject'), + ('modification_date', 'subject'), + ('created_by', 'subject'), + ('owned_by', 'subject'), + ('bookmarked_by', 'object'), + ]) + # XXX skip 'tags' relation here and in the hidden category because + # of some test interdependancy when pytest is launched on whole cw + # (appears here while expected in hidden + self.assertListEqual([x for x in rbc(e, 'main', 'relations') + if x != ('tags', 'object')], + [('connait', 'subject'), + ('custom_workflow', 'subject'), + ('primary_email', 'subject'), + ('checked_by', 'object'), + ]) + self.assertListEqual(rbc(e, 'main', 'inlined'), + [('use_email', 'subject'), + ]) + # owned_by is defined both as subject and object relations on CWUser + self.assertListEqual(sorted(x for x in rbc(e, 'main', 'hidden') + if x != ('tags', 'object')), + sorted([('for_user', 'object'), + ('created_by', 'object'), + ('wf_info_for', 'object'), + ('owned_by', 'object'), + ])) def test_inlined_view(self): - self.assertTrue('main_inlined' in AFS.etype_get('CWUser', 'use_email', 'subject', 'EmailAddress')) - self.assertFalse('main_inlined' in AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress')) - self.assertTrue('main_relations' in AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress')) + self.assertIn('main_inlined', + AFS.etype_get('CWUser', 'use_email', 'subject', 'EmailAddress')) + self.assertNotIn('main_inlined', + AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress')) + self.assertIn('main_relations', + AFS.etype_get('CWUser', 'primary_email', 'subject', 'EmailAddress')) def test_personne_relations_by_category(self): - e = self.vreg['etypes'].etype_class('Personne')(self.request()) - self.assertListEqual(rbc(e, 'main', 'attributes'), - [('nom', 'subject'), - ('prenom', 'subject'), - ('sexe', 'subject'), - ('promo', 'subject'), - ('titre', 'subject'), - ('ass', 'subject'), - ('web', 'subject'), - ('tel', 'subject'), - ('fax', 'subject'), - ('datenaiss', 'subject'), - ('test', 'subject'), - ('description', 'subject'), - ('salary', 'subject'), - ]) - self.assertListEqual(rbc(e, 'muledit', 'attributes'), - [('nom', 'subject'), - ]) - self.assertListEqual(rbc(e, 'main', 'metadata'), - [('cw_source', 'subject'), - ('creation_date', 'subject'), - ('cwuri', 'subject'), - ('modification_date', 'subject'), - ('created_by', 'subject'), - ('owned_by', 'subject'), - ]) - self.assertListEqual(rbc(e, 'main', 'relations'), - [('travaille', 'subject'), - ('manager', 'object'), - ('connait', 'object'), - ]) - self.assertListEqual(rbc(e, 'main', 'hidden'), - []) + with self.admin_access.web_request() as req: + e = self.vreg['etypes'].etype_class('Personne')(req) + self.assertListEqual(rbc(e, 'main', 'attributes'), + [('nom', 'subject'), + ('prenom', 'subject'), + ('sexe', 'subject'), + ('promo', 'subject'), + ('titre', 'subject'), + ('ass', 'subject'), + ('web', 'subject'), + ('tel', 'subject'), + ('fax', 'subject'), + ('datenaiss', 'subject'), + ('test', 'subject'), + ('description', 'subject'), + ('salary', 'subject'), + ]) + self.assertListEqual(rbc(e, 'muledit', 'attributes'), + [('nom', 'subject'), + ]) + self.assertListEqual(rbc(e, 'main', 'metadata'), + [('cw_source', 'subject'), + ('creation_date', 'subject'), + ('cwuri', 'subject'), + ('modification_date', 'subject'), + ('created_by', 'subject'), + ('owned_by', 'subject'), + ]) + self.assertListEqual(rbc(e, 'main', 'relations'), + [('travaille', 'subject'), + ('manager', 'object'), + ('connait', 'object'), + ]) + self.assertListEqual(rbc(e, 'main', 'hidden'), + []) def test_edition_form(self): - rset = self.execute('CWUser X LIMIT 1') - form = self.vreg['forms'].select('edition', rset.req, rset=rset, - row=0, col=0) - # should be also selectable by specifying entity - self.vreg['forms'].select('edition', rset.req, - entity=rset.get_entity(0, 0)) - self.assertFalse(any(f for f in form.fields if f is None)) + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X LIMIT 1') + form = self.vreg['forms'].select('edition', req, rset=rset, row=0, col=0) + # should be also selectable by specifying entity + self.vreg['forms'].select('edition', req, entity=rset.get_entity(0, 0)) + self.assertFalse(any(f for f in form.fields if f is None)) class FormViewsTC(CubicWebTC): + def test_delete_conf_formview(self): - rset = self.execute('CWGroup X') - self.view('deleteconf', rset, template=None).source + with self.admin_access.web_request() as req: + rset = req.execute('CWGroup X') + self.view('deleteconf', rset, template=None, req=req).source def test_automatic_edition_formview(self): - rset = self.execute('CWUser X') - self.view('edition', rset, row=0, template=None).source + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X') + self.view('edition', rset, row=0, template=None, req=req).source - def test_automatic_edition_formview(self): - rset = self.execute('CWUser X') - self.view('copy', rset, row=0, template=None).source + def test_automatic_edition_copyformview(self): + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X') + self.view('copy', rset, row=0, template=None, req=req).source def test_automatic_creation_formview(self): - self.view('creation', None, etype='CWUser', template=None).source + with self.admin_access.web_request() as req: + self.view('creation', None, etype='CWUser', template=None, req=req).source def test_automatic_muledit_formview(self): - rset = self.execute('CWUser X') - self.view('muledit', rset, template=None).source + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X') + self.view('muledit', rset, template=None, req=req).source def test_automatic_reledit_formview(self): - rset = self.execute('CWUser X') - self.view('reledit', rset, row=0, rtype='login', template=None).source + with self.admin_access.web_request() as req: + rset = req.execute('CWUser X') + self.view('reledit', rset, row=0, rtype='login', template=None, req=req).source def test_automatic_inline_edit_formview(self): - geid = self.execute('CWGroup X LIMIT 1')[0][0] - rset = self.execute('CWUser X LIMIT 1') - self.view('inline-edition', rset, row=0, col=0, rtype='in_group', - peid=geid, role='object', i18nctx='', pform=MOCKPFORM, - template=None).source + with self.admin_access.web_request() as req: + geid = req.execute('CWGroup X LIMIT 1')[0][0] + rset = req.execute('CWUser X LIMIT 1') + self.view('inline-edition', rset, row=0, col=0, rtype='in_group', + peid=geid, role='object', i18nctx='', pform=MOCKPFORM, + template=None, req=req).source def test_automatic_inline_creation_formview(self): - geid = self.execute('CWGroup X LIMIT 1')[0][0] - self.view('inline-creation', None, etype='CWUser', rtype='in_group', - peid=geid, petype='CWGroup', i18nctx='', role='object', pform=MOCKPFORM, - template=None) + with self.admin_access.web_request() as req: + geid = req.execute('CWGroup X LIMIT 1')[0][0] + self.view('inline-creation', None, etype='CWUser', rtype='in_group', + peid=geid, petype='CWGroup', i18nctx='', role='object', pform=MOCKPFORM, + template=None, req=req) MOCKPFORM = mock_object(form_previous_values={}, form_valerror=None) diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_json.py --- a/web/test/unittest_views_json.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_json.py Fri Jul 18 17:35:25 2014 +0200 @@ -30,14 +30,14 @@ def test_json_rsetexport(self): with self.admin_access.web_request() as req: rset = req.execute('Any GN,COUNT(X) GROUPBY GN ORDERBY GN WHERE X in_group G, G name GN') - data = self.view('jsonexport', rset) + data = self.view('jsonexport', rset, req=req) self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json']) self.assertListEqual(data, [["guests", 1], ["managers", 1]]) def test_json_rsetexport_empty_rset(self): with self.admin_access.web_request() as req: rset = req.execute('Any X WHERE X is CWUser, X login "foobarbaz"') - data = self.view('jsonexport', rset) + data = self.view('jsonexport', rset, req=req) self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json']) self.assertListEqual(data, []) @@ -65,7 +65,7 @@ def test_json_ersetexport(self): with self.admin_access.web_request() as req: rset = req.execute('Any G ORDERBY GN WHERE G is CWGroup, G name GN') - data = self.view('ejsonexport', rset) + data = self.view('ejsonexport', rset, req=req) self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json']) self.assertEqual(data[0]['name'], 'guests') self.assertEqual(data[1]['name'], 'managers') diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_navigation.py --- a/web/test/unittest_views_navigation.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_navigation.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -17,7 +17,7 @@ # with CubicWeb. If not, see . """cubicweb.web.views.navigation unit tests""" -from logilab.common.testlib import unittest_main, mock_object +from logilab.common.testlib import unittest_main from cubicweb.devtools.testlib import CubicWebTC from cubicweb.web.views.navigation import (PageNavigation, SortedNavigation, @@ -29,123 +29,94 @@ class NavigationTC(CubicWebTC): def test_navigation_selection_whatever(self): - req = self.request() - rset = self.execute('Any X,N WHERE X name N') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - self.assertIsInstance(navcomp, PageNavigation) - req.set_search_state('W:X:Y:Z') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - self.assertIsInstance(navcomp, PageNavigation) - req.set_search_state('normal') + with self.admin_access.web_request() as req: + rset = req.execute('Any X,N WHERE X name N') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + self.assertIsInstance(navcomp, PageNavigation) + req.set_search_state('W:X:Y:Z') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + self.assertIsInstance(navcomp, PageNavigation) + req.set_search_state('normal') def test_navigation_selection_ordered(self): - req = self.request() - rset = self.execute('Any X,N ORDERBY N LIMIT 40 WHERE X name N') - navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) - self.assertIsInstance(navcomp, SortedNavigation) - req.set_search_state('W:X:Y:Z') - navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) - self.assertIsInstance(navcomp, SortedNavigation) - req.set_search_state('normal') - html = navcomp.render() + with self.admin_access.web_request() as req: + rset = req.execute('Any X,N ORDERBY N LIMIT 40 WHERE X name N') + navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) + self.assertIsInstance(navcomp, SortedNavigation) + req.set_search_state('W:X:Y:Z') + navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) + self.assertIsInstance(navcomp, SortedNavigation) + req.set_search_state('normal') + navcomp.render() def test_navigation_selection_large_rset(self): - req = self.request() - rset = self.execute('Any X,N LIMIT 120 WHERE X name N') - navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) - self.assertIsInstance(navcomp, PageNavigationSelect) - rset = self.execute('Any X,N ORDERBY N LIMIT 120 WHERE X name N') - navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) - self.assertIsInstance(navcomp, PageNavigationSelect) + with self.admin_access.web_request() as req: + rset = req.execute('Any X,N LIMIT 120 WHERE X name N') + navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) + self.assertIsInstance(navcomp, PageNavigationSelect) + rset = req.execute('Any X,N ORDERBY N LIMIT 120 WHERE X name N') + navcomp = self.vreg['components'].select('navigation', req, rset=rset, page_size=20) + self.assertIsInstance(navcomp, PageNavigationSelect) def test_navigation_selection_not_enough_1(self): - req = self.request() - rset = self.execute('Any X,N LIMIT 10 WHERE X name N') - navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset) - self.assertEqual(navcomp, None) - req.set_search_state('W:X:Y:Z') - navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset) - self.assertEqual(navcomp, None) - req.set_search_state('normal') + with self.admin_access.web_request() as req: + rset = req.execute('Any X,N LIMIT 10 WHERE X name N') + navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset) + self.assertEqual(navcomp, None) + req.set_search_state('W:X:Y:Z') + navcomp = self.vreg['components'].select_or_none('navigation', req, rset=rset) + self.assertEqual(navcomp, None) + req.set_search_state('normal') def test_navigation_selection_not_enough_2(self): - req = self.request() - rset = self.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N WHERE RDEF relation_type RT, RT name N') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - self.assertIsInstance(navcomp, SortedNavigation) - req.set_search_state('W:X:Y:Z') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - self.assertIsInstance(navcomp, SortedNavigation) + with self.admin_access.web_request() as req: + rset = req.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N ' + 'WHERE RDEF relation_type RT, RT name N') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + self.assertIsInstance(navcomp, SortedNavigation) + req.set_search_state('W:X:Y:Z') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + self.assertIsInstance(navcomp, SortedNavigation) def test_navigation_selection_wrong_boundary(self): - req = self.request() - rset = self.execute('Any X,N WHERE X name N') - req = self.request() - req.form['__start'] = 1000000 - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - html = navcomp.render() + with self.admin_access.web_request() as req: + rset = req.execute('Any X,N WHERE X name N') + req.form['__start'] = 1000000 + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + html = navcomp.render() def test_sorted_navigation_1(self): - req = self.request() - rset = self.execute('Any RDEF ORDERBY RT WHERE RDEF relation_type RT') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - html = navcomp.render() + with self.admin_access.web_request() as req: + rset = req.execute('Any RDEF ORDERBY RT WHERE RDEF relation_type RT') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + html = navcomp.render() def test_sorted_navigation_2(self): - req = self.request() - rset = self.execute('Any RDEF ORDERBY RDEF WHERE RDEF relation_type RT') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - html = navcomp.render() + with self.admin_access.web_request() as req: + rset = req.execute('Any RDEF ORDERBY RDEF WHERE RDEF relation_type RT') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + html = navcomp.render() def test_sorted_navigation_3(self): - req = self.request() - rset = self.execute('CWAttribute RDEF ORDERBY RDEF') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - html = navcomp.render() + with self.admin_access.web_request() as req: + rset = req.execute('CWAttribute RDEF ORDERBY RDEF') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + html = navcomp.render() def test_sorted_navigation_4(self): - req = self.request() - rset = self.execute('Any RDEF ORDERBY N WHERE RDEF relation_type RT, RT name N') - navcomp = self.vreg['components'].select('navigation', req, rset=rset) - html = navcomp.render() + with self.admin_access.web_request() as req: + rset = req.execute('Any RDEF ORDERBY N ' + 'WHERE RDEF relation_type RT, RT name N') + navcomp = self.vreg['components'].select('navigation', req, rset=rset) + html = navcomp.render() def test_sorted_navigation_5(self): - req = self.request() - rset = self.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N WHERE RDEF relation_type RT, RT name N') - navcomp = self.vreg['components'].select('navigation', rset.req, rset=rset) - html = navcomp.render() - + with self.admin_access.web_request() as req: + rset = req.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N ' + 'WHERE RDEF relation_type RT, RT name N') + navcomp = self.vreg['components'].select('navigation', rset.req, rset=rset) + html = navcomp.render() -# XXX deactivate, contextual component has been removed -# class ContentNavigationTC(CubicWebTC): - # def test_component_context(self): - # view = mock_object(is_primary=lambda x: True) - # rset = self.execute('CWUser X LIMIT 1') - # req = self.request() - # objs = self.vreg['ctxcomponents'].poss_visible_objects( - # req, rset=rset, view=view, context='navtop') - # # breadcrumbs should be in headers by default - # clsids = set(obj.id for obj in objs) - # self.assertIn('breadcrumbs', clsids) - # objs = self.vreg['ctxcomponents'].poss_visible_objects( - # req, rset=rset, view=view, context='navbottom') - # # breadcrumbs should _NOT_ be in footers by default - # clsids = set(obj.id for obj in objs) - # self.assertNotIn('breadcrumbs', clsids) - # self.execute('INSERT CWProperty P: P pkey "ctxcomponents.breadcrumbs.context", ' - # 'P value "navbottom"') - # # breadcrumbs should now be in footers - # req.cnx.commit() - # objs = self.vreg['ctxcomponents'].poss_visible_objects( - # req, rset=rset, view=view, context='navbottom') - - # clsids = [obj.id for obj in objs] - # self.assertIn('breadcrumbs', clsids) - # objs = self.vreg['ctxcomponents'].poss_visible_objects( - # req, rset=rset, view=view, context='navtop') - - # clsids = [obj.id for obj in objs] - # self.assertNotIn('breadcrumbs', clsids) if __name__ == '__main__': diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_views_xmlrss.py --- a/web/test/unittest_views_xmlrss.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_views_xmlrss.py Fri Jul 18 17:35:25 2014 +0200 @@ -10,7 +10,7 @@ self.assertMultiLineEqual( req.user.view('xml'), '''\ - + admin @@ -21,10 +21,10 @@ - + - + diff -r 928732ec00dd -r fa44db7da2dc web/test/unittest_web.py --- a/web/test/unittest_web.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/test/unittest_web.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -18,6 +18,7 @@ from json import loads from os.path import join +import tempfile try: import requests @@ -64,7 +65,8 @@ @property def _post_url(self): - return self.request().build_url('ajax', fname='fileupload') + with self.admin_access.web_request() as req: + return req.build_url('ajax', fname='fileupload') def _fobject(self, fname): return open(join(self.datadir, fname), 'rb') @@ -92,6 +94,7 @@ self.assertEqual(webreq.status_code, 200) self.assertDictEqual(expect, loads(webreq.content)) + class LanguageTC(CubicWebServerTC): def test_language_neg(self): @@ -115,5 +118,21 @@ self.assertEqual(webreq.status, 200) +class LogQueriesTC(CubicWebServerTC): + @classmethod + def init_config(cls, config): + super(LogQueriesTC, cls).init_config(config) + cls.logfile = tempfile.NamedTemporaryFile() + config.global_set_option('query-log-file', cls.logfile.name) + + def test_log_queries(self): + self.web_request() + self.assertTrue(self.logfile.read()) + + @classmethod + def tearDownClass(cls): + cls.logfile.close() + + if __name__ == '__main__': unittest_main() diff -r 928732ec00dd -r fa44db7da2dc web/views/ajaxedit.py --- a/web/views/ajaxedit.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/views/ajaxedit.py Fri Jul 18 17:35:25 2014 +0200 @@ -53,9 +53,9 @@ self.w(u'

%s

' % self._cw._('relation %(relname)s of %(ent)s') % {'relname': rschema.display_name(self._cw, role(self)), 'ent': entity.view('incontext')}) - self.w(u'
    ') + self.w(u'
      ') for boxitem in self.unrelated_boxitems(entity): - self.w('' % boxitem) + self.w('
    • %s
    • ' % boxitem) self.w(u'
') def unrelated_entities(self, entity): diff -r 928732ec00dd -r fa44db7da2dc web/views/authentication.py --- a/web/views/authentication.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/views/authentication.py Fri Jul 18 17:35:25 2014 +0200 @@ -44,7 +44,7 @@ """ raise NotImplementedError() - def authenticated(self, retriever, req, cnx, login, authinfo): + def authenticated(self, retriever, req, session, login, authinfo): """callback when return authentication information have opened a repository connection successfully. Take care req has no session attached yet, hence req.execute isn't available. diff -r 928732ec00dd -r fa44db7da2dc web/views/autoform.py --- a/web/views/autoform.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/views/autoform.py Fri Jul 18 17:35:25 2014 +0200 @@ -504,15 +504,15 @@ label = rschema.display_name(req, role, context=form.edited_entity.cw_etype) w(u'%s' % label) w(u'') - w(u'
    ') + w(u'
      ') for viewparams in related: - w(u'' + w(u'
    • %s%s
    • ' % (viewparams[1], viewparams[0], viewparams[2], viewparams[3])) if not form.force_display and form.maxrelitems < len(related): - link = (u'
    ') w(u'') w(u'') diff -r 928732ec00dd -r fa44db7da2dc web/views/reledit.py --- a/web/views/reledit.py Thu Jul 17 11:08:56 2014 +0200 +++ b/web/views/reledit.py Fri Jul 18 17:35:25 2014 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -329,13 +329,13 @@ w = self.w w(u'
    ' % {'id': divid, 'css': 'releditField', - 'out': "jQuery('#%s').addClass('hidden')" % divid, - 'over': "jQuery('#%s').removeClass('hidden')" % divid}) + 'out': "jQuery('#%s').addClass('invisible')" % divid, + 'over': "jQuery('#%s').removeClass('invisible')" % divid}) w(u'
    ' % divid) w(value) w(u'
    ') form.render(w=w, renderer=renderer) - w(u'