package web
import (
"context"
"net/url"
"os"
"testing"
"sourcecraft.dev/bigbes/sr-ht-dolt/beads"
"sourcecraft.dev/bigbes/sr-ht-dolt/browse"
)
// TestRealBeadsStore is a manual smoke test against a real beads database. It
// is skipped unless BEADS_REAL_DB points at a *bare* NBS store dir (the shape
// production serves — an embedded working store has a chunk journal and won't
// open; push it to a file remote first: `dolt push file:///path/bare main`).
// Optionally set BEADS_REAL_ISSUE=<id> to dump one issue's epic rollup and
// merged history. Kept because browse reaches into version-fragile dolt
// internals, so a module bump should be re-verified against real data here.
//
// dolt push file:///tmp/bare main # from the working store
// BEADS_REAL_DB=/tmp/bare BEADS_REAL_ISSUE=<epic-id> \
// go test -tags gms_pure_go -run TestRealBeadsStore -v ./web/
func TestRealBeadsStore(t *testing.T) {
path := os.Getenv("BEADS_REAL_DB")
if path == "" {
t.Skip("set BEADS_REAL_DB to a real beads noms store dir")
}
ctx := context.Background()
dbh, err := browse.Open(ctx, path)
if err != nil {
t.Fatalf("open: %v", err)
}
defer dbh.Close()
branches, err := dbh.Branches(ctx)
if err != nil {
t.Fatalf("branches: %v", err)
}
ref := browse.DefaultBranch(branches)
t.Logf("branches=%v default=%q", branches, ref)
tables, err := dbh.Tables(ctx, ref)
if err != nil {
t.Fatalf("tables: %v", err)
}
var names []string
for _, tb := range tables {
names = append(names, tb.Name)
}
t.Logf("tables=%v", names)
issues, err := dbh.Rows(ctx, ref, "issues", 0, 5)
if err != nil {
t.Fatalf("rows: %v", err)
}
t.Logf("issues cols=%v total=%d", issues.Columns, issues.Total)
v := &beadsView{}
// Board mode: dump the filter options, then the effect of a type filter.
board, err := v.Build(ctx, dbh, nil, ref, url.Values{})
if err != nil {
t.Fatalf("board build: %v", err)
}
bd := board.(*beads.Data)
t.Logf("board total=%d types=%v priorities=%v labels=%v",
bd.Total, bd.FilterOpts.Types, bd.FilterOpts.Priorities, bd.FilterOpts.Labels)
if len(bd.FilterOpts.Types) > 0 {
ft := bd.FilterOpts.Types[0]
filtered, _ := v.Build(ctx, dbh, nil, ref, url.Values{"type": {ft}})
t.Logf("filter type=%q → %d issues (of %d)", ft, filtered.(*beads.Data).Total, bd.Total)
}
readyN := 0
for i := range bd.Lanes {
for _, c := range bd.Lanes[i].Issues {
if c.Ready {
readyN++
}
}
}
t.Logf("ready cards=%d", readyN)
// Milestones view.
msRaw, err := (&milestonesView{}).Build(ctx, dbh, nil, ref, url.Values{})
if err != nil {
t.Fatalf("milestones build: %v", err)
}
ms := msRaw.(*beads.MilestoneView)
t.Logf("milestones (%d, %d unlabeled of %d):", len(ms.Milestones), ms.Unlabeled, ms.Total)
for _, m := range ms.Milestones {
t.Logf(" %-24s %d/%d done (%d%%), %d heads, %d epics, %d loose",
m.Name, m.Done, m.Total, m.Pct(), len(m.Heads), len(m.Epics), len(m.Loose))
for _, e := range m.Epics {
t.Logf(" epic %s %d/%d: %s", e.Card.ID, e.Done, e.Total, e.Card.Title)
}
}
// Drive the detail view. With BEADS_REAL_ISSUE set to an epic id, dump the
// subtask rollup and merged history so a human can eyeball the output.
want := os.Getenv("BEADS_REAL_ISSUE")
if want == "" {
return
}
raw, err := v.Build(ctx, dbh, nil, ref, url.Values{"issue": {want}})
if err != nil {
t.Fatalf("build: %v", err)
}
data := raw.(*beads.Data)
if data.Issue == nil {
t.Fatalf("issue %q not found", want)
}
t.Logf("mode=%q issue=%q type=%q", data.Mode, data.Issue.Title, data.Issue.IssueType)
t.Logf("desc=%.80q closeReason=%.80q", data.Issue.Description, data.Issue.CloseReason)
t.Logf("subtasks %d/%d done (%d%%):", data.SubtaskDone, data.SubtaskTotal, data.SubtaskPct())
for _, s := range data.Subtasks {
t.Logf(" - %s [%s/%s] %s @%s", s.ID, s.Category, s.Status, s.Title, s.Assignee)
}
t.Logf("history (%d entries):", len(data.History))
for _, a := range data.History {
t.Logf(" %s | %s: %s %s | %s", a.CreatedAt, a.Kind, a.Actor, a.Summary, a.Text)
}
t.Logf("prerequisite chain (%d nodes):", len(data.DependsTree))
for _, n := range data.DependsTree {
t.Logf(" %*s%s %s [%s]", n.Depth*2, "", n.ID, n.Title, n.Status)
}
t.Logf("unblocks (%d nodes):", len(data.DependentTree))
for _, n := range data.DependentTree {
t.Logf(" %*s%s %s [%s]", n.Depth*2, "", n.ID, n.Title, n.Status)
}
}