package db import ( "errors" "testing" ) func TestTokenLifecycle(t *testing.T) { database := openTestDB(t) userID, err := CreateUser(database, "josie", "hash") if err != nil { t.Fatalf("CreateUser: %v", err) } tok, err := CreateToken(database, userID, "laptop", "sg_abcd123", "hash-1") if err != nil { t.Fatalf("CreateToken: %v", err) } if tok.ID == 0 || tok.UserID != userID || tok.Name != "laptop" || tok.Hint != "sg_abcd123" { t.Errorf("token = %+v, want populated row", tok) } if tok.LastUsedAt.Valid { t.Errorf("LastUsedAt = %+v, want NULL", tok.LastUsedAt) } byHash, err := GetTokenByHash(database, "hash-1") if err != nil { t.Fatalf("GetTokenByHash: %v", err) } if byHash.ID != tok.ID { t.Errorf("GetTokenByHash id = %d, want %d", byHash.ID, tok.ID) } if _, err := GetTokenByHash(database, "nope"); !errors.Is(err, ErrNotFound) { t.Errorf("missing hash err = %v, want ErrNotFound", err) } if err := TouchToken(database, tok.ID); err != nil { t.Fatalf("TouchToken: %v", err) } byHash, err = GetTokenByHash(database, "hash-1") if err != nil { t.Fatalf("GetTokenByHash after touch: %v", err) } if !byHash.LastUsedAt.Valid { t.Error("LastUsedAt still NULL after TouchToken") } if _, err := CreateToken(database, userID, "dup", "sg_x", "hash-1"); err == nil { t.Error("duplicate token_hash accepted, want UNIQUE error") } tokens, err := ListTokens(database, userID) if err != nil { t.Fatalf("ListTokens: %v", err) } if len(tokens) != 1 || tokens[0].ID != tok.ID { t.Errorf("ListTokens = %+v, want the one token", tokens) } if err := DeleteToken(database, userID+1, tok.ID); !errors.Is(err, ErrNotFound) { t.Errorf("DeleteToken by non-owner err = %v, want ErrNotFound", err) } if err := DeleteToken(database, userID, tok.ID); err != nil { t.Fatalf("DeleteToken: %v", err) } if _, err := GetTokenByHash(database, "hash-1"); !errors.Is(err, ErrNotFound) { t.Errorf("token still present after delete: %v", err) } } func TestTokenCascadeOnUserDelete(t *testing.T) { database := openTestDB(t) userID, err := CreateUser(database, "josie", "hash") if err != nil { t.Fatalf("CreateUser: %v", err) } if _, err := CreateToken(database, userID, "laptop", "sg_abcd123", "hash-1"); err != nil { t.Fatalf("CreateToken: %v", err) } if _, err := database.Exec(`DELETE FROM users WHERE id = ?`, userID); err != nil { t.Fatalf("delete user: %v", err) } if _, err := GetTokenByHash(database, "hash-1"); !errors.Is(err, ErrNotFound) { t.Errorf("token survived user delete: %v", err) } }