feat(go): add galaxy-browse CLI subcommand (§4.6)
This commit is contained in:
@@ -348,6 +348,146 @@ func TestRunBenchReadBulkRejectsNonPositiveBulkSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// browseFakeGalaxy implements BrowseChildren for the galaxy-browse subcommand
|
||||
// tests. It returns two root objects when no parent is supplied (the first
|
||||
// flagged as having children), and one child when the first root's gobject id
|
||||
// is supplied as the parent. The recorded last request lets a test assert the
|
||||
// CLI forwarded the parent and filter fields onto the wire.
|
||||
type browseFakeGalaxy struct {
|
||||
pb.UnimplementedGalaxyRepositoryServer
|
||||
lastRequest *pb.BrowseChildrenRequest
|
||||
}
|
||||
|
||||
func (g *browseFakeGalaxy) BrowseChildren(_ context.Context, req *pb.BrowseChildrenRequest) (*pb.BrowseChildrenReply, error) {
|
||||
g.lastRequest = req
|
||||
if req.GetParentGobjectId() == 10 {
|
||||
return &pb.BrowseChildrenReply{
|
||||
Children: []*pb.GalaxyObject{
|
||||
{GobjectId: 11, TagName: "Area1.Tank", BrowseName: "Tank"},
|
||||
},
|
||||
ChildHasChildren: []bool{false},
|
||||
}, nil
|
||||
}
|
||||
return &pb.BrowseChildrenReply{
|
||||
Children: []*pb.GalaxyObject{
|
||||
{GobjectId: 10, TagName: "Area1", BrowseName: "Area1"},
|
||||
{GobjectId: 20, TagName: "Area2", BrowseName: "Area2"},
|
||||
},
|
||||
ChildHasChildren: []bool{true, false},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func startBrowseFakeGalaxy(t *testing.T) (addr string, fake *browseFakeGalaxy) {
|
||||
t.Helper()
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
server := grpc.NewServer()
|
||||
fake = &browseFakeGalaxy{}
|
||||
pb.RegisterGalaxyRepositoryServer(server, fake)
|
||||
go func() { _ = server.Serve(listener) }()
|
||||
t.Cleanup(func() {
|
||||
server.Stop()
|
||||
_ = listener.Close()
|
||||
})
|
||||
return listener.Addr().String(), fake
|
||||
}
|
||||
|
||||
// TestRunGalaxyBrowseTextTree verifies the galaxy-browse subcommand issues
|
||||
// BrowseChildren for the root walk, eagerly expands one level when --depth is
|
||||
// set, and renders an indented tree.
|
||||
func TestRunGalaxyBrowseTextTree(t *testing.T) {
|
||||
addr, _ := startBrowseFakeGalaxy(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
args := []string{
|
||||
"galaxy-browse",
|
||||
"-endpoint", addr,
|
||||
"-plaintext",
|
||||
"-api-key", "test",
|
||||
"-depth", "1",
|
||||
}
|
||||
if err := runWithIO(t.Context(), args, &stdout, &stderr); err != nil {
|
||||
t.Fatalf("runWithIO() error = %v; stderr = %s", err, stderr.String())
|
||||
}
|
||||
out := stdout.String()
|
||||
// Both roots present; the first root's eagerly-expanded child appears
|
||||
// indented beneath it.
|
||||
for _, want := range []string{"Area1", "Area2", "Tank"} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Fatalf("galaxy-browse text output missing %q; got:\n%s", want, out)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(out, " ") {
|
||||
t.Fatalf("galaxy-browse text output not indented for children; got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunGalaxyBrowseJSON verifies the galaxy-browse subcommand emits valid
|
||||
// nested JSON and forwards filter options onto the BrowseChildren request.
|
||||
func TestRunGalaxyBrowseJSON(t *testing.T) {
|
||||
addr, fake := startBrowseFakeGalaxy(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
args := []string{
|
||||
"galaxy-browse",
|
||||
"-endpoint", addr,
|
||||
"-plaintext",
|
||||
"-api-key", "test",
|
||||
"-depth", "1",
|
||||
"-tag-name-glob", "Area%",
|
||||
"-alarm-bearing-only",
|
||||
"-json",
|
||||
}
|
||||
if err := runWithIO(t.Context(), args, &stdout, &stderr); err != nil {
|
||||
t.Fatalf("runWithIO() error = %v; stderr = %s", err, stderr.String())
|
||||
}
|
||||
|
||||
var payload map[string]any
|
||||
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("parse JSON: %v\noutput: %s", err, stdout.String())
|
||||
}
|
||||
if payload["command"] != "galaxy-browse" {
|
||||
t.Fatalf("command = %v, want galaxy-browse", payload["command"])
|
||||
}
|
||||
nodes, ok := payload["nodes"].([]any)
|
||||
if !ok || len(nodes) != 2 {
|
||||
t.Fatalf("nodes = %v, want 2 root nodes", payload["nodes"])
|
||||
}
|
||||
// Filter fields must have reached the wire.
|
||||
if got := fake.lastRequest.GetTagNameGlob(); got != "Area%" {
|
||||
t.Fatalf("BrowseChildren TagNameGlob = %q, want %q", got, "Area%")
|
||||
}
|
||||
if !fake.lastRequest.GetAlarmBearingOnly() {
|
||||
t.Fatalf("BrowseChildren AlarmBearingOnly = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunGalaxyBrowseParentSingleLevel verifies that passing --parent fetches a
|
||||
// single level of children for that parent via the parent-scoped request.
|
||||
func TestRunGalaxyBrowseParentSingleLevel(t *testing.T) {
|
||||
addr, fake := startBrowseFakeGalaxy(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
args := []string{
|
||||
"galaxy-browse",
|
||||
"-endpoint", addr,
|
||||
"-plaintext",
|
||||
"-api-key", "test",
|
||||
"-parent", "10",
|
||||
}
|
||||
if err := runWithIO(t.Context(), args, &stdout, &stderr); err != nil {
|
||||
t.Fatalf("runWithIO() error = %v; stderr = %s", err, stderr.String())
|
||||
}
|
||||
if !strings.Contains(stdout.String(), "Tank") {
|
||||
t.Fatalf("galaxy-browse -parent output missing child %q; got:\n%s", "Tank", stdout.String())
|
||||
}
|
||||
if got := fake.lastRequest.GetParentGobjectId(); got != 10 {
|
||||
t.Fatalf("BrowseChildren ParentGobjectId = %d, want 10", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunBatchSkipsBlankLinesAndContinuesUntilEOF pins the Client.Go-027 fix:
|
||||
// a blank line in the middle of a batch session must NOT terminate the loop —
|
||||
// only stdin EOF ends the session.
|
||||
|
||||
Reference in New Issue
Block a user