Some checks failed
release-tag / Resolve release metadata (push) Successful in 30s
release-tag / Build knowledge (push) Failing after 4m51s
release-tag / Build control (push) Failing after 5m0s
release-tag / Build agent (push) Failing after 5m0s
release-tag / Build agent-data-init (push) Failing after 5m5s
release-tag / Build neuroforge-worker (push) Failing after 5m7s
release-tag / Build neuroforge (push) Failing after 5m9s
76 lines
2.3 KiB
Go
76 lines
2.3 KiB
Go
package learning
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestOutcomeStorePreservesRevisionHistoryAndPersistsSync(t *testing.T) {
|
|
s, err := OpenOutcomes(t.TempDir(), 10)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a, err := s.Add(TicketOutcome{RunID: "r1", TicketID: 1, Decision: "accepted", TicketInput: "problem", ProposedReply: "fix", ConfirmedReply: "fix", Actor: "tech"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, err := s.Add(TicketOutcome{RunID: "r1", TicketID: 1, Decision: "corrected", TicketInput: "problem", ProposedReply: "fix", ConfirmedReply: "better", Actor: "tech"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(s.List()) != 2 || a.ID == b.ID || b.SupersedesID != a.ID {
|
|
t.Fatalf("expected immutable revision history: %#v", s.List())
|
|
}
|
|
retry, err := s.Add(TicketOutcome{RunID: "r1", TicketID: 1, Decision: "corrected", TicketInput: "problem", ProposedReply: "fix", ConfirmedReply: "better", Actor: "tech"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if retry.ID != b.ID || len(s.List()) != 2 {
|
|
t.Fatalf("exact repeated human decision must be idempotent: retry=%#v list=%#v", retry, s.List())
|
|
}
|
|
got, err := s.UpdateSync(b.ID, "learned", "mem-1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.SyncStatus != "learned" || got.NeuroForgeID != "mem-1" {
|
|
t.Fatalf("unexpected sync: %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestNeuroForgeOutcomeSink(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/api/v1/integrations/outcomes" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
if r.Header.Get("Authorization") != "Bearer secret" {
|
|
http.Error(w, "unauthorized", 401)
|
|
return
|
|
}
|
|
var v map[string]any
|
|
if err := json.NewDecoder(r.Body).Decode(&v); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v["decision"] != "accepted" {
|
|
t.Fatalf("unexpected payload %#v", v)
|
|
}
|
|
_ = json.NewEncoder(w).Encode(map[string]any{"memory": map[string]any{"id": "mem-7"}})
|
|
}))
|
|
defer srv.Close()
|
|
sink, err := NewNeuroForgeOutcomeSink(srv.URL, "secret", time.Second)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id, err := sink.LearnOutcome(context.Background(), TicketOutcome{ID: "o", RunID: "r", TicketID: 1, Decision: "accepted", TicketInput: "p", ProposedReply: "a", ConfirmedReply: "a", Actor: "tech"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if id != "mem-7" {
|
|
t.Fatalf("id=%q", id)
|
|
}
|
|
}
|