Repository: pulumi/pulumi-terraform-bridge
Pull request #1316 (2023-07-31 20:27:08)

Autonaming: deprecate DefaultInfo.From
This PR is the first in a series of changes to get Autonaming working for Plugin Framework providers; broken down into commits for easier review. The key change is to move from DefaultInfo.From to DefaultInfo.ComputeDefault. The ComputeDefaultOptions structure is there to extend with further context on the location where defaults are being computed, which is needed in subsequent PRs.

github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/49a5d41..c9b3151) with merge commit c0183bb9208c4bd0871a23675724be13615c7784
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/67a6eb2..87a0efa) with merge commit c0183bb9208c4bd0871a23675724be13615c7784
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/c2032a1..5698596) with merge commit 0f15a589d22e1e982dab7f2513169e53f9ef8356
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/5106567..29997dd) with merge commit 0f15a589d22e1e982dab7f2513169e53f9ef8356

Patch:
diff --git a/pf/internal/defaults/defaults.go b/pf/internal/defaults/defaults.go
index b22a70bd..1a81c6bb 100644
--- a/pf/internal/defaults/defaults.go
+++ b/pf/internal/defaults/defaults.go
@@ -40,8 +40,8 @@ type ApplyDefaultInfoValuesArgs struct {
 	// Toplevel SchemaInfo configuration matching TopSchemaMap.
 	SchemaInfos map[string]*tfbridge.SchemaInfo
 
-	// Optional. Note that ResourceInstance need not be specified for Invoke or Configure processing.
-	ResourceInstance *tfbridge.PulumiResource
+	// Note that URN need not be specified for Invoke or Configure processing.
+	ComputeDefaultOptions tfbridge.ComputeDefaultOptions
 
 	// Optional. If known, these are the provider-level configuration values, to support DefaultInfo.Config.
 	ProviderConfig resource.PropertyMap
@@ -60,10 +60,10 @@ func ApplyDefaultInfoValues(ctx context.Context, args ApplyDefaultInfoValuesArgs
 	}
 
 	t := &defaultsTransform{
-		resourceInstance: args.ResourceInstance,
-		topSchemaMap:     args.SchemaMap,
-		topFieldInfos:    args.SchemaInfos,
-		providerConfig:   args.ProviderConfig,
+		computeDefaultOptions: args.ComputeDefaultOptions,
+		topSchemaMap:          args.SchemaMap,
+		topFieldInfos:         args.SchemaInfos,
+		providerConfig:        args.ProviderConfig,
 	}
 	result := t.withDefaults(ctx, make(resource.PropertyPath, 0), resource.NewObjectProperty(args.PropertyMap))
 	contract.Assertf(result.IsObject(), "defaultsTransform.withDefaults returned a non-object value")
@@ -73,7 +73,7 @@ func ApplyDefaultInfoValues(ctx context.Context, args ApplyDefaultInfoValuesArgs
 func getDefaultValue(
 	ctx context.Context,
 	property resource.PropertyKey,
-	res *tfbridge.PulumiResource,
+	cdOptions tfbridge.ComputeDefaultOptions,
 	fieldSchema shim.Schema,
 	defaultInfo *tfbridge.DefaultInfo,
 	providerConfig resource.PropertyMap,
@@ -133,8 +133,26 @@ func getDefaultValue(
 				"property": string(property),
 			})
 		return recoverDefaultValue(defaultInfo.Value), true
-	} else if defaultInfo.From != nil && res != nil {
-		raw, err := defaultInfo.From(res)
+	} else if defaultInfo.ComputeDefault != nil {
+		raw, err := defaultInfo.ComputeDefault(ctx, cdOptions)
+		if err != nil {
+			msg := fmt.Errorf("Failed computing a default value for property '%s': %w",
+				string(property), err)
+			tflog.Error(ctx, msg.Error())
+			return na, false
+		}
+		if raw == nil {
+			return na, false
+		}
+		tflog.Trace(ctx, "DefaultInfo.ComputeDefault applied a computed default value",
+			map[string]any{"property": string(property)})
+		return recoverDefaultValue(raw), true
+	} else if defaultInfo.From != nil {
+		raw, err := defaultInfo.From(&tfbridge.PulumiResource{
+			URN:        cdOptions.URN,
+			Properties: cdOptions.Properties,
+			Seed:       cdOptions.Seed,
+		})
 		if err != nil {
 			msg := fmt.Errorf("Failed computing a default value for property '%s': %w",
 				string(property), err)
@@ -190,19 +208,10 @@ func recoverDefaultValue(defaultValue any) resource.PropertyValue {
 }
 
 type defaultsTransform struct {
-	topSchemaMap     shim.SchemaMap
-	topFieldInfos    map[string]*tfbridge.SchemaInfo // optional
-	resourceInstance *tfbridge.PulumiResource        // optional
-	providerConfig   resource.PropertyMap            // optional
-}
-
-// Returns a non-nil resourceInstance only if the defaults are being applied to a resource at the top level.
-func (du *defaultsTransform) resourceByPath(path resource.PropertyPath) *tfbridge.PulumiResource {
-	var res *tfbridge.PulumiResource
-	if len(path) == 0 {
-		res = du.resourceInstance
-	}
-	return res
+	topSchemaMap          shim.SchemaMap
+	topFieldInfos         map[string]*tfbridge.SchemaInfo // optional
+	computeDefaultOptions tfbridge.ComputeDefaultOptions
+	providerConfig        resource.PropertyMap // optional
 }
 
 // Returns matching object schema for a context determined by the PropertyPath, if any.
@@ -273,7 +282,7 @@ func (du *defaultsTransform) extendPropertyMapWithDefaults(
 		// using default value for empty property
 		pv, gotDefault := getDefaultValue(ctx,
 			pk,
-			du.resourceByPath(path),
+			du.computeDefaultOptions,
 			fieldSchema,
 			fld.Default,
 			du.providerConfig)
diff --git a/pf/internal/schemashim/provider.go b/pf/internal/schemashim/provider.go
index c1605871..da015529 100644
--- a/pf/internal/schemashim/provider.go
+++ b/pf/internal/schemashim/provider.go
@@ -86,7 +86,7 @@ func (p *SchemaOnlyProvider) Apply(t string, s shim.InstanceState,
 	panic("schemaOnlyProvider does not implement runtime operation Apply")
 }
 
-func (p *SchemaOnlyProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (p *SchemaOnlyProvider) Refresh(string, shim.InstanceState, shim.ResourceConfig) (shim.InstanceState, error) {
 	panic("schemaOnlyProvider does not implement runtime operation Refresh")
 }
 
diff --git a/pf/tfbridge/provider_check.go b/pf/tfbridge/provider_check.go
index 03a3049d..2f0dff87 100644
--- a/pf/tfbridge/provider_check.go
+++ b/pf/tfbridge/provider_check.go
@@ -46,11 +46,20 @@ func (p *provider) CheckWithContext(
 		return checkedInputs, []plugin.CheckFailure{}, err
 	}
 
+	if info := rh.pulumiResourceInfo; info != nil {
+		if check := info.PreCheckCallback; check != nil {
+			checkedInputs, err := check(ctx, checkedInputs, p.lastKnownProviderConfig.Copy())
+			if err != nil {
+				return checkedInputs, []plugin.CheckFailure{}, err
+			}
+		}
+	}
+
 	// Transform checkedInputs to apply Pulumi-level defaults.
 	news := defaults.ApplyDefaultInfoValues(ctx, defaults.ApplyDefaultInfoValuesArgs{
 		SchemaMap:   rh.schemaOnlyShimResource.Schema(),
 		SchemaInfos: rh.pulumiResourceInfo.Fields,
-		ResourceInstance: &tfbridge.PulumiResource{
+		ComputeDefaultOptions: tfbridge.ComputeDefaultOptions{
 			URN:        urn,
 			Properties: checkedInputs,
 			Seed:       randomSeed,
diff --git a/pf/tfbridge/provider_configure.go b/pf/tfbridge/provider_configure.go
index 48a63db8..fc506cb2 100644
--- a/pf/tfbridge/provider_configure.go
+++ b/pf/tfbridge/provider_configure.go
@@ -29,6 +29,8 @@ import (
 func (p *provider) ConfigureWithContext(ctx context.Context, inputs resource.PropertyMap) error {
 	ctx = p.initLogging(ctx, p.logSink, "")
 
+	p.lastKnownProviderConfig = inputs
+
 	config, err := convert.EncodePropertyMapToDynamic(p.configEncoder, p.configType, inputs)
 	if err != nil {
 		return fmt.Errorf("cannot encode provider configuration to call ConfigureProvider: %w", err)
diff --git a/pkg/tfbridge/info.go b/pkg/tfbridge/info.go
index f0fa5d13..310225d6 100644
--- a/pkg/tfbridge/info.go
+++ b/pkg/tfbridge/info.go
@@ -292,8 +292,15 @@ type ResourceInfo struct {
 	// Optional hook to run before upgrading the state. TODO[pulumi/pulumi-terraform-bridge#864] this is currently
 	// only supported for Plugin-Framework based providers.
 	PreStateUpgradeHook PreStateUpgradeHook
+
+	// An experimental way to augment the Check function in the Pulumi life cycle.
+	PreCheckCallback PreCheckCallback
 }
 
+type PreCheckCallback = func(
+	ctx context.Context, config resource.PropertyMap, meta resource.PropertyMap,
+) (resource.PropertyMap, error)
+
 // GetTok returns a resource type token
 func (info *ResourceInfo) GetTok() tokens.Token { return tokens.Token(info.Tok) }
 
@@ -455,8 +462,14 @@ type DefaultInfo struct {
 	AutoNamed bool
 	// Config uses a configuration variable from this package as the default value.
 	Config string
-	// From applies a transformation from other resource properties.
+
+	// Deprecated. Use ComputeDefault.
 	From func(res *PulumiResource) (interface{}, error)
+
+	// ComputeDefault specifies how to compute a default value for the given property by consulting other properties
+	// such as the resource's URN. See [ComputeDefaultOptions] for all available information.
+	ComputeDefault func(ctx context.Context, opts ComputeDefaultOptions) (interface{}, error)
+
 	// Value injects a raw literal value as the default.
 	Value interface{}
 	// EnvVars to use for defaults. If none of these variables have values at runtime, the value of `Value` (if any)
@@ -464,6 +477,20 @@ type DefaultInfo struct {
 	EnvVars []string
 }
 
+// Configures [DefaultInfo.ComputeDefault].
+type ComputeDefaultOptions struct {
+	// URN identifying the Resource. Set when computing default properties for a Resource, and unset for functions.
+	URN resource.URN
+
+	// Property map before computing the defaults.
+	Properties resource.PropertyMap
+
+	// The engine provides a stable seed useful for generating random values consistently. This guarantees, for
+	// example, that random values generated across "pulumi preview" and "pulumi up" in the same deployment are
+	// consistent. This currently is only available for resource changes.
+	Seed []byte
+}
+
 // PulumiResource is just a little bundle that carries URN, seed and properties around.
 type PulumiResource struct {
 	URN        resource.URN
@@ -908,7 +935,7 @@ func MarshalDefaultInfo(d *DefaultInfo) *MarshallableDefaultInfo {
 
 	return &MarshallableDefaultInfo{
 		AutoNamed: d.AutoNamed,
-		IsFunc:    d.From != nil,
+		IsFunc:    d.From != nil || d.ComputeDefault != nil,
 		Value:     d.Value,
 		EnvVars:   d.EnvVars,
 	}
@@ -920,19 +947,18 @@ func (m *MarshallableDefaultInfo) Unmarshal() *DefaultInfo {
 		return nil
 	}
 
-	var f func(*PulumiResource) (interface{}, error)
-	if m.IsFunc {
-		f = func(*PulumiResource) (interface{}, error) {
-			panic("transforms cannot be run on unmarshaled DefaultInfo values")
-		}
-	}
-
-	return &DefaultInfo{
+	defInfo := &DefaultInfo{
 		AutoNamed: m.AutoNamed,
-		From:      f,
 		Value:     m.Value,
 		EnvVars:   m.EnvVars,
 	}
+
+	if m.IsFunc {
+		defInfo.ComputeDefault = func(context.Context, ComputeDefaultOptions) (interface{}, error) {
+			panic("transforms cannot be run on unmarshaled DefaultInfo values")
+		}
+	}
+	return defInfo
 }
 
 // MarshallableResourceInfo is the JSON-marshallable form of a Pulumi ResourceInfo value.
diff --git a/pkg/tfbridge/names.go b/pkg/tfbridge/names.go
index 12b83ba6..45c6489b 100644
--- a/pkg/tfbridge/names.go
+++ b/pkg/tfbridge/names.go
@@ -15,6 +15,7 @@
 package tfbridge
 
 import (
+	"context"
 	"fmt"
 	"unicode"
 
@@ -278,15 +279,18 @@ type AutoNameOptions struct {
 //
 // Note how the automatic name combines the resource name from the program with a random suffix.
 func AutoName(name string, maxlength int, separator string) *SchemaInfo {
+	autoNameOptions := AutoNameOptions{
+		Separator: separator,
+		Maxlen:    maxlength,
+		Randlen:   7,
+	}
 	return &SchemaInfo{
 		Name: name,
 		Default: &DefaultInfo{
 			AutoNamed: true,
-			From: FromName(AutoNameOptions{
-				Separator: separator,
-				Maxlen:    maxlength,
-				Randlen:   7,
-			}),
+			ComputeDefault: func(ctx context.Context, opts ComputeDefaultOptions) (interface{}, error) {
+				return ComputeAutoNameDefault(ctx, autoNameOptions, opts)
+			},
 		},
 	}
 }
@@ -297,7 +301,9 @@ func AutoNameWithCustomOptions(name string, options AutoNameOptions) *SchemaInfo
 		Name: name,
 		Default: &DefaultInfo{
 			AutoNamed: true,
-			From:      FromName(options),
+			ComputeDefault: func(ctx context.Context, opts ComputeDefaultOptions) (interface{}, error) {
+				return ComputeAutoNameDefault(ctx, options, opts)
+			},
 		},
 	}
 }
@@ -307,16 +313,19 @@ func AutoNameWithCustomOptions(name string, options AutoNameOptions) *SchemaInfo
 // transformation function. This makes it easy to propagate the Pulumi resource's URN name part as the Terraform name
 // as a convenient default, while still permitting it to be overridden.
 func AutoNameTransform(name string, maxlen int, transform func(string) string) *SchemaInfo {
+	autoNameOptions := AutoNameOptions{
+		Separator: "-",
+		Maxlen:    maxlen,
+		Randlen:   7,
+		Transform: transform,
+	}
 	return &SchemaInfo{
 		Name: name,
 		Default: &DefaultInfo{
 			AutoNamed: true,
-			From: FromName(AutoNameOptions{
-				Separator: "-",
-				Maxlen:    maxlen,
-				Randlen:   7,
-				Transform: transform,
-			}),
+			ComputeDefault: func(ctx context.Context, opts ComputeDefaultOptions) (interface{}, error) {
+				return ComputeAutoNameDefault(ctx, autoNameOptions, opts)
+			},
 		},
 	}
 }
@@ -324,22 +333,41 @@ func AutoNameTransform(name string, maxlen int, transform func(string) string) *
 // FromName automatically propagates a resource's URN onto the resulting default info.
 func FromName(options AutoNameOptions) func(res *PulumiResource) (interface{}, error) {
 	return func(res *PulumiResource) (interface{}, error) {
-		// Take the URN name part, transform it if required, and then append some unique characters if requested.
-		vs := string(res.URN.Name())
-		if options.Transform != nil {
-			vs = options.Transform(vs)
-		}
-		if options.Randlen > 0 {
-			uniqueHex, err := resource.NewUniqueName(
-				res.Seed, vs+options.Separator, options.Randlen, options.Maxlen, options.Charset)
-			if err != nil {
-				return uniqueHex, errors.Wrapf(err, "could not make instance of '%v'", res.URN.Type())
-			}
-			vs = uniqueHex
-		}
-		if options.PostTransform != nil {
-			return options.PostTransform(res, vs)
+		return ComputeAutoNameDefault(context.Background(), options, ComputeDefaultOptions{
+			URN:        res.URN,
+			Properties: res.Properties,
+			Seed:       res.Seed,
+		})
+	}
+}
+
+func ComputeAutoNameDefault(
+	ctx context.Context,
+	options AutoNameOptions,
+	defaultOptions ComputeDefaultOptions,
+) (interface{}, error) {
+	if defaultOptions.URN == "" {
+		return nil, fmt.Errorf("AutoName is onnly supported for resources, expected Resource URN to be set")
+	}
+	// Take the URN name part, transform it if required, and then append some unique characters if requested.
+	vs := string(defaultOptions.URN.Name())
+	if options.Transform != nil {
+		vs = options.Transform(vs)
+	}
+	if options.Randlen > 0 {
+		uniqueHex, err := resource.NewUniqueName(
+			defaultOptions.Seed, vs+options.Separator, options.Randlen, options.Maxlen, options.Charset)
+		if err != nil {
+			return uniqueHex, errors.Wrapf(err, "could not make instance of '%v'", defaultOptions.URN.Type())
 		}
-		return vs, nil
+		vs = uniqueHex
+	}
+	if options.PostTransform != nil {
+		return options.PostTransform(&PulumiResource{
+			URN:        defaultOptions.URN,
+			Properties: defaultOptions.Properties,
+			Seed:       defaultOptions.Seed,
+		}, vs)
 	}
+	return vs, nil
 }
diff --git a/pkg/tfbridge/provider.go b/pkg/tfbridge/provider.go
index 92b111a8..004dd6eb 100644
--- a/pkg/tfbridge/provider.go
+++ b/pkg/tfbridge/provider.go
@@ -567,6 +567,13 @@ func (p *Provider) Check(ctx context.Context, req *pulumirpc.CheckRequest) (*pul
 		return nil, err
 	}
 
+	if check := res.Schema.PreCheckCallback; check != nil {
+		news, err = check(ctx, news, p.configValues.Copy())
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	// Now fetch the default values so that (a) we can return them to the caller and (b) so that validation
 	// includes the default values.  Otherwise, the provider wouldn't be presented with its own defaults.
 	tfname := res.TFName
@@ -825,7 +832,12 @@ func (p *Provider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*pulum
 		}
 	}
 
-	newstate, err := p.tf.Refresh(res.TFName, state)
+	config, _, err := MakeTerraformConfig(p, oldInputs, res.TF.Schema(), res.Schema.Fields)
+	if err != nil {
+		return nil, errors.Wrapf(err, "preparing %s's new property state", urn)
+	}
+
+	newstate, err := p.tf.Refresh(res.TFName, state, config)
 	if err != nil {
 		return nil, errors.Wrapf(err, "refreshing %s", urn)
 	}
diff --git a/pkg/tfbridge/schema.go b/pkg/tfbridge/schema.go
index 9c8c9512..1a621ecd 100644
--- a/pkg/tfbridge/schema.go
+++ b/pkg/tfbridge/schema.go
@@ -15,6 +15,7 @@
 package tfbridge
 
 import (
+	"context"
 	"encoding/json"
 	"fmt"
 	"os"
@@ -683,6 +684,20 @@ func (ctx *conversionContext) applyDefaults(result map[string]interface{}, olds,
 				}
 			} else if info.Default.Value != nil {
 				defaultValue, source = info.Default.Value, "Pulumi schema"
+			} else if compute := info.Default.ComputeDefault; compute != nil {
+				v, err := compute(
+					// Getting the correct context needs to refactor public methods such as
+					// MakeTerraformInput to MakeTerraformInputWithContext.
+					context.TODO(),
+					ComputeDefaultOptions{
+						URN:        ctx.Instance.URN,
+						Properties: ctx.Instance.Properties,
+						Seed:       ctx.Instance.Seed,
+					})
+				if err != nil {
+					return err
+				}
+				defaultValue, source = v, "func"
 			} else if from := info.Default.From; from != nil {
 				v, err := from(ctx.Instance)
 				if err != nil {
@@ -690,7 +705,6 @@ func (ctx *conversionContext) applyDefaults(result map[string]interface{}, olds,
 				}
 				defaultValue, source = v, "func"
 			}
-
 			if defaultValue != nil {
 				glog.V(9).Infof("Created Terraform input: %v = %v (from %s)", name, defaultValue, source)
 				result[name] = defaultValue
diff --git a/pkg/tfshim/schema/provider.go b/pkg/tfshim/schema/provider.go
index 368dc9d1..8006016e 100644
--- a/pkg/tfshim/schema/provider.go
+++ b/pkg/tfshim/schema/provider.go
@@ -64,7 +64,7 @@ func (ProviderShim) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (
 	panic("this provider is schema-only and does not support runtime operations")
 }
 
-func (ProviderShim) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (ProviderShim) Refresh(t string, s shim.InstanceState, c shim.ResourceConfig) (shim.InstanceState, error) {
 	panic("this provider is schema-only and does not support runtime operations")
 }
 
diff --git a/pkg/tfshim/sdk-v1/provider.go b/pkg/tfshim/sdk-v1/provider.go
index a931464f..935631d9 100644
--- a/pkg/tfshim/sdk-v1/provider.go
+++ b/pkg/tfshim/sdk-v1/provider.go
@@ -98,7 +98,7 @@ func (p v1Provider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (
 	return stateToShim(state), err
 }
 
-func (p v1Provider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (p v1Provider) Refresh(t string, s shim.InstanceState, _ shim.ResourceConfig) (shim.InstanceState, error) {
 	state, err := p.tf.Refresh(instanceInfo(t), stateFromShim(s))
 	return stateToShim(state), err
 }
diff --git a/pkg/tfshim/sdk-v2/provider.go b/pkg/tfshim/sdk-v2/provider.go
index 78709867..f90b86f0 100644
--- a/pkg/tfshim/sdk-v2/provider.go
+++ b/pkg/tfshim/sdk-v2/provider.go
@@ -101,15 +101,26 @@ func (p v2Provider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (
 	return stateToShim(r, state), errors(diags)
 }
 
-func (p v2Provider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (p v2Provider) Refresh(t string, s shim.InstanceState, c shim.ResourceConfig) (shim.InstanceState, error) {
+	opts, err := getProviderOptions(p.opts)
+	if err != nil {
+		return nil, err
+	}
+
 	r, ok := p.tf.ResourcesMap[t]
 	if !ok {
 		return nil, fmt.Errorf("unknown resource %v", t)
 	}
+
 	state, err := upgradeResourceState(p.tf, r, stateFromShim(s))
 	if err != nil {
 		return nil, fmt.Errorf("failed to upgrade resource state: %w", err)
 	}
+
+	if c != nil {
+		state.RawConfig = makeResourceRawConfig(opts.diffStrategy, configFromShim(c), r)
+	}
+
 	state, diags := r.RefreshWithoutUpgrade(context.TODO(), state, p.tf.Meta())
 	return stateToShim(r, state), errors(diags)
 }
diff --git a/pkg/tfshim/shim.go b/pkg/tfshim/shim.go
index 767c888b..1663b0ca 100644
--- a/pkg/tfshim/shim.go
+++ b/pkg/tfshim/shim.go
@@ -194,7 +194,7 @@ type Provider interface {
 	Configure(c ResourceConfig) error
 	Diff(t string, s InstanceState, c ResourceConfig) (InstanceDiff, error)
 	Apply(t string, s InstanceState, d InstanceDiff) (InstanceState, error)
-	Refresh(t string, s InstanceState) (InstanceState, error)
+	Refresh(t string, s InstanceState, c ResourceConfig) (InstanceState, error)
 
 	ReadDataDiff(t string, c ResourceConfig) (InstanceDiff, error)
 	ReadDataApply(t string, d InstanceDiff) (InstanceState, error)
diff --git a/pkg/tfshim/tfplugin5/provider.go b/pkg/tfshim/tfplugin5/provider.go
index 07c62a8a..c3b62055 100644
--- a/pkg/tfshim/tfplugin5/provider.go
+++ b/pkg/tfshim/tfplugin5/provider.go
@@ -421,7 +421,7 @@ func (p *provider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (s
 	return newState, unmarshalErrors(resp.Diagnostics)
 }
 
-func (p *provider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (p *provider) Refresh(t string, s shim.InstanceState, _ shim.ResourceConfig) (shim.InstanceState, error) {
 	state, ok := s.(*instanceState)
 	if s != nil && !ok {
 		return nil, fmt.Errorf("internal error: foreign resource state")
diff --git a/pkg/tfshim/util/filter.go b/pkg/tfshim/util/filter.go
index 9eedbb7f..a7aec126 100644
--- a/pkg/tfshim/util/filter.go
+++ b/pkg/tfshim/util/filter.go
@@ -81,8 +81,8 @@ func (p *FilteringProvider) Apply(t string, s shim.InstanceState, d shim.Instanc
 	return p.Provider.Apply(t, s, d)
 }
 
-func (p *FilteringProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
-	return p.Provider.Refresh(t, s)
+func (p *FilteringProvider) Refresh(t string, s shim.InstanceState, c shim.ResourceConfig) (shim.InstanceState, error) {
+	return p.Provider.Refresh(t, s, c)
 }
 
 func (p *FilteringProvider) ReadDataDiff(t string, c shim.ResourceConfig) (shim.InstanceDiff, error) {
diff --git a/pkg/tfshim/util/util.go b/pkg/tfshim/util/util.go
index 86bb3938..a48ce99e 100644
--- a/pkg/tfshim/util/util.go
+++ b/pkg/tfshim/util/util.go
@@ -44,7 +44,7 @@ func (UnimplementedProvider) Diff(t string, s shim.InstanceState, c shim.Resourc
 func (UnimplementedProvider) Apply(t string, s shim.InstanceState, d shim.InstanceDiff) (shim.InstanceState, error) {
 	panic("unimplemented")
 }
-func (UnimplementedProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (UnimplementedProvider) Refresh(string, shim.InstanceState, shim.ResourceConfig) (shim.InstanceState, error) {
 	panic("unimplemented")
 }
 


Test patch:
diff --git a/internal/testprovider/schema.go b/internal/testprovider/schema.go
index 1d195d12..3cec9430 100644
--- a/internal/testprovider/schema.go
+++ b/internal/testprovider/schema.go
@@ -567,7 +567,12 @@ func ProviderV2() *schemav2.Provider {
 						MustSetIfUnset(data, "bool_property_value", false)
 						MustSetIfUnset(data, "number_property_value", 42)
 						MustSetIfUnset(data, "float_property_value", 99.6767932)
-						MustSetIfUnset(data, "string_property_value", "ognirts")
+						if data.Id() == "set-raw-config-id" {
+							v := data.GetRawConfig().AsValueMap()["raw_config_value"]
+							MustSet(data, "string_property_value", v.AsString())
+						} else {
+							MustSetIfUnset(data, "string_property_value", "ognirts")
+						}
 						MustSetIfUnset(data, "array_property_value", []interface{}{"an array"})
 						MustSetIfUnset(data, "object_property_value", map[string]interface{}{
 							"property_a": "a",
diff --git a/pf/internal/defaults/defaults_test.go b/pf/internal/defaults/defaults_test.go
index 8f080f5f..c137e968 100644
--- a/pf/internal/defaults/defaults_test.go
+++ b/pf/internal/defaults/defaults_test.go
@@ -51,13 +51,30 @@ func TestApplyDefaultInfoValues(t *testing.T) {
 	}
 
 	type testCase struct {
-		name             string
-		env              map[string]string
-		resourceInstance *tfbridge.PulumiResource
-		props            resource.PropertyMap
-		expected         resource.PropertyMap
-		fieldInfos       map[string]*tfbridge.SchemaInfo
-		providerConfig   resource.PropertyMap
+		name                  string
+		env                   map[string]string
+		computeDefaultOptions tfbridge.ComputeDefaultOptions
+		props                 resource.PropertyMap
+		expected              resource.PropertyMap
+		fieldInfos            map[string]*tfbridge.SchemaInfo
+		providerConfig        resource.PropertyMap
+	}
+
+	testFrom := func(res *tfbridge.PulumiResource) (interface{}, error) {
+		n := string(res.URN.Name()) + "-"
+		a := []rune("12345")
+		unique, err := resource.NewUniqueName(res.Seed, n, 3, 12, a)
+		return resource.NewStringProperty(unique), err
+	}
+
+	testComputeDefaults := func(
+		_ context.Context,
+		opts tfbridge.ComputeDefaultOptions,
+	) (interface{}, error) {
+		n := string(opts.URN.Name()) + "-"
+		a := []rune("12345")
+		unique, err := resource.NewUniqueName(opts.Seed, n, 3, 12, a)
+		return resource.NewStringProperty(unique), err
 	}
 
 	testCases := []testCase{
@@ -179,20 +196,100 @@ func TestApplyDefaultInfoValues(t *testing.T) {
 				"boolProp": resource.NewBoolProperty(true),
 			},
 		},
+		{
+			name: "ComputeDefaults function can compute defaults",
+			fieldInfos: map[string]*tfbridge.SchemaInfo{
+				"string_prop": {
+					Default: &tfbridge.DefaultInfo{
+						ComputeDefault: testComputeDefaults,
+					},
+				},
+			},
+			computeDefaultOptions: tfbridge.ComputeDefaultOptions{
+				URN:        "urn:pulumi:test::test::pkgA:index:t1::n1",
+				Properties: resource.PropertyMap{},
+				Seed:       []byte(`123`),
+			},
+			expected: resource.PropertyMap{
+				"stringProp": resource.NewStringProperty("n1-453"),
+			},
+		},
 		{
 			name: "From function can compute defaults",
 			fieldInfos: map[string]*tfbridge.SchemaInfo{
 				"string_prop": {
 					Default: &tfbridge.DefaultInfo{
-						From: func(res *tfbridge.PulumiResource) (interface{}, error) {
-							return resource.NewStringProperty("OK"), nil
+						From: testFrom,
+					},
+				},
+			},
+			computeDefaultOptions: tfbridge.ComputeDefaultOptions{
+				URN:        "urn:pulumi:test::test::pkgA:index:t1::n1",
+				Properties: resource.PropertyMap{},
+				Seed:       []byte(`123`),
+			},
+			expected: resource.PropertyMap{
+				"stringProp": resource.NewStringProperty("n1-453"),
+			},
+		},
+		{
+			name: "ComputeDefaults function can compute nested defaults",
+			fieldInfos: map[string]*tfbridge.SchemaInfo{
+				"object_prop": {
+					Fields: map[string]*tfbridge.SchemaInfo{
+						"y_prop": {
+							Default: &tfbridge.DefaultInfo{
+								ComputeDefault: testComputeDefaults,
+							},
+						},
+					},
+				},
+			},
+			props: resource.PropertyMap{
+				"objectProp": resource.NewObjectProperty(resource.PropertyMap{
+					"xProp": resource.NewStringProperty("X"),
+				}),
+			},
+			computeDefaultOptions: tfbridge.ComputeDefaultOptions{
+				URN:        "urn:pulumi:test::test::pkgA:index:t1::n1",
+				Properties: resource.PropertyMap{},
+				Seed:       []byte(`123`),
+			},
+			expected: resource.PropertyMap{
+				"objectProp": resource.NewObjectProperty(resource.PropertyMap{
+					"xProp": resource.NewStringProperty("X"),
+					"yProp": resource.NewStringProperty("n1-453"),
+				}),
+			},
+		},
+		{
+			name: "From function can compute nested defaults",
+			fieldInfos: map[string]*tfbridge.SchemaInfo{
+				"object_prop": {
+					Fields: map[string]*tfbridge.SchemaInfo{
+						"y_prop": {
+							Default: &tfbridge.DefaultInfo{
+								From: testFrom,
+							},
 						},
 					},
 				},
 			},
-			resourceInstance: &tfbridge.PulumiResource{},
+			props: resource.PropertyMap{
+				"objectProp": resource.NewObjectProperty(resource.PropertyMap{
+					"xProp": resource.NewStringProperty("X"),
+				}),
+			},
+			computeDefaultOptions: tfbridge.ComputeDefaultOptions{
+				URN:        "urn:pulumi:test::test::pkgA:index:t1::n1",
+				Properties: resource.PropertyMap{},
+				Seed:       []byte(`123`),
+			},
 			expected: resource.PropertyMap{
-				"stringProp": resource.NewStringProperty("OK"),
+				"objectProp": resource.NewObjectProperty(resource.PropertyMap{
+					"xProp": resource.NewStringProperty("X"),
+					"yProp": resource.NewStringProperty("n1-453"),
+				}),
 			},
 		},
 		{
@@ -236,11 +333,11 @@ func TestApplyDefaultInfoValues(t *testing.T) {
 			}
 			ctx := context.Background()
 			actual := ApplyDefaultInfoValues(ctx, ApplyDefaultInfoValuesArgs{
-				SchemaMap:        schemaMap,
-				SchemaInfos:      tc.fieldInfos,
-				ResourceInstance: tc.resourceInstance,
-				PropertyMap:      tc.props,
-				ProviderConfig:   tc.providerConfig,
+				SchemaMap:             schemaMap,
+				SchemaInfos:           tc.fieldInfos,
+				ComputeDefaultOptions: tc.computeDefaultOptions,
+				PropertyMap:           tc.props,
+				ProviderConfig:        tc.providerConfig,
 			})
 			assert.Equal(t, tc.expected, actual)
 		})
diff --git a/pf/tests/provider_check_test.go b/pf/tests/provider_check_test.go
index 03785358..52964992 100644
--- a/pf/tests/provider_check_test.go
+++ b/pf/tests/provider_check_test.go
@@ -15,14 +15,16 @@
 package tfbridgetests
 
 import (
+	"context"
 	"fmt"
 	"testing"
 
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
 	pschema "github.com/hashicorp/terraform-plugin-framework/provider/schema"
 	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
-
-	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
 	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
+
 	"github.com/pulumi/pulumi-terraform-bridge/pf/tests/internal/providerbuilder"
 	"github.com/pulumi/pulumi-terraform-bridge/pf/tfbridge"
 	testutils "github.com/pulumi/pulumi-terraform-bridge/testing/x"
@@ -36,6 +38,7 @@ func TestCheck(t *testing.T) {
 		schema      schema.Schema
 		replay      string
 		replayMulti string
+		callback    tfbridge0.PreCheckCallback
 	}
 
 	testCases := []testCase{
@@ -204,6 +207,56 @@ func TestCheck(t *testing.T) {
 			  }
 			]`,
 		},
+		{
+			name: "callback",
+			schema: schema.Schema{
+				Attributes: map[string]schema.Attribute{
+					"id":   schema.StringAttribute{Computed: true},
+					"prop": schema.StringAttribute{Required: true},
+				},
+			},
+			replayMulti: `
+			[
+			  {
+			    "method": "/pulumirpc.ResourceProvider/Configure",
+			    "request": {
+			      "args": {
+				"prop": "global"
+			      },
+			      "variables": {
+				"prop": "global"
+			      },
+			      "acceptSecrets": true,
+			      "acceptResources": true
+			    },
+			    "response": {
+			      "supportsPreview": true,
+			      "acceptResources": true
+			    }
+			  },
+			  {
+			    "method": "/pulumirpc.ResourceProvider/Check",
+			    "request": {
+			      "urn": "urn:pulumi:st::pg::testprovider:index/res:Res::r",
+			      "olds": {},
+			      "news": {},
+			      "randomSeed": "wqZZaHWVfsS1ozo3bdauTfZmjslvWcZpUjn7BzpS79c="
+			    },
+			    "response": {
+			      "inputs": {
+				"prop": "global"
+			      }
+			    }
+			  }
+			]`,
+			callback: func(
+				_ context.Context, config, meta resource.PropertyMap,
+			) (resource.PropertyMap, error) {
+				t.Logf("Meta: %#v", meta)
+				config["prop"] = meta["prop"]
+				return config, nil
+			},
+		},
 	}
 
 	for _, tc := range testCases {
@@ -211,9 +264,15 @@ func TestCheck(t *testing.T) {
 
 		t.Run(tc.name, func(t *testing.T) {
 			testProvider := &providerbuilder.Provider{
-				TypeName:       "testprovider",
-				Version:        "0.0.1",
-				ProviderSchema: pschema.Schema{},
+				TypeName: "testprovider",
+				Version:  "0.0.1",
+				ProviderSchema: pschema.Schema{
+					Attributes: map[string]pschema.Attribute{
+						"prop": pschema.StringAttribute{
+							Optional: true,
+						},
+					},
+				},
 				AllResources: []providerbuilder.Resource{{
 					Name:           "res",
 					ResourceSchema: tc.schema,
@@ -230,6 +289,7 @@ func TestCheck(t *testing.T) {
 						Docs: &tfbridge0.DocInfo{
 							Markdown: []byte("OK"),
 						},
+						PreCheckCallback: tc.callback,
 					},
 				},
 			}
diff --git a/pkg/tfbridge/provider_test.go b/pkg/tfbridge/provider_test.go
index f110feba..dbe3b448 100644
--- a/pkg/tfbridge/provider_test.go
+++ b/pkg/tfbridge/provider_test.go
@@ -495,25 +495,10 @@ func testCheckFailures(t *testing.T, provider *Provider, typeName tokens.Type) [
 		News: pulumiIns,
 	})
 	assert.NoError(t, err)
-	assert.Len(t, checkResp.Failures, 3)
 	return checkResp.Failures
 }
 
-func TestProviderCheck(t *testing.T) {
-	provider := &Provider{
-		tf:     shimv1.NewProvider(testTFProvider),
-		config: shimv1.NewSchemaMap(testTFProvider.Schema),
-	}
-	provider.resources = map[tokens.Type]Resource{
-		"SecondResource": {
-			TF:     shimv1.NewResource(testTFProvider.ResourcesMap["second_resource"]),
-			TFName: "second_resource",
-			Schema: &ResourceInfo{Tok: "SecondResource"},
-		},
-	}
-
-	failures := testCheckFailures(t, provider, "SecondResource")
-	sort.SliceStable(failures, func(i, j int) bool { return failures[i].Reason < failures[j].Reason })
+func testCheckFailuresV1(t *testing.T, failures []*pulumirpc.CheckFailure) {
 	assert.Equal(t, "\"conflicting_property\": conflicts with conflicting_property2."+
 		" Examine values at 'name.conflictingProperty'.", failures[0].Reason)
 	assert.Equal(t, "", failures[0].Property)
@@ -524,21 +509,7 @@ func TestProviderCheck(t *testing.T) {
 	assert.Equal(t, "", failures[2].Property)
 }
 
-func TestProviderCheckV2(t *testing.T) {
-	provider := &Provider{
-		tf:     shimv2.NewProvider(testTFProviderV2),
-		config: shimv2.NewSchemaMap(testTFProviderV2.Schema),
-	}
-	provider.resources = map[tokens.Type]Resource{
-		"SecondResource": {
-			TF:     shimv2.NewResource(testTFProviderV2.ResourcesMap["second_resource"]),
-			TFName: "second_resource",
-			Schema: &ResourceInfo{Tok: "SecondResource"},
-		},
-	}
-
-	failures := testCheckFailures(t, provider, "SecondResource")
-	sort.SliceStable(failures, func(i, j int) bool { return failures[i].Reason < failures[j].Reason })
+func testCheckFailuresV2(t *testing.T, failures []*pulumirpc.CheckFailure) {
 	assert.Equal(t, "Conflicting configuration arguments: \"conflicting_property\": conflicts with "+
 		"conflicting_property2. Examine values at 'name.conflictingProperty'.", failures[0].Reason)
 	assert.Equal(t, "", failures[0].Property)
@@ -550,14 +521,120 @@ func TestProviderCheckV2(t *testing.T) {
 	assert.Equal(t, "", failures[2].Property)
 }
 
-func testProviderRead(t *testing.T, provider *Provider, typeName tokens.Type) {
+func TestProviderCheck(t *testing.T) {
+	testFailures := map[string]func(*testing.T, []*pulumirpc.CheckFailure){
+		"v1": testCheckFailuresV1,
+		"v2": testCheckFailuresV2,
+	}
+	for _, f := range factories {
+		provider := &Provider{
+			tf:     f.NewTestProvider(),
+			config: f.NewTestProvider().Schema(),
+		}
+
+		provider.resources = map[tokens.Type]Resource{
+			"SecondResource": {
+				TF:     provider.tf.ResourcesMap().Get("second_resource"),
+				TFName: "second_resource",
+				Schema: &ResourceInfo{Tok: "SecondResource"},
+			},
+		}
+
+		t.Run(f.SDKVersion(), func(t *testing.T) {
+			t.Run("failures", func(t *testing.T) {
+				failures := testCheckFailures(t, provider, "SecondResource")
+				assert.Len(t, failures, 3)
+				sort.SliceStable(failures, func(i, j int) bool {
+					return failures[i].Reason < failures[j].Reason
+				})
+				testFailures[f.SDKVersion()](t, failures)
+			})
+		})
+	}
+}
+
+func TestCheckCallback(t *testing.T) {
+	t.Parallel()
+	test := func(t *testing.T, p *Provider) {
+		testutils.ReplaySequence(t, p, `
+			[
+			  {
+			    "method": "/pulumirpc.ResourceProvider/Configure",
+			    "request": {
+			      "args": {
+				"prop": "global"
+			      },
+			      "variables": {
+				"prop": "global"
+			      }
+			    },
+			    "response": {
+			      "supportsPreview": true
+			    }
+			  },
+			  {
+			    "method": "/pulumirpc.ResourceProvider/Check",
+			    "request": {
+			      "urn": "urn:pulumi:st::pg::testprovider:index/res:Res::r",
+			      "olds": {},
+			      "news": {},
+			      "randomSeed": "wqZZaHWVfsS1ozo3bdauTfZmjslvWcZpUjn7BzpS79c="
+			    },
+			    "response": {
+			      "inputs": {
+				"__defaults": [],
+				"arrayPropertyValues": ["global"]
+			      }
+			    }
+			  }
+			]`)
+	}
+
+	callback := func(
+		_ context.Context, config, meta resource.PropertyMap,
+	) (resource.PropertyMap, error) {
+		config["arrayPropertyValues"] = resource.NewArrayProperty(
+			[]resource.PropertyValue{meta["prop"]},
+		)
+		return config, nil
+	}
+
+	for _, f := range factories {
+		f := f
+		t.Run(f.SDKVersion(), func(t *testing.T) {
+			t.Parallel()
+			p := &Provider{
+				tf:     f.NewTestProvider(),
+				config: f.NewTestProvider().Schema(),
+			}
+			p.resources = map[tokens.Type]Resource{
+				"testprovider:index/res:Res": {
+					TF:     p.tf.ResourcesMap().Get("example_resource"),
+					TFName: "example_resource",
+					Schema: &ResourceInfo{
+						Tok:              "testprovider:index/res:Res",
+						PreCheckCallback: callback,
+					},
+				},
+			}
+			test(t, p)
+		})
+	}
+}
+
+func testProviderRead(t *testing.T, provider *Provider, typeName tokens.Type, checkRawConfig bool) {
 	urn := resource.NewURN("stack", "project", "", typeName, "name")
+	props, err := structpb.NewStruct(map[string]interface{}{
+		"rawConfigValue": "fromRawConfig",
+	})
+	require.NoError(t, err)
 	readResp, err := provider.Read(context.Background(), &pulumirpc.ReadRequest{
 		Id:         string("resource-id"),
 		Urn:        string(urn),
 		Properties: nil,
+		Inputs:     props,
 	})
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	assert.NotNil(t, readResp.GetInputs())
 	assert.NotNil(t, readResp.GetProperties())
@@ -592,6 +669,19 @@ func testProviderRead(t *testing.T, provider *Provider, typeName tokens.Type) {
 	assert.Equal(t, resource.NewStringProperty("some ${interpolated:value} with syntax errors"),
 		ins["stringWithBadInterpolation"])
 
+	if checkRawConfig {
+		readResp, err := provider.Read(context.Background(), &pulumirpc.ReadRequest{
+			Id:     string("set-raw-config-id"),
+			Urn:    string(urn),
+			Inputs: props,
+		})
+		require.NoError(t, err)
+		outs, err := plugin.UnmarshalProperties(readResp.GetProperties(),
+			plugin.MarshalOptions{KeepUnknowns: true})
+		require.NoError(t, err)
+		assert.Equal(t, "fromRawConfig", outs["stringPropertyValue"].StringValue())
+	}
+
 	// Read again with the ID that results in all the optinal fields not being set
 	readResp, err = provider.Read(context.Background(), &pulumirpc.ReadRequest{
 		Id:         string("empty-resource-id"),
@@ -632,7 +722,7 @@ func TestProviderReadV1(t *testing.T) {
 		},
 	}
 
-	testProviderRead(t, provider, "ExampleResource")
+	testProviderRead(t, provider, "ExampleResource", false /* CheckRawConfig */)
 }
 
 func TestProviderReadV2(t *testing.T) {
@@ -648,7 +738,7 @@ func TestProviderReadV2(t *testing.T) {
 		},
 	}
 
-	testProviderRead(t, provider, "ExampleResource")
+	testProviderRead(t, provider, "ExampleResource", true /* CheckRawConfig */)
 }
 
 func testProviderReadNestedSecret(t *testing.T, provider *Provider, typeName tokens.Type) {
diff --git a/pkg/tfbridge/schema_test.go b/pkg/tfbridge/schema_test.go
index 2602ad64..0bfb53f5 100644
--- a/pkg/tfbridge/schema_test.go
+++ b/pkg/tfbridge/schema_test.go
@@ -641,7 +641,7 @@ func TestMetaProperties(t *testing.T) {
 			res := prov.ResourcesMap().Get(resName)
 
 			state := f.NewInstanceState("0")
-			read, err := prov.Refresh(resName, state)
+			read, err := prov.Refresh(resName, state, nil)
 			assert.NoError(t, err)
 			assert.NotNil(t, read)
 
@@ -655,7 +655,7 @@ func TestMetaProperties(t *testing.T) {
 
 			assert.Equal(t, strconv.Itoa(res.SchemaVersion()), state.Meta()["schema_version"])
 
-			read2, err := prov.Refresh(resName, state)
+			read2, err := prov.Refresh(resName, state, nil)
 			assert.NoError(t, err)
 			assert.NotNil(t, read2)
 			assert.Equal(t, read, read2)
@@ -716,7 +716,7 @@ func TestInjectingCustomTimeouts(t *testing.T) {
 			res := prov.ResourcesMap().Get(resName)
 
 			state := f.NewInstanceState("0")
-			read, err := prov.Refresh(resName, state)
+			read, err := prov.Refresh(resName, state, nil)
 			assert.NoError(t, err)
 			assert.NotNil(t, read)
 
@@ -730,7 +730,7 @@ func TestInjectingCustomTimeouts(t *testing.T) {
 
 			assert.Equal(t, strconv.Itoa(res.SchemaVersion()), state.Meta()["schema_version"])
 
-			read2, err := prov.Refresh(resName, state)
+			read2, err := prov.Refresh(resName, state, nil)
 			assert.NoError(t, err)
 			assert.NotNil(t, read2)
 			assert.Equal(t, read, read2)
@@ -821,7 +821,7 @@ func TestResultAttributesRoundTrip(t *testing.T) {
 			res := prov.ResourcesMap().Get("example_resource")
 
 			state := f.NewInstanceState("0")
-			read, err := prov.Refresh(resName, state)
+			read, err := prov.Refresh(resName, state, nil)
 			assert.NoError(t, err)
 			assert.NotNil(t, read)
 
diff --git a/pkg/tfshim/tfplugin5/provider_test.go b/pkg/tfshim/tfplugin5/provider_test.go
index 04c52da1..10a20d54 100644
--- a/pkg/tfshim/tfplugin5/provider_test.go
+++ b/pkg/tfshim/tfplugin5/provider_test.go
@@ -1294,7 +1294,7 @@ func TestRefresh(t *testing.T) {
 		"string_with_bad_interpolation": cty.StringVal("some ${interpolated:value} with syntax errors"),
 	}
 
-	state, err = p.Refresh("example_resource", state)
+	state, err = p.Refresh("example_resource", state, nil)
 	require.NoError(t, err)
 
 	expectedObject, err := ctyToGo(cty.ObjectVal(expected))