Test: quota NaN chiede il capoturno, migrazione 022 conserva le righe
Refs #125 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -379,3 +379,55 @@ class TestMeasurementValueNullableMigration:
|
|||||||
assert value_nullable() is False
|
assert value_nullable() is False
|
||||||
command.upgrade(cfg, "head") # e di nuovo su
|
command.upgrade(cfg, "head") # e di nuovo su
|
||||||
assert value_nullable() is True
|
assert value_nullable() is True
|
||||||
|
|
||||||
|
def test_022_keeps_rows(self, sqlite_database_url):
|
||||||
|
"""#125: la ricostruzione della tabella conserva righe, somma dei value e indici."""
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
db_path, _ = sqlite_database_url
|
||||||
|
cfg = _alembic_config()
|
||||||
|
command.upgrade(cfg, "021_task_acquisition")
|
||||||
|
|
||||||
|
def indexes(con):
|
||||||
|
return sorted(r[0] for r in con.execute(
|
||||||
|
"select name from sqlite_master where type='index' and tbl_name='measurements'"
|
||||||
|
))
|
||||||
|
|
||||||
|
con = sqlite3.connect(db_path)
|
||||||
|
# Colonne NOT NULL senza default riempite per tipo (stessa idea di mig_check.py)
|
||||||
|
vals = {}
|
||||||
|
for _cid, name, typ, notnull, dflt, pk in con.execute("pragma table_info(measurements)").fetchall():
|
||||||
|
if pk or not notnull or dflt is not None:
|
||||||
|
continue
|
||||||
|
t = typ.upper()
|
||||||
|
vals[name] = (
|
||||||
|
1 if "INT" in t
|
||||||
|
else 1.5 if ("DEC" in t or "FLOAT" in t or "NUM" in t)
|
||||||
|
else "2026-01-01 00:00:00" if ("DATE" in t or "TIME" in t)
|
||||||
|
else "x"
|
||||||
|
)
|
||||||
|
vals["pass_fail"] = "pass"
|
||||||
|
vals["value"] = 12.5
|
||||||
|
sql = f"insert into measurements ({','.join(vals)}) values ({','.join('?' * len(vals))})"
|
||||||
|
for _ in range(3):
|
||||||
|
con.execute(sql, list(vals.values()))
|
||||||
|
con.commit()
|
||||||
|
before_idx = indexes(con)
|
||||||
|
before = con.execute("select count(*), sum(value) from measurements").fetchone()
|
||||||
|
con.close()
|
||||||
|
assert before == (3, 37.5)
|
||||||
|
|
||||||
|
command.upgrade(cfg, "head")
|
||||||
|
|
||||||
|
con = sqlite3.connect(db_path)
|
||||||
|
try:
|
||||||
|
assert con.execute("select count(*), sum(value) from measurements").fetchone() == before
|
||||||
|
assert indexes(con) == before_idx
|
||||||
|
assert con.execute("pragma integrity_check").fetchone()[0] == "ok"
|
||||||
|
vals["value"] = None
|
||||||
|
vals["pass_fail"] = "fail"
|
||||||
|
con.execute(sql, list(vals.values())) # una riga NaN (value NULL) ora e' accettata
|
||||||
|
con.commit()
|
||||||
|
assert con.execute("select count(*) from measurements where value is null").fetchone()[0] == 1
|
||||||
|
finally:
|
||||||
|
con.close()
|
||||||
|
|||||||
@@ -216,10 +216,11 @@ async def test_a_non_finite_output_is_saved_as_nan(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_a_nan_quote_still_blocks_the_next_acquisition(
|
async def test_a_nan_quote_needs_supervisor_authorisation(
|
||||||
client, db_session, measurement_tec_user, worker_says,
|
client, db_session, measurement_tec_user, worker_says,
|
||||||
):
|
):
|
||||||
"""#118: la quota NaN e' un fail come gli altri, il blocco di tolleranza resta."""
|
"""#125: la quota NaN e' un fail come gli altri e chiede il capoturno (pending_authorisation);
|
||||||
|
la prossima acquisizione non e' bloccata."""
|
||||||
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
|
||||||
version, task, first, second = await two_vision_quotes(db_session, recipe.id)
|
version, task, first, second = await two_vision_quotes(db_session, recipe.id)
|
||||||
worker_says({"t1.radius": GOOD})
|
worker_says({"t1.radius": GOOD})
|
||||||
@@ -230,6 +231,15 @@ async def test_a_nan_quote_still_blocks_the_next_acquisition(
|
|||||||
)
|
)
|
||||||
assert blocking is not None and blocking.subtask_id == first.id and blocking.value is None
|
assert blocking is not None and blocking.subtask_id == first.id and blocking.value is None
|
||||||
|
|
||||||
|
# #125: una seconda acquisizione sullo stesso task risponde 200, non e' bloccata
|
||||||
|
again = await client.post(
|
||||||
|
"/api/vision/execute",
|
||||||
|
headers=auth_headers(measurement_tec_user),
|
||||||
|
files={"image": ("p.png", an_image(), "image/png")},
|
||||||
|
data={"task_id": str(task.id)},
|
||||||
|
)
|
||||||
|
assert again.status_code == 200, again.text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_check_lists_a_missing_quote_as_nan(
|
async def test_check_lists_a_missing_quote_as_nan(
|
||||||
|
|||||||
Reference in New Issue
Block a user