devtools/testlib.py
changeset 9044 cfec5cc46008
parent 9043 97c3bb9a7c99
child 9070 4a803380f718
equal deleted inserted replaced
9043:97c3bb9a7c99 9044:cfec5cc46008
   184         self._cnx = None  # current connection
   184         self._cnx = None  # current connection
   185         self.repo = None
   185         self.repo = None
   186         self.websession = None
   186         self.websession = None
   187         super(CubicWebTC, self).__init__(*args, **kwargs)
   187         super(CubicWebTC, self).__init__(*args, **kwargs)
   188 
   188 
       
   189     # repository connection handling ###########################################
       
   190 
   189     # Too much complicated stuff. the class doesn't need to bear the repo anymore
   191     # Too much complicated stuff. the class doesn't need to bear the repo anymore
   190     def set_cnx(self, cnx):
   192     def set_cnx(self, cnx):
   191         self._cnxs.add(cnx)
   193         self._cnxs.add(cnx)
   192         self._cnx = cnx
   194         self._cnx = cnx
   193 
   195 
   194     @property
   196     @property
   195     def cnx(self):
   197     def cnx(self):
   196         return self._cnx
   198         return self._cnx
       
   199 
       
   200     def _close_cnx(self):
       
   201         for cnx in list(self._cnxs):
       
   202             if not cnx._closed:
       
   203                 cnx.rollback()
       
   204                 cnx.close()
       
   205             self._cnxs.remove(cnx)
       
   206 
       
   207     @property
       
   208     def session(self):
       
   209         """return current server side session (using default manager account)"""
       
   210         session = self.repo._sessions[self.cnx.sessionid]
       
   211         session.set_cnxset()
       
   212         return session
       
   213 
       
   214     def login(self, login, **kwargs):
       
   215         """return a connection for the given login/password"""
       
   216         if login == self.admlogin:
       
   217             self.restore_connection()
       
   218             # definitly don't want autoclose when used as a context manager
       
   219             return self.cnx
       
   220         autoclose = kwargs.pop('autoclose', True)
       
   221         if not kwargs:
       
   222             kwargs['password'] = str(login)
       
   223         self.set_cnx(dbapi._repo_connect(self.repo, unicode(login), **kwargs))
       
   224         self.websession = dbapi.DBAPISession(self.cnx)
       
   225         if autoclose:
       
   226             return TestCaseConnectionProxy(self, self.cnx)
       
   227         return self.cnx
       
   228 
       
   229     def restore_connection(self):
       
   230         if not self.cnx is self._orig_cnx[0]:
       
   231             if not self.cnx._closed:
       
   232                 self.cnx.close()
       
   233         cnx, self.websession = self._orig_cnx
       
   234         self.set_cnx(cnx)
       
   235 
       
   236     #XXX this doesn't need to a be classmethod anymore
       
   237     def _init_repo(self):
       
   238         """init the repository and connection to it.
       
   239         """
       
   240         # setup configuration for test
       
   241         self.init_config(self.config)
       
   242         # get or restore and working db.
       
   243         db_handler = devtools.get_test_db_handler(self.config)
       
   244         db_handler.build_db_cache(self.test_db_id, self.pre_setup_database)
       
   245 
       
   246         self.repo, cnx = db_handler.get_repo_and_cnx(self.test_db_id)
       
   247         # no direct assignation to cls.cnx anymore.
       
   248         # cnx is now an instance property that use a class protected attributes.
       
   249         self.set_cnx(cnx)
       
   250         self.websession = dbapi.DBAPISession(cnx, self.admlogin)
       
   251         self._orig_cnx = (cnx, self.websession)
       
   252         self.config.repository = lambda x=None: self.repo
       
   253 
       
   254     # db api ##################################################################
       
   255 
       
   256     @nocoverage
       
   257     def cursor(self, req=None):
       
   258         return self.cnx.cursor(req or self.request())
       
   259 
       
   260     @nocoverage
       
   261     def execute(self, rql, args=None, eidkey=None, req=None):
       
   262         """executes <rql>, builds a resultset, and returns a couple (rset, req)
       
   263         where req is a FakeRequest
       
   264         """
       
   265         if eidkey is not None:
       
   266             warn('[3.8] eidkey is deprecated, you can safely remove this argument',
       
   267                  DeprecationWarning, stacklevel=2)
       
   268         req = req or self.request(rql=rql)
       
   269         return req.execute(unicode(rql), args)
       
   270 
       
   271     @nocoverage
       
   272     def commit(self):
       
   273         try:
       
   274             return self.cnx.commit()
       
   275         finally:
       
   276             self.session.set_cnxset() # ensure cnxset still set after commit
       
   277 
       
   278     @nocoverage
       
   279     def rollback(self):
       
   280         try:
       
   281             self.cnx.rollback()
       
   282         except dbapi.ProgrammingError:
       
   283             pass # connection closed
       
   284         finally:
       
   285             self.session.set_cnxset() # ensure cnxset still set after commit
       
   286 
       
   287     requestcls = fake.FakeRequest
       
   288     def request(self, rollbackfirst=False, url=None, headers={}, **kwargs):
       
   289         """return a web ui request"""
       
   290         req = self.requestcls(self.vreg, url=url, headers=headers, form=kwargs)
       
   291         if rollbackfirst:
       
   292             self.websession.cnx.rollback()
       
   293         req.set_session(self.websession)
       
   294         return req
       
   295 
       
   296     @property
       
   297     def adminsession(self):
       
   298         """return current server side session (using default manager account)"""
       
   299         return self.repo._sessions[self._orig_cnx[0].sessionid]
       
   300 
       
   301 
       
   302 
       
   303     # server side db api #######################################################
       
   304 
       
   305     def sexecute(self, rql, args=None, eid_key=None):
       
   306         if eid_key is not None:
       
   307             warn('[3.8] eid_key is deprecated, you can safely remove this argument',
       
   308                  DeprecationWarning, stacklevel=2)
       
   309         self.session.set_cnxset()
       
   310         return self.session.execute(rql, args)
       
   311 
       
   312 
       
   313     # config management ########################################################
   197 
   314 
   198     @classproperty
   315     @classproperty
   199     def config(cls):
   316     def config(cls):
   200         """return the configuration object
   317         """return the configuration object
   201 
   318 
   239         try:
   356         try:
   240             config.global_set_option('embed-allowed', re.compile('.*'))
   357             config.global_set_option('embed-allowed', re.compile('.*'))
   241         except Exception: # not in server only configuration
   358         except Exception: # not in server only configuration
   242             pass
   359             pass
   243 
   360 
   244     #XXX this doesn't need to a be classmethod anymore
       
   245     def _init_repo(self):
       
   246         """init the repository and connection to it.
       
   247         """
       
   248         # setup configuration for test
       
   249         self.init_config(self.config)
       
   250         # get or restore and working db.
       
   251         db_handler = devtools.get_test_db_handler(self.config)
       
   252         db_handler.build_db_cache(self.test_db_id, self.pre_setup_database)
       
   253 
       
   254         self.repo, cnx = db_handler.get_repo_and_cnx(self.test_db_id)
       
   255         # no direct assignation to cls.cnx anymore.
       
   256         # cnx is now an instance property that use a class protected attributes.
       
   257         self.set_cnx(cnx)
       
   258         self.websession = dbapi.DBAPISession(cnx, self.admlogin)
       
   259         self._orig_cnx = (cnx, self.websession)
       
   260         self.config.repository = lambda x=None: self.repo
       
   261 
       
   262     @property
   361     @property
   263     def vreg(self):
   362     def vreg(self):
   264         return self.repo.vreg
   363         return self.repo.vreg
   265 
   364 
   266     def _close_cnx(self):
       
   267         for cnx in list(self._cnxs):
       
   268             if not cnx._closed:
       
   269                 cnx.rollback()
       
   270                 cnx.close()
       
   271             self._cnxs.remove(cnx)
       
   272 
   365 
   273     # global resources accessors ###############################################
   366     # global resources accessors ###############################################
   274 
   367 
   275     @property
   368     @property
   276     def schema(self):
   369     def schema(self):
   277         """return the application schema"""
   370         """return the application schema"""
   278         return self.vreg.schema
   371         return self.vreg.schema
   279 
       
   280     @property
       
   281     def session(self):
       
   282         """return current server side session (using default manager account)"""
       
   283         session = self.repo._sessions[self.cnx.sessionid]
       
   284         session.set_cnxset()
       
   285         return session
       
   286 
       
   287     @property
       
   288     def adminsession(self):
       
   289         """return current server side session (using default manager account)"""
       
   290         return self.repo._sessions[self._orig_cnx[0].sessionid]
       
   291 
   372 
   292     def shell(self):
   373     def shell(self):
   293         """return a shell session object"""
   374         """return a shell session object"""
   294         from cubicweb.server.migractions import ServerMigrationHelper
   375         from cubicweb.server.migractions import ServerMigrationHelper
   295         return ServerMigrationHelper(None, repo=self.repo, cnx=self.cnx,
   376         return ServerMigrationHelper(None, repo=self.repo, cnx=self.cnx,
   392                 req.commit() # req is a session
   473                 req.commit() # req is a session
   393             except AttributeError:
   474             except AttributeError:
   394                 req.cnx.commit()
   475                 req.cnx.commit()
   395         return user
   476         return user
   396 
   477 
   397     def login(self, login, **kwargs):
       
   398         """return a connection for the given login/password"""
       
   399         if login == self.admlogin:
       
   400             self.restore_connection()
       
   401             # definitly don't want autoclose when used as a context manager
       
   402             return self.cnx
       
   403         autoclose = kwargs.pop('autoclose', True)
       
   404         if not kwargs:
       
   405             kwargs['password'] = str(login)
       
   406         self.set_cnx(dbapi._repo_connect(self.repo, unicode(login), **kwargs))
       
   407         self.websession = dbapi.DBAPISession(self.cnx)
       
   408         if autoclose:
       
   409             return TestCaseConnectionProxy(self, self.cnx)
       
   410         return self.cnx
       
   411 
       
   412     def restore_connection(self):
       
   413         if not self.cnx is self._orig_cnx[0]:
       
   414             if not self.cnx._closed:
       
   415                 self.cnx.close()
       
   416         cnx, self.websession = self._orig_cnx
       
   417         self.set_cnx(cnx)
       
   418 
       
   419     # db api ##################################################################
       
   420 
       
   421     @nocoverage
       
   422     def cursor(self, req=None):
       
   423         return self.cnx.cursor(req or self.request())
       
   424 
       
   425     @nocoverage
       
   426     def execute(self, rql, args=None, eidkey=None, req=None):
       
   427         """executes <rql>, builds a resultset, and returns a couple (rset, req)
       
   428         where req is a FakeRequest
       
   429         """
       
   430         if eidkey is not None:
       
   431             warn('[3.8] eidkey is deprecated, you can safely remove this argument',
       
   432                  DeprecationWarning, stacklevel=2)
       
   433         req = req or self.request(rql=rql)
       
   434         return req.execute(unicode(rql), args)
       
   435 
       
   436     @nocoverage
       
   437     def commit(self):
       
   438         try:
       
   439             return self.cnx.commit()
       
   440         finally:
       
   441             self.session.set_cnxset() # ensure cnxset still set after commit
       
   442 
       
   443     @nocoverage
       
   444     def rollback(self):
       
   445         try:
       
   446             self.cnx.rollback()
       
   447         except dbapi.ProgrammingError:
       
   448             pass # connection closed
       
   449         finally:
       
   450             self.session.set_cnxset() # ensure cnxset still set after commit
       
   451 
       
   452     # server side db api #######################################################
       
   453 
       
   454     def sexecute(self, rql, args=None, eid_key=None):
       
   455         if eid_key is not None:
       
   456             warn('[3.8] eid_key is deprecated, you can safely remove this argument',
       
   457                  DeprecationWarning, stacklevel=2)
       
   458         self.session.set_cnxset()
       
   459         return self.session.execute(rql, args)
       
   460 
   478 
   461     # other utilities #########################################################
   479     # other utilities #########################################################
   462 
   480 
   463     @contextmanager
   481     @contextmanager
   464     def temporary_appobjects(self, *appobjects):
   482     def temporary_appobjects(self, *appobjects):
   638         publisher = application.CubicWebPublisher(self.repo, self.config)
   656         publisher = application.CubicWebPublisher(self.repo, self.config)
   639         def raise_error_handler(*args, **kwargs):
   657         def raise_error_handler(*args, **kwargs):
   640             raise
   658             raise
   641         publisher.error_handler = raise_error_handler
   659         publisher.error_handler = raise_error_handler
   642         return publisher
   660         return publisher
   643 
       
   644     requestcls = fake.FakeRequest
       
   645     def request(self, rollbackfirst=False, url=None, headers={}, **kwargs):
       
   646         """return a web ui request"""
       
   647         req = self.requestcls(self.vreg, url=url, headers=headers, form=kwargs)
       
   648         if rollbackfirst:
       
   649             self.websession.cnx.rollback()
       
   650         req.set_session(self.websession)
       
   651         return req
       
   652 
   661 
   653     def remote_call(self, fname, *args):
   662     def remote_call(self, fname, *args):
   654         """remote json call simulation"""
   663         """remote json call simulation"""
   655         dump = json.dumps
   664         dump = json.dumps
   656         args = [dump(arg) for arg in args]
   665         args = [dump(arg) for arg in args]