mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-10-21 05:05:36 +00:00
test(sunset): cover hosted account purge guards
This commit is contained in:
parent
b40e5f135d
commit
d78f95ef33
2 changed files with 126 additions and 1 deletions
|
|
@ -51,7 +51,6 @@ On the web, `proxy.ts` sends every non-public route to `/sunset` with a 307. The
|
|||
- The web redirect is not gated on `DEPLOYMENT_MODE`: a self-hosted web app with `SUNSET_MODE` set redirects to `/sunset`.
|
||||
- The 410 body carries no `sunset_url`.
|
||||
- The purge selects every user, so once license mode creates synthetic license users it would erase them too.
|
||||
- The purge script has no test.
|
||||
- Celery beat keeps scheduling its periodic tasks, connector indexing checks and automation triggers among them, and none checks `is_sunset_mode()`; the middleware covers HTTP only.
|
||||
- The synchronous export has no size warning and no timeout.
|
||||
- The web app's unit tests, `tests/unit/sunset-redirect.test.ts` among them, are not run in CI.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from uuid import UUID
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts import purge_hosted_accounts as purge
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
_ACCOUNTS = [
|
||||
(UUID("00000000-0000-0000-0000-000000000001"), "ada@example.com"),
|
||||
(UUID("00000000-0000-0000-0000-000000000002"), "bob@example.com"),
|
||||
(UUID("00000000-0000-0000-0000-000000000003"), "cy@example.com"),
|
||||
]
|
||||
|
||||
|
||||
def _argv(monkeypatch: pytest.MonkeyPatch, *args: str) -> None:
|
||||
monkeypatch.setattr(sys, "argv", ["purge_hosted_accounts", *args])
|
||||
|
||||
|
||||
async def test_refuses_outside_sunset_mode(monkeypatch, capsys):
|
||||
_argv(monkeypatch, "--execute", "--yes")
|
||||
monkeypatch.setattr(purge, "is_sunset_mode", lambda: False)
|
||||
|
||||
async def accounts():
|
||||
pytest.fail("accounts must not be read before the sunset guard")
|
||||
|
||||
monkeypatch.setattr(purge, "_accounts", accounts)
|
||||
|
||||
assert await purge.main() == 2
|
||||
assert "SUNSET_MODE is not set" in capsys.readouterr().err
|
||||
|
||||
|
||||
async def test_defaults_to_a_dry_run(monkeypatch, capsys):
|
||||
_argv(monkeypatch)
|
||||
monkeypatch.setattr(purge, "is_sunset_mode", lambda: True)
|
||||
|
||||
async def accounts():
|
||||
return _ACCOUNTS
|
||||
|
||||
erased = []
|
||||
|
||||
async def erase(user_id):
|
||||
erased.append(user_id)
|
||||
|
||||
monkeypatch.setattr(purge, "_accounts", accounts)
|
||||
monkeypatch.setattr(purge, "erase_account", erase)
|
||||
|
||||
assert await purge.main() == 0
|
||||
assert erased == []
|
||||
assert "Dry run. Nothing was changed." in capsys.readouterr().out
|
||||
|
||||
|
||||
async def test_wrong_confirmation_aborts_without_erasing(monkeypatch, capsys):
|
||||
_argv(monkeypatch, "--execute")
|
||||
monkeypatch.setattr(purge, "is_sunset_mode", lambda: True)
|
||||
|
||||
async def accounts():
|
||||
return _ACCOUNTS
|
||||
|
||||
erased = []
|
||||
|
||||
async def erase(user_id):
|
||||
erased.append(user_id)
|
||||
|
||||
monkeypatch.setattr(purge, "_accounts", accounts)
|
||||
monkeypatch.setattr(purge, "erase_account", erase)
|
||||
monkeypatch.setattr("builtins.input", lambda _prompt: "not the confirmation")
|
||||
|
||||
assert await purge.main() == 1
|
||||
assert erased == []
|
||||
assert "Aborted." in capsys.readouterr().err
|
||||
|
||||
|
||||
async def test_failure_is_recorded_and_the_purge_continues(monkeypatch, capsys):
|
||||
_argv(monkeypatch, "--execute", "--yes")
|
||||
monkeypatch.setattr(purge, "is_sunset_mode", lambda: True)
|
||||
|
||||
async def accounts():
|
||||
return _ACCOUNTS
|
||||
|
||||
erased = []
|
||||
|
||||
async def erase(user_id):
|
||||
erased.append(user_id)
|
||||
if user_id == _ACCOUNTS[0][0]:
|
||||
raise RuntimeError("blob cleanup failed")
|
||||
|
||||
async def remaining():
|
||||
return 1
|
||||
|
||||
monkeypatch.setattr(purge, "_accounts", accounts)
|
||||
monkeypatch.setattr(purge, "erase_account", erase)
|
||||
monkeypatch.setattr(purge, "_remaining", remaining)
|
||||
|
||||
assert await purge.main() == 1
|
||||
assert erased == [account[0] for account in _ACCOUNTS]
|
||||
captured = capsys.readouterr()
|
||||
assert "Erased 2 account(s)." in captured.out
|
||||
assert "blob cleanup failed" in captured.err
|
||||
assert "re-run to retry the failures" in captured.err
|
||||
|
||||
|
||||
async def test_limit_bounds_the_accounts_erased(monkeypatch):
|
||||
_argv(monkeypatch, "--execute", "--yes", "--limit", "2")
|
||||
monkeypatch.setattr(purge, "is_sunset_mode", lambda: True)
|
||||
|
||||
async def accounts():
|
||||
return _ACCOUNTS
|
||||
|
||||
erased = []
|
||||
|
||||
async def erase(user_id):
|
||||
erased.append(user_id)
|
||||
|
||||
async def remaining():
|
||||
return 1
|
||||
|
||||
monkeypatch.setattr(purge, "_accounts", accounts)
|
||||
monkeypatch.setattr(purge, "erase_account", erase)
|
||||
monkeypatch.setattr(purge, "_remaining", remaining)
|
||||
|
||||
assert await purge.main() == 0
|
||||
assert erased == [account[0] for account in _ACCOUNTS[:2]]
|
||||
Loading…
Add table
Add a link
Reference in a new issue