ODM2 / ODM2PythonAPI

A set of Python functions that provides data read/write access to an ODM2 database by leveraging SQLAlchemy.
http://odm2.github.io/ODM2PythonAPI/
BSD 3-Clause "New" or "Revised" License
4 stars 13 forks source link

CreateService Session closes on failed create #52

Open valentinedwv opened 8 years ago

valentinedwv commented 8 years ago

Adding tests based on @Castronova branch, and seeing that if a constraint is invalid, that the session becomes invalid.

Need to see check is the session is still open before attempting to create.

  # goal of this is to see that if we force errors like a null value, or duplicate that the session does not fail

    # create some people
    setup.odmcreate.createPerson(firstName="tony",
                                 lastName='castronova',
                                 middleName='michael')

    with pytest.raises(Exception) as excinfo:
        # this one should fail due to a not null constraint
        setup.odmcreate.createPerson(firstName=None,
                                     lastName='castronova',
                                     middleName='michael')

    assert 'People.PersonFirstName may not be NULL' in str(excinfo.value)

    # now add again
    setup.odmcreate.createPerson(firstName="tony",
                                 lastName='castronova',
                                 middleName=None)
2016-04-14 12:24:44,496 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-04-14 12:24:44,496 INFO sqlalchemy.engine.base.Engine INSERT INTO people (personfirstname, personmiddlename, personlastname) VALUES (?, ?, ?)
2016-04-14 12:24:44,496 INFO sqlalchemy.engine.base.Engine ('tony', 'michael', 'castronova')
2016-04-14 12:24:44,497 INFO sqlalchemy.engine.base.Engine COMMIT
2016-04-14 12:24:44,499 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-04-14 12:24:44,499 INFO sqlalchemy.engine.base.Engine INSERT INTO people (personfirstname, personmiddlename, personlastname) VALUES (?, ?, ?)
2016-04-14 12:24:44,499 INFO sqlalchemy.engine.base.Engine (None, 'michael', 'castronova')
2016-04-14 12:24:44,500 INFO sqlalchemy.engine.base.Engine ROLLBACK
F
setup = <class tests.test_odm2.odmConnection at 0x00000000088B34C8>

    def test_SessionNotFailed(setup):
        # goal of this is to see that if we force errors like a null value, or duplicate that the session does not fail

        # create some people
        setup.odmcreate.createPerson(firstName="tony",
                                     lastName='castronova',
                                     middleName='michael')

        with pytest.raises(Exception) as excinfo:
            # this one should fail due to a not null constraint
            setup.odmcreate.createPerson(firstName=None,
                                         lastName='castronova',
                                         middleName='michael')

        assert 'People.PersonFirstName may not be NULL' in str(excinfo.value)

        # now add again
        setup.odmcreate.createPerson(firstName="tony",
                                     lastName='castronova',
>                                    middleName=None)

tests\test_odm2.py:75: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
odm2api\ODM2\services\createService.py:226: in createPerson
    self._session.commit()
build\bdist.win-amd64\egg\sqlalchemy\orm\session.py:801: in commit
    ???
build\bdist.win-amd64\egg\sqlalchemy\orm\session.py:390: in commit
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <sqlalchemy.orm.session.SessionTransaction object at 0x00000000088EC668>
prepared_ok = True, rollback_ok = False, deactive_ok = False
closed_msg = 'This transaction is closed'

>   ???
E   InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) People.PersonFirstName may not be NULL [SQL: u'INSERT INTO people (personfirstname, personmiddlename, personlastname) VALUES (?, ?, ?)'] [parameters: (None, 'michael', 'castronova')]

build\bdist.win-amd64\egg\sqlalchemy\orm\session.py:214: InvalidRequestError
valentinedwv commented 8 years ago

Digging (looking into random failures)

base:
    def getSession(self):
        return self._session

base:
    def getSession(self):
         if self._session is None:
               self._session= self._session_factory.getSession()
        return self._session

Then all Service classes need to use getSession(), rather than self._session

valentinedwv commented 8 years ago

This is from the turned on test_odm2.py/test_sessionNotFailed

tests/test_odm2/test_odm2.py:93: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
odm2api/ODM2/services/createService.py:226: in createPerson
    self._session.commit()
../venv_odm/lib/python2.7/site-packages/sqlalchemy/orm/session.py:801: in commit
    self.transaction.commit()
../venv_odm/lib/python2.7/site-packages/sqlalchemy/orm/session.py:390: in commit
    self._assert_active(prepared_ok=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <sqlalchemy.orm.session.SessionTransaction object at 0x104d38f10>
prepared_ok = True, rollback_ok = False, deactive_ok = False
closed_msg = 'This transaction is closed'

    def _assert_active(self, prepared_ok=False,
                       rollback_ok=False,
                       deactive_ok=False,
                       closed_msg="This transaction is closed"):
        if self._state is COMMITTED:
            raise sa_exc.InvalidRequestError(
                "This session is in 'committed' state; no further "
                "SQL can be emitted within this transaction."
            )
        elif self._state is PREPARED:
            if not prepared_ok:
                raise sa_exc.InvalidRequestError(
                    "This session is in 'prepared' state; no further "
                    "SQL can be emitted within this transaction."
                )
        elif self._state is DEACTIVE:
            if not deactive_ok and not rollback_ok:
                if self._rollback_exception:
                    raise sa_exc.InvalidRequestError(
                        "This Session's transaction has been rolled back "
                        "due to a previous exception during flush."
                        " To begin a new transaction with this Session, "
                        "first issue Session.rollback()."
                        " Original exception was: %s"
>                       % self._rollback_exception
E                       InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) NOT NULL constraint failed: People.PersonFirstName [SQL: u'INSERT INTO people (personfirstname, personmiddlename, personlastname) VALUES (?, ?, ?)'] [parameters: (None, 'michael', 'castronova')]
valentinedwv commented 8 years ago

I think we will need to do a try-exception block, with session.rollback if things do not work. Or is there an object.isValid command that can be run before commiting