134 lines
4.0 KiB
Go
134 lines
4.0 KiB
Go
// ©AngelaMos | 2026
|
|
// ideate_test.go
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/CarterPerez-dev/nadezhda/internal/setup"
|
|
"github.com/CarterPerez-dev/nadezhda/internal/store"
|
|
)
|
|
|
|
func seedCluster(t *testing.T, st *store.Store) {
|
|
t.Helper()
|
|
stmts := []string{
|
|
`INSERT INTO sources (id, name, url, type, weight, enabled) VALUES (1, 'krebs', 'https://krebsonsecurity.com', 'rss', 1.0, 1)`,
|
|
`INSERT INTO articles (id, source_id, canonical_url, content_hash, title, published_at) VALUES (1, 1, 'https://krebsonsecurity.com/a', 'h1', 'Critical RCE exploited in the wild', 1000)`,
|
|
`INSERT INTO clusters (id, cluster_key, first_seen, last_seen, size) VALUES (1, 'k1', 900, 1000, 1)`,
|
|
`INSERT INTO cluster_members (cluster_id, article_id) VALUES (1, 1)`,
|
|
}
|
|
for _, s := range stmts {
|
|
if _, err := st.DB().Exec(s); err != nil {
|
|
t.Fatalf("seed %q: %v", s, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIdeateCommandEndToEnd(t *testing.T) {
|
|
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
|
t.Setenv(setup.EnvProvider, "")
|
|
t.Setenv(setup.EnvQwenURL, "")
|
|
dir := t.TempDir()
|
|
dbPath := filepath.Join(dir, "test.db")
|
|
st, err := store.Open(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("open store: %v", err)
|
|
}
|
|
seedCluster(t, st)
|
|
st.Close()
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
body, _ := json.Marshal(map[string]any{
|
|
"choices": []map[string]any{{"message": map[string]any{
|
|
"content": `{"summary":"a critical rce","why":"widely exploited","angles":["hook one","hook two","hook three"],"format":"newsletter"}`,
|
|
}}},
|
|
})
|
|
_, _ = w.Write(body)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
cfgPath := filepath.Join(dir, "config.yaml")
|
|
cfgYAML := "ai:\n enabled: true\n provider: qwen\n qwen:\n base_url: " + srv.URL + "\n model: qwen2.5:7b\n"
|
|
if err := os.WriteFile(cfgPath, []byte(cfgYAML), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prevCfg, prevDB, prevTop, prevProv, prevForce, prevSince := flagConfig, flagDB, ideateTop, ideateProvider, ideateForce, ideateSince
|
|
defer func() {
|
|
flagConfig, flagDB, ideateTop, ideateProvider, ideateForce, ideateSince = prevCfg, prevDB, prevTop, prevProv, prevForce, prevSince
|
|
}()
|
|
flagConfig, flagDB, ideateTop, ideateProvider, ideateForce, ideateSince = cfgPath, dbPath, 1, "", false, ""
|
|
|
|
cmd := &cobra.Command{}
|
|
cmd.SetContext(context.Background())
|
|
var buf bytes.Buffer
|
|
cmd.SetOut(&buf)
|
|
|
|
if err := runIdeate(cmd, nil); err != nil {
|
|
t.Fatalf("runIdeate: %v\noutput:\n%s", err, buf.String())
|
|
}
|
|
out := buf.String()
|
|
for _, want := range []string{"ideated 1", "a critical rce", "hook one", "newsletter"} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("ideate output missing %q\n---\n%s", want, out)
|
|
}
|
|
}
|
|
|
|
st2, err := store.Open(dbPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ok, err := st2.AINoteExists(1, "qwen")
|
|
st2.Close()
|
|
if err != nil || !ok {
|
|
t.Fatalf("note not persisted: ok=%v err=%v", ok, err)
|
|
}
|
|
|
|
buf.Reset()
|
|
if err := runIdeate(cmd, nil); err != nil {
|
|
t.Fatalf("second runIdeate: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "skip cluster 1") {
|
|
t.Errorf("second run should skip existing note:\n%s", buf.String())
|
|
}
|
|
|
|
buf.Reset()
|
|
ideateForce = true
|
|
if err := runIdeate(cmd, nil); err != nil {
|
|
t.Fatalf("force runIdeate: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "ideated 1") {
|
|
t.Errorf("--force should regenerate, not skip:\n%s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestIdeateDisabledErrors(t *testing.T) {
|
|
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
|
t.Setenv(setup.EnvProvider, "")
|
|
t.Setenv(setup.EnvQwenURL, "")
|
|
prevCfg, prevProv := flagConfig, ideateProvider
|
|
defer func() { flagConfig, ideateProvider = prevCfg, prevProv }()
|
|
flagConfig, ideateProvider = "", ""
|
|
|
|
cmd := &cobra.Command{}
|
|
cmd.SetContext(context.Background())
|
|
cmd.SetOut(&bytes.Buffer{})
|
|
cmd.SetIn(strings.NewReader(""))
|
|
|
|
err := runIdeate(cmd, nil)
|
|
if err == nil || !strings.Contains(err.Error(), "not set up") {
|
|
t.Fatalf("expected a 'not set up' error, got %v", err)
|
|
}
|
|
}
|