Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions pkg/api/idea_matches_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package api

import (
"encoding/json"
"net/http"
"os"
"testing"

"github.com/hivecommons/dibs/pkg/catalog"
"github.com/hivecommons/dibs/pkg/match"
"github.com/hivecommons/dibs/pkg/store"
)

// seedCatalog writes a cncf-catalog.json into dir and opens a catalog store
// over it. One project deliberately shares its RepoID with a hive-managed
// registry repo so the handler's "keep CNCF section non-hive only" filter
// has something to drop.
func seedCatalog(t *testing.T, dir string) *catalog.Store {
t.Helper()
projects := []catalog.Project{
{Name: "Dibs", RepoID: "kubestellar/dibs", RepoURL: "https://github.com/kubestellar/dibs",
Maturity: "sandbox", Category: "Exchange", Description: "ideas exchange kubernetes"},
{Name: "Istio", RepoID: "istio/istio", RepoURL: "https://github.com/istio/istio",
Maturity: "graduated", Category: "Service Mesh", Description: "ideas exchange kubernetes mesh"},
}
raw, err := json.Marshal(projects)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if err := os.WriteFile(dir+"/cncf-catalog.json", raw, 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
cs, err := catalog.New(dir, "")
if err != nil {
t.Fatalf("catalog.New: %v", err)
}
return cs
}

func TestIdeaMatchesWithoutEngineIs503(t *testing.T) {
a, mux := newAPIFixture(t)
idea := mustCreate(t, a, "bob", "Sched idea", store.VisibilityPrivate, store.StatusDraft)
rec := do(t, mux, ident("bob"), "GET", "/api/ideas/"+idea.ID+"/matches", "")
if rec.Code != http.StatusServiceUnavailable {
t.Fatalf("matches without engine: status=%d, want 503", rec.Code)
}
}

func TestIdeaMatchesFallbackScoringAndCNCFFilter(t *testing.T) {
a, mux := newAPIFixture(t)
a.Engine = &match.Engine{Store: a.Store, Registry: a.Registry, Catalog: seedCatalog(t, t.TempDir())}

idea := mustCreate(t, a, "bob", "Kubernetes ideas exchange", store.VisibilityPrivate, store.StatusDraft)
rec := do(t, mux, ident("bob"), "GET", "/api/ideas/"+idea.ID+"/matches", "")
if rec.Code != http.StatusOK {
t.Fatalf("matches: status=%d body=%s", rec.Code, rec.Body.String())
}
out := decodeBody[struct {
TLDR string `json:"tldr"`
Matches []matchView `json:"matches"`
CNCF []store.CNCFMatch `json:"cncf"`
}](t, rec)
if out.TLDR == "" {
t.Fatal("matches response has empty tldr; want fallback TLDR")
}
// The registry holds two repos, but the ideator feed is capped at
// maxIdeaHiveMatches (1) and returns full repo profiles.
if len(out.Matches) != maxIdeaHiveMatches {
t.Fatalf("hive matches = %+v, want %d entry", out.Matches, maxIdeaHiveMatches)
}
if out.Matches[0].Repo == nil || out.Matches[0].Repo.RepoID == "" {
t.Fatalf("hive match missing repo profile: %+v", out.Matches[0])
}
// kubestellar/dibs is hive-managed, so only istio/istio may appear in
// the CNCF companion section.
for _, m := range out.CNCF {
if m.RepoID == "kubestellar/dibs" {
t.Fatalf("cncf section includes hive-managed repo: %+v", out.CNCF)
}
}
if len(out.CNCF) != 1 || out.CNCF[0].RepoID != "istio/istio" {
t.Fatalf("cncf matches = %+v, want exactly istio/istio", out.CNCF)
}

// The scored matches were persisted on the idea.
stored, err := a.Store.Get(idea.ID)
if err != nil {
t.Fatalf("Get: %v", err)
}
if len(stored.Matches) == 0 || stored.MatchesUpdatedAt.IsZero() {
t.Fatalf("stored idea matches = %+v (updated %v), want persisted scores", stored.Matches, stored.MatchesUpdatedAt)
}
if stored.TLDR == "" {
t.Fatal("stored idea TLDR empty; want persisted fallback TLDR")
}
}

func TestIdeaMatchesSkipsPassedAndOfferedRepos(t *testing.T) {
a, mux := newAPIFixture(t)
a.Engine = &match.Engine{Store: a.Store, Registry: a.Registry}

idea := mustCreate(t, a, "bob", "Kubernetes ideas exchange", store.VisibilityPrivate, store.StatusDraft)
if _, err := a.Store.Mutate(idea.ID, false, func(i *store.Idea) error {
i.PassedRepos = append(i.PassedRepos, "kubestellar/dibs", "org/other")
return nil
}); err != nil {
t.Fatalf("Mutate: %v", err)
}
rec := do(t, mux, ident("bob"), "GET", "/api/ideas/"+idea.ID+"/matches", "")
if rec.Code != http.StatusOK {
t.Fatalf("matches: status=%d body=%s", rec.Code, rec.Body.String())
}
out := decodeBody[struct {
Matches []matchView `json:"matches"`
CNCF []store.CNCFMatch `json:"cncf"`
}](t, rec)
if len(out.Matches) != 0 {
t.Fatalf("matches = %+v, want none after passing on every repo", out.Matches)
}
if len(out.CNCF) != 0 {
t.Fatalf("cncf = %+v, want empty with nil catalog", out.CNCF)
}
}
35 changes: 35 additions & 0 deletions pkg/auth/fake_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package auth

import (
"context"
"errors"
"testing"
)

func TestFakeHubWhoAmI(t *testing.T) {
f := &FakeHub{Sessions: map[string]Identity{"cookie-1": {Username: "alice"}}}

id, err := f.WhoAmI(context.Background(), "cookie-1")
if err != nil || id == nil || id.Username != "alice" {
t.Fatalf("WhoAmI(cookie-1) = %+v, %v; want alice", id, err)
}

id, err = f.WhoAmI(context.Background(), "unknown")
if !errors.Is(err, ErrUnauthenticated) || id != nil {
t.Fatalf("WhoAmI(unknown) = %+v, %v; want ErrUnauthenticated", id, err)
}
}

func TestFakeHubWhoAmIBearer(t *testing.T) {
f := &FakeHub{BearerTokens: map[string]Identity{"tok-1": {Username: "bob"}}}

id, err := f.WhoAmIBearer(context.Background(), "tok-1")
if err != nil || id == nil || id.Username != "bob" {
t.Fatalf("WhoAmIBearer(tok-1) = %+v, %v; want bob", id, err)
}

id, err = f.WhoAmIBearer(context.Background(), "unknown")
if !errors.Is(err, ErrUnauthenticated) || id != nil {
t.Fatalf("WhoAmIBearer(unknown) = %+v, %v; want ErrUnauthenticated", id, err)
}
}
47 changes: 47 additions & 0 deletions pkg/intake/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package intake

import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)

