package usecase import ( "context" "errors" "reflect" "testing" "gitea.maximumdirect.net/eric/promptkit/internal/defaults" "gitea.maximumdirect.net/eric/promptkit/internal/domain" "gitea.maximumdirect.net/eric/promptkit/internal/profile" ) type inspectionProfileRepository struct { profile *domain.ExecutionProfile err error calls int id string } func (r *inspectionProfileRepository) GetProfile( _ context.Context, id string, ) (*domain.ExecutionProfile, error) { r.calls++ r.id = id if r.err != nil { return nil, r.err } return r.profile, nil } type inspectionBackendResolver struct { backend domain.Backend err error calls int id string } func (r *inspectionBackendResolver) GetBackend(id string) (domain.Backend, error) { r.calls++ r.id = id if r.err != nil { return domain.Backend{}, r.err } return r.backend, nil } func TestRunnerInspectProfileResolvesProfileAndBackendOnce(t *testing.T) { profiles := &inspectionProfileRepository{profile: &domain.ExecutionProfile{ ID: "profile", BackendID: " backend ", Model: "profile-model", Temperature: 0.4, MaxTokens: 32, TimeoutSeconds: 45, ServiceTier: "priority", ReasoningEffort: "high", ExtraParams: map[string]any{ "profile": "value", }, }} backends := &inspectionBackendResolver{backend: domain.Backend{ ID: "backend", Endpoint: "https://backend.example/v1", APIKeyEnv: "BACKEND_KEY", ExtraParams: map[string]any{ "backend": "value", }, }} runner := &Runner{profiles: profiles, backends: backends} inspection, err := runner.InspectProfile(context.Background(), " profile ") if err != nil { t.Fatalf("inspect profile: %v", err) } if profiles.calls != 1 || profiles.id != "profile" { t.Fatalf("profile lookup=(calls=%d id=%q), want one exact lookup", profiles.calls, profiles.id) } if backends.calls != 1 || backends.id != "backend" { t.Fatalf("backend lookup=(calls=%d id=%q), want one exact lookup", backends.calls, backends.id) } if profiles.profile.BackendID != " backend " { t.Fatalf("inspection mutated repository profile backend: %q", profiles.profile.BackendID) } wantTarget := domain.ExecutionTarget{ BackendID: "backend", Endpoint: "https://backend.example/v1", Model: "profile-model", Temperature: 0.4, MaxTokens: 32, TopP: defaults.ExecutionTargetDefault().TopP, TimeoutSeconds: 45, ServiceTier: "priority", ReasoningEffort: "high", APIKeyEnv: "BACKEND_KEY", ExtraParams: map[string]any{ "profile": "value", }, } if inspection.ProfileID != "profile" || inspection.APIKeyRequired || !reflect.DeepEqual(inspection.EffectiveModelParams, wantTarget) { t.Fatalf("inspection=%#v, want profile=%q target=%#v", inspection, "profile", wantTarget) } } func TestRunnerInspectProfileDoesNotNeedExecutionCollaboratorsOrCredentials(t *testing.T) { t.Setenv("PROMPTKIT_INSPECTION_TEST_KEY", "") profiles := &inspectionProfileRepository{profile: &domain.ExecutionProfile{ ID: "endpoint-only", Endpoint: "https://profile.example/v1", Model: "profile-model", APIKeyEnv: "PROMPTKIT_INSPECTION_TEST_KEY", }} runner := &Runner{profiles: profiles} inspection, err := runner.InspectProfile(context.Background(), "endpoint-only") if err != nil { t.Fatalf("inspect endpoint-only profile: %v", err) } if inspection.EffectiveModelParams.BackendID != "" || inspection.EffectiveModelParams.APIKeyEnv != "PROMPTKIT_INSPECTION_TEST_KEY" || inspection.APIKeyRequired { t.Fatalf("unexpected endpoint-only inspection: %#v", inspection) } } func TestRunnerInspectProfileDirectCredentialRequirementClearsBackendEnvironment(t *testing.T) { profiles := &inspectionProfileRepository{profile: &domain.ExecutionProfile{ ID: "direct-key", BackendID: "backend", Model: "profile-model", APIKeyRequired: true, }} backends := &inspectionBackendResolver{backend: domain.Backend{ ID: "backend", Endpoint: "https://backend.example/v1", APIKeyEnv: "BACKEND_KEY", }} inspection, err := (&Runner{profiles: profiles, backends: backends}).InspectProfile( context.Background(), "direct-key", ) if err != nil { t.Fatalf("inspect direct-key profile: %v", err) } if !inspection.APIKeyRequired || inspection.EffectiveModelParams.APIKeyEnv != "" { t.Fatalf("credential requirement was not resolved exclusively: %#v", inspection) } } func TestRunnerInspectProfileClassifiesFailuresWithoutRepositoryWorkAfterCancellation(t *testing.T) { t.Run("blank ID", func(t *testing.T) { profiles := &inspectionProfileRepository{} _, err := (&Runner{profiles: profiles}).InspectProfile(context.Background(), " \t ") if !errors.Is(err, ErrInvalidRequest) || profiles.calls != 0 { t.Fatalf("blank inspection=(%v, calls=%d), want invalid request without lookup", err, profiles.calls) } }) t.Run("canceled context", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() profiles := &inspectionProfileRepository{} _, err := (&Runner{profiles: profiles}).InspectProfile(ctx, "profile") if !errors.Is(err, ErrProfileLoad) || !errors.Is(err, context.Canceled) || profiles.calls != 0 { t.Fatalf("canceled inspection=(%v, calls=%d), want profile load and context identities without lookup", err, profiles.calls) } }) t.Run("missing profile", func(t *testing.T) { profiles := &inspectionProfileRepository{err: profile.ErrProfileNotFound} _, err := (&Runner{profiles: profiles}).InspectProfile(context.Background(), "missing") if !errors.Is(err, ErrProfileLoad) || !errors.Is(err, profile.ErrProfileNotFound) { t.Fatalf("missing profile error=%v, want profile load and not-found identities", err) } }) t.Run("unknown backend", func(t *testing.T) { backendErr := errors.New("unknown backend") profiles := &inspectionProfileRepository{profile: &domain.ExecutionProfile{ ID: "profile", BackendID: "backend", Model: "profile-model", }} backends := &inspectionBackendResolver{err: backendErr} _, err := (&Runner{profiles: profiles, backends: backends}).InspectProfile(context.Background(), "profile") if !errors.Is(err, ErrProfileLoad) || !errors.Is(err, backendErr) { t.Fatalf("unknown backend error=%v, want profile load and backend identities", err) } }) t.Run("defensive invalid dependencies", func(t *testing.T) { cases := []struct { name string runner *Runner }{ {name: "nil repository", runner: &Runner{}}, {name: "nil profile", runner: &Runner{profiles: &inspectionProfileRepository{}}}, {name: "invalid target", runner: &Runner{profiles: &inspectionProfileRepository{ profile: &domain.ExecutionProfile{ID: "profile", Endpoint: "https://profile.example/v1"}, }}}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, err := tc.runner.InspectProfile(context.Background(), "profile") if !errors.Is(err, ErrProfileLoad) { t.Fatalf("inspection error=%v, want profile load", err) } }) } }) }