"""Health evaluation failing with a database error must not sink the check-in. The health rollup is fail-open: a caught exception leaves the previous verdict standing. A caught IntegrityError from a flush, though, leaves the session needing a rollback, and the outer commit of the whole check-in would then fail. The evaluation runs inside a SAVEPOINT so only its own writes are discarded. """ from shopdb.core.models import Asset, AssetType def _computer(db, hostname): from plugins.computers.models import Computer atype = AssetType.query.filter_by(assettype='computer').first() if not atype: atype = AssetType(assettype='computer') db.session.add(atype) db.session.flush() asset = Asset(assetnumber=hostname, assettypeid=atype.assettypeid, isactive=True) db.session.add(asset) db.session.flush() db.session.add(Computer(assetid=asset.assetid, hostname=hostname)) db.session.commit() return asset def test_integrity_error_in_health_keeps_the_checkin(client, db, app, monkeypatch): from plugins.endpoints.plugin import EndpointsPlugin from plugins.endpoints.models import EndpointState from plugins.endpoints.services import health calls = [] def exploding_health(assetid, state, computertypeid=None): calls.append(assetid) # A duplicate unique value: the flush raises IntegrityError. db.session.add(AssetType(assettype='computer')) db.session.flush() monkeypatch.setattr(health, 'evaluate_endpoint_health', exploding_health) asset = _computer(db, 'SAVEPT01') plugin = EndpointsPlugin() plugin.apply_collector_payload({'hostname': 'SAVEPT01', 'services': []}) db.session.commit() assert calls == [asset.assetid] state = EndpointState.query.filter_by(assetid=asset.assetid).first() assert state is not None assert AssetType.query.filter_by(assettype='computer').count() == 1