File size: 3,185 Bytes
bfd6783
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import pytest

from finbot.config import Settings
from finbot.limits import WINDOW_SECONDS, RateLimiter


def settings(**overrides):
    base = dict(
        telegram_bot_token="",
        telegram_webhook_secret="",
        allowed_telegram_user_ids="",
        hf_token="",
        hf_dataset_repo="",
        open_access=False,
    )
    base.update(overrides)
    return Settings(**base)


class TestAuthorisation:
    def test_empty_allowlist_authorises_nobody(self):
        # The safe default: a forgotten allowlist must not mean "open to all".
        assert settings().is_authorised(42) is False

    def test_allowlist_match(self):
        s = settings(allowed_telegram_user_ids="42, 99")
        assert s.is_authorised(42)
        assert s.is_authorised(99)
        assert not s.is_authorised(7)

    def test_open_access_authorises_anyone(self):
        s = settings(open_access=True)
        assert s.is_authorised(1)
        assert s.is_authorised(123456789)

    def test_open_access_ignores_the_allowlist(self):
        s = settings(open_access=True, allowed_telegram_user_ids="42")
        assert s.is_authorised(7)

    def test_malformed_ids_are_dropped_not_fatal(self):
        s = settings(allowed_telegram_user_ids="42,,abc, 99 ,")
        assert s.allowed_user_ids == frozenset({42, 99})

    def test_open_access_removes_the_allowlist_warning(self):
        assert any("ALLOWED" in g for g in settings().missing_required())
        assert not any(
            "ALLOWED" in g for g in settings(open_access=True).missing_required()
        )


class TestRateLimiter:
    def test_allows_up_to_the_cap(self):
        limiter = RateLimiter(3)
        assert [limiter.check(1) for _ in range(3)] == [True, True, True]

    def test_blocks_past_the_cap(self):
        limiter = RateLimiter(2)
        limiter.check(1)
        limiter.check(1)
        assert limiter.check(1) is False

    def test_users_are_independent(self):
        limiter = RateLimiter(1)
        assert limiter.check(1) is True
        assert limiter.check(2) is True
        assert limiter.check(1) is False

    def test_zero_disables_the_cap(self):
        limiter = RateLimiter(0)
        assert not limiter.enabled
        assert all(limiter.check(1) for _ in range(500))

    def test_negative_disables_the_cap(self):
        assert not RateLimiter(-1).enabled

    def test_window_expires(self):
        limiter = RateLimiter(1)
        assert limiter.check(1, now=1000.0) is True
        assert limiter.check(1, now=1000.0) is False
        # Just past the 24h window, the old hit no longer counts.
        assert limiter.check(1, now=1000.0 + WINDOW_SECONDS + 1) is True

    def test_remaining(self):
        limiter = RateLimiter(3)
        assert limiter.remaining(1) == 3
        limiter.check(1)
        assert limiter.remaining(1) == 2

    def test_remaining_is_unlimited_when_disabled(self):
        assert RateLimiter(0).remaining(1) == -1

    @pytest.mark.parametrize("cap", [1, 5, 20])
    def test_never_exceeds_cap(self, cap):
        limiter = RateLimiter(cap)
        granted = sum(1 for _ in range(cap * 3) if limiter.check(1, now=500.0))
        assert granted == cap