github.com/crossplane/upjet@v1.3.0/pkg/controller/external_tfpluginfw_test.go (about)

     1  // SPDX-FileCopyrightText: 2024 The Crossplane Authors <https://crossplane.io>
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package controller
     6  
     7  import (
     8  	"context"
     9  	"testing"
    10  
    11  	"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
    12  	xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
    13  	"github.com/crossplane/crossplane-runtime/pkg/test"
    14  	"github.com/google/go-cmp/cmp"
    15  	"github.com/hashicorp/terraform-plugin-framework/datasource"
    16  	"github.com/hashicorp/terraform-plugin-framework/provider"
    17  	"github.com/hashicorp/terraform-plugin-framework/resource"
    18  	rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
    19  	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
    20  	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
    21  	"github.com/hashicorp/terraform-plugin-framework/tfsdk"
    22  	"github.com/hashicorp/terraform-plugin-framework/types"
    23  	"github.com/hashicorp/terraform-plugin-go/tfprotov5"
    24  	"github.com/hashicorp/terraform-plugin-go/tftypes"
    25  	"github.com/pkg/errors"
    26  	"sigs.k8s.io/controller-runtime/pkg/client"
    27  
    28  	"github.com/crossplane/upjet/pkg/config"
    29  	"github.com/crossplane/upjet/pkg/resource/fake"
    30  	"github.com/crossplane/upjet/pkg/terraform"
    31  )
    32  
    33  func newBaseObject() fake.Terraformed {
    34  	return fake.Terraformed{
    35  		Parameterizable: fake.Parameterizable{
    36  			Parameters: map[string]any{
    37  				"name": "example",
    38  				"map": map[string]any{
    39  					"key": "value",
    40  				},
    41  				"list": []any{"elem1", "elem2"},
    42  			},
    43  		},
    44  		Observable: fake.Observable{
    45  			Observation: map[string]any{},
    46  		},
    47  	}
    48  }
    49  
    50  func newBaseSchema() rschema.Schema {
    51  	return rschema.Schema{
    52  		Attributes: map[string]rschema.Attribute{
    53  			"name": rschema.StringAttribute{
    54  				Required: true,
    55  				PlanModifiers: []planmodifier.String{
    56  					stringplanmodifier.UseStateForUnknown(),
    57  				},
    58  			},
    59  			"id": rschema.StringAttribute{
    60  				Computed: true,
    61  				PlanModifiers: []planmodifier.String{
    62  					stringplanmodifier.UseStateForUnknown(),
    63  				},
    64  			},
    65  			"map": rschema.MapAttribute{
    66  				Required:    true,
    67  				ElementType: types.StringType,
    68  			},
    69  			"list": rschema.ListAttribute{
    70  				Required:    true,
    71  				ElementType: types.StringType,
    72  			},
    73  		},
    74  	}
    75  }
    76  
    77  func newMockBaseTPFResource() *mockTPFResource {
    78  	return &mockTPFResource{
    79  		SchemaMethod: func(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) {
    80  			response.Schema = newBaseSchema()
    81  		},
    82  		ReadMethod: func(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
    83  			response.State = tfsdk.State{
    84  				Raw:    tftypes.Value{},
    85  				Schema: nil,
    86  			}
    87  		},
    88  	}
    89  }
    90  
    91  func newBaseUpjetConfig() *config.Resource {
    92  	return &config.Resource{
    93  		TerraformPluginFrameworkResource: newMockBaseTPFResource(),
    94  		ExternalName:                     config.IdentifierFromProvider,
    95  		Sensitive: config.Sensitive{AdditionalConnectionDetailsFn: func(attr map[string]any) (map[string][]byte, error) {
    96  			return nil, nil
    97  		}},
    98  	}
    99  }
   100  
   101  type testConfiguration struct {
   102  	r               resource.Resource
   103  	cfg             *config.Resource
   104  	obj             fake.Terraformed
   105  	params          map[string]any
   106  	currentStateMap map[string]any
   107  	plannedStateMap map[string]any
   108  	newStateMap     map[string]any
   109  
   110  	readErr   error
   111  	readDiags []*tfprotov5.Diagnostic
   112  
   113  	applyErr   error
   114  	applyDiags []*tfprotov5.Diagnostic
   115  
   116  	planErr   error
   117  	planDiags []*tfprotov5.Diagnostic
   118  }
   119  
   120  func prepareTPFExternalWithTestConfig(testConfig testConfiguration) *terraformPluginFrameworkExternalClient {
   121  	testConfig.cfg.TerraformPluginFrameworkResource = testConfig.r
   122  	schemaResp := &resource.SchemaResponse{}
   123  	testConfig.r.Schema(context.TODO(), resource.SchemaRequest{}, schemaResp)
   124  	tfValueType := schemaResp.Schema.Type().TerraformType(context.TODO())
   125  
   126  	currentStateVal, err := protov5DynamicValueFromMap(testConfig.currentStateMap, tfValueType)
   127  	if err != nil {
   128  		panic("cannot prepare TPF")
   129  	}
   130  	plannedStateVal, err := protov5DynamicValueFromMap(testConfig.plannedStateMap, tfValueType)
   131  	if err != nil {
   132  		panic("cannot prepare TPF")
   133  	}
   134  	newStateAfterApplyVal, err := protov5DynamicValueFromMap(testConfig.newStateMap, tfValueType)
   135  	if err != nil {
   136  		panic("cannot prepare TPF")
   137  	}
   138  	return &terraformPluginFrameworkExternalClient{
   139  		ts: terraform.Setup{
   140  			FrameworkProvider: &mockTPFProvider{},
   141  		},
   142  		config: cfg,
   143  		logger: logTest,
   144  		// metricRecorder:             nil,
   145  		opTracker: NewAsyncTracker(),
   146  		resource:  testConfig.r,
   147  		server: &mockTPFProviderServer{
   148  			ReadResourceFn: func(ctx context.Context, request *tfprotov5.ReadResourceRequest) (*tfprotov5.ReadResourceResponse, error) {
   149  				return &tfprotov5.ReadResourceResponse{
   150  					NewState:    currentStateVal,
   151  					Diagnostics: testConfig.readDiags,
   152  				}, testConfig.readErr
   153  			},
   154  			PlanResourceChangeFn: func(ctx context.Context, request *tfprotov5.PlanResourceChangeRequest) (*tfprotov5.PlanResourceChangeResponse, error) {
   155  				return &tfprotov5.PlanResourceChangeResponse{
   156  					PlannedState: plannedStateVal,
   157  					Diagnostics:  testConfig.planDiags,
   158  				}, testConfig.planErr
   159  			},
   160  			ApplyResourceChangeFn: func(ctx context.Context, request *tfprotov5.ApplyResourceChangeRequest) (*tfprotov5.ApplyResourceChangeResponse, error) {
   161  				return &tfprotov5.ApplyResourceChangeResponse{
   162  					NewState:    newStateAfterApplyVal,
   163  					Diagnostics: testConfig.applyDiags,
   164  				}, testConfig.applyErr
   165  			},
   166  		},
   167  		params:                     testConfig.params,
   168  		planResponse:               &tfprotov5.PlanResourceChangeResponse{PlannedState: plannedStateVal},
   169  		resourceSchema:             schemaResp.Schema,
   170  		resourceValueTerraformType: tfValueType,
   171  	}
   172  }
   173  
   174  func TestTPFConnect(t *testing.T) {
   175  	type args struct {
   176  		setupFn terraform.SetupFn
   177  		cfg     *config.Resource
   178  		ots     *OperationTrackerStore
   179  		obj     fake.Terraformed
   180  	}
   181  	type want struct {
   182  		err error
   183  	}
   184  	cases := map[string]struct {
   185  		args
   186  		want
   187  	}{
   188  		"Successful": {
   189  			args: args{
   190  				setupFn: func(_ context.Context, _ client.Client, _ xpresource.Managed) (terraform.Setup, error) {
   191  					return terraform.Setup{
   192  						FrameworkProvider: &mockTPFProvider{},
   193  					}, nil
   194  				},
   195  				cfg: newBaseUpjetConfig(),
   196  				obj: newBaseObject(),
   197  				ots: ots,
   198  			},
   199  		},
   200  	}
   201  
   202  	for name, tc := range cases {
   203  		t.Run(name, func(t *testing.T) {
   204  			c := NewTerraformPluginFrameworkConnector(nil, tc.args.setupFn, tc.args.cfg, tc.args.ots, WithTerraformPluginFrameworkLogger(logTest))
   205  			_, err := c.Connect(context.TODO(), &tc.args.obj)
   206  			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
   207  				t.Errorf("\n%s\nConnect(...): -want error, +got error:\n", diff)
   208  			}
   209  		})
   210  	}
   211  }
   212  
   213  func TestTPFObserve(t *testing.T) {
   214  	type want struct {
   215  		obs managed.ExternalObservation
   216  		err error
   217  	}
   218  	cases := map[string]struct {
   219  		testConfiguration
   220  		want
   221  	}{
   222  		"NotExists": {
   223  			testConfiguration: testConfiguration{
   224  				r:               newMockBaseTPFResource(),
   225  				cfg:             newBaseUpjetConfig(),
   226  				obj:             obj,
   227  				currentStateMap: nil,
   228  				plannedStateMap: map[string]any{
   229  					"name": "example",
   230  				},
   231  				params: map[string]any{
   232  					"name": "example",
   233  				},
   234  			},
   235  			want: want{
   236  				obs: managed.ExternalObservation{
   237  					ResourceExists:          false,
   238  					ResourceUpToDate:        false,
   239  					ResourceLateInitialized: false,
   240  					ConnectionDetails:       nil,
   241  					Diff:                    "",
   242  				},
   243  			},
   244  		},
   245  
   246  		"UpToDate": {
   247  			testConfiguration: testConfiguration{
   248  				r:   newMockBaseTPFResource(),
   249  				cfg: newBaseUpjetConfig(),
   250  				obj: newBaseObject(),
   251  				params: map[string]any{
   252  					"id":   "example-id",
   253  					"name": "example",
   254  				},
   255  				currentStateMap: map[string]any{
   256  					"id":   "example-id",
   257  					"name": "example",
   258  				},
   259  				plannedStateMap: map[string]any{
   260  					"id":   "example-id",
   261  					"name": "example",
   262  				},
   263  			},
   264  			want: want{
   265  				obs: managed.ExternalObservation{
   266  					ResourceExists:          true,
   267  					ResourceUpToDate:        true,
   268  					ResourceLateInitialized: true,
   269  					ConnectionDetails:       nil,
   270  					Diff:                    "",
   271  				},
   272  			},
   273  		},
   274  
   275  		"LateInitialize": {
   276  			testConfiguration: testConfiguration{
   277  				r:   newMockBaseTPFResource(),
   278  				cfg: newBaseUpjetConfig(),
   279  				obj: fake.Terraformed{
   280  					Parameterizable: fake.Parameterizable{
   281  						Parameters: map[string]any{
   282  							"name": "example",
   283  							"map": map[string]any{
   284  								"key": "value",
   285  							},
   286  							"list": []any{"elem1", "elem2"},
   287  						},
   288  						InitParameters: map[string]any{
   289  							"list": []any{"elem1", "elem2", "elem3"},
   290  						},
   291  					},
   292  					Observable: fake.Observable{
   293  						Observation: map[string]any{},
   294  					},
   295  				},
   296  				params: map[string]any{
   297  					"id": "example-id",
   298  				},
   299  				currentStateMap: map[string]any{
   300  					"id":   "example-id",
   301  					"name": "example2",
   302  				},
   303  				plannedStateMap: map[string]any{
   304  					"id":   "example-id",
   305  					"name": "example2",
   306  				},
   307  			},
   308  			want: want{
   309  				obs: managed.ExternalObservation{
   310  					ResourceExists:          true,
   311  					ResourceUpToDate:        true,
   312  					ResourceLateInitialized: true,
   313  					ConnectionDetails:       nil,
   314  					Diff:                    "",
   315  				},
   316  			},
   317  		},
   318  	}
   319  
   320  	for name, tc := range cases {
   321  		t.Run(name, func(t *testing.T) {
   322  			tpfExternal := prepareTPFExternalWithTestConfig(tc.testConfiguration)
   323  			observation, err := tpfExternal.Observe(context.TODO(), &tc.testConfiguration.obj)
   324  			if diff := cmp.Diff(tc.want.obs, observation); diff != "" {
   325  				t.Errorf("\n%s\nObserve(...): -want observation, +got observation:\n", diff)
   326  			}
   327  			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
   328  				t.Errorf("\n%s\nConnect(...): -want error, +got error:\n", diff)
   329  			}
   330  		})
   331  	}
   332  }
   333  
   334  func TestTPFCreate(t *testing.T) {
   335  	type want struct {
   336  		err error
   337  	}
   338  	cases := map[string]struct {
   339  		testConfiguration
   340  		want
   341  	}{
   342  		"Successful": {
   343  			testConfiguration: testConfiguration{
   344  				r:               newMockBaseTPFResource(),
   345  				cfg:             newBaseUpjetConfig(),
   346  				obj:             obj,
   347  				currentStateMap: nil,
   348  				plannedStateMap: map[string]any{
   349  					"name": "example",
   350  				},
   351  				params: map[string]any{
   352  					"name": "example",
   353  				},
   354  				newStateMap: map[string]any{
   355  					"name": "example",
   356  					"id":   "example-id",
   357  				},
   358  			},
   359  		},
   360  		"EmptyStateAfterCreation": {
   361  			testConfiguration: testConfiguration{
   362  				r:               newMockBaseTPFResource(),
   363  				cfg:             newBaseUpjetConfig(),
   364  				obj:             obj,
   365  				currentStateMap: nil,
   366  				plannedStateMap: map[string]any{
   367  					"name": "example",
   368  				},
   369  				params: map[string]any{
   370  					"name": "example",
   371  				},
   372  				newStateMap: nil,
   373  			},
   374  			want: want{
   375  				err: errors.New("new state is empty after creation"),
   376  			},
   377  		},
   378  		"ApplyWithError": {
   379  			testConfiguration: testConfiguration{
   380  				r:               newMockBaseTPFResource(),
   381  				cfg:             newBaseUpjetConfig(),
   382  				obj:             obj,
   383  				currentStateMap: nil,
   384  				plannedStateMap: map[string]any{
   385  					"name": "example",
   386  				},
   387  				params: map[string]any{
   388  					"name": "example",
   389  				},
   390  				newStateMap: nil,
   391  				applyErr:    errors.New("foo error"),
   392  			},
   393  			want: want{
   394  				err: errors.Wrap(errors.New("foo error"), "cannot create resource"),
   395  			},
   396  		},
   397  		"ApplyWithDiags": {
   398  			testConfiguration: testConfiguration{
   399  				r:               newMockBaseTPFResource(),
   400  				cfg:             newBaseUpjetConfig(),
   401  				obj:             obj,
   402  				currentStateMap: nil,
   403  				plannedStateMap: map[string]any{
   404  					"name": "example",
   405  				},
   406  				params: map[string]any{
   407  					"name": "example",
   408  				},
   409  				newStateMap: nil,
   410  				applyDiags: []*tfprotov5.Diagnostic{
   411  					{
   412  						Severity: tfprotov5.DiagnosticSeverityError,
   413  						Summary:  "foo summary",
   414  						Detail:   "foo detail",
   415  					},
   416  				},
   417  			},
   418  			want: want{
   419  				err: errors.Wrap(errors.New("foo summary: foo detail"), "resource creation call returned error diags"),
   420  			},
   421  		},
   422  	}
   423  	for name, tc := range cases {
   424  		t.Run(name, func(t *testing.T) {
   425  			tpfExternal := prepareTPFExternalWithTestConfig(tc.testConfiguration)
   426  			_, err := tpfExternal.Create(context.TODO(), &tc.testConfiguration.obj)
   427  			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
   428  				t.Errorf("\n%s\nConnect(...): -want error, +got error:\n", diff)
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  func TestTPFUpdate(t *testing.T) {
   435  	type want struct {
   436  		err error
   437  	}
   438  	cases := map[string]struct {
   439  		testConfiguration
   440  		want
   441  	}{
   442  		"Successful": {
   443  			testConfiguration: testConfiguration{
   444  				r:   newMockBaseTPFResource(),
   445  				cfg: newBaseUpjetConfig(),
   446  				obj: newBaseObject(),
   447  				currentStateMap: map[string]any{
   448  					"name": "example",
   449  					"id":   "example-id",
   450  				},
   451  				plannedStateMap: map[string]any{
   452  					"name": "example-updated",
   453  					"id":   "example-id",
   454  				},
   455  				params: map[string]any{
   456  					"name": "example-updated",
   457  				},
   458  				newStateMap: map[string]any{
   459  					"name": "example-updated",
   460  					"id":   "example-id",
   461  				},
   462  			},
   463  		},
   464  	}
   465  	for name, tc := range cases {
   466  		t.Run(name, func(t *testing.T) {
   467  			tpfExternal := prepareTPFExternalWithTestConfig(tc.testConfiguration)
   468  			_, err := tpfExternal.Update(context.TODO(), &tc.testConfiguration.obj)
   469  			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
   470  				t.Errorf("\n%s\nConnect(...): -want error, +got error:\n", diff)
   471  			}
   472  		})
   473  	}
   474  }
   475  
   476  func TestTPFDelete(t *testing.T) {
   477  
   478  	type want struct {
   479  		err error
   480  	}
   481  	cases := map[string]struct {
   482  		testConfiguration
   483  		want
   484  	}{
   485  		"Successful": {
   486  			testConfiguration: testConfiguration{
   487  				r:   newMockBaseTPFResource(),
   488  				cfg: newBaseUpjetConfig(),
   489  				obj: newBaseObject(),
   490  				currentStateMap: map[string]any{
   491  					"name": "example",
   492  					"id":   "example-id",
   493  				},
   494  				plannedStateMap: nil,
   495  				params: map[string]any{
   496  					"name": "example",
   497  				},
   498  				newStateMap: nil,
   499  			},
   500  		},
   501  	}
   502  	for name, tc := range cases {
   503  		t.Run(name, func(t *testing.T) {
   504  			tpfExternal := prepareTPFExternalWithTestConfig(tc.testConfiguration)
   505  			err := tpfExternal.Delete(context.TODO(), &tc.testConfiguration.obj)
   506  			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
   507  				t.Errorf("\n%s\nConnect(...): -want error, +got error:\n", diff)
   508  			}
   509  		})
   510  	}
   511  }
   512  
   513  // Mocks
   514  
   515  var _ resource.Resource = &mockTPFResource{}
   516  var _ tfprotov5.ProviderServer = &mockTPFProviderServer{}
   517  var _ provider.Provider = &mockTPFProvider{}
   518  
   519  type mockTPFProviderServer struct {
   520  	GetMetadataFn                func(ctx context.Context, request *tfprotov5.GetMetadataRequest) (*tfprotov5.GetMetadataResponse, error)
   521  	GetProviderSchemaFn          func(ctx context.Context, request *tfprotov5.GetProviderSchemaRequest) (*tfprotov5.GetProviderSchemaResponse, error)
   522  	PrepareProviderConfigFn      func(ctx context.Context, request *tfprotov5.PrepareProviderConfigRequest) (*tfprotov5.PrepareProviderConfigResponse, error)
   523  	ConfigureProviderFn          func(ctx context.Context, request *tfprotov5.ConfigureProviderRequest) (*tfprotov5.ConfigureProviderResponse, error)
   524  	StopProviderFn               func(ctx context.Context, request *tfprotov5.StopProviderRequest) (*tfprotov5.StopProviderResponse, error)
   525  	ValidateResourceTypeConfigFn func(ctx context.Context, request *tfprotov5.ValidateResourceTypeConfigRequest) (*tfprotov5.ValidateResourceTypeConfigResponse, error)
   526  	UpgradeResourceStateFn       func(ctx context.Context, request *tfprotov5.UpgradeResourceStateRequest) (*tfprotov5.UpgradeResourceStateResponse, error)
   527  	ReadResourceFn               func(ctx context.Context, request *tfprotov5.ReadResourceRequest) (*tfprotov5.ReadResourceResponse, error)
   528  	PlanResourceChangeFn         func(ctx context.Context, request *tfprotov5.PlanResourceChangeRequest) (*tfprotov5.PlanResourceChangeResponse, error)
   529  	ApplyResourceChangeFn        func(ctx context.Context, request *tfprotov5.ApplyResourceChangeRequest) (*tfprotov5.ApplyResourceChangeResponse, error)
   530  	ImportResourceStateFn        func(ctx context.Context, request *tfprotov5.ImportResourceStateRequest) (*tfprotov5.ImportResourceStateResponse, error)
   531  	ValidateDataSourceConfigFn   func(ctx context.Context, request *tfprotov5.ValidateDataSourceConfigRequest) (*tfprotov5.ValidateDataSourceConfigResponse, error)
   532  	ReadDataSourceFn             func(ctx context.Context, request *tfprotov5.ReadDataSourceRequest) (*tfprotov5.ReadDataSourceResponse, error)
   533  }
   534  
   535  func (m *mockTPFProviderServer) GetMetadata(_ context.Context, _ *tfprotov5.GetMetadataRequest) (*tfprotov5.GetMetadataResponse, error) {
   536  	// TODO implement me
   537  	panic("implement me")
   538  }
   539  
   540  func (m *mockTPFProviderServer) GetProviderSchema(_ context.Context, _ *tfprotov5.GetProviderSchemaRequest) (*tfprotov5.GetProviderSchemaResponse, error) {
   541  	// TODO implement me
   542  	panic("implement me")
   543  }
   544  
   545  func (m *mockTPFProviderServer) PrepareProviderConfig(_ context.Context, _ *tfprotov5.PrepareProviderConfigRequest) (*tfprotov5.PrepareProviderConfigResponse, error) {
   546  	// TODO implement me
   547  	panic("implement me")
   548  }
   549  
   550  func (m *mockTPFProviderServer) ConfigureProvider(_ context.Context, _ *tfprotov5.ConfigureProviderRequest) (*tfprotov5.ConfigureProviderResponse, error) {
   551  	// TODO implement me
   552  	panic("implement me")
   553  }
   554  
   555  func (m *mockTPFProviderServer) StopProvider(_ context.Context, _ *tfprotov5.StopProviderRequest) (*tfprotov5.StopProviderResponse, error) {
   556  	// TODO implement me
   557  	panic("implement me")
   558  }
   559  
   560  func (m *mockTPFProviderServer) ValidateResourceTypeConfig(_ context.Context, _ *tfprotov5.ValidateResourceTypeConfigRequest) (*tfprotov5.ValidateResourceTypeConfigResponse, error) {
   561  	// TODO implement me
   562  	panic("implement me")
   563  }
   564  
   565  func (m *mockTPFProviderServer) UpgradeResourceState(_ context.Context, _ *tfprotov5.UpgradeResourceStateRequest) (*tfprotov5.UpgradeResourceStateResponse, error) {
   566  	// TODO implement me
   567  	panic("implement me")
   568  }
   569  
   570  func (m *mockTPFProviderServer) ReadResource(ctx context.Context, request *tfprotov5.ReadResourceRequest) (*tfprotov5.ReadResourceResponse, error) {
   571  	if m.ReadResourceFn == nil {
   572  		return nil, nil
   573  	}
   574  	return m.ReadResourceFn(ctx, request)
   575  }
   576  
   577  func (m *mockTPFProviderServer) PlanResourceChange(ctx context.Context, request *tfprotov5.PlanResourceChangeRequest) (*tfprotov5.PlanResourceChangeResponse, error) {
   578  	if m.PlanResourceChangeFn == nil {
   579  		return nil, nil
   580  	}
   581  	return m.PlanResourceChangeFn(ctx, request)
   582  }
   583  
   584  func (m *mockTPFProviderServer) ApplyResourceChange(ctx context.Context, request *tfprotov5.ApplyResourceChangeRequest) (*tfprotov5.ApplyResourceChangeResponse, error) {
   585  	if m.ApplyResourceChangeFn == nil {
   586  		return nil, nil
   587  	}
   588  	return m.ApplyResourceChangeFn(ctx, request)
   589  }
   590  
   591  func (m *mockTPFProviderServer) ImportResourceState(_ context.Context, _ *tfprotov5.ImportResourceStateRequest) (*tfprotov5.ImportResourceStateResponse, error) {
   592  	// TODO implement me
   593  	panic("implement me")
   594  }
   595  
   596  func (m *mockTPFProviderServer) ValidateDataSourceConfig(_ context.Context, _ *tfprotov5.ValidateDataSourceConfigRequest) (*tfprotov5.ValidateDataSourceConfigResponse, error) {
   597  	// TODO implement me
   598  	panic("implement me")
   599  }
   600  
   601  func (m *mockTPFProviderServer) ReadDataSource(_ context.Context, _ *tfprotov5.ReadDataSourceRequest) (*tfprotov5.ReadDataSourceResponse, error) {
   602  	// TODO implement me
   603  	panic("implement me")
   604  }
   605  
   606  type mockTPFProvider struct {
   607  	// Provider interface methods
   608  	MetadataMethod    func(context.Context, provider.MetadataRequest, *provider.MetadataResponse)
   609  	ConfigureMethod   func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse)
   610  	SchemaMethod      func(context.Context, provider.SchemaRequest, *provider.SchemaResponse)
   611  	DataSourcesMethod func(context.Context) []func() datasource.DataSource
   612  	ResourcesMethod   func(context.Context) []func() resource.Resource
   613  }
   614  
   615  // Configure satisfies the provider.Provider interface.
   616  func (p *mockTPFProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
   617  	if p == nil || p.ConfigureMethod == nil {
   618  		return
   619  	}
   620  
   621  	p.ConfigureMethod(ctx, req, resp)
   622  }
   623  
   624  // DataSources satisfies the provider.Provider interface.
   625  func (p *mockTPFProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
   626  	if p == nil || p.DataSourcesMethod == nil {
   627  		return nil
   628  	}
   629  
   630  	return p.DataSourcesMethod(ctx)
   631  }
   632  
   633  // Metadata satisfies the provider.Provider interface.
   634  func (p *mockTPFProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
   635  	if p == nil || p.MetadataMethod == nil {
   636  		return
   637  	}
   638  
   639  	p.MetadataMethod(ctx, req, resp)
   640  }
   641  
   642  // Schema satisfies the provider.Provider interface.
   643  func (p *mockTPFProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
   644  	if p == nil || p.SchemaMethod == nil {
   645  		return
   646  	}
   647  
   648  	p.SchemaMethod(ctx, req, resp)
   649  }
   650  
   651  // Resources satisfies the provider.Provider interface.
   652  func (p *mockTPFProvider) Resources(ctx context.Context) []func() resource.Resource {
   653  	if p == nil || p.ResourcesMethod == nil {
   654  		return nil
   655  	}
   656  
   657  	return p.ResourcesMethod(ctx)
   658  }
   659  
   660  type mockTPFResource struct {
   661  	// Resource interface methods
   662  	MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse)
   663  	SchemaMethod   func(context.Context, resource.SchemaRequest, *resource.SchemaResponse)
   664  	CreateMethod   func(context.Context, resource.CreateRequest, *resource.CreateResponse)
   665  	DeleteMethod   func(context.Context, resource.DeleteRequest, *resource.DeleteResponse)
   666  	ReadMethod     func(context.Context, resource.ReadRequest, *resource.ReadResponse)
   667  	UpdateMethod   func(context.Context, resource.UpdateRequest, *resource.UpdateResponse)
   668  }
   669  
   670  // Metadata satisfies the resource.Resource interface.
   671  func (r *mockTPFResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
   672  	if r.MetadataMethod == nil {
   673  		return
   674  	}
   675  
   676  	r.MetadataMethod(ctx, req, resp)
   677  }
   678  
   679  // Schema satisfies the resource.Resource interface.
   680  func (r *mockTPFResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
   681  	if r.SchemaMethod == nil {
   682  		return
   683  	}
   684  
   685  	r.SchemaMethod(ctx, req, resp)
   686  }
   687  
   688  // Create satisfies the resource.Resource interface.
   689  func (r *mockTPFResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
   690  	if r.CreateMethod == nil {
   691  		return
   692  	}
   693  
   694  	r.CreateMethod(ctx, req, resp)
   695  }
   696  
   697  // Delete satisfies the resource.Resource interface.
   698  func (r *mockTPFResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
   699  	if r.DeleteMethod == nil {
   700  		return
   701  	}
   702  
   703  	r.DeleteMethod(ctx, req, resp)
   704  }
   705  
   706  // Read satisfies the resource.Resource interface.
   707  func (r *mockTPFResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
   708  	if r.ReadMethod == nil {
   709  		return
   710  	}
   711  
   712  	r.ReadMethod(ctx, req, resp)
   713  }
   714  
   715  // Update satisfies the resource.Resource interface.
   716  func (r *mockTPFResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
   717  	if r.UpdateMethod == nil {
   718  		return
   719  	}
   720  
   721  	r.UpdateMethod(ctx, req, resp)
   722  }