mirror of
https://github.com/RunLit/Bambu-Run.git
synced 2026-10-21 15:37:38 +01:00
fix(mcp): address final-review findings (sentinel exclusion, per-unit AMS data, generated_at, gating test, docs, cleanup)
This commit is contained in:
@@ -15,6 +15,7 @@ def test_list_filaments_filters_material_sub_type_color():
|
||||
|
||||
assert len(result["filaments"]) == 1
|
||||
assert result["filaments"][0]["sub_type"] == "PLA Matte"
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -117,6 +118,7 @@ def test_get_filament_returns_full_usage_history_with_data_quality():
|
||||
assert reliable["consumed_grams"] == 100
|
||||
assert unreliable["data_quality"] == "unreliable"
|
||||
assert unreliable["consumed_grams"] is None
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -16,6 +16,7 @@ def test_list_print_jobs_orders_most_recent_first():
|
||||
result = list_print_jobs()
|
||||
|
||||
assert [j["id"] for j in result["jobs"]] == [newer.id, older.id]
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -86,6 +87,7 @@ def test_get_print_job_marks_negative_consumption_unreliable():
|
||||
usage = result["filament_usages"][0]
|
||||
assert usage["consumed_grams"] is None
|
||||
assert usage["data_quality"] == "unreliable"
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -121,6 +123,21 @@ def test_get_print_statistics_success_rate_and_status_counts():
|
||||
assert result["success_rate"] == 0.5
|
||||
assert result["status_counts"]["FINISH"] == 1
|
||||
assert result["status_counts"]["FAILED"] == 1
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_print_statistics_excludes_ending_sentinel_from_material_mix():
|
||||
p = Printer.objects.create(name="RNL-H2C", model="H2C", is_active=True)
|
||||
job = PrintJob.objects.create(device=p, project_name="A", start_time=timezone.now(), final_status="FINISH")
|
||||
pla = Filament.objects.create(type="PLA", brand="Bambu Lab", color="Black", initial_weight_grams=1000)
|
||||
# ending_percent=-1 (no RFID read at job end) must not be counted as 610g of consumption
|
||||
FilamentUsage.objects.create(print_job=job, filament=pla, tray_id=0, starting_percent=60, ending_percent=-1)
|
||||
|
||||
result = get_print_statistics(days=30)
|
||||
|
||||
assert result["material_mix_grams"] == {}
|
||||
assert result["most_used_material"] is None
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -97,6 +97,44 @@ def test_get_printer_status_ams_slot_unread_sentinel():
|
||||
assert slot["remain_status"] == "unread"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_printer_status_ams_units_have_independent_humidity():
|
||||
p = Printer.objects.create(name="RNL-H2C", model="H2C", is_active=True)
|
||||
PrinterMetrics.objects.create(
|
||||
device=p, timestamp=timezone.now(), gcode_state="RUNNING",
|
||||
ams_humidity_raw=4, # unit-0-only flat column, must NOT be used for unit 1
|
||||
ams_units=[
|
||||
{"unit_id": 0, "ams_type": "AMS 2 Pro", "humidity_raw": 4, "temp": 28.0},
|
||||
{"unit_id": 1, "ams_type": "AMS", "humidity_raw": 7, "temp": 24.0},
|
||||
],
|
||||
filaments=[
|
||||
{"ams_unit_id": 0, "tray_id": "0", "type": "ABS", "remain_percent": 50},
|
||||
{"ams_unit_id": 1, "tray_id": "0", "type": "PLA", "remain_percent": 60},
|
||||
],
|
||||
)
|
||||
|
||||
result = get_printer_status(printer=p.id)
|
||||
|
||||
units_by_id = {u["unit_id"]: u for u in result["printers"][0]["ams_units"]}
|
||||
assert units_by_id[0]["humidity_raw"] == 4
|
||||
assert units_by_id[1]["humidity_raw"] == 7
|
||||
assert units_by_id[0]["temp_c"] == 28.0
|
||||
assert units_by_id[1]["temp_c"] == 24.0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_printer_status_tolerates_malformed_tray_id():
|
||||
p = Printer.objects.create(name="RNL-H2C", model="H2C", is_active=True)
|
||||
PrinterMetrics.objects.create(
|
||||
device=p, timestamp=timezone.now(), gcode_state="RUNNING",
|
||||
filaments=[{"ams_unit_id": 0, "tray_id": None, "type": "ABS", "remain_percent": 50}],
|
||||
)
|
||||
|
||||
result = get_printer_status(printer=p.id) # must not raise
|
||||
|
||||
assert result["printers"][0]["ams_units"][0]["slots"][0]["slot"] == -1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_printer_status_never_exposes_serial_or_ip():
|
||||
p = Printer.objects.create(
|
||||
@@ -151,6 +189,7 @@ def test_get_metrics_history_returns_series_within_window():
|
||||
assert result["printer"]["id"] == p.id
|
||||
assert len(result["timestamps"]) == 3
|
||||
assert 999.0 not in result["series"]["nozzle_c"]
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -181,7 +220,10 @@ def test_get_metrics_history_hard_ceiling_500_points():
|
||||
@pytest.mark.django_db
|
||||
def test_get_metrics_history_no_matching_printer_returns_empty_shape():
|
||||
result = get_metrics_history(printer=None)
|
||||
assert result == {"printer": None, "timestamps": [], "series": {}}
|
||||
assert result["printer"] is None
|
||||
assert result["timestamps"] == []
|
||||
assert result["series"] == {}
|
||||
assert "generated_at" in result
|
||||
|
||||
|
||||
from bambu_run.models import Hotend
|
||||
|
||||
@@ -56,6 +56,7 @@ async def test_read_printer_only_caller_cannot_see_or_call_filament_tool(db):
|
||||
visible = await client.list_tools()
|
||||
visible_names = {t.name for t in visible.tools}
|
||||
assert "list_filaments" not in visible_names
|
||||
assert "list_print_jobs" not in visible_names
|
||||
assert "get_printer_status" in visible_names
|
||||
|
||||
with pytest.raises(MCPError):
|
||||
|
||||
Reference in New Issue
Block a user