Files
Memoh/internal/schedule/service_test.go
T
BBQ 83b6ee608c refactor: bind container lifecycle to bot and improve schedule trigger flow
- Add SetupBotContainer to ContainerLifecycle interface so containers
  are automatically created when a bot is created, matching the existing
  cleanup-on-delete behavior.
- Refactor schedule tools to use bot-scoped API paths and pass identity
  context for proper authorization.
- Introduce dedicated trigger-schedule endpoint in chat resolver with
  explicit schedule payload instead of reusing the generic chat path.
- Generate short-lived JWT tokens for schedule trigger callbacks with
  resolved bot owner identity.
- Validate required parameters in NewLLMClient and NewOpenAIEmbedder
  constructors, returning errors instead of falling back to defaults.
- Add unit tests for schedule token generation and chat resolver.
2026-02-07 12:04:37 +08:00

92 lines
2.0 KiB
Go

package schedule
import (
"context"
"log/slog"
"strings"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
)
type mockTriggerer struct {
called bool
botID string
payload TriggerPayload
token string
}
func (m *mockTriggerer) TriggerSchedule(_ context.Context, botID string, payload TriggerPayload, token string) error {
m.called = true
m.botID = botID
m.payload = payload
m.token = token
return nil
}
func TestGenerateTriggerToken(t *testing.T) {
secret := "test-secret-key-for-schedule"
svc := &Service{
jwtSecret: secret,
logger: slog.Default(),
}
userID := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
tok, err := svc.generateTriggerToken(userID)
if err != nil {
t.Fatalf("generateTriggerToken returned error: %v", err)
}
if !strings.HasPrefix(tok, "Bearer ") {
t.Fatalf("expected Bearer prefix, got: %s", tok)
}
raw := strings.TrimPrefix(tok, "Bearer ")
parsed, err := jwt.Parse(raw, func(token *jwt.Token) (any, error) {
return []byte(secret), nil
})
if err != nil {
t.Fatalf("failed to parse JWT: %v", err)
}
claims, ok := parsed.Claims.(jwt.MapClaims)
if !ok {
t.Fatal("expected MapClaims")
}
if sub, _ := claims["sub"].(string); sub != userID {
t.Errorf("expected sub=%s, got=%s", userID, sub)
}
if uid, _ := claims["user_id"].(string); uid != userID {
t.Errorf("expected user_id=%s, got=%s", userID, uid)
}
exp, _ := claims["exp"].(float64)
if exp == 0 {
t.Fatal("expected non-zero exp")
}
expTime := time.Unix(int64(exp), 0)
if expTime.Before(time.Now().Add(9 * time.Minute)) {
t.Error("token expires too soon")
}
}
func TestGenerateTriggerToken_EmptySecret(t *testing.T) {
svc := &Service{
jwtSecret: "",
logger: slog.Default(),
}
_, err := svc.generateTriggerToken("user-123")
if err == nil {
t.Fatal("expected error for empty secret")
}
}
func TestGenerateTriggerToken_EmptyUserID(t *testing.T) {
svc := &Service{
jwtSecret: "some-secret",
logger: slog.Default(),
}
_, err := svc.generateTriggerToken("")
if err == nil {
t.Fatal("expected error for empty user ID")
}
}