[multi-sources-removal] Drop pyrorql and zmqrql sources
After a few years experementing "true" multi-sources, we're now
moving to "copy-based" source à la datafeed.
As pyro and zmq sources have no more known customers and the related
code is in the way of future refactoring of cubicweb's core, we decided
to drop support for those sources without backward compatibility.
If you're still using a zmqrql or pyrorql source and you want to upgrade,
ask support to move it to datafeed using a pre-3.19 version first.
Related to #2919300 (first step)
# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""unit tests for cubicweb.web.application"""importbase64,Cookieimportsysfromurllibimportunquotefromlogilab.common.testlibimportTestCase,unittest_mainfromlogilab.common.decoratorsimportclear_cache,classpropertyfromcubicwebimportAuthenticationError,Unauthorizedfromcubicweb.devtools.testlibimportCubicWebTCfromcubicweb.devtools.fakeimportFakeRequestfromcubicweb.webimportLogOut,Redirect,INTERNAL_FIELD_VALUEfromcubicweb.web.views.basecontrollersimportViewControllerfromcubicweb.web.applicationimportanonymized_requestfromcubicweb.dbapiimportDBAPISession,_NeedAuthAccessMockfromcubicwebimportrepoapiclassFakeMapping:"""emulates a mapping module"""def__init__(self):self.ENTITIES_MAP={}self.ATTRIBUTES_MAP={}self.RELATIONS_MAP={}classMockCursor:def__init__(self):self.executed=[]defexecute(self,rql,args=None,build_descr=False):args=argsor{}self.executed.append(rql%args)classFakeController(ViewController):def__init__(self,form=None):self._cw=FakeRequest()self._cw.form=formor{}self._cursor=MockCursor()self._cw.execute=self._cursor.executedefnew_cursor(self):self._cursor=MockCursor()self._cw.execute=self._cursor.executedefset_form(self,form):self._cw.form=formclassRequestBaseTC(TestCase):defsetUp(self):self._cw=FakeRequest()deftest_list_arg(self):"""tests the list_arg() function"""list_arg=self._cw.list_form_paramself.assertEqual(list_arg('arg3',{}),[])d={'arg1':"value1",'arg2':('foo',INTERNAL_FIELD_VALUE,),'arg3':['bar']}self.assertEqual(list_arg('arg1',d,True),['value1'])self.assertEqual(d,{'arg2':('foo',INTERNAL_FIELD_VALUE),'arg3':['bar'],})self.assertEqual(list_arg('arg2',d,True),['foo'])self.assertEqual({'arg3':['bar'],},d)self.assertEqual(list_arg('arg3',d),['bar',])self.assertEqual({'arg3':['bar'],},d)deftest_from_controller(self):self._cw.vreg['controllers']={'view':1,'login':1}self.assertEqual(self._cw.from_controller(),'view')req=FakeRequest(url='project?vid=list')req.vreg['controllers']={'view':1,'login':1}# this assertion is just to make sure that relative_path can be# correctly computed as it is used in from_controller()self.assertEqual(req.relative_path(False),'project')self.assertEqual(req.from_controller(),'view')# test on a valid non-view controllerreq=FakeRequest(url='login?x=1&y=2')req.vreg['controllers']={'view':1,'login':1}self.assertEqual(req.relative_path(False),'login')self.assertEqual(req.from_controller(),'login')classUtilsTC(TestCase):"""test suite for misc application utilities"""defsetUp(self):self.ctrl=FakeController()#def test_which_mapping(self):# """tests which mapping is used (application or core)"""# init_mapping()# from cubicweb.common import mapping# self.assertEqual(mapping.MAPPING_USED, 'core')# sys.modules['mapping'] = FakeMapping()# init_mapping()# self.assertEqual(mapping.MAPPING_USED, 'application')# del sys.modules['mapping']deftest_execute_linkto(self):"""tests the execute_linkto() function"""self.assertEqual(self.ctrl.execute_linkto(),None)self.assertEqual(self.ctrl._cursor.executed,[])self.ctrl.set_form({'__linkto':'works_for:12_13_14:object','eid':8})self.ctrl.execute_linkto()self.assertEqual(self.ctrl._cursor.executed,['SET Y works_for X WHERE X eid 8, Y eid %s'%iforiin(12,13,14)])self.ctrl.new_cursor()self.ctrl.set_form({'__linkto':'works_for:12_13_14:subject','eid':8})self.ctrl.execute_linkto()self.assertEqual(self.ctrl._cursor.executed,['SET X works_for Y WHERE X eid 8, Y eid %s'%iforiin(12,13,14)])self.ctrl.new_cursor()self.ctrl._cw.form={'__linkto':'works_for:12_13_14:object'}self.ctrl.execute_linkto(eid=8)self.assertEqual(self.ctrl._cursor.executed,['SET Y works_for X WHERE X eid 8, Y eid %s'%iforiin(12,13,14)])self.ctrl.new_cursor()self.ctrl.set_form({'__linkto':'works_for:12_13_14:subject'})self.ctrl.execute_linkto(eid=8)self.assertEqual(self.ctrl._cursor.executed,['SET X works_for Y WHERE X eid 8, Y eid %s'%iforiin(12,13,14)])classApplicationTC(CubicWebTC):@classpropertydefconfig(cls):try:returncls.__dict__['_config']exceptKeyError:config=super(ApplicationTC,cls).configconfig.global_set_option('allow-email-login',True)returnconfigdeftest_cnx_user_groups_sync(self):user=self.user()self.assertEqual(user.groups,set(('managers',)))self.execute('SET X in_group G WHERE X eid %s, G name "guests"'%user.eid)user=self.user()self.assertEqual(user.groups,set(('managers',)))self.commit()user=self.user()self.assertEqual(user.groups,set(('managers','guests')))# cleanupself.execute('DELETE X in_group G WHERE X eid %s, G name "guests"'%user.eid)self.commit()deftest_publish_validation_error(self):req=self.request()user=self.user()eid=unicode(user.eid)req.form={'eid':eid,'__type:'+eid:'CWUser','_cw_entity_fields:'+eid:'login-subject','login-subject:'+eid:'',# ERROR: no login specified# just a sample, missing some necessary information for real life'__errorurl':'view?vid=edition...'}path,params=self.expect_redirect_handle_request(req,'edit')forminfo=req.session.data['view?vid=edition...']eidmap=forminfo['eidmap']self.assertEqual(eidmap,{})values=forminfo['values']self.assertEqual(values['login-subject:'+eid],'')self.assertEqual(values['eid'],eid)error=forminfo['error']self.assertEqual(error.entity,user.eid)self.assertEqual(error.errors['login-subject'],'required field')deftest_validation_error_dont_loose_subentity_data_ctrl(self):"""test creation of two linked entities error occurs on the web controller """req=self.request()# set Y before X to ensure both entities are edited, not only Xreq.form={'eid':['Y','X'],'__maineid':'X','__type:X':'CWUser','_cw_entity_fields:X':'login-subject',# missing required field'login-subject:X':u'',# but email address is set'__type:Y':'EmailAddress','_cw_entity_fields:Y':'address-subject','address-subject:Y':u'bougloup@logilab.fr','use_email-object:Y':'X',# necessary to get validation error handling'__errorurl':'view?vid=edition...',}path,params=self.expect_redirect_handle_request(req,'edit')forminfo=req.session.data['view?vid=edition...']self.assertEqual(set(forminfo['eidmap']),set('XY'))self.assertEqual(forminfo['eidmap']['X'],None)self.assertIsInstance(forminfo['eidmap']['Y'],int)self.assertEqual(forminfo['error'].entity,'X')self.assertEqual(forminfo['error'].errors,{'login-subject':'required field'})self.assertEqual(forminfo['values'],req.form)deftest_validation_error_dont_loose_subentity_data_repo(self):"""test creation of two linked entities error occurs on the repository """req=self.request()# set Y before X to ensure both entities are edited, not only Xreq.form={'eid':['Y','X'],'__maineid':'X','__type:X':'CWUser','_cw_entity_fields:X':'login-subject,upassword-subject',# already existent user'login-subject:X':u'admin','upassword-subject:X':u'admin','upassword-subject-confirm:X':u'admin','__type:Y':'EmailAddress','_cw_entity_fields:Y':'address-subject','address-subject:Y':u'bougloup@logilab.fr','use_email-object:Y':'X',# necessary to get validation error handling'__errorurl':'view?vid=edition...',}path,params=self.expect_redirect_handle_request(req,'edit')forminfo=req.session.data['view?vid=edition...']self.assertEqual(set(forminfo['eidmap']),set('XY'))self.assertIsInstance(forminfo['eidmap']['X'],int)self.assertIsInstance(forminfo['eidmap']['Y'],int)self.assertEqual(forminfo['error'].entity,forminfo['eidmap']['X'])self.assertEqual(forminfo['error'].errors,{'login-subject':u'the value "admin" is already used, use another one'})self.assertEqual(forminfo['values'],req.form)def_test_cleaned(self,kwargs,injected,cleaned):req=self.request(**kwargs)page=self.app_handle_request(req,'view')self.assertNotIn(injected,page)self.assertIn(cleaned,page)deftest_nonregr_script_kiddies(self):"""test against current script injection"""injected='<i>toto</i>'cleaned='toto'forkwargsin({'__message':injected},{'vid':injected},{'vtitle':injected},):yieldself._test_cleaned,kwargs,injected,cleaneddeftest_site_wide_eproperties_sync(self):# XXX work in all-in-one configuration but not in twisted for instance# in which case we need a kindof repo -> http server notification# protocolvreg=self.app.vreg# default valueself.assertEqual(vreg.property_value('ui.language'),'en')self.execute('INSERT CWProperty X: X value "fr", X pkey "ui.language"')self.assertEqual(vreg.property_value('ui.language'),'en')self.commit()self.assertEqual(vreg.property_value('ui.language'),'fr')self.execute('SET X value "de" WHERE X pkey "ui.language"')self.assertEqual(vreg.property_value('ui.language'),'fr')self.commit()self.assertEqual(vreg.property_value('ui.language'),'de')self.execute('DELETE CWProperty X WHERE X pkey "ui.language"')self.assertEqual(vreg.property_value('ui.language'),'de')self.commit()self.assertEqual(vreg.property_value('ui.language'),'en')# authentication tests ####################################################deftest_http_auth_no_anon(self):req,origsession=self.init_authentication('http')self.assertAuthFailure(req)self.app.handle_request(req,'login')self.assertEqual(401,req.status_out)clear_cache(req,'get_authorization')authstr=base64.encodestring('%s:%s'%(self.admlogin,self.admpassword))req.set_request_header('Authorization','basic %s'%authstr)self.assertAuthSuccess(req,origsession)self.assertRaises(LogOut,self.app_handle_request,req,'logout')self.assertEqual(len(self.open_sessions),0)deftest_cookie_auth_no_anon(self):req,origsession=self.init_authentication('cookie')self.assertAuthFailure(req)try:form=self.app.handle_request(req,'login')exceptRedirectasredir:self.fail('anonymous user should get login form')clear_cache(req,'get_authorization')self.assertTrue('__login'inform)self.assertTrue('__password'inform)self.assertFalse(req.cnx)# Mock cnx are Falsereq.form['__login']=self.admloginreq.form['__password']=self.admpasswordself.assertAuthSuccess(req,origsession)self.assertRaises(LogOut,self.app_handle_request,req,'logout')self.assertEqual(len(self.open_sessions),0)deftest_login_by_email(self):login=self.request().user.loginaddress=login+u'@localhost'self.execute('INSERT EmailAddress X: X address %(address)s, U primary_email X ''WHERE U login %(login)s',{'address':address,'login':login})self.commit()# # option allow-email-login not setreq,origsession=self.init_authentication('cookie')# req.form['__login'] = address# req.form['__password'] = self.admpassword# self.assertAuthFailure(req)# option allow-email-login set#origsession.login = addressself.set_option('allow-email-login',True)req.form['__login']=addressreq.form['__password']=self.admpasswordself.assertAuthSuccess(req,origsession)self.assertRaises(LogOut,self.app_handle_request,req,'logout')self.assertEqual(len(self.open_sessions),0)def_reset_cookie(self,req):# preparing the suite of the test# set session id in cookiecookie=Cookie.SimpleCookie()sessioncookie=self.app.session_handler.session_cookie(req)cookie[sessioncookie]=req.session.sessionidreq.set_request_header('Cookie',cookie[sessioncookie].OutputString(),raw=True)clear_cache(req,'get_authorization')# reset session as if it was a new incoming requestreq.session=DBAPISession(None)req.user=req.cnx=_NeedAuthAccessMockdef_test_auth_anon(self,req):asession=self.app.get_session(req)# important otherwise _reset_cookie will not use the right sessionreq.set_cnx(repoapi.ClientConnection(asession))self.assertEqual(len(self.open_sessions),1)self.assertEqual(asession.login,'anon')self.assertTrue(asession.anonymous_session)self._reset_cookie(req)def_test_anon_auth_fail(self,req):self.assertEqual(1,len(self.open_sessions))session=self.app.get_session(req)# important otherwise _reset_cookie will not use the right sessionreq.set_cnx(repoapi.ClientConnection(session))self.assertEqual(req.message,'authentication failure')self.assertEqual(req.session.anonymous_session,True)self.assertEqual(1,len(self.open_sessions))self._reset_cookie(req)deftest_http_auth_anon_allowed(self):req,origsession=self.init_authentication('http','anon')self._test_auth_anon(req)authstr=base64.encodestring('toto:pouet')req.set_request_header('Authorization','basic %s'%authstr)self._test_anon_auth_fail(req)authstr=base64.encodestring('%s:%s'%(self.admlogin,self.admpassword))req.set_request_header('Authorization','basic %s'%authstr)self.assertAuthSuccess(req,origsession)self.assertRaises(LogOut,self.app_handle_request,req,'logout')self.assertEqual(len(self.open_sessions),0)deftest_cookie_auth_anon_allowed(self):req,origsession=self.init_authentication('cookie','anon')self._test_auth_anon(req)req.form['__login']='toto'req.form['__password']='pouet'self._test_anon_auth_fail(req)req.form['__login']=self.admloginreq.form['__password']=self.admpasswordself.assertAuthSuccess(req,origsession)self.assertRaises(LogOut,self.app_handle_request,req,'logout')self.assertEqual(0,len(self.open_sessions))deftest_anonymized_request(self):req=self.request()self.assertEqual(self.admlogin,req.session.user.login)# admin should see anon + adminself.assertEqual(2,len(list(req.find_entities('CWUser'))))withanonymized_request(req):self.assertEqual('anon',req.session.login,'anon')# anon should only see anon userself.assertEqual(1,len(list(req.find_entities('CWUser'))))self.assertEqual(self.admlogin,req.session.login)self.assertEqual(2,len(list(req.find_entities('CWUser'))))deftest_non_regr_optional_first_var(self):req=self.request()# expect a rset with None in [0][0]req.form['rql']='rql:Any OV1, X WHERE X custom_workflow OV1?'self.app_handle_request(req)if__name__=='__main__':unittest_main()