func TestAudioEnabled(t *testing.T) {
t.Setenv("DIBS_STT_URL", "")
if AudioEnabled() {
t.Fatal("AudioEnabled() = true with DIBS_STT_URL unset")
}
t.Setenv("DIBS_STT_URL", " ")
if AudioEnabled() {
t.Fatal("AudioEnabled() = true with whitespace-only DIBS_STT_URL")
}
t.Setenv("DIBS_STT_URL", "http://stt.local")
if !AudioEnabled() {
t.Fatal("AudioEnabled() = false with DIBS_STT_URL set")
}
}

func TestHandleConfig(t *testing.T) {
for _, tc := range []struct {
sttURL string
want bool
}{
{"", false},
{"http://stt.local", true},
} {
t.Setenv("DIBS_STT_URL", tc.sttURL)
rec := httptest.NewRecorder()
HandleConfig(rec, httptest.NewRequest("GET", "/api/intake/config", nil))
if rec.Code != http.StatusOK {
t.Fatalf("HandleConfig status = %d, want 200", rec.Code)
}
var body map[string]bool
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
t.Fatalf("decode %q: %v", rec.Body.String(), err)
}
if body["audio"] != tc.want {
t.Fatalf("audio = %v with DIBS_STT_URL=%q, want %v", body["audio"], tc.sttURL, tc.want)
}
}
}
29 changes: 29 additions & 0 deletions pkg/settle/fromenv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package settle

import "testing"

func TestFromEnvUnsetReturnsNil(t *testing.T) {
t.Setenv(EnvGitHubToken, "")
t.Setenv("IDEATE_GITHUB_TOKEN", "")
if c := FromEnv(); c != nil {
t.Fatalf("FromEnv() with no token = %+v, want nil", c)
}
}

func TestFromEnvPrimaryToken(t *testing.T) {
t.Setenv(EnvGitHubToken, " primary-tok ")
t.Setenv("IDEATE_GITHUB_TOKEN", "legacy-tok")
c := FromEnv()
if c == nil || c.Token != "primary-tok" {
t.Fatalf("FromEnv() = %+v, want Token=primary-tok", c)
}
}

func TestFromEnvLegacyFallback(t *testing.T) {
t.Setenv(EnvGitHubToken, "")
t.Setenv("IDEATE_GITHUB_TOKEN", "legacy-tok")
c := FromEnv()
if c == nil || c.Token != "legacy-tok" {
t.Fatalf("FromEnv() = %+v, want Token=legacy-tok", c)
}
}
Loading