package broker import ( "context" "encoding/json" "testing" "time" "gitea.alexandru.macocian.me/Charlie/sherlock/internal/authn" "gitea.alexandru.macocian.me/Charlie/sherlock/internal/keyring" fakekeyring "gitea.alexandru.macocian.me/Charlie/sherlock/internal/keyring/fake" "gitea.alexandru.macocian.me/Charlie/sherlock/internal/rpc" ) func newMethods(t *testing.T) *Methods { t.Helper() return &Methods{ Store: fakekeyring.New(), Cfg: authn.Config{}, AgentNames: func() []string { return []string{"copilot"} }, } } func TestStatus_NotLoggedIn(t *testing.T) { m := newMethods(t) res, rpcErr := m.handleStatus(context.Background(), nil) if rpcErr != nil { t.Fatalf("rpc err: %v", rpcErr) } s := res.(StatusResult) if s.LoggedIn { t.Fatal("expected not logged in") } if s.AuthnConfigured { t.Fatal("expected not configured") } if len(s.Agents) != 1 || s.Agents[0] != "copilot" { t.Fatalf("agents = %v", s.Agents) } } func TestStatus_LoggedIn(t *testing.T) { m := newMethods(t) exp := time.Now().Add(time.Hour).UTC().Truncate(time.Second) if err := m.Store.SetAuthentikTokens(keyring.TokenSet{ IDToken: "id", Subject: "alice", Email: "a@e", Name: "Alice", IDExpiresAt: exp, Issuer: "https://id.example/", }); err != nil { t.Fatal(err) } res, rpcErr := m.handleStatus(context.Background(), nil) if rpcErr != nil { t.Fatalf("rpc err: %v", rpcErr) } s := res.(StatusResult) if !s.LoggedIn || s.Subject != "alice" { t.Fatalf("got %+v", s) } if s.IDExpiresAt == nil || !s.IDExpiresAt.Equal(exp) { t.Fatalf("expiry: got %v want %v", s.IDExpiresAt, exp) } } func TestWhoami_NotLoggedIn(t *testing.T) { m := newMethods(t) _, rpcErr := m.handleWhoami(context.Background(), nil) if rpcErr == nil || rpcErr.Code != rpc.CodeNotLoggedIn { t.Fatalf("want not_logged_in, got %+v", rpcErr) } } func TestLoginStart_NotConfigured(t *testing.T) { m := newMethods(t) _, rpcErr := m.handleLoginStart(context.Background(), nil) if rpcErr == nil || rpcErr.Code != rpc.CodeNotConfigured { t.Fatalf("want not_configured, got %+v", rpcErr) } } func TestLogout_Idempotent(t *testing.T) { m := newMethods(t) if _, err := m.handleLogout(context.Background(), nil); err != nil { t.Fatalf("logout1: %v", err) } if _, err := m.handleLogout(context.Background(), nil); err != nil { t.Fatalf("logout2: %v", err) } } func TestShutdown_InvokesFn(t *testing.T) { done := make(chan struct{}) m := newMethods(t) m.ShutdownFn = func() { close(done) } if _, err := m.handleShutdown(context.Background(), nil); err != nil { t.Fatalf("shutdown: %v", err) } select { case <-done: case <-time.After(time.Second): t.Fatal("ShutdownFn not invoked") } } func TestLoginWait_BadParams(t *testing.T) { m := newMethods(t) _, rpcErr := m.handleLoginWait(context.Background(), json.RawMessage(`{}`)) if rpcErr == nil || rpcErr.Code != rpc.CodeBadRequest { t.Fatalf("want bad_request, got %+v", rpcErr) } }