Skip to content

Commit 79943d5

Browse files
committed
green
1 parent 84437cb commit 79943d5

File tree

4 files changed

+169
-122
lines changed

4 files changed

+169
-122
lines changed

internal/proto5server/server_listresource.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/hashicorp/terraform-plugin-framework/internal/fromproto5"
1111
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
1212
"github.com/hashicorp/terraform-plugin-framework/internal/toproto5"
13+
"github.com/hashicorp/terraform-plugin-framework/list"
1314
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
1415
sdk "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1516
)
@@ -66,10 +67,10 @@ func (s *Server) ListResource(ctx context.Context, protoReq *tfprotov5.ListResou
6667
_, ok := SDKResourceFromContext(ctx)
6768
switch ok {
6869
case true:
69-
protoStream.Results = func(push func(tfprotov5.ListResourceResult) bool) {
70-
listResult := tfprotov5.ListResourceResult{}
71-
push(listResult)
72-
}
70+
req := list.ListRequest{}
71+
stream := list.ListResultsStream{Proto5Results: tfprotov5.NoListResults}
72+
listResource.List(ctx, req, &stream)
73+
protoStream.Results = stream.Proto5Results
7374
case false:
7475
resourceSchema, diags := s.FrameworkServer.ResourceSchema(ctx, protoReq.TypeName)
7576
allDiags.Append(diags...)

internal/proto5server/server_listresource_test.go

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@ package proto5server
55

66
import (
77
"context"
8-
"fmt"
98
"slices"
109
"strings"
1110
"testing"
1211

1312
"github.com/google/go-cmp/cmp"
1413
"github.com/google/go-cmp/cmp/cmpopts"
15-
"github.com/hashicorp/go-cty/cty/msgpack"
1614
"github.com/hashicorp/terraform-plugin-framework/diag"
17-
"github.com/hashicorp/terraform-plugin-framework/hcl2shim"
1815
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
1916
"github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider"
2017
"github.com/hashicorp/terraform-plugin-framework/list"
@@ -24,8 +21,6 @@ import (
2421
resourceschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
2522
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
2623
"github.com/hashicorp/terraform-plugin-go/tftypes"
27-
sdk "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
28-
terraformsdk "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
2924
)
3025

3126
func TestServerListResource(t *testing.T) {
@@ -281,115 +276,3 @@ func TestServerListResource(t *testing.T) {
281276
})
282277
}
283278
}
284-
285-
// a resource type defined in SDKv2
286-
var sdkResource sdk.Resource = sdk.Resource{
287-
Schema: map[string]*sdk.Schema{
288-
"id": &sdk.Schema{
289-
Type: sdk.TypeString,
290-
},
291-
"name": &sdk.Schema{
292-
Type: sdk.TypeString,
293-
},
294-
},
295-
}
296-
297-
func listFunc(ctx context.Context, req list.ListRequest, stream *list.ListResultsStream) {
298-
panic("hats")
299-
}
300-
301-
func TestServerListResourceProto5ToProto5(t *testing.T) {
302-
t.Parallel()
303-
304-
server := func(listResource func() list.ListResource) *Server {
305-
return &Server{
306-
FrameworkServer: fwserver.Server{
307-
Provider: &testprovider.Provider{
308-
ListResourcesMethod: func(ctx context.Context) []func() list.ListResource {
309-
return []func() list.ListResource{listResource}
310-
},
311-
},
312-
},
313-
}
314-
}
315-
316-
listResource := func() list.ListResource {
317-
return &testprovider.ListResource{
318-
ListMethod: listFunc,
319-
MetadataMethod: func(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
320-
resp.TypeName = "test_resource"
321-
},
322-
}
323-
}
324-
aServer := server(listResource)
325-
326-
ctx := context.Background()
327-
ctx = NewContextWithSDKResource(ctx, &sdkResource)
328-
req := &tfprotov5.ListResourceRequest{
329-
TypeName: "test_resource",
330-
}
331-
332-
stream, err := aServer.ListResource(ctx, req)
333-
if err != nil {
334-
t.Fatalf("unexpected error returned from ListResource: %v", err)
335-
}
336-
337-
values := slices.Collect(stream.Results)
338-
if len(values) > 0 {
339-
if len(values[0].Diagnostics) > 0 {
340-
for _, diag := range values[0].Diagnostics {
341-
t.Logf("unexpected diagnostic returned from ListResource: %v", diag)
342-
}
343-
t.FailNow()
344-
}
345-
}
346-
347-
if len(values) == 0 {
348-
t.Fatalf("expected 1 list result; got 0 list results")
349-
}
350-
351-
// 2: from the resource type, we can obtain an initialized ResourceData value
352-
d := sdkResource.Data(&terraformsdk.InstanceState{ID: "#groot"})
353-
354-
// 3: the initialized ResourceData value is schema-aware
355-
if err := d.Set("name", "Groot"); err != nil {
356-
t.Fatalf("Error setting `name`: %v", err)
357-
}
358-
359-
if err := d.Set("nom", "groot"); err == nil {
360-
t.Fatal("False negative outcome: `nom` is not a schema attribute")
361-
}
362-
363-
displayName := "I am Groot"
364-
365-
// 4: mimic SDK GRPCProviderServer.ReadResource ResourceData -> MsgPack
366-
state := d.State()
367-
if state == nil {
368-
t.Fatal("Expected state to be non-nil")
369-
}
370-
371-
schemaBlock := sdkResource.CoreConfigSchema()
372-
if schemaBlock == nil {
373-
t.Fatal("Expected schemaBlock to be non-nil")
374-
}
375-
376-
// Copied hcl2shim wholesale for purposes of making the test pass
377-
newStateVal, err := hcl2shim.HCL2ValueFromFlatmap(state.Attributes, schemaBlock.ImpliedType())
378-
if err != nil {
379-
t.Fatalf("Error converting state attributes to HCL2 value: %v", err)
380-
}
381-
382-
// newStateVal = normalizeNullValues(newStateVal, stateVal, false)
383-
384-
pack, err := msgpack.Marshal(newStateVal, schemaBlock.ImpliedType())
385-
if err != nil {
386-
t.Fatalf("Error marshaling new state value to MsgPack: %v", err)
387-
}
388-
389-
fmt.Printf("MsgPack: %s\n", pack)
390-
391-
// 5: construct a tfprotov5.ListResourceResult
392-
listResult := tfprotov5.ListResourceResult{}
393-
listResult.Resource = &tfprotov5.DynamicValue{MsgPack: pack}
394-
listResult.DisplayName = displayName
395-
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package proto5server
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"slices"
7+
"testing"
8+
9+
"github.com/hashicorp/go-cty/cty/msgpack"
10+
"github.com/hashicorp/terraform-plugin-framework/hcl2shim"
11+
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
12+
"github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider"
13+
"github.com/hashicorp/terraform-plugin-framework/list"
14+
"github.com/hashicorp/terraform-plugin-framework/resource"
15+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
16+
sdk "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
17+
terraformsdk "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
18+
)
19+
20+
// a resource type defined in SDKv2
21+
var sdkResource sdk.Resource = sdk.Resource{
22+
Schema: map[string]*sdk.Schema{
23+
"id": &sdk.Schema{
24+
Type: sdk.TypeString,
25+
},
26+
"name": &sdk.Schema{
27+
Type: sdk.TypeString,
28+
},
29+
},
30+
}
31+
32+
func diagnosticResult(format string, args ...any) tfprotov5.ListResourceResult {
33+
return tfprotov5.ListResourceResult{
34+
Diagnostics: []*tfprotov5.Diagnostic{
35+
{
36+
Summary: fmt.Sprintf(format, args...),
37+
},
38+
},
39+
}
40+
41+
}
42+
func listFunc(ctx context.Context, req list.ListRequest, stream *list.ListResultsStream) {
43+
sdkResource, ok := SDKResourceFromContext(ctx)
44+
if !ok {
45+
return
46+
}
47+
48+
stream.Proto5Results = func(push func(tfprotov5.ListResourceResult) bool) {
49+
// From the resource type, we can obtain an initialized ResourceData value
50+
d := sdkResource.Data(&terraformsdk.InstanceState{ID: "#groot"})
51+
52+
// The initialized ResourceData value is schema-aware
53+
if err := d.Set("name", "Groot"); err != nil {
54+
push(diagnosticResult("Error setting `name`: %v", err))
55+
return
56+
}
57+
58+
if err := d.Set("nom", "groot"); err == nil {
59+
push(diagnosticResult("False negative outcome: `nom` is not a schema attribute"))
60+
return
61+
}
62+
63+
displayName := "I am Groot"
64+
65+
// Mimic SDK GRPCProviderServer.ReadResource ResourceData -> MsgPack
66+
state := d.State()
67+
if state == nil {
68+
push(diagnosticResult("Expected state to be non-nil"))
69+
return
70+
}
71+
72+
schemaBlock := sdkResource.CoreConfigSchema()
73+
if schemaBlock == nil {
74+
push(diagnosticResult("Expected schemaBlock to be non-nil"))
75+
return
76+
}
77+
78+
// We've copied hcl2shim wholesale for purposes of making the test pass
79+
newStateVal, err := hcl2shim.HCL2ValueFromFlatmap(state.Attributes, schemaBlock.ImpliedType())
80+
if err != nil {
81+
push(diagnosticResult("Error converting state attributes to HCL2 value: %v", err))
82+
return
83+
}
84+
85+
// Think about this later
86+
// newStateVal = normalizeNullValues(newStateVal, stateVal, false)
87+
88+
pack, err := msgpack.Marshal(newStateVal, schemaBlock.ImpliedType())
89+
if err != nil {
90+
push(diagnosticResult("Error marshaling new state value to MsgPack: %v", err))
91+
return
92+
}
93+
94+
fmt.Printf("MsgPack: %s\n", pack)
95+
96+
// Construct a tfprotov5.ListResourceResult
97+
listResult := tfprotov5.ListResourceResult{}
98+
listResult.Resource = &tfprotov5.DynamicValue{MsgPack: pack}
99+
listResult.DisplayName = displayName
100+
101+
if !push(listResult) {
102+
return
103+
}
104+
}
105+
}
106+
107+
func TestServerListResourceProto5ToProto5(t *testing.T) {
108+
t.Parallel()
109+
110+
server := func(listResource func() list.ListResource) *Server {
111+
return &Server{
112+
FrameworkServer: fwserver.Server{
113+
Provider: &testprovider.Provider{
114+
ListResourcesMethod: func(ctx context.Context) []func() list.ListResource {
115+
return []func() list.ListResource{listResource}
116+
},
117+
},
118+
},
119+
}
120+
}
121+
122+
listResource := func() list.ListResource {
123+
return &testprovider.ListResource{
124+
ListMethod: listFunc,
125+
MetadataMethod: func(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
126+
resp.TypeName = "test_resource"
127+
},
128+
}
129+
}
130+
aServer := server(listResource)
131+
132+
ctx := context.Background()
133+
ctx = NewContextWithSDKResource(ctx, &sdkResource)
134+
req := &tfprotov5.ListResourceRequest{
135+
TypeName: "test_resource",
136+
}
137+
138+
stream, err := aServer.ListResource(ctx, req)
139+
if err != nil {
140+
t.Fatalf("unexpected error returned from ListResource: %v", err)
141+
}
142+
143+
values := slices.Collect(stream.Results)
144+
if len(values) > 0 {
145+
if len(values[0].Diagnostics) > 0 {
146+
for _, diag := range values[0].Diagnostics {
147+
t.Logf("unexpected diagnostic returned from ListResource: %v", diag)
148+
}
149+
t.FailNow()
150+
}
151+
}
152+
153+
if len(values) != 1 {
154+
t.Fatalf("expected 1 list result; got %d list results", len(values))
155+
}
156+
157+
value := values[0]
158+
if value.DisplayName != "I am Groot" {
159+
t.Fatalf("I am not Groot")
160+
}
161+
}

list/list_resource.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
1212
"github.com/hashicorp/terraform-plugin-framework/resource"
1313
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
14+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
1415
)
1516

1617
// ListResource represents an implementation of listing instances of a managed resource
@@ -130,7 +131,8 @@ type ListResultsStream struct {
130131
//
131132
// To indicate a fatal processing error, push a [ListResult] that contains
132133
// a [diag.ErrorDiagnostic].
133-
Results iter.Seq[ListResult]
134+
Results iter.Seq[ListResult]
135+
Proto5Results iter.Seq[tfprotov5.ListResourceResult]
134136
}
135137

136138
// NoListResults is an iterator that pushes zero results.

0 commit comments

Comments
 (0)