Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Ticket #2404 (closed defect: wontfix)

Opened 10 years ago

Last modified 10 years ago

Model initialisation fails while running functional tests

Reported by: goodgravy Owned by:
Priority: normal Milestone: 2.x
Component: TurboGears Version: 2.0.3
Severity: major Keywords:
Cc:

Description

When testing controller methods that have interactions with the database, running more than one test at a time results in "no such table" OperationalErrors.

To reproduce:

  • create a new virtualenv with tg2-bootstrap.py
  • quickstart a TG2 project
  • add a method to the root controller which interacts with the DB. E.g.:
        @expose()
        def change_name(self, name):
            usr = model.User.by_user_name('manager')
            usr.display_name = name
            return {}
    
  • add two functional tests to TestRootController in test_root.py. E.g.:
        def test_a(self):
            rsp = self.app.get('/change_name/dave', status=200)
            usr = model.User.by_user_name('manager')
            assert_equals(usr.display_name, 'dave')
        def test_b(self):
            rsp = self.app.get('/change_name/bob', status=200)
            usr = model.User.by_user_name('manager')
            assert_equals(usr.display_name, 'bob')
    
  • run nosetests and wait for the "no such table" errors.

Attachments

sqlalchemy.log Download (10.4 KB) - added by goodgravy 10 years ago.
INFO level logging of sqlalchemy.engine, showing correct CREATE TABLE / DROP TABLE statements being issued.

Change History

Changed 10 years ago by goodgravy

INFO level logging of sqlalchemy.engine, showing correct CREATE TABLE / DROP TABLE statements being issued.

comment:1 Changed 10 years ago by goodgravy

INFO level logging of sqlalchemy.engine (see attachment) shows that the expected CREATE TABLE and DROP TABLE statements are being issued before and after each test method respectively.

Why, then, can SQLAlchemy not the tables it's just created?

comment:2 Changed 10 years ago by goodgravy

Cause of the problem is that different SQLAlchemy engines are being used during the set-up and run phases of my second test.

Advice from the SQLAlchemy list was that there should only ever be one engine (i.e. one call to create_engine). However, I assume that the multiple calls TG2 makes is symptomatic of wanting a completely blank slate for each test method.

While running the second test in a suite, a new engine is created and used for the DDL statements results from model.metadata.create_all, but the original engine from the first test is used by the ORM during the actual test.

Invoking DBSession.configure(bind=my_new_engine) does not seem to update the engine in use by the ORM.

There seems to be two possible fixes:

  1. get SQLAlchemy to realise we've moved on to a new engine
  2. only use one engine throughout an entire TG2 test suite, as SQLAlchemy currently expects

I've created a github project here:  http://github.com/goodgravy/tg2-broken which recreates the bug. It's a new TG2 application, with the one new controller method (in root.py) and two new tests (in test_root.py).

comment:3 follow-up: ↓ 4 Changed 10 years ago by jorge.vargas

  • Milestone changed from __unclassified__ to 2.x

This is a problem with the "total isolation" we currently have with unit tests. We have several long threads in the MLs and tickets outlining the issue.

Are you using SQLite? this bug is supposed to be exclusive to it as it does not flush properly our current fix to the total isolation which as you point out is to tier down the db on each call (which btw is very inefficient).

comment:4 in reply to: ↑ 3 Changed 10 years ago by goodgravy

Replying to jorge.vargas:

Are you using SQLite? this bug is supposed to be exclusive to it as it does not flush properly our current fix to the total isolation which as you point out is to tier down the db on each call (which btw is very inefficient).

Yes: when I switch over to MySQL, this problem goes away, which should be sufficient as a stop-gap fix.

However, not using SQLite triggers a different problem: ticket:2410...

comment:5 Changed 10 years ago by jorge.vargas

  • Status changed from new to closed
  • Resolution set to wontfix

Sadly this is a wontfix. The only way to make this work properly is to fix sqlite itself. The sad solution is to use a real db for functional testing.

Note: See TracTickets for help on using tickets.