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:
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user