Files
shopdb-flask/tests/test_endpoint_command_reaper.py
Cam Proudlock 6680c3c5de Merge the wilm delivery work into main
Ben Baker's installed-software collection, software delivery (run_script and
update_app), agentless adoption tool and command-queue hardening, with his
authorship preserved.

Reviewed before promotion. Fixed: the endpoints plugin tests were never collected
by pytest, the SBOM snapshot table's key would exhaust on MySQL, ingest did not
truncate two columns strict MySQL would reject, and update_app's version branch
pinned a digest for a file that route never serves. Agent packaging moved off
require_role('admin') onto a new endpoints.agentpackage permission.

Contract 0.27.0. Full suite 2231, frontend 314.
2026-08-30 19:41:15 -04:00

70 lines
2.6 KiB
Python

"""Regression tests for the endpoint command-queue staleness reaper.
A claimed command whose agent never reports back (agent killed, uninstalled, or
offline mid-flight) would otherwise pin the at-most-one-in-flight queue forever,
so every operator action against that endpoint returns 409 "already in flight".
The enqueue path reaps such rows to STATUS_EXPIRED so the queue self-heals.
"""
from datetime import timedelta
def test_reap_stale_commands_frees_a_wedged_queue(db):
from plugins.endpoints.models import EndpointCommand
from plugins.endpoints.api.routes import _reap_stale_commands, _naive_utcnow
now = _naive_utcnow()
asset_id = 4242
stale_running = EndpointCommand(
assetid=asset_id, action='mtconnect_start',
status=EndpointCommand.STATUS_RUNNING,
createdat=now - timedelta(hours=2),
claimedat=now - timedelta(hours=2))
stale_pending = EndpointCommand(
assetid=asset_id, action='mtconnect_stop',
status=EndpointCommand.STATUS_PENDING,
createdat=now - timedelta(hours=2))
fresh_running = EndpointCommand(
assetid=asset_id + 1, action='mtconnect_start',
status=EndpointCommand.STATUS_RUNNING,
createdat=now, claimedat=now)
db.session.add_all([stale_running, stale_pending, fresh_running])
db.session.commit()
reaped = _reap_stale_commands(asset_id)
db.session.commit()
reaped_ids = {command.endpointcommandid for command in reaped}
assert stale_running.endpointcommandid in reaped_ids
assert stale_pending.endpointcommandid in reaped_ids
assert stale_running.status == EndpointCommand.STATUS_EXPIRED
assert stale_pending.status == EndpointCommand.STATUS_EXPIRED
assert stale_running.completedat is not None
assert stale_running.resultmessage
# A live, recently claimed command on another endpoint is untouched.
assert fresh_running.status == EndpointCommand.STATUS_RUNNING
def test_reap_leaves_a_recently_claimed_running_command_in_flight(db):
from plugins.endpoints.models import EndpointCommand
from plugins.endpoints.api.routes import _reap_stale_commands, _naive_utcnow
now = _naive_utcnow()
asset_id = 777
# Claimed a minute ago: a slow-but-alive command must not be reaped.
running = EndpointCommand(
assetid=asset_id, action='mtconnect_start',
status=EndpointCommand.STATUS_RUNNING,
createdat=now - timedelta(minutes=1),
claimedat=now - timedelta(minutes=1))
db.session.add(running)
db.session.commit()
reaped = _reap_stale_commands(asset_id)
db.session.commit()
assert reaped == []
assert running.status == EndpointCommand.STATUS_RUNNING