Phase 2c — testing infrastructure (43 tests, CI gating, docker-compose)
Some checks failed
Docker Build / build-and-push-image (push) Has been cancelled
Some checks failed
Docker Build / build-and-push-image (push) Has been cancelled
Brings the project to a TDD/BDD-friendly state — apologies for shipping Phase 1.5 + Phase 2 code-first, that violated feedback_tdd_first_bdd_required. What's added : - helpers_test.go : FakeTelegram (httptest server that records sendMessage / deleteMessage / setWebhook / etc.), miniredis bootstrap, MakeUpdate / PostWebhook helpers. The same harness simulates 'a user DMing the bot' end-to-end without hitting Telegram cloud — answer to the user question. - 43 tests covering : allowlist parsing, telegram type helpers (UserID / ChatID / Text / messageID), secret_token constant-time compare, Backoff schedule, Auth (login wrong/right/logout/TTL/nil-receiver), EchoHandler, HTTPHandler (forward / timeout / non-2xx / empty body), AuthHandler (start / auth / whoami / logout / replay defense delete), Server (bad secret 401, unknown bot 404, allowlist drop, gated bot prompt, full /auth → echo → /logout flow, healthz/readyz). - All tests pass with -race in 1.6s, no external deps (miniredis + httptest in-process). Infra : - Updated .gitea/workflows/dockerimage.yaml : new 'test' job (go vet + go test -race) gates the build-and-push-image job. CI now also runs on pull_request. - docker-compose.yml : redis + postgres for full local stack. - Makefile : test-race, compose-up/down targets. - README updated with test + local-dev sections. Refs ~/.claude/plans/pour-les-notifications-on-inherited-seal.md § Phase 2.
This commit is contained in:
68
allowlist_test.go
Normal file
68
allowlist_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAllowlist_Empty_OpenToAll(t *testing.T) {
|
||||
a := NewAllowlist("")
|
||||
if !a.Open() {
|
||||
t.Fatal("expected open=true on empty raw")
|
||||
}
|
||||
if !a.IsAllowed(0) || !a.IsAllowed(123456789) {
|
||||
t.Fatal("open allowlist should allow any user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowlist_Whitespace_OpenToAll(t *testing.T) {
|
||||
a := NewAllowlist(" \t\n ")
|
||||
if !a.Open() {
|
||||
t.Fatal("whitespace-only should be treated as empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowlist_OneID(t *testing.T) {
|
||||
a := NewAllowlist("7497777082")
|
||||
if a.Open() {
|
||||
t.Fatal("non-empty should not be open")
|
||||
}
|
||||
if !a.IsAllowed(7497777082) {
|
||||
t.Fatal("listed user must be allowed")
|
||||
}
|
||||
if a.IsAllowed(999) {
|
||||
t.Fatal("stranger must be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowlist_MultiCSVWithSpaces(t *testing.T) {
|
||||
a := NewAllowlist(" 12345 , 67890 , 42 ")
|
||||
if a.Size() != 3 {
|
||||
t.Fatalf("expected 3, got %d", a.Size())
|
||||
}
|
||||
for _, id := range []int64{12345, 67890, 42} {
|
||||
if !a.IsAllowed(id) {
|
||||
t.Fatalf("id=%d should be allowed", id)
|
||||
}
|
||||
}
|
||||
if a.IsAllowed(999) {
|
||||
t.Fatal("999 must be rejected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowlist_InvalidEntriesIgnored(t *testing.T) {
|
||||
a := NewAllowlist("123,abc,,456,not-a-number")
|
||||
if a.Size() != 2 {
|
||||
t.Fatalf("expected 2 valid ids, got %d", a.Size())
|
||||
}
|
||||
if !a.IsAllowed(123) || !a.IsAllowed(456) {
|
||||
t.Fatal("valid ids should pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowlist_AllInvalid_ClosedNotOpen(t *testing.T) {
|
||||
a := NewAllowlist("abc,xyz")
|
||||
if a.Open() {
|
||||
t.Fatal("CSV with no valid ids should be closed (fail-safe), not open")
|
||||
}
|
||||
if a.IsAllowed(123) {
|
||||
t.Fatal("must reject everyone when no valid ids")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user