Skip to content

Commit 78fc148

Browse files
committed
fwserver: validate each ListResult
1 parent 877b2b8 commit 78fc148

File tree

3 files changed

+38
-16
lines changed

3 files changed

+38
-16
lines changed

internal/fwserver/server_listresource.go

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ type ListRequest struct {
3333

3434
// ListResultsStream represents a streaming response to a ListRequest. An
3535
// instance of this struct is supplied as an argument to the provider's List
36-
// function. The provider should set a Results iterator function that yields
36+
// function. The provider should set a Results iterator function that pushes
3737
// zero or more results of type ListResult.
3838
//
3939
// For convenience, a provider implementation may choose to convert a slice of
4040
// results into an iterator using [slices.Values].
4141
//
4242
// [slices.Values]: https://pkg.go.dev/slices#Values
4343
type ListResourceStream struct {
44-
// Results is a function that emits ListResult values via its yield
44+
// Results is a function that emits ListResult values via its push
4545
// function argument.
4646
Results iter.Seq[ListResult]
4747
}
@@ -85,19 +85,40 @@ func (s *Server) ListResource(ctx context.Context, fwReq *ListRequest, fwStream
8585
logging.FrameworkTrace(ctx, "Called provider defined ListResource")
8686

8787
if stream.Results == nil {
88-
// If the provider returned a nil results stream, we treat it as an empty stream.
89-
stream.Results = func(func(list.ListResult) bool) {}
88+
// If the provider returned a nil results stream, we return an empty stream.
89+
stream.Results = list.NoListResults
9090
}
9191

92-
fwStream.Results = listResourceEventStreamAdapter(stream.Results)
92+
fwStream.Results = processListResults(req, stream.Results)
9393
}
9494

95-
func listResourceEventStreamAdapter(stream iter.Seq[list.ListResult]) iter.Seq[ListResult] {
96-
// TODO: is this any more efficient than a for-range?
97-
return func(yieldFw func(ListResult) bool) {
98-
yield := func(event list.ListResult) bool {
99-
return yieldFw(ListResult(event))
95+
func processListResults(req list.ListRequest, stream iter.Seq[list.ListResult]) iter.Seq[ListResult] {
96+
return func(push func(ListResult) bool) {
97+
for result := range stream {
98+
if !push(processListResult(req, result)) {
99+
return
100+
}
100101
}
101-
stream(yield)
102102
}
103103
}
104+
105+
// processListResult validates the content of a list.ListResult and returns a
106+
// ListResult
107+
func processListResult(req list.ListRequest, result list.ListResult) ListResult {
108+
if result.Identity == nil {
109+
return ListResult{
110+
Diagnostics: diag.Diagnostics{
111+
diag.NewErrorDiagnostic("Incomplete List Result", "ListResult.Identity is nil."),
112+
},
113+
}
114+
}
115+
116+
if req.IncludeResource && result.Resource == nil {
117+
result.Diagnostics.AddWarning(
118+
"Incomplete List Result",
119+
"ListRequest.IncludeResource is true and ListResult.Resource is nil.",
120+
)
121+
}
122+
123+
return ListResult(result)
124+
}

internal/fwserver/server_listresource_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func TestServerListResource(t *testing.T) {
8383
request: &fwserver.ListRequest{
8484
ListResource: &testprovider.ListResource{
8585
ListMethod: func(ctx context.Context, req list.ListRequest, resp *list.ListResultsStream) { // TODO
86-
resp.Results = slices.Values([]list.ListResult{})
86+
resp.Results = list.NoListResults
8787
},
8888
},
8989
},

list/list_resource.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,19 @@ type ListRequest struct {
102102
// ListResultsStream represents a streaming response to a ListRequest. An
103103
// instance of this struct is supplied as an argument to the provider's
104104
// ListResource function. The provider should set a Results iterator function
105-
// that yields zero or more results of type ListResult.
105+
// that pushes zero or more results of type ListResult.
106106
//
107107
// For convenience, a provider implementation may choose to convert a slice of
108108
// results into an iterator using [slices.Values].
109-
//
110-
// [slices.Values]: https://pkg.go.dev/slices#Values
111109
type ListResultsStream struct {
112-
// Results is a function that emits ListResult values via its yield
110+
// Results is a function that emits ListResult values via its push
113111
// function argument.
114112
Results iter.Seq[ListResult]
115113
}
116114

115+
// NoListResults is an iterator that pushes zero results.
116+
var NoListResults = func(func(ListResult) bool) {}
117+
117118
// ListResult represents a listed managed resource instance.
118119
type ListResult struct {
119120
// Identity is the identity of the managed resource instance.

0 commit comments

Comments
 (0)