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] |