Flask + Vue rewrite of the classic-ASP shopdb, built as a plugin framework so sister GE Aerospace sites can adopt it. Product version 0.7.0-pre-0.8.0, plugin contract 0.11.0, 966 backend tests. Key entry points: - docs/INSTALL-WINDOWS-IIS.md - tested Windows + IIS install runbook (own-site and subpath deployment methods) - docs/PILOT-DEPLOY.md - production pilot: stand up + import + verify - docs/IMPORT-API.md - schema-agnostic legacy data import contract - scripts/site_imports/wjf/ - West Jefferson reference import loader - docs/adr/ - twelve accepted architecture decision records
69 lines
3.0 KiB
Python
69 lines
3.0 KiB
Python
"""Network device create/update attaches a primary IP Communication.
|
|
|
|
Classic network devices carry their IP in the communications table, and the
|
|
legacy import needs an HTTP path to set it. The network create/update routes
|
|
accept an `ipaddress` and materialize a primary Communication (mirroring the
|
|
printer route); GET surfaces it back.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def network_setup(db):
|
|
from shopdb.core.models import AssetType, CommunicationType
|
|
db.session.add(AssetType(assettype='network_device', pluginname='network',
|
|
tablename='networkdevices', description='Network devices'))
|
|
db.session.add(CommunicationType(comtype='IP', description='IP'))
|
|
db.session.commit()
|
|
|
|
|
|
def test_create_network_device_with_ipaddress(client, db, auth_headers, network_setup):
|
|
"""POST /api/network with an ipaddress creates a primary Communication and
|
|
echoes the IP back."""
|
|
from shopdb.core.models import Communication
|
|
resp = client.post('/api/network', json={
|
|
'assetnumber': 'SW-CORE-01', 'name': 'Core switch',
|
|
'hostname': 'sw-core-01', 'ipaddress': '10.129.22.101',
|
|
}, headers=auth_headers)
|
|
assert resp.status_code == 201, resp.get_json()
|
|
data = resp.get_json()['data']
|
|
assert data['ipaddress'] == '10.129.22.101'
|
|
|
|
assetid = data['assetid']
|
|
comm = Communication.query.filter_by(assetid=assetid, isprimary=True).first()
|
|
assert comm is not None and comm.ipaddress == '10.129.22.101'
|
|
|
|
# GET surfaces it too.
|
|
got = client.get(f"/api/network/{data['networkdevice']['networkdeviceid']}",
|
|
headers=auth_headers)
|
|
assert got.get_json()['data']['ipaddress'] == '10.129.22.101'
|
|
|
|
|
|
def test_update_network_device_ipaddress_upserts(client, db, auth_headers, network_setup):
|
|
"""PUT changes the IP in place without creating a second Communication."""
|
|
from shopdb.core.models import Communication
|
|
created = client.post('/api/network', json={
|
|
'assetnumber': 'AP-01', 'name': 'AP', 'ipaddress': '10.0.0.5',
|
|
}, headers=auth_headers).get_json()['data']
|
|
devid = created['networkdevice']['networkdeviceid']
|
|
|
|
updated = client.put(f'/api/network/{devid}', json={'ipaddress': '10.0.0.9'},
|
|
headers=auth_headers)
|
|
assert updated.status_code == 200, updated.get_json()
|
|
assert updated.get_json()['data']['ipaddress'] == '10.0.0.9'
|
|
|
|
comms = Communication.query.filter_by(assetid=created['assetid']).all()
|
|
assert len(comms) == 1 and comms[0].ipaddress == '10.0.0.9'
|
|
|
|
|
|
def test_seed_reference_data_creates_ip_commtype(app, db):
|
|
"""The reference-data seed now creates the IP communication type the asset
|
|
import depends on."""
|
|
from shopdb.core.models import CommunicationType
|
|
runner = app.test_cli_runner()
|
|
assert runner.invoke(args=['seed', 'reference-data']).exit_code in (0, None)
|
|
with app.app_context():
|
|
assert CommunicationType.query.filter_by(comtype='IP').first() is not None
|
|
assert CommunicationType.query.count() >= 8
|