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:
82
auth_test.go
Normal file
82
auth_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAuth_LoginWrongCode(t *testing.T) {
|
||||
m := StartMiniRedis(t)
|
||||
a := NewTestAuth(t, m, "rightcode", time.Hour)
|
||||
|
||||
ok, err := a.Login(context.Background(), 42, "wrongcode")
|
||||
if err != nil {
|
||||
t.Fatalf("login err: %v", err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatal("wrong code should fail")
|
||||
}
|
||||
|
||||
authed, err := a.IsAuthed(context.Background(), 42)
|
||||
if err != nil || authed {
|
||||
t.Fatalf("user must NOT be authed after wrong code (authed=%v err=%v)", authed, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_LoginRightCode_SetsTTL(t *testing.T) {
|
||||
m := StartMiniRedis(t)
|
||||
a := NewTestAuth(t, m, "rightcode", 30*time.Second)
|
||||
|
||||
ok, err := a.Login(context.Background(), 7, "rightcode")
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("login: ok=%v err=%v", ok, err)
|
||||
}
|
||||
|
||||
authed, err := a.IsAuthed(context.Background(), 7)
|
||||
if err != nil || !authed {
|
||||
t.Fatalf("user must be authed after correct code (authed=%v err=%v)", authed, err)
|
||||
}
|
||||
|
||||
rem, err := a.Remaining(context.Background(), 7)
|
||||
if err != nil {
|
||||
t.Fatalf("Remaining err: %v", err)
|
||||
}
|
||||
if rem <= 0 || rem > 30*time.Second {
|
||||
t.Fatalf("Remaining = %s, want (0, 30s]", rem)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_Logout(t *testing.T) {
|
||||
m := StartMiniRedis(t)
|
||||
a := NewTestAuth(t, m, "code", time.Hour)
|
||||
|
||||
if _, err := a.Login(context.Background(), 1, "code"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := a.Logout(context.Background(), 1); err != nil {
|
||||
t.Fatalf("logout: %v", err)
|
||||
}
|
||||
authed, _ := a.IsAuthed(context.Background(), 1)
|
||||
if authed {
|
||||
t.Fatal("must NOT be authed after logout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_NewAuth_RequiresSecret(t *testing.T) {
|
||||
m := StartMiniRedis(t)
|
||||
if _, err := NewAuth("redis://"+m.Addr(), "", time.Hour); err == nil {
|
||||
t.Fatal("expected error when AUTH_SECRET is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_NilReceiver_Safe(t *testing.T) {
|
||||
var a *Auth
|
||||
authed, err := a.IsAuthed(context.Background(), 1)
|
||||
if err != nil || authed {
|
||||
t.Fatalf("nil Auth.IsAuthed must return (false,nil), got (%v,%v)", authed, err)
|
||||
}
|
||||
if err := a.Logout(context.Background(), 1); err != nil {
|
||||
t.Fatalf("nil Auth.Logout must be no-op, got: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user