Files
FabledCurator/tests/test_api_settings_downloader.py
T
bvandeusenandClaude Opus 5 31de54e326
CI and images / lint (push) Failing after 2s
CI and images / extension-version (push) Successful in 2s
CI and images / frontend-build (push) Successful in 20s
CI and images / backend-lint-and-test (push) Successful in 31s
CI and images / integration (push) Failing after 2m15s
CI and images / sign-extension (push) Skipped
CI and images / build-web (push) Skipped
CI and images / smoke-web (push) Skipped
CI and images / promote (push) Skipped
CI and images / build-agent (push) Skipped
feat: FC links a conclusive pair itself instead of asking (4392)
Operator, 2026-09-24: *"I don't want this to be manual that defeats the
convenience that I'm going for."*

Confirm-only was right while every signal was circumstantial. Time proximity
and a body that mentions Discord can never be more than suggestive, so asking
was the honest response to what FC actually knew. A shared working name is
different in kind: when the creator's own name for a piece appears in exactly
these two posts and nowhere else in their library, there is nothing left for
the operator to adjudicate, and asking is a chore FC invented for them.

AUTO_LINK_FLOOR is 1.0 and sits deliberately above IDENTITY_FLOOR's 0.75. The
gap between them IS the review queue — real evidence, not certain enough for
FC to act on alone. Measured on artist 8, of 15 name-sharing pairs: 11 are
conclusive, 2 more propose, 2 fall short of both.

Three refusals, because an auto-link is FC asserting something the operator
never saw:

  * Exactly one candidate may be conclusive. Two is not a tie to be broken by
    score — one post can tease two pieces dropped separately, and then each
    drop carries a different name from the same teaser, each individually
    conclusive. Two conclusive answers to "which drop is this" means the
    question was wrong, so both queue and FC says nothing.
  * Neither end may already be claimed by an accepted link. That link is the
    operator's decision and reassigning its other end would overrule them
    silently.
  * The whole thing is one setting, defaulting on, reversible in the UI —
    an accepted link is a row they can dismiss.

`match_post` now returns (proposed, linked) so a sweep can report what it did
on its own rather than only what it queued.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
2026-09-24 08:14:04 -04:00

138 lines
4.4 KiB
Python

import pytest
pytestmark = pytest.mark.integration
@pytest.mark.asyncio
async def test_get_includes_downloader_fields(client):
resp = await client.get("/api/settings/import")
assert resp.status_code == 200
body = await resp.get_json()
assert body["download_rate_limit_seconds"] == 3.0
assert body["download_validate_files"] is True
@pytest.mark.asyncio
async def test_patch_download_rate_limit(client):
resp = await client.patch(
"/api/settings/import", json={"download_rate_limit_seconds": 1.5}
)
assert resp.status_code == 200
assert (await resp.get_json())["download_rate_limit_seconds"] == 1.5
@pytest.mark.asyncio
async def test_patch_download_validate_files_false(client):
resp = await client.patch(
"/api/settings/import", json={"download_validate_files": False}
)
assert resp.status_code == 200
assert (await resp.get_json())["download_validate_files"] is False
@pytest.mark.asyncio
async def test_patch_rejects_negative_rate_limit(client):
resp = await client.patch(
"/api/settings/import", json={"download_rate_limit_seconds": -1.0}
)
assert resp.status_code == 400
@pytest.mark.asyncio
async def test_patch_rejects_non_bool_validate(client):
resp = await client.patch(
"/api/settings/import", json={"download_validate_files": "yes"}
)
assert resp.status_code == 400
@pytest.mark.asyncio
async def test_extdl_host_toggles_default_on_and_patch(client):
body = await (await client.get("/api/settings/import")).get_json()
assert body["extdl_mega_enabled"] is True
assert body["extdl_pixeldrain_enabled"] is True
resp = await client.patch(
"/api/settings/import", json={"extdl_mega_enabled": False}
)
assert resp.status_code == 200
assert (await resp.get_json())["extdl_mega_enabled"] is False
@pytest.mark.asyncio
async def test_extdl_toggle_rejects_non_bool(client):
resp = await client.patch(
"/api/settings/import", json={"extdl_gdrive_enabled": "nope"}
)
assert resp.status_code == 400
# -- download_revisit_days: how far back a tick looks for EDITED posts --------
@pytest.mark.asyncio
async def test_revisit_window_defaults_to_thirty_days(client):
body = await (await client.get("/api/settings/import")).get_json()
assert body["download_revisit_days"] == 30
@pytest.mark.asyncio
async def test_revisit_window_is_settable(client):
resp = await client.patch(
"/api/settings/import", json={"download_revisit_days": 7}
)
assert resp.status_code == 200
assert (await resp.get_json())["download_revisit_days"] == 7
@pytest.mark.asyncio
async def test_zero_is_accepted_because_it_is_the_off_switch(client):
"""0 turns the revisit off and restores the pure count early-out. Pinned
because the obvious bounds check for a "days" field is `>= 1`, and that
would take the off switch away without anything failing."""
resp = await client.patch(
"/api/settings/import", json={"download_revisit_days": 0}
)
assert resp.status_code == 200
assert (await resp.get_json())["download_revisit_days"] == 0
@pytest.mark.asyncio
async def test_a_negative_window_is_refused(client):
resp = await client.patch(
"/api/settings/import", json={"download_revisit_days": -1}
)
assert resp.status_code == 400
# --- the announcement matcher's own switch ---------------------------------
@pytest.mark.asyncio
async def test_auto_linking_is_on_by_default(client):
"""Operator, 2026-09-24: "I don't want this to be manual that defeats the
convenience that I'm going for." Defaulting ON is the change of posture
that request asks for, so the default is what this pins."""
resp = await client.get("/api/settings/import")
assert resp.status_code == 200
assert (await resp.get_json())["discord_link_auto"] is True
@pytest.mark.asyncio
async def test_auto_linking_can_be_turned_off(client):
"""Confirm-only has to stay reachable — linking without asking is a change
of posture, and not everyone wants it."""
resp = await client.patch(
"/api/settings/import", json={"discord_link_auto": False}
)
assert resp.status_code == 200
assert (await resp.get_json())["discord_link_auto"] is False
@pytest.mark.asyncio
async def test_auto_linking_refuses_a_non_boolean(client):
resp = await client.patch(
"/api/settings/import", json={"discord_link_auto": "yes"}
)
assert resp.status_code == 400