Files
FabledCurator/tests/test_api_settings_downloader.py
T
bvandeusenandClaude Opus 5.5 30a263a47a feat: a teaser's card references the drop it announced and the piece's variants (4402, 4401)
The operator's problem: a Patreon teaser is a pointer, and its card showed the
censored crop plus a text link while the content it pointed at sat on another
card. The fix is a REFERENCE, not an absorption: "the nested items on the
unified post are a duplicate or reference of existing content". Nothing is
written. Discord posts keep their own rows, dates and places in the feed.

- post_unification: for each teaser with a linked association, the drop's
  images and text, plus its variant family: Discord images sharing the
  seed's gated LEADING working name, or a phash near-duplicate, within a
  window of the teaser. One hop only, oldest first.
- Measured on artist 8 before writing it: of 121 message pairs 2-60 days
  apart that share a gated token, 106 share the leading name and all read
  as real families. Of the 15 sharing only a trailing word, 14 are sibling
  pieces and one is a plain collision (`bottom`, 56 days). The family cap
  is 8, not the pairing cap of 6, because `tentacooler` and `0-k1` (6 posts
  each) are real families.
- The feed drops a linked drop's own card only within discord_link_fold_hours
  of its teaser (default 24): "only hidden from the post view they're posted
  the same day". Older referenced posts stay where they landed.
- post_association.linked_by records whether FC or a person made the link,
  so the card can say so. Undo is the existing dismiss.
- `image0` (gallery-dl's fallback name) becomes a stopword.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
2026-09-24 11:25:52 -04:00

169 lines
5.7 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
# --- #4402: the unified card's two windows ---------------------------------
@pytest.mark.asyncio
async def test_the_unified_card_windows_ship_with_their_measured_defaults(client):
"""24h is "the same day" without a timezone the server cannot know; 60 days
is the measured family boundary (named families up to 44d on artist 8,
every collision over 500)."""
resp = await client.get("/api/settings/import")
body = await resp.get_json()
assert body["discord_link_fold_hours"] == 24
assert body["discord_family_window_days"] == 60
@pytest.mark.asyncio
@pytest.mark.parametrize("key", ["discord_link_fold_hours", "discord_family_window_days"])
async def test_zero_turns_a_unified_card_window_off(client, key):
"""Zero is a real answer for both: fold nothing, reference no variants."""
resp = await client.patch("/api/settings/import", json={key: 0})
assert resp.status_code == 200
assert (await resp.get_json())[key] == 0
@pytest.mark.asyncio
@pytest.mark.parametrize("key", ["discord_link_fold_hours", "discord_family_window_days"])
@pytest.mark.parametrize("bad", [-1, "24", True])
async def test_a_unified_card_window_refuses_nonsense(client, key, bad):
resp = await client.patch("/api/settings/import", json={key: bad})
assert resp.status_code == 400