Claude-assisted improvements (untested)

- dev auth flow (side-step OAuth)
- db event processing integration tests
- dev scripts (eg Makefile)
- db / test db migration setup scripts.
This commit is contained in:
2026-08-05 17:56:21 -06:00
parent c51ad80dc6
commit ccc00d5c89
35 changed files with 1242 additions and 144 deletions
+95
View File
@@ -0,0 +1,95 @@
package authentication
import (
"context"
"errors"
"testing"
"time"
"ruben/inventory2/consts"
"ruben/inventory2/internal/testdb"
)
func TestDevLogin(t *testing.T) {
pool := testdb.Pool(t)
auth := &Authenticator{db: pool}
ctx := context.Background()
userID := testdb.NewUserID(t)
t.Cleanup(func() {
pool.Exec(context.Background(), "DELETE FROM oauth_tokens WHERE id_token_subject = $1", userID)
pool.Exec(context.Background(), "DELETE FROM oauth_users WHERE user_id = $1", userID)
})
accessToken, expiration, err := auth.DevLogin(ctx, userID, "Test User")
if err != nil {
t.Fatalf("DevLogin() error = %v", err)
}
if accessToken == "" {
t.Fatal("DevLogin() returned an empty access token")
}
if !expiration.After(time.Now().Add(30 * 24 * time.Hour)) {
t.Errorf("DevLogin() expiration = %v, want something far enough out to avoid the near-expiry refresh path", expiration)
}
claims, err := auth.GetAccessTokenClaimsAndExpiration(ctx, accessToken)
if err != nil {
t.Fatalf("GetAccessTokenClaimsAndExpiration() error = %v", err)
}
if claims.Name != "Test User" {
t.Errorf("claims.Name = %q, want %q", claims.Name, "Test User")
}
// Postgres timestamptz has microsecond precision, so the round-tripped
// value loses the sub-microsecond portion of Go's nanosecond clock.
if diff := claims.Expiration.Sub(expiration); diff > time.Millisecond || diff < -time.Millisecond {
t.Errorf("claims.Expiration = %v, want ~%v (diff %v)", claims.Expiration, expiration, diff)
}
_, tokenType, err := auth.getRefreshTokenForAccessToken(ctx, accessToken)
if err != nil {
t.Fatalf("getRefreshTokenForAccessToken() error = %v", err)
}
if tokenType != "dev" {
t.Errorf("tokenType = %q, want %q", tokenType, "dev")
}
}
// DevLogin should be safe to call more than once for the same user_id -
// e.g. testing multiple times as the same dev identity - since oauth_users
// is keyed on user_id but each call mints its own oauth_tokens row.
func TestDevLogin_SameUserIDTwice(t *testing.T) {
pool := testdb.Pool(t)
auth := &Authenticator{db: pool}
ctx := context.Background()
userID := testdb.NewUserID(t)
t.Cleanup(func() {
pool.Exec(context.Background(), "DELETE FROM oauth_tokens WHERE id_token_subject = $1", userID)
pool.Exec(context.Background(), "DELETE FROM oauth_users WHERE user_id = $1", userID)
})
token1, _, err := auth.DevLogin(ctx, userID, "Test User")
if err != nil {
t.Fatalf("first DevLogin() error = %v", err)
}
token2, _, err := auth.DevLogin(ctx, userID, "Test User")
if err != nil {
t.Fatalf("second DevLogin() error = %v", err)
}
if token1 == token2 {
t.Fatalf("DevLogin() returned the same access token twice: %q", token1)
}
}
func TestGetAccessTokenClaimsAndExpiration_UnknownToken(t *testing.T) {
pool := testdb.Pool(t)
auth := &Authenticator{db: pool}
ctx := context.Background()
_, err := auth.GetAccessTokenClaimsAndExpiration(ctx, "no-such-token-"+testdb.NewUserID(t))
if !errors.Is(err, consts.ErrNotFound) {
t.Fatalf("GetAccessTokenClaimsAndExpiration() error = %v, want %v", err, consts.ErrNotFound)
}
}