diff --git a/helper/plugin/grpc_provider.go b/helper/plugin/grpc_provider.go index 7df45862e..83ab81f84 100644 --- a/helper/plugin/grpc_provider.go +++ b/helper/plugin/grpc_provider.go @@ -502,7 +502,14 @@ func (s *GRPCProviderServer) ApplyResourceChange(_ context.Context, req *proto.A return resp, nil } + if diff == nil { + diff = &terraform.InstanceDiff{ + Attributes: make(map[string]*terraform.ResourceAttrDiff), + Meta: make(map[string]interface{}), + } + } diff.Meta = private + newInstanceState, err := s.provider.Apply(info, priorState, diff) if err != nil { resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err) diff --git a/helper/plugin/grpc_provider_test.go b/helper/plugin/grpc_provider_test.go index f95e18491..4e8c518ad 100644 --- a/helper/plugin/grpc_provider_test.go +++ b/helper/plugin/grpc_provider_test.go @@ -357,3 +357,71 @@ func TestPlanResourceChange(t *testing.T) { t.Fatal(cmp.Diff(proposedVal, plannedStateVal, valueComparer)) } } + +func TestApplyResourceChange(t *testing.T) { + r := &schema.Resource{ + SchemaVersion: 4, + Schema: map[string]*schema.Schema{ + "foo": { + Type: schema.TypeInt, + Optional: true, + }, + }, + Create: func(rd *schema.ResourceData, _ interface{}) error { + rd.SetId("bar") + return nil + }, + } + + server := &GRPCProviderServer{ + provider: &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test": r, + }, + }, + } + + schema := r.CoreConfigSchema() + priorState, err := msgpack.Marshal(cty.NullVal(schema.ImpliedType()), schema.ImpliedType()) + if err != nil { + t.Fatal(err) + } + + // A propsed state with only the ID unknown will produce a nil diff, and + // should return the propsed state value. + plannedVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{ + "id": cty.UnknownVal(cty.String), + })) + if err != nil { + t.Fatal(err) + } + plannedState, err := msgpack.Marshal(plannedVal, schema.ImpliedType()) + if err != nil { + t.Fatal(err) + } + + testReq := &proto.ApplyResourceChange_Request{ + TypeName: "test", + PriorState: &proto.DynamicValue{ + Msgpack: priorState, + }, + PlannedState: &proto.DynamicValue{ + Msgpack: plannedState, + }, + } + + resp, err := server.ApplyResourceChange(context.Background(), testReq) + if err != nil { + t.Fatal(err) + } + + newStateVal, err := msgpack.Unmarshal(resp.NewState.Msgpack, schema.ImpliedType()) + if err != nil { + t.Fatal(err) + } + + id := newStateVal.GetAttr("id").AsString() + if id != "bar" { + t.Fatalf("incorrect final state: %#v\n", newStateVal) + } +}