diff --git a/plugin/grpc_provider.go b/plugin/grpc_provider.go index 60586d399..495347bfd 100644 --- a/plugin/grpc_provider.go +++ b/plugin/grpc_provider.go @@ -603,14 +603,17 @@ func (p *GRPCProvider) Close() error { // Decode a DynamicValue from either the JSON or MsgPack encoding. func decodeDynamicValue(v *proto.DynamicValue, ty cty.Type) (cty.Value, error) { // always return a valid value + var err error res := cty.NullVal(ty) if v == nil { return res, nil } - if len(v.Msgpack) > 0 { - return msgpack.Unmarshal(v.Msgpack, ty) + switch { + case len(v.Msgpack) > 0: + res, err = msgpack.Unmarshal(v.Msgpack, ty) + case len(v.Json) > 0: + res, err = ctyjson.Unmarshal(v.Json, ty) } - - return ctyjson.Unmarshal(v.Json, ty) + return res, err } diff --git a/plugin/grpc_provider_test.go b/plugin/grpc_provider_test.go index 3746ae220..9cf2dca31 100644 --- a/plugin/grpc_provider_test.go +++ b/plugin/grpc_provider_test.go @@ -310,6 +310,38 @@ func TestGRPCProvider_ReadResourceJSON(t *testing.T) { } } +func TestGRPCProvider_ReadEmptyJSON(t *testing.T) { + client := mockProviderClient(t) + p := &GRPCProvider{ + client: client, + } + + client.EXPECT().ReadResource( + gomock.Any(), + gomock.Any(), + ).Return(&proto.ReadResource_Response{ + NewState: &proto.DynamicValue{ + Json: []byte(``), + }, + }, nil) + + obj := cty.ObjectVal(map[string]cty.Value{ + "attr": cty.StringVal("foo"), + }) + resp := p.ReadResource(providers.ReadResourceRequest{ + TypeName: "resource", + PriorState: obj, + }) + + checkDiags(t, resp.Diagnostics) + + expected := cty.NullVal(obj.Type()) + + if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) { + t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty)) + } +} + func TestGRPCProvider_PlanResourceChange(t *testing.T) { client := mockProviderClient(t) p := &GRPCProvider{