Skip to content

Commit 73a8116

Browse files
authored
Dynamic Provider: Add tests for Delete and Update (#2111)
1 parent 690347b commit 73a8116

File tree

11 files changed

+371
-200
lines changed

11 files changed

+371
-200
lines changed

dynamic/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ test.unit:
1111
go test -short ${LDFLAGS} ./...
1212

1313
test:
14-
cd internal/shim && go test ${LDFLAGS} ./...
15-
go test ${LDFLAGS} ./... -count 1
14+
cd internal/shim && go test -v ${LDFLAGS} ./...
15+
go test -v ${LDFLAGS} ./...
1616

1717
test.update:
18-
go test ${LDFLAGS} ./... -update
18+
go test -v ${LDFLAGS} ./... -update
1919

2020
bin:
2121
mkdir bin

dynamic/internal/shim/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ func runProvider(ctx context.Context, meta *providercache.CachedProvider) (Provi
203203
Logger: logging.NewProviderLogger(""),
204204
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
205205
Managed: true,
206-
Cmd: exec.Command(execFile),
206+
Cmd: exec.CommandContext(ctx, execFile),
207207
AutoMTLS: true,
208208
VersionedPlugins: tfplugin.VersionedPlugins,
209209
SyncStdout: logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", meta.Provider)),

dynamic/provider_test.go

Lines changed: 210 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,13 @@ func TestPrimitiveTypes(t *testing.T) {
5454

5555
grpc := grpcTestServer(ctx, t)
5656

57-
_, err := grpc.Parameterize(ctx, &pulumirpc.ParameterizeRequest{
57+
t.Run("parameterize", assertGRPCCall(grpc.Parameterize, &pulumirpc.ParameterizeRequest{
5858
Parameters: &pulumirpc.ParameterizeRequest_Args{
5959
Args: &pulumirpc.ParameterizeRequest_ParametersArgs{
6060
Args: []string{pfProviderPath(t)},
6161
},
6262
},
63-
})
64-
require.NoError(t, err)
63+
}, noParallel))
6564

6665
inputProps := func() resource.PropertyMap {
6766
return resource.PropertyMap{
@@ -73,119 +72,218 @@ func TestPrimitiveTypes(t *testing.T) {
7372
}
7473
}
7574

76-
inputs := func() *structpb.Struct {
77-
return must(plugin.MarshalProperties(inputProps(), plugin.MarshalOptions{}))
75+
inputs := func() *structpb.Struct { return marshal(inputProps()) }
76+
77+
with := func(base, layer resource.PropertyMap) resource.PropertyMap {
78+
dst := base.Copy()
79+
for k, v := range layer {
80+
dst[k] = v
81+
}
82+
return dst
7883
}
7984

8085
outputProps := func() resource.PropertyMap {
81-
props := inputProps()
82-
props["attrStringDefault"] = resource.NewProperty("default-value")
83-
return props
86+
return with(inputProps(), resource.PropertyMap{
87+
"attrStringDefault": resource.NewProperty("default-value"),
88+
"attrStringComputed": resource.NewProperty("t"),
89+
"id": resource.NewProperty("output-id"),
90+
})
8491
}
8592

86-
outputs := func() *structpb.Struct {
87-
return must(plugin.MarshalProperties(outputProps(), plugin.MarshalOptions{}))
88-
}
93+
outputs := func() *structpb.Struct { return marshal(outputProps()) }
8994

9095
urn := string(resource.NewURN(
9196
"test", "test", "", "pfprovider:index/primitive:Primitive", "prim",
9297
))
9398

94-
t.Run("check", func(t *testing.T) {
95-
resp, err := grpc.Check(ctx, &pulumirpc.CheckRequest{
96-
Urn: urn,
97-
News: inputs(),
98-
})
99-
require.NoError(t, err)
100-
assertGRPC(t, resp)
101-
})
99+
t.Run("check", assertGRPCCall(grpc.Check, &pulumirpc.CheckRequest{
100+
Urn: urn,
101+
News: inputs(),
102+
}))
103+
104+
t.Run("create(preview)", assertGRPCCall(grpc.Create, &pulumirpc.CreateRequest{
105+
Preview: true,
106+
Urn: urn,
107+
Properties: inputs(),
108+
}))
109+
110+
t.Run("create", assertGRPCCall(grpc.Create, &pulumirpc.CreateRequest{
111+
Urn: urn,
112+
Properties: inputs(),
113+
}))
114+
115+
t.Run("diff(none)", assertGRPCCall(grpc.Diff, &pulumirpc.DiffRequest{
116+
Id: "example-id-0",
117+
Urn: urn,
118+
Olds: outputs(),
119+
News: inputs(),
120+
OldInputs: inputs(),
121+
}))
122+
123+
t.Run("diff(some)", assertGRPCCall(grpc.Diff, &pulumirpc.DiffRequest{
124+
Id: "example-id-1",
125+
Urn: urn,
126+
Olds: marshal(resource.PropertyMap{
127+
"attrBoolComputed": resource.NewProperty(false),
128+
"attrBoolRequired": resource.NewProperty(true),
129+
"attrIntComputed": resource.NewProperty(128.0),
130+
"attrIntRequired": resource.NewProperty(64.0),
131+
"attrNumberRequired": resource.NewProperty(12.3456),
132+
"attrStringComputed": resource.NewProperty("t"),
133+
"attrStringRequired": resource.NewProperty("s"),
134+
"id": resource.NewProperty("example-id"),
135+
}),
136+
News: marshal(resource.PropertyMap{
137+
"attrBoolRequired": resource.NewProperty(true),
138+
"attrStringRequired": resource.NewProperty("u"),
139+
"attrIntRequired": resource.NewProperty(64.0),
140+
"attrStringDefaultOverridden": resource.NewProperty("overridden"),
141+
}),
142+
OldInputs: inputs(),
143+
}))
144+
145+
t.Run("diff(all)", assertGRPCCall(grpc.Diff, &pulumirpc.DiffRequest{
146+
Id: "example-id-2",
147+
Urn: urn,
148+
Olds: marshal(resource.PropertyMap{
149+
"attrBoolComputed": resource.NewProperty(false),
150+
"attrBoolRequired": resource.NewProperty(true),
151+
"attrIntComputed": resource.NewProperty(128.0),
152+
"attrIntRequired": resource.NewProperty(64.0),
153+
"attrNumberRequired": resource.NewProperty(12.3456),
154+
"attrStringComputed": resource.NewProperty("t"),
155+
"attrStringRequired": resource.NewProperty("s"),
156+
"id": resource.NewProperty("example-id"),
157+
}),
158+
News: marshal(resource.PropertyMap{
159+
"attrBoolRequired": resource.NewProperty(false),
160+
"attrStringRequired": resource.NewProperty("u"),
161+
"attrIntRequired": resource.NewProperty(65.0),
162+
"attrNumberRequired": resource.NewProperty(12.3456789),
163+
}),
164+
OldInputs: inputs(),
165+
}))
166+
167+
t.Run("delete", assertGRPCCall(grpc.Delete, &pulumirpc.DeleteRequest{
168+
Id: "example-id-delete",
169+
Urn: urn,
170+
Properties: outputs(),
171+
}))
172+
173+
t.Run("update", assertGRPCCall(grpc.Update, &pulumirpc.UpdateRequest{
174+
Id: "example-update-id",
175+
Urn: urn,
176+
Olds: outputs(),
177+
News: marshal(with(outputProps(), resource.PropertyMap{
178+
"attrBoolRequired": resource.NewProperty(false),
179+
})),
180+
}))
181+
182+
t.Run("read", assertGRPCCall(grpc.Read, &pulumirpc.ReadRequest{
183+
Id: "example-read-id",
184+
Urn: urn,
185+
Properties: outputs(),
186+
}))
187+
188+
t.Run("import", assertGRPCCall(grpc.Read, &pulumirpc.ReadRequest{
189+
Id: "example-read-id",
190+
Urn: urn,
191+
}))
192+
}
102193

103-
t.Run("create(preview)", func(t *testing.T) {
104-
resp, err := grpc.Create(ctx, &pulumirpc.CreateRequest{
105-
Preview: true,
106-
Urn: urn,
107-
Properties: inputs(),
108-
})
109-
require.NoError(t, err)
110-
assertGRPC(t, resp)
111-
})
194+
func TestConfigure(t *testing.T) {
195+
t.Parallel()
196+
skipWindows(t)
112197

113-
t.Run("create", func(t *testing.T) {
114-
resp, err := grpc.Create(ctx, &pulumirpc.CreateRequest{
115-
Urn: urn,
116-
Properties: inputs(),
117-
})
118-
require.NoError(t, err)
119-
assertGRPC(t, resp)
120-
})
198+
s := grpcTestServer(context.Background(), t)
121199

122-
t.Run("diff(none)", func(t *testing.T) {
123-
resp, err := grpc.Diff(ctx, &pulumirpc.DiffRequest{
124-
Id: "example-id-0",
125-
Urn: urn,
126-
Olds: outputs(),
127-
News: inputs(),
128-
OldInputs: inputs(),
129-
})
130-
require.NoError(t, err)
131-
assertGRPC(t, resp)
132-
})
200+
t.Run("parameterize", assertGRPCCall(s.Parameterize, &pulumirpc.ParameterizeRequest{
201+
Parameters: &pulumirpc.ParameterizeRequest_Args{
202+
Args: &pulumirpc.ParameterizeRequest_ParametersArgs{
203+
Args: []string{pfProviderPath(t)},
204+
},
205+
},
206+
}, noParallel, expect(autogold.Expect(`{
207+
"name": "pfprovider",
208+
"version": "0.0.0"
209+
}`))))
210+
211+
t.Run("check-config", assertGRPCCall(s.CheckConfig, &pulumirpc.CheckRequest{
212+
News: marshal(resource.PropertyMap{
213+
"endpoint": resource.NewProperty("explicit endpoint"),
214+
}),
215+
}, expect(autogold.Expect(`{
216+
"inputs": {
217+
"endpoint": "explicit endpoint"
218+
}
219+
}`))))
220+
221+
// TODO: This should error
222+
t.Run("check-config (invalid)", assertGRPCCall(s.CheckConfig, &pulumirpc.CheckRequest{
223+
News: marshal(resource.PropertyMap{
224+
"endpoint": resource.NewProperty(123.456),
225+
}),
226+
}, expect(autogold.Expect(`{
227+
"inputs": {
228+
"endpoint": 123.456
229+
}
230+
}`))))
231+
232+
t.Run("configure (args)", assertGRPCCall(s.Configure, &pulumirpc.ConfigureRequest{
233+
Args: marshal(resource.PropertyMap{
234+
"endpoint": resource.NewProperty("my-endpoint"),
235+
}),
236+
}, expect(autogold.Expect(`{
237+
"acceptResources": true,
238+
"supportsPreview": true
239+
}`))))
240+
241+
t.Run("validate config", assertGRPCCall(s.Invoke, &pulumirpc.InvokeRequest{
242+
Tok: "pfprovider:index/getConfigEndpoint:getConfigEndpoint",
243+
}, expect(autogold.Expect(`{
244+
"return": {
245+
"endpoint": "my-endpoint"
246+
}
247+
}`))))
248+
}
133249

134-
t.Run("diff(some)", func(t *testing.T) {
135-
resp, err := grpc.Diff(ctx, &pulumirpc.DiffRequest{
136-
Id: "example-id-1",
137-
Urn: urn,
138-
Olds: must(plugin.MarshalProperties(resource.PropertyMap{
139-
"attrBoolComputed": resource.NewProperty(false),
140-
"attrBoolRequired": resource.NewProperty(true),
141-
"attrIntComputed": resource.NewProperty(128.0),
142-
"attrIntRequired": resource.NewProperty(64.0),
143-
"attrNumberRequired": resource.NewProperty(12.3456),
144-
"attrStringComputed": resource.NewProperty("t"),
145-
"attrStringRequired": resource.NewProperty("s"),
146-
"id": resource.NewProperty("example-id"),
147-
}, plugin.MarshalOptions{})),
148-
News: must(plugin.MarshalProperties(resource.PropertyMap{
149-
"attrBoolRequired": resource.NewProperty(true),
150-
"attrStringRequired": resource.NewProperty("u"),
151-
"attrIntRequired": resource.NewProperty(64.0),
152-
"attrStringDefaultOverridden": resource.NewProperty("overridden"),
153-
}, plugin.MarshalOptions{})),
154-
OldInputs: inputs(),
155-
})
156-
require.NoError(t, err)
157-
assertGRPC(t, resp)
158-
})
250+
type assertGRPCCallOptions struct {
251+
noParallel bool
252+
expect autogold.Value
253+
}
159254

160-
t.Run("diff(all)", func(t *testing.T) {
161-
resp, err := grpc.Diff(ctx, &pulumirpc.DiffRequest{
162-
Id: "example-id-2",
163-
Urn: urn,
164-
Olds: must(plugin.MarshalProperties(resource.PropertyMap{
165-
"attrBoolComputed": resource.NewProperty(false),
166-
"attrBoolRequired": resource.NewProperty(true),
167-
"attrIntComputed": resource.NewProperty(128.0),
168-
"attrIntRequired": resource.NewProperty(64.0),
169-
"attrNumberRequired": resource.NewProperty(12.3456),
170-
"attrStringComputed": resource.NewProperty("t"),
171-
"attrStringRequired": resource.NewProperty("s"),
172-
"id": resource.NewProperty("example-id"),
173-
}, plugin.MarshalOptions{})),
174-
News: must(plugin.MarshalProperties(resource.PropertyMap{
175-
"attrBoolRequired": resource.NewProperty(false),
176-
"attrStringRequired": resource.NewProperty("u"),
177-
"attrIntRequired": resource.NewProperty(65.0),
178-
"attrNumberRequired": resource.NewProperty(12.3456789),
179-
}, plugin.MarshalOptions{})),
180-
OldInputs: inputs(),
181-
})
255+
func noParallel(o *assertGRPCCallOptions) { o.noParallel = true }
256+
257+
func expect(v autogold.Value) assertGRPCCallOption {
258+
return func(o *assertGRPCCallOptions) {
259+
o.expect = v
260+
}
261+
}
262+
263+
type assertGRPCCallOption func(*assertGRPCCallOptions)
264+
265+
// assertGRPCCall makes a gRPC call and then asserts on the result using [assertGRPC].
266+
func assertGRPCCall[T any, R proto.Message](
267+
method func(context.Context, T) (R, error), req T,
268+
opts ...assertGRPCCallOption,
269+
) func(*testing.T) {
270+
var o assertGRPCCallOptions
271+
for _, opt := range opts {
272+
opt(&o)
273+
}
274+
return func(t *testing.T) {
275+
t.Helper()
276+
if !o.noParallel {
277+
t.Parallel()
278+
}
279+
resp, err := method(context.Background(), req)
182280
require.NoError(t, err)
183-
assertGRPC(t, resp)
184-
})
281+
assertGRPC(t, resp, o.expect)
282+
}
185283
}
186284

187285
// assertGRPC uses autogold to check/save msg.
188-
func assertGRPC(t *testing.T, msg proto.Message) {
286+
func assertGRPC(t *testing.T, msg proto.Message, v autogold.Value) {
189287
t.Helper()
190288
j, err := protojson.MarshalOptions{
191289
Multiline: true,
@@ -202,7 +300,11 @@ func assertGRPC(t *testing.T, msg proto.Message) {
202300
require.NoError(t, json.Unmarshal(j, &m))
203301
j, err = json.MarshalIndent(m, "", " ")
204302
require.NoError(t, err)
205-
autogold.ExpectFile(t, autogold.Raw(string(j)))
303+
if v == nil {
304+
autogold.ExpectFile(t, autogold.Raw(string(j)))
305+
} else {
306+
v.Equal(t, string(j))
307+
}
206308
}
207309

208310
// pfProviderPath returns the path the the PF provider binary for use in testing.
@@ -218,13 +320,17 @@ var pfProviderPath = func() func(t *testing.T) string {
218320
out := filepath.Join(globalTempDir, "terraform-provider-pfprovider")
219321
cmd := exec.Command("go", "build", "-o", out, "github.com/pulumi/pulumi-terraform-bridge/dynamic/tests/pfprovider")
220322
cmd.Dir = filepath.Join(wd, "test", "pfprovider")
221-
return out, cmd.Run()
323+
stdoutput, err := cmd.CombinedOutput()
324+
if err != nil {
325+
return "", fmt.Errorf("failed to build provider: %w:\n%s", err, string(stdoutput))
326+
}
327+
return out, nil
222328
})
223329

224330
return func(t *testing.T) string {
225331
t.Helper()
226332
path, err := mkBin()
227-
require.NoError(t, err)
333+
require.NoErrorf(t, err, "failed find provider path")
228334
return path
229335
}
230336
}()
@@ -350,3 +456,7 @@ func must[T any](v T, err error) T {
350456
}
351457
return v
352458
}
459+
460+
func marshal(m resource.PropertyMap) *structpb.Struct {
461+
return must(plugin.MarshalProperties(m, plugin.MarshalOptions{}))
462+
}

0 commit comments

Comments
 (0)