| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- """The discoveries bundle (goal 24): the fleet's global, EDITABLE
- knowledge base of non-project facts — the /api/saddle/discovery
- insert + update callbacks, the /api/saddle/discoveries search, the
- human edit/delete actions on the Discoveries page, and the newest
- rows riding the assignment payload."""
- from harness import * # noqa: F401,F403 — the shared wire helpers
- def run(ctx):
- auth, fake, fake_id, fake_token = ctx.auth, ctx.fake, ctx.fake_id, ctx.fake_token
- def db_rows(sql, params=()):
- conn = db()
- try:
- return conn.execute(sql, params).fetchall()
- finally:
- conn.close()
- print("== discoveries: the migration ==")
- # A fresh database: M0001..M0005 ran at startup, so the table
- # exists with the goal-24 shape.
- tables = [r[0] for r in db_rows(
- "select name from sqlite_master where type = 'table'")]
- check("discoveries" in tables,
- "M0005 creates the discoveries table on a fresh DB")
- columns = [r[1] for r in db_rows("pragma table_info(discoveries)")]
- check(columns == ["id", "body", "source_task_id", "created_at",
- "updated_at"],
- "the table carries the goal-24 columns (%s)" % columns)
- print("== discoveries: POST auth + validation ==")
- status, _ = saddle_api("POST", "/api/saddle/discovery", None, {"body": "x"})
- check(status == 401, "POST rejects a missing token")
- status, _ = saddle_api("POST", "/api/saddle/discovery", "saddle-bogus",
- {"body": "x"})
- check(status == 401, "POST rejects a wrong token")
- status, body = saddle_api("POST", "/api/saddle/discovery", fake_token,
- {"body": " "})
- check(status == 400 and body.get("ok") is False,
- "POST rejects an empty body")
- print("== discoveries: inserts and ordering ==")
- status, body = saddle_api("POST", "/api/saddle/discovery", fake_token,
- {"task_id": 21,
- "body": "valac chokes on `size` for Invercargill's Vector; use `length`."})
- check(status == 200 and body.get("ok") is True
- and int(body.get("discovery_id", 0)) > 0,
- "POST inserts and returns the discovery id")
- first_id = int(body["discovery_id"])
- status, body = saddle_api("POST", "/api/saddle/discovery", fake_token,
- {"body": "meson setup needs a fresh build dir after editing meson.build custom_targets."})
- check(status == 200 and int(body.get("discovery_id", 0)) > first_id,
- "a second insert gets a LATER id")
- second_id = int(body["discovery_id"])
- rows = db_rows("select id, body, source_task_id, created_at, updated_at"
- " from discoveries order by id")
- check([r[0] for r in rows] == [first_id, second_id],
- "rows land in insert order")
- check(rows[0][2] == 21 and rows[1][2] == 0,
- "rows keep the optional source task (21 / 0)")
- check(all(r[3] is not None and r[4] is not None for r in rows),
- "created_at and updated_at are stamped")
- print("== discoveries: GET search ==")
- status, _ = saddle_api("GET", "/api/saddle/discoveries?q=valac", None)
- check(status == 401, "GET rejects a missing token")
- status, body = saddle_api("GET", "/api/saddle/discoveries?q=VALAC",
- fake_token)
- check(status == 200 and body.get("ok") is True,
- "GET answers a search")
- hits = body.get("discoveries") or []
- check(len(hits) == 1 and hits[0]["id"] == first_id,
- "the search is a case-insensitive substring match over the body")
- check((hits[0].get("created") or "").endswith("Z")
- and (hits[0].get("updated") or "").endswith("Z"),
- "rows carry ISO-8601 created/updated stamps")
- status, body = saddle_api("GET", "/api/saddle/discoveries", fake_token)
- check(status == 200 and len(body.get("discoveries") or []) == 2
- and body["discoveries"][0]["id"] == second_id,
- "an empty q lists the newest 20 (newest first)")
- print("== discoveries: update refines in place ==")
- status, _ = saddle_api("POST", "/api/saddle/discovery/update", None,
- {"id": first_id, "body": "x"})
- check(status == 401, "update rejects a missing token")
- status, body = saddle_api("POST", "/api/saddle/discovery/update",
- fake_token, {"id": 999999, "body": "x"})
- check(status == 400 and body.get("ok") is False,
- "update rejects an unknown id with an error JSON")
- status, body = saddle_api("POST", "/api/saddle/discovery/update",
- fake_token,
- {"id": first_id,
- "body": "valac chokes on `size` for Invercargill's Vector; use `length` (also `count`, a uint)."})
- check(status == 200 and body.get("ok") is True, "update answers ok")
- rows = db_rows("select id, body, source_task_id, created_at, updated_at"
- " from discoveries order by id")
- check(len(rows) == 2 and rows[0][0] == first_id,
- "update INSERTS NOTHING — the row is refined in place")
- check("also `count`" in rows[0][1], "the body was replaced")
- check(rows[0][2] == 21, "update keeps the original source task")
- check(rows[0][4] >= rows[0][3],
- "updated_at bumped at or after created_at")
- print("== discoveries: the page and the human actions ==")
- state = slot_public(auth, "/discoveries", "discoveries")
- listed = state.get("discoveries") or []
- check([r["id"] for r in listed] == [str(second_id), str(first_id)],
- "the page lists rows newest first")
- check("also `count`" in listed[1]["body"],
- "the page shows the refined body")
- check(listed[1].get("updated_display", "") != ""
- and listed[0].get("updated_display", "") != "",
- "refined rows show an updated stamp")
- check(all(r.get("update") is not None and r.get("delete") is not None
- for r in listed),
- "every row authors the edit and delete actions")
- # The human edit path: the same update-in-place semantics.
- result = act(auth, listed[1]["update"],
- {"body": "valac: Invercargill Vector exposes `length` (uint) and `count()`, never `size`."})
- check(any(d.get("type") == "notify" and d.get("kind") == "success"
- for d in result), "the human edit notifies success")
- rows = db_rows("select body from discoveries where id = %d" % first_id)
- check("never `size`" in rows[0][0],
- "the human edit replaced the body in place")
- # The human delete path.
- result = act(auth, listed[0]["delete"], {})
- check(any(d.get("type") == "notify" and d.get("kind") == "success"
- for d in result), "the human delete notifies success")
- rows = db_rows("select id from discoveries order by id")
- check([r[0] for r in rows] == [first_id],
- "the human delete removed the row")
- print("== discoveries: the page search filter ==")
- # The browser filters client-side (the script above), but the
- # entrypoint still honours a server-side q: a direct entrypoint
- # hit passes the filter as a sibling query param next to uri=
- # (the same shape the task page's status filter documents).
- status, body = http(
- "GET",
- "/_statum/entrypoint?uri=" + urllib.parse.quote("/discoveries")
- + "&q=" + urllib.parse.quote("never `size`"),
- headers={"X-Statum-Slot": "key=%s; as_at=%s" % (auth["key"], auth["as_at"])})
- check(status == 200, "a direct entrypoint hit with q= answers")
- filtered = None
- for directive in json.loads(body):
- if directive.get("type") == "set":
- content = json.loads(directive["snapshot_frame"]["content"])
- if content["slot"]["type"] == "discoveries":
- filtered = content["public"]
- check(filtered is not None and filtered.get("query") == "never `size`",
- "the entrypoint seeds the search box from q")
- check(len(filtered.get("discoveries") or []) == 1
- and "never `size`" in (filtered["discoveries"][0].get("body", "")),
- "the q filter narrows the rows server-side")
- state = slot_public(auth, "/discoveries", "discoveries")
- check(state.get("query", "") == "" and len(state.get("discoveries") or []) == 1,
- "a plain hit stays unfiltered")
- print("== discoveries: ride the assignment payload ==")
- payload_count = len(fake.start_payloads)
- create_queued(auth, {
- "project_id": "1",
- "title": "Discovery dispatch",
- "priority": "2",
- })
- check(wait_for(lambda: len(fake.start_payloads) > payload_count or False,
- timeout=30, what="discovery /start push") is not None,
- "dispatcher pushes the discovery task")
- payload = fake.start_payloads[-1]
- check("discoveries" in payload,
- "the assignment payload carries a discoveries member")
- shipped = payload.get("discoveries")
- check(isinstance(shipped, list) and len(shipped) == 1
- and "never `size`" in shipped[0].get("body", ""),
- "the payload ships the newest rows as {body} objects")
- # The cap: 12 giant rows → at most 10 entries / 8000 chars.
- conn = db()
- for i in range(12):
- conn.execute(
- "insert into discoveries (body, source_task_id, created_at, updated_at)"
- " values (?, 0, strftime('%s','now'), strftime('%s','now'))",
- ("cap%02d " % i + "z" * 1500,))
- conn.commit()
- conn.close()
- payload_count = len(fake.start_payloads)
- create_queued(auth, {
- "project_id": "1",
- "title": "Discovery cap dispatch",
- "priority": "2",
- })
- check(wait_for(lambda: len(fake.start_payloads) > payload_count or False,
- timeout=30, what="cap /start push") is not None,
- "dispatcher pushes the cap task")
- shipped = fake.start_payloads[-1].get("discoveries")
- check(isinstance(shipped, list) and len(shipped) <= 10,
- "the payload caps the discoveries at 10 entries (%d)" % len(shipped))
- check(sum(len(r.get("body", "")) for r in shipped) <= 8000,
- "the payload caps the discoveries at 8000 chars total (%d)"
- % sum(len(r.get("body", "")) for r in shipped))
- check(shipped[0].get("body", "").startswith("cap11"),
- "the newest rows ship first")
- print("== discoveries: the dashboard slice ==")
- home = slot_public(auth, "/", "dashboard")
- latest = home.get("discoveries") or []
- check(len(latest) == 5 and latest[0].get("body", "").startswith("cap11"),
- "the dashboard shows the five newest discoveries newest first")
|