144 lines
4.6 KiB
Python
144 lines
4.6 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
|
|
import time
|
|
|
|
import pytest
|
|
|
|
from devplacepy.database import get_table, set_consent, set_setting
|
|
from devplacepy.database.nodes import save_node_settings
|
|
from devplacepy.services.nodes.consent import REASONS, ConsentGate
|
|
from devplacepy.utils import register_account
|
|
|
|
GATE = ConsentGate()
|
|
_counter = [0]
|
|
|
|
|
|
def fresh(age_band="adult"):
|
|
_counter[0] += 1
|
|
name = f"gate{int(time.time() * 1000)}{_counter[0]}"
|
|
uid, _, _ = register_account(
|
|
name, f"{name}@t.dev", "secret123", age_band=age_band, accepted_terms=True
|
|
)
|
|
return uid
|
|
|
|
|
|
@pytest.fixture
|
|
def switched_on(local_db):
|
|
set_setting("nodes_enabled", "1")
|
|
yield
|
|
set_setting("nodes_enabled", "0")
|
|
|
|
|
|
def ready():
|
|
uid = fresh()
|
|
set_consent("user", uid, "bandwidth_sharing", True)
|
|
save_node_settings(uid, {"enabled": True})
|
|
return uid
|
|
|
|
|
|
def test_a_fully_qualified_member_is_allowed(switched_on):
|
|
verdict = GATE.allows(ready())
|
|
assert verdict.allowed and verdict.reason == "" and verdict.message == ""
|
|
|
|
|
|
def test_the_kill_switch_beats_everything(local_db):
|
|
set_setting("nodes_enabled", "1")
|
|
uid = ready()
|
|
set_setting("nodes_enabled", "0")
|
|
assert GATE.allows(uid).reason == "kill_switch"
|
|
|
|
|
|
def test_default_is_off_without_the_setting(local_db):
|
|
get_table("site_settings").delete(key="nodes_enabled")
|
|
assert GATE.allows(ready()).reason == "kill_switch"
|
|
|
|
|
|
def test_unknown_account(switched_on):
|
|
assert GATE.allows("nobody").reason == "no_account"
|
|
assert GATE.allows("").reason == "no_account"
|
|
|
|
|
|
def test_each_missing_requirement_has_its_own_reason(switched_on):
|
|
no_consent = fresh()
|
|
save_node_settings(no_consent, {"enabled": True})
|
|
assert GATE.allows(no_consent).reason == "no_consent"
|
|
not_enabled = fresh()
|
|
set_consent("user", not_enabled, "bandwidth_sharing", True)
|
|
assert GATE.allows(not_enabled).reason == "not_enabled"
|
|
withdrawn = ready()
|
|
set_consent("user", withdrawn, "bandwidth_sharing", False)
|
|
assert GATE.allows(withdrawn).reason == "no_consent"
|
|
|
|
|
|
@pytest.mark.parametrize("band", ["", "under_min", "13_15", "16_17", "adult"])
|
|
def test_age_band_is_not_checked(switched_on, band):
|
|
uid = fresh(age_band=band)
|
|
set_consent("user", uid, "bandwidth_sharing", True)
|
|
save_node_settings(uid, {"enabled": True})
|
|
assert GATE.allows(uid).allowed
|
|
|
|
|
|
def test_account_states_block(switched_on):
|
|
uid = ready()
|
|
users = get_table("users")
|
|
users.update({"uid": uid, "suspended_until": "2999-01-01T00:00:00+00:00"}, ["uid"])
|
|
assert GATE.allows(uid).reason == "suspended"
|
|
users.update({"uid": uid, "suspended_until": ""}, ["uid"])
|
|
users.update({"uid": uid, "is_active": False}, ["uid"])
|
|
assert GATE.allows(uid).reason == "account_inactive"
|
|
users.update({"uid": uid, "is_active": True}, ["uid"])
|
|
users.update({"uid": uid, "deletion_requested_at": "2026-01-01T00:00:00+00:00"}, ["uid"])
|
|
assert GATE.allows(uid).reason == "deletion_pending"
|
|
|
|
|
|
def test_every_reason_is_described():
|
|
for reason in (
|
|
"kill_switch",
|
|
"no_account",
|
|
"account_inactive",
|
|
"deletion_pending",
|
|
"suspended",
|
|
"no_consent",
|
|
"not_enabled",
|
|
):
|
|
assert REASONS[reason]
|
|
|
|
|
|
def test_batch_decisions_equal_single_decisions(switched_on):
|
|
qualified = ready()
|
|
no_consent = fresh()
|
|
save_node_settings(no_consent, {"enabled": True})
|
|
minor = fresh(age_band="16_17")
|
|
set_consent("user", minor, "bandwidth_sharing", True)
|
|
save_node_settings(minor, {"enabled": True})
|
|
withdrawn = ready()
|
|
set_consent("user", withdrawn, "bandwidth_sharing", False)
|
|
uids = [qualified, no_consent, minor, withdrawn, "nobody"]
|
|
many = GATE.allows_many(uids)
|
|
assert list(many) == uids
|
|
for uid in uids:
|
|
assert many[uid] == GATE.allows(uid)
|
|
assert [many[uid].reason for uid in uids] == [
|
|
"", "no_consent", "", "no_consent", "no_account",
|
|
]
|
|
|
|
|
|
def test_batch_with_the_kill_switch_off_refuses_everyone(local_db):
|
|
set_setting("nodes_enabled", "0")
|
|
many = GATE.allows_many([ready(), ready()])
|
|
assert {verdict.reason for verdict in many.values()} == {"kill_switch"}
|
|
|
|
|
|
def test_batches_larger_than_the_chunk_size_are_all_decided(switched_on, monkeypatch):
|
|
monkeypatch.setattr("devplacepy.services.nodes.consent.BATCH_SIZE", 2)
|
|
uids = [ready() for _ in range(5)]
|
|
many = GATE.allows_many(uids)
|
|
assert len(many) == 5 and all(item.allowed for item in many.values())
|
|
|
|
|
|
def test_the_latest_consent_row_wins_in_a_batch(switched_on):
|
|
uid = ready()
|
|
set_consent("user", uid, "bandwidth_sharing", False)
|
|
set_consent("user", uid, "bandwidth_sharing", True)
|
|
assert GATE.allows_many([uid])[uid].allowed
|