'Test revision compare and swap update breaking on concurrent update.
In this test we start an update of the name on a model in an eventlet
coroutine where it will be blocked before it can commit the results.
Then while it is blocked, we will update the description of the model
in the foregound and ensure that this results in the coroutine
receiving a StaleDataError as expected.'

def _test_staledata_error_on_concurrent_object_update(self, model, dbid):

    lock = functools.partial(lockutils.lock, uuidutils.generate_uuid())
    self._blocked_on_lock = False
    def _lock_blocked_name_update():
        ctx = context.get_admin_context()
        with db_api.context_manager.writer.using(ctx):
            thing = ctx.session.query(model).filter_by(id=dbid).one()
            thing.bump_revision()
            thing.name = 'newname'
            self._blocked_on_lock = True
            with lock():
                return thing
    with lock():
        coro = eventlet.spawn(_lock_blocked_name_update)
        while (not self._blocked_on_lock):
            eventlet.sleep(0)
        ctx = context.get_admin_context()
        with db_api.context_manager.writer.using(ctx):
            thing = ctx.session.query(model).filter_by(id=dbid).one()
            thing.bump_revision()
            thing.description = 'a    description'
        revision_after_build = thing.revision_number
    with testtools.ExpectedException(orm.exc.StaleDataError):
        coro.wait()
    thing = _lock_blocked_name_update()
    self.assertEqual('a    description', thing.description)
    self.assertEqual('newname', thing.name)
    self.assertGreater(thing.revision_number, revision_after_build)
