client/go: paginate DiscoverHierarchy across multi-page galaxies
This commit is contained in:
@@ -18,6 +18,11 @@ import (
|
|||||||
// browseChildrenPageSize is the per-request page size used by the lazy walker.
|
// browseChildrenPageSize is the per-request page size used by the lazy walker.
|
||||||
const browseChildrenPageSize = 500
|
const browseChildrenPageSize = 500
|
||||||
|
|
||||||
|
// discoverHierarchyPageSize is the per-request page size used by DiscoverHierarchy.
|
||||||
|
// Mirrors the .NET client constant so large galaxies are not silently truncated
|
||||||
|
// by the server's default page cap.
|
||||||
|
const discoverHierarchyPageSize = 5000
|
||||||
|
|
||||||
// RawGalaxyRepositoryClient is the generated gRPC client interface for the
|
// RawGalaxyRepositoryClient is the generated gRPC client interface for the
|
||||||
// Galaxy Repository service exposed for callers that need direct contract
|
// Galaxy Repository service exposed for callers that need direct contract
|
||||||
// access.
|
// access.
|
||||||
@@ -155,16 +160,35 @@ func (c *GalaxyClient) GetLastDeployTime(ctx context.Context) (time.Time, bool,
|
|||||||
|
|
||||||
// DiscoverHierarchy returns the deployed Galaxy object hierarchy with each
|
// DiscoverHierarchy returns the deployed Galaxy object hierarchy with each
|
||||||
// object's dynamic attributes. The objects are returned in the order supplied
|
// object's dynamic attributes. The objects are returned in the order supplied
|
||||||
// by the server.
|
// by the server. The call pages over the server's NextPageToken until the
|
||||||
|
// server signals it has no more results, matching the .NET client.
|
||||||
func (c *GalaxyClient) DiscoverHierarchy(ctx context.Context) ([]*GalaxyObject, error) {
|
func (c *GalaxyClient) DiscoverHierarchy(ctx context.Context) ([]*GalaxyObject, error) {
|
||||||
callCtx, cancel := c.callContext(ctx)
|
var objects []*GalaxyObject
|
||||||
defer cancel()
|
pageToken := ""
|
||||||
|
seen := map[string]struct{}{}
|
||||||
reply, err := c.raw.DiscoverHierarchy(callCtx, &pb.DiscoverHierarchyRequest{})
|
for {
|
||||||
if err != nil {
|
callCtx, cancel := c.callContext(ctx)
|
||||||
return nil, &GatewayError{Op: "galaxy discover hierarchy", Err: err}
|
reply, err := c.raw.DiscoverHierarchy(callCtx, &pb.DiscoverHierarchyRequest{
|
||||||
|
PageSize: discoverHierarchyPageSize,
|
||||||
|
PageToken: pageToken,
|
||||||
|
})
|
||||||
|
cancel()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &GatewayError{Op: "galaxy discover hierarchy", Err: err}
|
||||||
|
}
|
||||||
|
objects = append(objects, reply.GetObjects()...)
|
||||||
|
pageToken = reply.GetNextPageToken()
|
||||||
|
if pageToken == "" {
|
||||||
|
return objects, nil
|
||||||
|
}
|
||||||
|
if _, dup := seen[pageToken]; dup {
|
||||||
|
return nil, &GatewayError{
|
||||||
|
Op: "galaxy discover hierarchy",
|
||||||
|
Err: fmt.Errorf("repeated page token %q", pageToken),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seen[pageToken] = struct{}{}
|
||||||
}
|
}
|
||||||
return reply.GetObjects(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchDeployEventsRaw starts the generated WatchDeployEvents stream for callers
|
// WatchDeployEventsRaw starts the generated WatchDeployEvents stream for callers
|
||||||
|
|||||||
@@ -146,6 +146,47 @@ func TestGalaxyDiscoverHierarchyReturnsObjects(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGalaxyDiscoverHierarchyPaginatesAcrossMultiplePages(t *testing.T) {
|
||||||
|
page1 := &pb.DiscoverHierarchyReply{
|
||||||
|
Objects: []*pb.GalaxyObject{
|
||||||
|
{GobjectId: 1, TagName: "A"},
|
||||||
|
{GobjectId: 2, TagName: "B"},
|
||||||
|
},
|
||||||
|
NextPageToken: "page-2",
|
||||||
|
TotalObjectCount: 3,
|
||||||
|
}
|
||||||
|
page2 := &pb.DiscoverHierarchyReply{
|
||||||
|
Objects: []*pb.GalaxyObject{
|
||||||
|
{GobjectId: 3, TagName: "C"},
|
||||||
|
},
|
||||||
|
TotalObjectCount: 3,
|
||||||
|
}
|
||||||
|
fake := &fakeGalaxyServer{
|
||||||
|
discoverHierarchyReplies: []*pb.DiscoverHierarchyReply{page1, page2},
|
||||||
|
}
|
||||||
|
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
objs, err := client.DiscoverHierarchy(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DiscoverHierarchy: %v", err)
|
||||||
|
}
|
||||||
|
if got, want := len(objs), 3; got != want {
|
||||||
|
t.Fatalf("len(objs) = %d, want %d", got, want)
|
||||||
|
}
|
||||||
|
if len(fake.discoverHierarchyCalls) != 2 {
|
||||||
|
t.Fatalf("expected 2 RPC calls, got %d", len(fake.discoverHierarchyCalls))
|
||||||
|
}
|
||||||
|
if fake.discoverHierarchyCalls[0].GetPageSize() != discoverHierarchyPageSize {
|
||||||
|
t.Fatalf("first call PageSize = %d, want %d",
|
||||||
|
fake.discoverHierarchyCalls[0].GetPageSize(), discoverHierarchyPageSize)
|
||||||
|
}
|
||||||
|
if fake.discoverHierarchyCalls[1].GetPageToken() != "page-2" {
|
||||||
|
t.Fatalf("second call page token = %q, want %q",
|
||||||
|
fake.discoverHierarchyCalls[1].GetPageToken(), "page-2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGalaxyDialReturnsGatewayErrorOnRpcFailure(t *testing.T) {
|
func TestGalaxyDialReturnsGatewayErrorOnRpcFailure(t *testing.T) {
|
||||||
fake := &fakeGalaxyServer{failTest: true}
|
fake := &fakeGalaxyServer{failTest: true}
|
||||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||||
@@ -372,18 +413,20 @@ func newGalaxyBufconnClient(t *testing.T, fake *fakeGalaxyServer) (*GalaxyClient
|
|||||||
type fakeGalaxyServer struct {
|
type fakeGalaxyServer struct {
|
||||||
pb.UnimplementedGalaxyRepositoryServer
|
pb.UnimplementedGalaxyRepositoryServer
|
||||||
|
|
||||||
testReply *pb.TestConnectionReply
|
testReply *pb.TestConnectionReply
|
||||||
testAuth string
|
testAuth string
|
||||||
failTest bool
|
failTest bool
|
||||||
deployReply *pb.GetLastDeployTimeReply
|
deployReply *pb.GetLastDeployTimeReply
|
||||||
discoverReply *pb.DiscoverHierarchyReply
|
discoverReply *pb.DiscoverHierarchyReply
|
||||||
watchEvents []*pb.DeployEvent
|
discoverHierarchyCalls []*pb.DiscoverHierarchyRequest
|
||||||
watchRequest *pb.WatchDeployEventsRequest
|
discoverHierarchyReplies []*pb.DiscoverHierarchyReply
|
||||||
watchSendInterval time.Duration
|
watchEvents []*pb.DeployEvent
|
||||||
watchHoldOpen bool
|
watchRequest *pb.WatchDeployEventsRequest
|
||||||
browseChildrenCalls []*pb.BrowseChildrenRequest
|
watchSendInterval time.Duration
|
||||||
browseChildrenReplies []*pb.BrowseChildrenReply
|
watchHoldOpen bool
|
||||||
browseChildrenError error
|
browseChildrenCalls []*pb.BrowseChildrenRequest
|
||||||
|
browseChildrenReplies []*pb.BrowseChildrenReply
|
||||||
|
browseChildrenError error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fakeGalaxyServer) TestConnection(ctx context.Context, req *pb.TestConnectionRequest) (*pb.TestConnectionReply, error) {
|
func (s *fakeGalaxyServer) TestConnection(ctx context.Context, req *pb.TestConnectionRequest) (*pb.TestConnectionReply, error) {
|
||||||
@@ -405,6 +448,12 @@ func (s *fakeGalaxyServer) GetLastDeployTime(ctx context.Context, req *pb.GetLas
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *fakeGalaxyServer) DiscoverHierarchy(ctx context.Context, req *pb.DiscoverHierarchyRequest) (*pb.DiscoverHierarchyReply, error) {
|
func (s *fakeGalaxyServer) DiscoverHierarchy(ctx context.Context, req *pb.DiscoverHierarchyRequest) (*pb.DiscoverHierarchyReply, error) {
|
||||||
|
s.discoverHierarchyCalls = append(s.discoverHierarchyCalls, req)
|
||||||
|
if len(s.discoverHierarchyReplies) > 0 {
|
||||||
|
reply := s.discoverHierarchyReplies[0]
|
||||||
|
s.discoverHierarchyReplies = s.discoverHierarchyReplies[1:]
|
||||||
|
return reply, nil
|
||||||
|
}
|
||||||
if s.discoverReply != nil {
|
if s.discoverReply != nil {
|
||||||
return s.discoverReply, nil
|
return s.discoverReply, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user