Files
shopdb-flask/tests/test_plugins/test_endpoints_fleet_alias.py
benjamin.baker 0134eaa219 Hard delete applications, nest installer packages, detect PE versions
Soft delete left orphaned executables on disk and let a deleted name collide
with a fresh import, so delete is now a hard delete that removes the
associated files. The destructive paths (delete, revert-to-record) require a
typed OK because neither can be undone.

Installers keep their filename at import and nest per application/version,
which stops repeat imports doubling up. Version now comes from the same PE
detection the endpoints agent uses; when no version can be read the caller is
asked for one rather than silently storing a blank.

Applications also surface Version and a monitorable toggle, with launch path
and process name required only while monitorable is ticked. Fleet shows the
PC alias, matching PC Details.
2026-09-07 15:04:21 -04:00

111 lines
4.1 KiB
Python

"""The Fleet list must carry the asset alias.
The alias is what people actually call a PC ("Bay 3 Controller"); the hostname
is what DNS calls it. The PCs list has shown both for a long time, but the
Fleet list query never selected Asset.name, so the column could not be built
even though the data existed - it was missing rather than broken.
These pin the field on the payload and its inclusion in search, so the column
cannot quietly lose its source again.
"""
LIST_URL = '/api/endpoints/'
def _endpoint(db, hostname='fleetbox', alias='Bay 3 Controller'):
"""An Asset + Computer + EndpointState triple: one row on the fleet list.
The list joins through Computer and filters on Asset.isactive, so all three
are required for a row to appear at all.
"""
from shopdb.api import Asset, AssetType
from plugins.computers.models import Computer
from plugins.endpoints.models import EndpointState
assettype = AssetType.query.filter_by(assettype='computer').first()
if assettype is None:
assettype = AssetType(assettype='computer', pluginname='computers',
tablename='computers')
db.session.add(assettype)
db.session.flush()
asset = Asset(assetnumber=hostname, name=alias,
assettypeid=assettype.assettypeid, isactive=True)
db.session.add(asset)
db.session.flush()
db.session.add(Computer(assetid=asset.assetid, hostname=hostname))
db.session.add(EndpointState(assetid=asset.assetid, hostname=hostname))
db.session.commit()
return asset.assetid
def _rows(response):
return response.get_json()['data']
def test_the_fleet_list_carries_the_alias(client, db, auth_headers):
_endpoint(db)
response = client.get(LIST_URL, headers=auth_headers)
assert response.status_code == 200, response.get_json()
rows = _rows(response)
assert len(rows) == 1
# Exposed as 'alias', not 'name': the row already has a hostname, and
# 'name' beside 'hostname' reads as a duplicate of the same thing.
assert rows[0]['alias'] == 'Bay 3 Controller'
def test_an_endpoint_without_an_alias_still_lists(client, db, auth_headers):
# The column renders '-' for these. A null must not drop the row or 500.
_endpoint(db, hostname='namelessbox', alias=None)
response = client.get(LIST_URL, headers=auth_headers)
assert response.status_code == 200, response.get_json()
rows = _rows(response)
assert len(rows) == 1
assert rows[0]['alias'] is None
assert rows[0]['hostname'] == 'namelessbox'
def test_the_alias_is_searchable(client, db, auth_headers):
# Someone looking for a PC types what it is called, not its hostname.
_endpoint(db, hostname='pc-a', alias='Bay 3 Controller')
_endpoint(db, hostname='pc-b', alias='Paint Booth')
response = client.get(LIST_URL + '?search=Bay 3', headers=auth_headers)
assert response.status_code == 200, response.get_json()
rows = _rows(response)
assert [r['hostname'] for r in rows] == ['pc-a']
def test_searching_by_hostname_still_works(client, db, auth_headers):
# The alias clause was added to an existing OR; prove it did not replace
# what was already there.
_endpoint(db, hostname='pc-a', alias='Bay 3 Controller')
_endpoint(db, hostname='pc-b', alias='Paint Booth')
response = client.get(LIST_URL + '?search=pc-b', headers=auth_headers)
assert response.status_code == 200, response.get_json()
rows = _rows(response)
assert [r['hostname'] for r in rows] == ['pc-b']
def test_the_row_keeps_its_other_columns(client, db, auth_headers):
# The alias was added mid-tuple in the query, so every following column
# shifted position. If that unpacking is wrong the values silently swap
# rather than raising.
_endpoint(db, hostname='fleetbox', alias='Bay 3 Controller')
response = client.get(LIST_URL, headers=auth_headers)
row = _rows(response)[0]
assert row['hostname'] == 'fleetbox'
assert row['assetnumber'] == 'fleetbox'
assert row['alias'] == 'Bay 3 Controller'
assert row['status'] in ('never', 'quiet', 'reporting')
assert 'computerid' in row and row['computerid'] is not None