package service import ( "context" "errors" "testing" "gitea.stevedudenhoeffer.com/steve/pansy/internal/config" "gitea.stevedudenhoeffer.com/steve/pansy/internal/domain" ) // settingsTestService builds a service whose env config carries the given agent // model/enabled/key, so EffectiveAgent's env fallback can be exercised. func settingsTestService(t *testing.T, envModel string, envEnabled bool, key string) (*Service, int64) { t.Helper() cfg := openConfig() cfg.Agent = config.AgentConfig{Model: envModel, Enabled: envEnabled, OllamaCloudAPIKey: key} s := newTestService(t, cfg) admin := seedUser(t, s, "admin@example.com") // first user is admin return s, admin } // TestRequireAdmin: the first user is admin; a second is not and gets // ErrForbidden (not ErrNotFound — settings existence isn't masked). func TestRequireAdmin(t *testing.T) { s, admin := settingsTestService(t, "ollama-cloud/x", true, "k") member := seedUser(t, s, "member@example.com") if err := s.requireAdmin(context.Background(), admin); err != nil { t.Errorf("admin rejected: %v", err) } if err := s.requireAdmin(context.Background(), member); !errors.Is(err, domain.ErrForbidden) { t.Errorf("member requireAdmin = %v, want ErrForbidden", err) } } // TestEffectiveAgentLayering: DB settings override env; the API key always comes // from env; the "inherit" sentinels fall back. func TestEffectiveAgentLayering(t *testing.T) { ctx := context.Background() s, admin := settingsTestService(t, "ollama-cloud/env-model", true, "envkey") // Untouched: everything inherits env. eff, err := s.EffectiveAgent(ctx) if err != nil { t.Fatalf("effective: %v", err) } if eff.Model != "ollama-cloud/env-model" || !eff.Enabled || eff.APIKey != "envkey" { t.Errorf("inherited effective = %+v, want the env values", eff) } // Override the model only; enabled still inherits env (true). cur, _ := s.GetInstanceSettings(ctx, admin) if _, err := s.UpdateInstanceSettings(ctx, admin, InstanceSettingsPatch{ AgentModel: "ollama-cloud/glm-5.2:cloud", Version: cur.Version, }); err != nil { t.Fatalf("update model: %v", err) } eff, _ = s.EffectiveAgent(ctx) if eff.Model != "ollama-cloud/glm-5.2:cloud" { t.Errorf("model = %q, want the DB override", eff.Model) } if !eff.Enabled { t.Error("enabled should still inherit env (true) when unset") } // Now override enabled to false explicitly. cur, _ = s.GetInstanceSettings(ctx, admin) no := false if _, err := s.UpdateInstanceSettings(ctx, admin, InstanceSettingsPatch{ AgentModel: "ollama-cloud/glm-5.2:cloud", AgentEnabled: &no, Version: cur.Version, }); err != nil { t.Fatalf("update enabled: %v", err) } eff, _ = s.EffectiveAgent(ctx) if eff.Enabled { t.Error("enabled should be the explicit false override now") } if eff.Ready() { t.Error("Ready() should be false when disabled") } } // TestUpdateInstanceSettingsRejectsBadModel: a spec that won't resolve is // ErrInvalidInput, before it is stored. func TestUpdateInstanceSettingsRejectsBadModel(t *testing.T) { ctx := context.Background() s, admin := settingsTestService(t, "ollama-cloud/x", true, "k") cur, _ := s.GetInstanceSettings(ctx, admin) if _, err := s.UpdateInstanceSettings(ctx, admin, InstanceSettingsPatch{ AgentModel: "nonesuch/model", Version: cur.Version, }); !errors.Is(err, domain.ErrInvalidInput) { t.Errorf("bad model = %v, want ErrInvalidInput", err) } // The rejected write didn't touch the row. after, _ := s.GetInstanceSettings(ctx, admin) if after.Version != cur.Version || after.AgentModel != "" { t.Errorf("a rejected update changed the row: %+v", after) } } // TestInstanceSettingsAdminGate: the read/write operations are admin-gated at the // service seam, not just in the handler. func TestInstanceSettingsAdminGate(t *testing.T) { ctx := context.Background() s, _ := settingsTestService(t, "ollama-cloud/x", true, "k") member := seedUser(t, s, "member@example.com") if _, err := s.GetInstanceSettings(ctx, member); !errors.Is(err, domain.ErrForbidden) { t.Errorf("member GetInstanceSettings = %v, want ErrForbidden", err) } if _, err := s.UpdateInstanceSettings(ctx, member, InstanceSettingsPatch{Version: 1}); !errors.Is(err, domain.ErrForbidden) { t.Errorf("member UpdateInstanceSettings = %v, want ErrForbidden", err) } }