"""Tests for the public shopdb.api namespace exposed to plugins. Pins audit_log, resolve_asset_position, and the BasePlugin get_setting/set_setting helpers as part of the contract surface. """ import pytest from shopdb.api import audit_log, resolve_asset_position from shopdb.core.models import AuditLog, Setting def test_audit_log_creates_row(db, client): """audit_log writes an AuditLog row with the standard fields.""" with client.application.test_request_context('/'): entry = audit_log( action='created', entitytype='Computer', entityid=42, entityname='PC-1234', changes={'before': {}, 'after': {'hostname': 'PC-1234'}}, ) assert entry is not None assert entry.action == 'created' assert entry.entitytype == 'Computer' assert entry.entityid == 42 assert entry.entityname == 'PC-1234' saved = AuditLog.query.filter_by(entityid=42, entitytype='Computer').first() assert saved is not None def test_resolve_asset_position_returns_none_when_no_data(): """An asset with no coords and no location returns None.""" class FakeAsset: mapx = None mapy = None location = None assert resolve_asset_position(FakeAsset()) is None def test_resolve_asset_position_uses_self_when_set(): """Asset-specific coords win over everything else.""" class FakeLocation: mapx = 10 mapy = 20 class FakeAsset: mapx = 100 mapy = 200 location = FakeLocation() result = resolve_asset_position(FakeAsset()) assert result == {'mapx': 100, 'mapy': 200, 'positionsource': 'self'} def test_resolve_asset_position_falls_back_to_location(): """When asset has no coords, falls back to location coords.""" class FakeLocation: mapx = 50 mapy = 75 class FakeAsset: mapx = None mapy = None location = FakeLocation() result = resolve_asset_position(FakeAsset()) assert result == {'mapx': 50, 'mapy': 75, 'positionsource': 'location'} def test_resolve_asset_position_handles_asset_without_mapx_attr(): """Assets that don't yet have mapx/mapy columns degrade gracefully.""" class FakeLocation: mapx = 1 mapy = 2 class FakeAsset: location = FakeLocation() result = resolve_asset_position(FakeAsset()) assert result == {'mapx': 1, 'mapy': 2, 'positionsource': 'location'} def test_plugin_get_setting_returns_default_when_unset(db, app): """A plugin reading an unset setting gets the default.""" from shopdb.plugins import plugin_manager with app.app_context(): printers = plugin_manager.get_plugin('printers') if printers is None: pytest.skip('printers plugin not loaded') assert printers.get_setting('nonexistentkey', default='fallback') == 'fallback' def test_plugin_set_and_get_setting_roundtrip(db, app): """A plugin can set and read its own setting; key is namespaced.""" from shopdb.plugins import plugin_manager with app.app_context(): printers = plugin_manager.get_plugin('printers') if printers is None: pytest.skip('printers plugin not loaded') printers.set_setting('zabbix_url', 'http://zabbix.example.com') assert printers.get_setting('zabbix_url') == 'http://zabbix.example.com' raw = Setting.query.filter_by(key='plugin.printers.zabbix_url').first() assert raw is not None assert raw.value == 'http://zabbix.example.com' def test_plugin_setting_is_namespaced_per_plugin(db, app): """Two plugins using the same key do not collide.""" from shopdb.plugins import plugin_manager with app.app_context(): printers = plugin_manager.get_plugin('printers') computers = plugin_manager.get_plugin('computers') if printers is None or computers is None: pytest.skip('required plugins not loaded') printers.set_setting('shared_key', 'printers_value') computers.set_setting('shared_key', 'computers_value') assert printers.get_setting('shared_key') == 'printers_value' assert computers.get_setting('shared_key') == 'computers_value'