server/test/unittest_multisources.py
branchstable
changeset 7088 76e0dba5f8f3
parent 6944 0cf10429ad39
parent 7078 bad26a22fe29
child 7631 4ac19f288149
equal deleted inserted replaced
7087:376314ebf273 7088:76e0dba5f8f3
    18 
    18 
    19 from datetime import datetime, timedelta
    19 from datetime import datetime, timedelta
    20 from itertools import repeat
    20 from itertools import repeat
    21 
    21 
    22 from cubicweb.devtools import TestServerConfiguration, init_test_database
    22 from cubicweb.devtools import TestServerConfiguration, init_test_database
    23 from cubicweb.devtools.testlib import CubicWebTC, refresh_repo
    23 from cubicweb.devtools.testlib import CubicWebTC, Tags
    24 from cubicweb.devtools.repotest import do_monkey_patch, undo_monkey_patch
    24 from cubicweb.devtools.repotest import do_monkey_patch, undo_monkey_patch
    25 
    25 from cubicweb.devtools import get_test_db_handler
    26 
    26 
    27 class ExternalSource1Configuration(TestServerConfiguration):
    27 class ExternalSource1Configuration(TestServerConfiguration):
    28     sourcefile = 'sources_extern'
    28     sourcefile = 'sources_extern'
    29 
    29 
    30 class ExternalSource2Configuration(TestServerConfiguration):
    30 class ExternalSource2Configuration(TestServerConfiguration):
    50     source.init_mapping(zip(('Card', 'Affaire', 'State',
    50     source.init_mapping(zip(('Card', 'Affaire', 'State',
    51                              'in_state', 'documented_by', 'multisource_inlined_rel'),
    51                              'in_state', 'documented_by', 'multisource_inlined_rel'),
    52                             repeat(u'write')))
    52                             repeat(u'write')))
    53 
    53 
    54 
    54 
    55 def setUpModule(*args):
    55 def pre_setup_database_extern(session, config):
    56     global repo2, cnx2, repo3, cnx3
    56     session.execute('INSERT Card X: X title "C3: An external card", X wikiid "aaa"')
    57     cfg1 = ExternalSource1Configuration('data', apphome=TwoSourcesTC.datadir)
    57     session.execute('INSERT Card X: X title "C4: Ze external card", X wikiid "zzz"')
    58     repo2, cnx2 = init_test_database(config=cfg1)
    58     session.execute('INSERT Affaire X: X ref "AFFREF"')
    59     cfg2 = ExternalSource2Configuration('data', apphome=TwoSourcesTC.datadir)
    59     session.commit()
    60     repo3, cnx3 = init_test_database(config=cfg2)
    60 
    61     src = cnx3.request().create_entity('CWSource', name=u'extern',
    61 def pre_setup_database_multi(session, config):
    62                                        type=u'pyrorql', config=EXTERN_SOURCE_CFG)
    62     session.create_entity('CWSource', name=u'extern', type=u'pyrorql',
    63     cnx3.commit() # must commit before adding the mapping
    63                                  config=EXTERN_SOURCE_CFG)
    64     add_extern_mapping(src)
    64     session.commit()
    65     cnx3.commit()
       
    66 
       
    67     TestServerConfiguration.no_sqlite_wrap = True
       
    68     # hi-jack PyroRQLSource.get_connection to access existing connection (no
       
    69     # pyro connection)
       
    70     PyroRQLSource.get_connection = lambda x: x.uri == 'extern-multi' and cnx3 or cnx2
       
    71     # also necessary since the repository is closing its initial connections
       
    72     # pool though we want to keep cnx2 valid
       
    73     Connection.close = lambda x: None
       
    74 
       
    75 def tearDownModule(*args):
       
    76     PyroRQLSource.get_connection = PyroRQLSource_get_connection
       
    77     Connection.close = Connection_close
       
    78     global repo2, cnx2, repo3, cnx3
       
    79     repo2.shutdown()
       
    80     repo3.shutdown()
       
    81     del repo2, cnx2, repo3, cnx3
       
    82     #del TwoSourcesTC.config.vreg
       
    83     #del TwoSourcesTC.config
       
    84     TestServerConfiguration.no_sqlite_wrap = False
       
    85 
    65 
    86 class TwoSourcesTC(CubicWebTC):
    66 class TwoSourcesTC(CubicWebTC):
    87     """Main repo -> extern-multi -> extern
    67     """Main repo -> extern-multi -> extern
    88                   \-------------/
    68                   \-------------/
    89     """
    69     """
       
    70     test_db_id= 'cw-server-multisources'
       
    71     tags = CubicWebTC.tags | Tags(('multisources'))
       
    72 
    90     @classmethod
    73     @classmethod
    91     def _refresh_repo(cls):
    74     def setUpClass(cls):
    92         super(TwoSourcesTC, cls)._refresh_repo()
    75         cls._cfg2 = ExternalSource1Configuration('data', apphome=TwoSourcesTC.datadir)
    93         cnx2.rollback()
    76         cls._cfg3 = ExternalSource2Configuration('data', apphome=TwoSourcesTC.datadir)
    94         refresh_repo(repo2)
    77         TestServerConfiguration.no_sqlite_wrap = True
    95         cnx3.rollback()
    78         # hi-jack PyroRQLSource.get_connection to access existing connection (no
    96         refresh_repo(repo3)
    79         # pyro connection)
       
    80         PyroRQLSource.get_connection = lambda x: x.uri == 'extern-multi' and cls.cnx3 or cls.cnx2
       
    81         # also necessary since the repository is closing its initial connections
       
    82         # pool though we want to keep cnx2 valid
       
    83         Connection.close = lambda x: None
       
    84 
       
    85     @classmethod
       
    86     def tearDowncls(cls):
       
    87         PyroRQLSource.get_connection = PyroRQLSource_get_connection
       
    88         Connection.close = Connection_close
       
    89         cls.cnx2.close()
       
    90         cls.cnx3.close()
       
    91         TestServerConfiguration.no_sqlite_wrap = False
       
    92 
       
    93 
       
    94     @classmethod
       
    95     def _init_repo(cls):
       
    96         repo2_handler = get_test_db_handler(cls._cfg2)
       
    97         repo2_handler.build_db_cache('4cards-1affaire',pre_setup_func=pre_setup_database_extern)
       
    98         cls.repo2, cls.cnx2 = repo2_handler.get_repo_and_cnx('4cards-1affaire')
       
    99 
       
   100         repo3_handler = get_test_db_handler(cls._cfg3)
       
   101         repo3_handler.build_db_cache('multisource',pre_setup_func=pre_setup_database_multi)
       
   102         cls.repo3, cls.cnx3 = repo3_handler.get_repo_and_cnx('multisource')
       
   103 
       
   104 
       
   105         super(TwoSourcesTC, cls)._init_repo()
    97 
   106 
    98     def setUp(self):
   107     def setUp(self):
    99         CubicWebTC.setUp(self)
   108         CubicWebTC.setUp(self)
       
   109         self.addCleanup(self.cnx2.close)
       
   110         self.addCleanup(self.cnx3.close)
   100         do_monkey_patch()
   111         do_monkey_patch()
   101 
   112 
   102     def tearDown(self):
   113     def tearDown(self):
   103         for source in self.repo.sources[1:]:
   114         for source in self.repo.sources[1:]:
   104             self.repo.remove_source(source.uri)
   115             self.repo.remove_source(source.uri)
   105         CubicWebTC.tearDown(self)
   116         CubicWebTC.tearDown(self)
       
   117         self.cnx2.close()
       
   118         self.cnx3.close()
   106         undo_monkey_patch()
   119         undo_monkey_patch()
   107 
   120 
   108     def setup_database(self):
   121     @staticmethod
   109         cu = cnx2.cursor()
   122     def pre_setup_database(session, config):
   110         self.ec1 = cu.execute('INSERT Card X: X title "C3: An external card", X wikiid "aaa"')[0][0]
   123         for uri, src_config in [('extern', EXTERN_SOURCE_CFG),
   111         cu.execute('INSERT Card X: X title "C4: Ze external card", X wikiid "zzz"')
       
   112         self.aff1 = cu.execute('INSERT Affaire X: X ref "AFFREF"')[0][0]
       
   113         cnx2.commit()
       
   114         for uri, config in [('extern', EXTERN_SOURCE_CFG),
       
   115                             ('extern-multi', '''
   124                             ('extern-multi', '''
   116 pyro-ns-id = extern-multi
   125 pyro-ns-id = extern-multi
   117 cubicweb-user = admin
   126 cubicweb-user = admin
   118 cubicweb-password = gingkow
   127 cubicweb-password = gingkow
   119 ''')]:
   128 ''')]:
   120             source = self.request().create_entity(
   129             source = session.create_entity('CWSource', name=unicode(uri),
   121                 'CWSource', name=unicode(uri), type=u'pyrorql',
   130                                            type=u'pyrorql',
   122                 config=unicode(config))
   131                                            config=unicode(src_config))
   123             self.commit() # must commit before adding the mapping
   132             session.commit()
   124             add_extern_mapping(source)
   133             add_extern_mapping(source)
   125         self.commit()
   134 
       
   135         session.commit()
   126         # trigger discovery
   136         # trigger discovery
   127         self.sexecute('Card X')
   137         session.execute('Card X')
   128         self.sexecute('Affaire X')
   138         session.execute('Affaire X')
   129         self.sexecute('State X')
   139         session.execute('State X')
       
   140 
       
   141     def setup_database(self):
       
   142         cu2 = self.cnx2.cursor()
       
   143         self.ec1 = cu2.execute('Any X WHERE X is Card, X title "C3: An external card", X wikiid "aaa"')[0][0]
       
   144         self.aff1 = cu2.execute('Any X WHERE X is Affaire, X ref "AFFREF"')[0][0]
       
   145         cu2.close()
   130         # add some entities
   146         # add some entities
   131         self.ic1 = self.sexecute('INSERT Card X: X title "C1: An internal card", X wikiid "aaai"')[0][0]
   147         self.ic1 = self.sexecute('INSERT Card X: X title "C1: An internal card", X wikiid "aaai"')[0][0]
   132         self.ic2 = self.sexecute('INSERT Card X: X title "C2: Ze internal card", X wikiid "zzzi"')[0][0]
   148         self.ic2 = self.sexecute('INSERT Card X: X title "C2: Ze internal card", X wikiid "zzzi"')[0][0]
   133 
   149 
   134     def test_eid_comp(self):
   150     def test_eid_comp(self):
   184         rset = cu.execute('Any X ORDERBY FTIRANK(X) WHERE X has_text "card"')
   200         rset = cu.execute('Any X ORDERBY FTIRANK(X) WHERE X has_text "card"')
   185         self.assertEqual(len(rset), 5, zip(rset.rows, rset.description))
   201         self.assertEqual(len(rset), 5, zip(rset.rows, rset.description))
   186         Connection_close(cnx.cnx) # cnx is a TestCaseConnectionProxy
   202         Connection_close(cnx.cnx) # cnx is a TestCaseConnectionProxy
   187 
   203 
   188     def test_synchronization(self):
   204     def test_synchronization(self):
   189         cu = cnx2.cursor()
   205         cu = self.cnx2.cursor()
   190         assert cu.execute('Any X WHERE X eid %(x)s', {'x': self.aff1})
   206         assert cu.execute('Any X WHERE X eid %(x)s', {'x': self.aff1})
   191         cu.execute('SET X ref "BLAH" WHERE X eid %(x)s', {'x': self.aff1})
   207         cu.execute('SET X ref "BLAH" WHERE X eid %(x)s', {'x': self.aff1})
   192         aff2 = cu.execute('INSERT Affaire X: X ref "AFFREUX"')[0][0]
   208         aff2 = cu.execute('INSERT Affaire X: X ref "AFFREUX"')[0][0]
   193         cnx2.commit()
   209         self.cnx2.commit()
   194         try:
   210         try:
   195             # force sync
   211             # force sync
   196             self.repo.sources_by_uri['extern'].synchronize(MTIME)
   212             self.repo.sources_by_uri['extern'].synchronize(MTIME)
   197             self.failUnless(self.sexecute('Any X WHERE X has_text "blah"'))
   213             self.failUnless(self.sexecute('Any X WHERE X has_text "blah"'))
   198             self.failUnless(self.sexecute('Any X WHERE X has_text "affreux"'))
   214             self.failUnless(self.sexecute('Any X WHERE X has_text "affreux"'))
   199             cu.execute('DELETE Affaire X WHERE X eid %(x)s', {'x': aff2})
   215             cu.execute('DELETE Affaire X WHERE X eid %(x)s', {'x': aff2})
   200             cnx2.commit()
   216             self.cnx2.commit()
   201             self.repo.sources_by_uri['extern'].synchronize(MTIME)
   217             self.repo.sources_by_uri['extern'].synchronize(MTIME)
   202             rset = self.sexecute('Any X WHERE X has_text "affreux"')
   218             rset = self.sexecute('Any X WHERE X has_text "affreux"')
   203             self.failIf(rset)
   219             self.failIf(rset)
   204         finally:
   220         finally:
   205             # restore state
   221             # restore state
   206             cu.execute('SET X ref "AFFREF" WHERE X eid %(x)s', {'x': self.aff1})
   222             cu.execute('SET X ref "AFFREF" WHERE X eid %(x)s', {'x': self.aff1})
   207             cnx2.commit()
   223             self.cnx2.commit()
   208 
   224 
   209     def test_simplifiable_var(self):
   225     def test_simplifiable_var(self):
   210         affeid = self.sexecute('Affaire X WHERE X ref "AFFREF"')[0][0]
   226         affeid = self.sexecute('Affaire X WHERE X ref "AFFREF"')[0][0]
   211         rset = self.sexecute('Any X,AA,AB WHERE E eid %(x)s, E in_state X, X name AA, X modification_date AB',
   227         rset = self.sexecute('Any X,AA,AB WHERE E eid %(x)s, E in_state X, X name AA, X modification_date AB',
   212                             {'x': affeid})
   228                             {'x': affeid})
   232         self.assertEqual(sorted(r[0] for r in rset.rows), sorted([iec1, self.ic1]))
   248         self.assertEqual(sorted(r[0] for r in rset.rows), sorted([iec1, self.ic1]))
   233 
   249 
   234     def test_greater_eid(self):
   250     def test_greater_eid(self):
   235         rset = self.sexecute('Any X WHERE X eid > %s' % (self.ic1 - 1))
   251         rset = self.sexecute('Any X WHERE X eid > %s' % (self.ic1 - 1))
   236         self.assertEqual(len(rset.rows), 2) # self.ic1 and self.ic2
   252         self.assertEqual(len(rset.rows), 2) # self.ic1 and self.ic2
   237         cu = cnx2.cursor()
   253         cu = self.cnx2.cursor()
   238         ec2 = cu.execute('INSERT Card X: X title "glup"')[0][0]
   254         ec2 = cu.execute('INSERT Card X: X title "glup"')[0][0]
   239         cnx2.commit()
   255         self.cnx2.commit()
   240         # 'X eid > something' should not trigger discovery
   256         # 'X eid > something' should not trigger discovery
   241         rset = self.sexecute('Any X WHERE X eid > %s' % (self.ic1 - 1))
   257         rset = self.sexecute('Any X WHERE X eid > %s' % (self.ic1 - 1))
   242         self.assertEqual(len(rset.rows), 2)
   258         self.assertEqual(len(rset.rows), 2)
   243         # trigger discovery using another query
   259         # trigger discovery using another query
   244         crset = self.sexecute('Card X WHERE X title "glup"')
   260         crset = self.sexecute('Card X WHERE X title "glup"')
   254         n2 = self.sexecute('INSERT Note X: X type "AFFREU"')[0][0]
   270         n2 = self.sexecute('INSERT Note X: X type "AFFREU"')[0][0]
   255         rset = self.sexecute('Any X,Y WHERE X is Note, Y is Affaire, X type T, Y ref T')
   271         rset = self.sexecute('Any X,Y WHERE X is Note, Y is Affaire, X type T, Y ref T')
   256         self.assertEqual(len(rset), 1, rset.rows)
   272         self.assertEqual(len(rset), 1, rset.rows)
   257 
   273 
   258     def test_attr_unification_2(self):
   274     def test_attr_unification_2(self):
   259         cu = cnx2.cursor()
   275         cu = self.cnx2.cursor()
   260         ec2 = cu.execute('INSERT Card X: X title "AFFREF"')[0][0]
   276         ec2 = cu.execute('INSERT Card X: X title "AFFREF"')[0][0]
   261         cnx2.commit()
   277         self.cnx2.commit()
   262         try:
   278         try:
   263             c1 = self.sexecute('INSERT Card C: C title "AFFREF"')[0][0]
   279             c1 = self.sexecute('INSERT Card C: C title "AFFREF"')[0][0]
   264             rset = self.sexecute('Any X,Y WHERE X is Card, Y is Affaire, X title T, Y ref T')
   280             rset = self.sexecute('Any X,Y WHERE X is Card, Y is Affaire, X title T, Y ref T')
   265             self.assertEqual(len(rset), 2, rset.rows)
   281             self.assertEqual(len(rset), 2, rset.rows)
   266         finally:
   282         finally:
   267             cu.execute('DELETE Card X WHERE X eid %(x)s', {'x': ec2})
   283             cu.execute('DELETE Card X WHERE X eid %(x)s', {'x': ec2})
   268             cnx2.commit()
   284             self.cnx2.commit()
   269 
   285 
   270     def test_attr_unification_neq_1(self):
   286     def test_attr_unification_neq_1(self):
   271         # XXX complete
   287         # XXX complete
   272         self.sexecute('Any X,Y WHERE X is Note, Y is Affaire, X creation_date D, Y creation_date > D')
   288         self.sexecute('Any X,Y WHERE X is Note, Y is Affaire, X creation_date D, Y creation_date > D')
   273 
   289 
   315         notstates = set(tuple(x) for x in self.sexecute('Any S,SN WHERE S is State, S name SN, NOT X in_state S, X eid %(x)s',
   331         notstates = set(tuple(x) for x in self.sexecute('Any S,SN WHERE S is State, S name SN, NOT X in_state S, X eid %(x)s',
   316                                                        {'x': aff1}))
   332                                                        {'x': aff1}))
   317         self.assertSetEqual(notstates, states)
   333         self.assertSetEqual(notstates, states)
   318 
   334 
   319     def test_absolute_url_base_url(self):
   335     def test_absolute_url_base_url(self):
   320         cu = cnx2.cursor()
   336         cu = self.cnx2.cursor()
   321         ceid = cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0]
   337         ceid = cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0]
   322         cnx2.commit()
   338         self.cnx2.commit()
   323         lc = self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0, 0)
   339         lc = self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0, 0)
   324         self.assertEqual(lc.absolute_url(), 'http://extern.org/card/eid/%s' % ceid)
   340         self.assertEqual(lc.absolute_url(), 'http://extern.org/card/eid/%s' % ceid)
   325         cu.execute('DELETE Card X WHERE X eid %(x)s', {'x':ceid})
   341         cu.execute('DELETE Card X WHERE X eid %(x)s', {'x':ceid})
   326         cnx2.commit()
   342         self.cnx2.commit()
   327 
   343 
   328     def test_absolute_url_no_base_url(self):
   344     def test_absolute_url_no_base_url(self):
   329         cu = cnx3.cursor()
   345         cu = self.cnx3.cursor()
   330         ceid = cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0]
   346         ceid = cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0]
   331         cnx3.commit()
   347         self.cnx3.commit()
   332         lc = self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0, 0)
   348         lc = self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0, 0)
   333         self.assertEqual(lc.absolute_url(), 'http://testing.fr/cubicweb/card/eid/%s' % lc.eid)
   349         self.assertEqual(lc.absolute_url(), 'http://testing.fr/cubicweb/card/eid/%s' % lc.eid)
   334         cu.execute('DELETE Card X WHERE X eid %(x)s', {'x':ceid})
   350         cu.execute('DELETE Card X WHERE X eid %(x)s', {'x':ceid})
   335         cnx3.commit()
   351         self.cnx3.commit()
   336 
   352 
   337     def test_crossed_relation_noeid_needattr(self):
   353     def test_crossed_relation_noeid_needattr(self):
   338         """http://www.cubicweb.org/ticket/1382452"""
   354         """http://www.cubicweb.org/ticket/1382452"""
   339         aff1 = self.sexecute('INSERT Affaire X: X ref "AFFREF"')[0][0]
   355         aff1 = self.sexecute('INSERT Affaire X: X ref "AFFREF"')[0][0]
   340         # link within extern source
   356         # link within extern source