sobjects/test/unittest_cwxmlparser.py
changeset 8221 fd02d0120ddc
parent 8188 1867e252e487
child 8435 5064b6e0d6f4
equal deleted inserted replaced
8220:e4ea285510e5 8221:fd02d0120ddc
       
     1 # copyright 2011-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 
       
    19 from __future__ import with_statement
       
    20 
       
    21 from datetime import datetime
       
    22 
       
    23 from cubicweb.devtools.testlib import CubicWebTC
       
    24 
       
    25 from cubicweb.sobjects.cwxmlparser import CWEntityXMLParser
       
    26 
       
    27 orig_parse = CWEntityXMLParser.parse
       
    28 
       
    29 def parse(self, url):
       
    30     try:
       
    31         url = RELATEDXML[url.split('?')[0]]
       
    32     except KeyError:
       
    33         pass
       
    34     return orig_parse(self, url)
       
    35 
       
    36 def setUpModule():
       
    37     CWEntityXMLParser.parse = parse
       
    38 
       
    39 def tearDownModule():
       
    40     CWEntityXMLParser.parse = orig_parse
       
    41 
       
    42 
       
    43 BASEXML = ''.join(u'''
       
    44 <rset size="1">
       
    45  <CWUser eid="5" cwuri="http://pouet.org/5" cwsource="system">
       
    46   <login>sthenault</login>
       
    47   <upassword>toto</upassword>
       
    48   <last_login_time>2011-01-25 14:14:06</last_login_time>
       
    49   <creation_date>2010-01-22 10:27:59</creation_date>
       
    50   <modification_date>2011-01-25 14:14:06</modification_date>
       
    51   <use_email role="subject">
       
    52     <EmailAddress cwuri="http://pouet.org/6" eid="6"/>
       
    53   </use_email>
       
    54   <in_group role="subject">
       
    55     <CWGroup cwuri="http://pouet.org/7" eid="7"/>
       
    56     <CWGroup cwuri="http://pouet.org/8" eid="8"/>
       
    57   </in_group>
       
    58   <tags role="object">
       
    59     <Tag cwuri="http://pouet.org/9" eid="9"/>
       
    60     <Tag cwuri="http://pouet.org/10" eid="10"/>
       
    61   </tags>
       
    62   <in_state role="subject">
       
    63     <State cwuri="http://pouet.org/11" eid="11" name="activated"/>
       
    64   </in_state>
       
    65  </CWUser>
       
    66 </rset>
       
    67 '''.splitlines())
       
    68 
       
    69 RELATEDXML = {
       
    70     'http://pouet.org/6': u'''
       
    71 <rset size="1">
       
    72  <EmailAddress eid="6" cwuri="http://pouet.org/6">
       
    73   <address>syt@logilab.fr</address>
       
    74   <modification_date>2010-04-13 14:35:56</modification_date>
       
    75   <creation_date>2010-04-13 14:35:56</creation_date>
       
    76   <tags role="object">
       
    77     <Tag cwuri="http://pouet.org/9" eid="9"/>
       
    78   </tags>
       
    79  </EmailAddress>
       
    80 </rset>
       
    81 ''',
       
    82     'http://pouet.org/7': u'''
       
    83 <rset size="1">
       
    84  <CWGroup eid="7" cwuri="http://pouet.org/7">
       
    85   <name>users</name>
       
    86   <tags role="object">
       
    87     <Tag cwuri="http://pouet.org/9" eid="9"/>
       
    88   </tags>
       
    89  </CWGroup>
       
    90 </rset>
       
    91 ''',
       
    92     'http://pouet.org/8': u'''
       
    93 <rset size="1">
       
    94  <CWGroup eid="8" cwuri="http://pouet.org/8">
       
    95   <name>unknown</name>
       
    96  </CWGroup>
       
    97 </rset>
       
    98 ''',
       
    99     'http://pouet.org/9': u'''
       
   100 <rset size="1">
       
   101  <Tag eid="9" cwuri="http://pouet.org/9">
       
   102   <name>hop</name>
       
   103  </Tag>
       
   104 </rset>
       
   105 ''',
       
   106     'http://pouet.org/10': u'''
       
   107 <rset size="1">
       
   108  <Tag eid="10" cwuri="http://pouet.org/10">
       
   109   <name>unknown</name>
       
   110  </Tag>
       
   111 </rset>
       
   112 ''',
       
   113     }
       
   114 
       
   115 
       
   116 OTHERXML = ''.join(u'''
       
   117 <rset size="1">
       
   118  <CWUser eid="5" cwuri="http://pouet.org/5" cwsource="myfeed">
       
   119   <login>sthenault</login>
       
   120   <upassword>toto</upassword>
       
   121   <last_login_time>2011-01-25 14:14:06</last_login_time>
       
   122   <creation_date>2010-01-22 10:27:59</creation_date>
       
   123   <modification_date>2011-01-25 14:14:06</modification_date>
       
   124   <in_group role="subject">
       
   125     <CWGroup cwuri="http://pouet.org/7" eid="7"/>
       
   126   </in_group>
       
   127  </CWUser>
       
   128 </rset>
       
   129 '''.splitlines()
       
   130 )
       
   131 
       
   132 
       
   133 class CWEntityXMLParserTC(CubicWebTC):
       
   134     """/!\ this test use a pre-setup database /!\, if you modify above xml,
       
   135     REMOVE THE DATABASE TEMPLATE else it won't be considered
       
   136     """
       
   137     test_db_id = 'xmlparser'
       
   138     @classmethod
       
   139     def pre_setup_database(cls, session, config):
       
   140         myfeed = session.create_entity('CWSource', name=u'myfeed', type=u'datafeed',
       
   141                                    parser=u'cw.entityxml', url=BASEXML)
       
   142         myotherfeed = session.create_entity('CWSource', name=u'myotherfeed', type=u'datafeed',
       
   143                                             parser=u'cw.entityxml', url=OTHERXML)
       
   144         session.commit()
       
   145         myfeed.init_mapping([(('CWUser', 'use_email', '*'),
       
   146                               u'role=subject\naction=copy'),
       
   147                              (('CWUser', 'in_group', '*'),
       
   148                               u'role=subject\naction=link\nlinkattr=name'),
       
   149                              (('CWUser', 'in_state', '*'),
       
   150                               u'role=subject\naction=link\nlinkattr=name'),
       
   151                              (('*', 'tags', '*'),
       
   152                               u'role=object\naction=link-or-create\nlinkattr=name'),
       
   153                             ])
       
   154         myotherfeed.init_mapping([(('CWUser', 'in_group', '*'),
       
   155                                    u'role=subject\naction=link\nlinkattr=name'),
       
   156                                   (('CWUser', 'in_state', '*'),
       
   157                                    u'role=subject\naction=link\nlinkattr=name'),
       
   158                                   ])
       
   159         session.create_entity('Tag', name=u'hop')
       
   160 
       
   161     def test_complete_url(self):
       
   162         dfsource = self.repo.sources_by_uri['myfeed']
       
   163         parser = dfsource._get_parser(self.session)
       
   164         self.assertEqual(parser.complete_url('http://www.cubicweb.org/CWUser'),
       
   165                          'http://www.cubicweb.org/CWUser?relation=tags-object&relation=in_group-subject&relation=in_state-subject&relation=use_email-subject')
       
   166         self.assertEqual(parser.complete_url('http://www.cubicweb.org/cwuser'),
       
   167                          'http://www.cubicweb.org/cwuser?relation=tags-object&relation=in_group-subject&relation=in_state-subject&relation=use_email-subject')
       
   168         self.assertEqual(parser.complete_url('http://www.cubicweb.org/cwuser?vid=rdf&relation=hop'),
       
   169                          'http://www.cubicweb.org/cwuser?relation=hop&relation=tags-object&relation=in_group-subject&relation=in_state-subject&relation=use_email-subject&vid=rdf')
       
   170         self.assertEqual(parser.complete_url('http://www.cubicweb.org/?rql=cwuser&vid=rdf&relation=hop'),
       
   171                          'http://www.cubicweb.org/?rql=cwuser&relation=hop&vid=rdf')
       
   172         self.assertEqual(parser.complete_url('http://www.cubicweb.org/?rql=cwuser&relation=hop'),
       
   173                          'http://www.cubicweb.org/?rql=cwuser&relation=hop')
       
   174 
       
   175 
       
   176     def test_actions(self):
       
   177         dfsource = self.repo.sources_by_uri['myfeed']
       
   178         self.assertEqual(dfsource.mapping,
       
   179                          {u'CWUser': {
       
   180                              (u'in_group', u'subject', u'link'): [
       
   181                                  (u'CWGroup', {u'linkattr': u'name'})],
       
   182                              (u'in_state', u'subject', u'link'): [
       
   183                                  (u'State', {u'linkattr': u'name'})],
       
   184                              (u'tags', u'object', u'link-or-create'): [
       
   185                                  (u'Tag', {u'linkattr': u'name'})],
       
   186                              (u'use_email', u'subject', u'copy'): [
       
   187                                  (u'EmailAddress', {})]
       
   188                              },
       
   189                           u'CWGroup': {
       
   190                              (u'tags', u'object', u'link-or-create'): [
       
   191                                  (u'Tag', {u'linkattr': u'name'})],
       
   192                              },
       
   193                           u'EmailAddress': {
       
   194                              (u'tags', u'object', u'link-or-create'): [
       
   195                                  (u'Tag', {u'linkattr': u'name'})],
       
   196                              },
       
   197                           })
       
   198         session = self.repo.internal_session(safe=True)
       
   199         stats = dfsource.pull_data(session, force=True, raise_on_error=True)
       
   200         self.assertEqual(sorted(stats.keys()), ['created', 'updated'])
       
   201         self.assertEqual(len(stats['created']), 2)
       
   202         self.assertEqual(stats['updated'], set())
       
   203 
       
   204         user = self.execute('CWUser X WHERE X login "sthenault"').get_entity(0, 0)
       
   205         self.assertEqual(user.creation_date, datetime(2010, 01, 22, 10, 27, 59))
       
   206         self.assertEqual(user.modification_date, datetime(2011, 01, 25, 14, 14, 06))
       
   207         self.assertEqual(user.cwuri, 'http://pouet.org/5')
       
   208         self.assertEqual(user.cw_source[0].name, 'myfeed')
       
   209         self.assertEqual(user.absolute_url(), 'http://pouet.org/5')
       
   210         self.assertEqual(len(user.use_email), 1)
       
   211         # copy action
       
   212         email = user.use_email[0]
       
   213         self.assertEqual(email.address, 'syt@logilab.fr')
       
   214         self.assertEqual(email.cwuri, 'http://pouet.org/6')
       
   215         self.assertEqual(email.absolute_url(), 'http://pouet.org/6')
       
   216         self.assertEqual(email.cw_source[0].name, 'myfeed')
       
   217         self.assertEqual(len(email.reverse_tags), 1)
       
   218         self.assertEqual(email.reverse_tags[0].name, 'hop')
       
   219         # link action
       
   220         self.assertFalse(self.execute('CWGroup X WHERE X name "unknown"'))
       
   221         groups = sorted([g.name for g in user.in_group])
       
   222         self.assertEqual(groups, ['users'])
       
   223         group = user.in_group[0]
       
   224         self.assertEqual(len(group.reverse_tags), 1)
       
   225         self.assertEqual(group.reverse_tags[0].name, 'hop')
       
   226         # link or create action
       
   227         tags = set([(t.name, t.cwuri.replace(str(t.eid), ''), t.cw_source[0].name)
       
   228                     for t in user.reverse_tags])
       
   229         self.assertEqual(tags, set((('hop', 'http://testing.fr/cubicweb/', 'system'),
       
   230                                     ('unknown', 'http://testing.fr/cubicweb/', 'system')))
       
   231                          )
       
   232         session.set_cnxset()
       
   233         with session.security_enabled(read=False): # avoid Unauthorized due to password selection
       
   234             stats = dfsource.pull_data(session, force=True, raise_on_error=True)
       
   235         self.assertEqual(stats['created'], set())
       
   236         self.assertEqual(len(stats['updated']), 2)
       
   237         self.repo._type_source_cache.clear()
       
   238         self.repo._extid_cache.clear()
       
   239         session.set_cnxset()
       
   240         with session.security_enabled(read=False): # avoid Unauthorized due to password selection
       
   241             stats = dfsource.pull_data(session, force=True, raise_on_error=True)
       
   242         self.assertEqual(stats['created'], set())
       
   243         self.assertEqual(len(stats['updated']), 2)
       
   244         session.commit()
       
   245 
       
   246         # test move to system source
       
   247         self.sexecute('SET X cw_source S WHERE X eid %(x)s, S name "system"', {'x': email.eid})
       
   248         self.commit()
       
   249         rset = self.sexecute('EmailAddress X WHERE X address "syt@logilab.fr"')
       
   250         self.assertEqual(len(rset), 1)
       
   251         e = rset.get_entity(0, 0)
       
   252         self.assertEqual(e.eid, email.eid)
       
   253         self.assertEqual(e.cw_metainformation(), {'source': {'type': u'native', 'uri': u'system',
       
   254                                                              'use-cwuri-as-url': False},
       
   255                                                   'type': 'EmailAddress',
       
   256                                                   'extid': None})
       
   257         self.assertEqual(e.cw_source[0].name, 'system')
       
   258         self.assertEqual(e.reverse_use_email[0].login, 'sthenault')
       
   259         self.commit()
       
   260         # test everything is still fine after source synchronization
       
   261         session.set_cnxset()
       
   262         with session.security_enabled(read=False): # avoid Unauthorized due to password selection
       
   263             stats = dfsource.pull_data(session, force=True, raise_on_error=True)
       
   264         rset = self.sexecute('EmailAddress X WHERE X address "syt@logilab.fr"')
       
   265         self.assertEqual(len(rset), 1)
       
   266         e = rset.get_entity(0, 0)
       
   267         self.assertEqual(e.eid, email.eid)
       
   268         self.assertEqual(e.cw_metainformation(), {'source': {'type': u'native', 'uri': u'system',
       
   269                                                              'use-cwuri-as-url': False},
       
   270                                                   'type': 'EmailAddress',
       
   271                                                   'extid': None})
       
   272         self.assertEqual(e.cw_source[0].name, 'system')
       
   273         self.assertEqual(e.reverse_use_email[0].login, 'sthenault')
       
   274         session.commit()
       
   275 
       
   276         # test delete entity
       
   277         e.cw_delete()
       
   278         self.commit()
       
   279         # test everything is still fine after source synchronization
       
   280         session.set_cnxset()
       
   281         with session.security_enabled(read=False): # avoid Unauthorized due to password selection
       
   282             stats = dfsource.pull_data(session, force=True, raise_on_error=True)
       
   283         rset = self.sexecute('EmailAddress X WHERE X address "syt@logilab.fr"')
       
   284         self.assertEqual(len(rset), 0)
       
   285         rset = self.sexecute('Any X WHERE X use_email E, X login "sthenault"')
       
   286         self.assertEqual(len(rset), 0)
       
   287 
       
   288     def test_external_entity(self):
       
   289         dfsource = self.repo.sources_by_uri['myotherfeed']
       
   290         session = self.repo.internal_session(safe=True)
       
   291         stats = dfsource.pull_data(session, force=True, raise_on_error=True)
       
   292         user = self.execute('CWUser X WHERE X login "sthenault"').get_entity(0, 0)
       
   293         self.assertEqual(user.creation_date, datetime(2010, 01, 22, 10, 27, 59))
       
   294         self.assertEqual(user.modification_date, datetime(2011, 01, 25, 14, 14, 06))
       
   295         self.assertEqual(user.cwuri, 'http://pouet.org/5')
       
   296         self.assertEqual(user.cw_source[0].name, 'myfeed')
       
   297 
       
   298     def test_noerror_missing_fti_attribute(self):
       
   299         dfsource = self.repo.sources_by_uri['myfeed']
       
   300         session = self.repo.internal_session(safe=True)
       
   301         parser = dfsource._get_parser(session)
       
   302         dfsource.process_urls(parser, ['''
       
   303 <rset size="1">
       
   304  <Card eid="50" cwuri="http://pouet.org/50" cwsource="system">
       
   305   <title>how-to</title>
       
   306  </Card>
       
   307 </rset>
       
   308 '''], raise_on_error=True)
       
   309 
       
   310     def test_noerror_unspecified_date(self):
       
   311         dfsource = self.repo.sources_by_uri['myfeed']
       
   312         session = self.repo.internal_session(safe=True)
       
   313         parser = dfsource._get_parser(session)
       
   314         dfsource.process_urls(parser, ['''
       
   315 <rset size="1">
       
   316  <Card eid="50" cwuri="http://pouet.org/50" cwsource="system">
       
   317   <title>how-to</title>
       
   318   <content>how-to</content>
       
   319   <synopsis>how-to</synopsis>
       
   320   <creation_date/>
       
   321  </Card>
       
   322 </rset>
       
   323 '''], raise_on_error=True)
       
   324 
       
   325 if __name__ == '__main__':
       
   326     from logilab.common.testlib import unittest_main
       
   327     unittest_main()