github.com/opentofu/opentofu@v1.7.1/internal/legacy/tofu/provider_mock.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tofu
     7  
     8  import (
     9  	"encoding/json"
    10  	"sync"
    11  
    12  	"github.com/zclconf/go-cty/cty"
    13  	ctyjson "github.com/zclconf/go-cty/cty/json"
    14  
    15  	"github.com/opentofu/opentofu/internal/configs/hcl2shim"
    16  	"github.com/opentofu/opentofu/internal/providers"
    17  )
    18  
    19  var _ providers.Interface = (*MockProvider)(nil)
    20  
    21  // MockProvider implements providers.Interface but mocks out all the
    22  // calls for testing purposes.
    23  type MockProvider struct {
    24  	sync.Mutex
    25  
    26  	// Anything you want, in case you need to store extra data with the mock.
    27  	Meta interface{}
    28  
    29  	GetSchemaCalled bool
    30  	GetSchemaReturn *ProviderSchema // This is using ProviderSchema directly rather than providers.GetProviderSchemaResponse for compatibility with old tests
    31  
    32  	ValidateProviderConfigCalled   bool
    33  	ValidateProviderConfigResponse providers.ValidateProviderConfigResponse
    34  	ValidateProviderConfigRequest  providers.ValidateProviderConfigRequest
    35  	ValidateProviderConfigFn       func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse
    36  
    37  	ValidateResourceConfigCalled   bool
    38  	ValidateResourceConfigTypeName string
    39  	ValidateResourceConfigResponse providers.ValidateResourceConfigResponse
    40  	ValidateResourceConfigRequest  providers.ValidateResourceConfigRequest
    41  	ValidateResourceConfigFn       func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse
    42  
    43  	ValidateDataResourceConfigCalled   bool
    44  	ValidateDataResourceConfigTypeName string
    45  	ValidateDataResourceConfigResponse providers.ValidateDataResourceConfigResponse
    46  	ValidateDataResourceConfigRequest  providers.ValidateDataResourceConfigRequest
    47  	ValidateDataResourceConfigFn       func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse
    48  
    49  	UpgradeResourceStateCalled   bool
    50  	UpgradeResourceStateTypeName string
    51  	UpgradeResourceStateResponse providers.UpgradeResourceStateResponse
    52  	UpgradeResourceStateRequest  providers.UpgradeResourceStateRequest
    53  	UpgradeResourceStateFn       func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse
    54  
    55  	ConfigureProviderCalled   bool
    56  	ConfigureProviderResponse providers.ConfigureProviderResponse
    57  	ConfigureProviderRequest  providers.ConfigureProviderRequest
    58  	ConfigureProviderFn       func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse
    59  
    60  	StopCalled   bool
    61  	StopFn       func() error
    62  	StopResponse error
    63  
    64  	ReadResourceCalled   bool
    65  	ReadResourceResponse providers.ReadResourceResponse
    66  	ReadResourceRequest  providers.ReadResourceRequest
    67  	ReadResourceFn       func(providers.ReadResourceRequest) providers.ReadResourceResponse
    68  
    69  	PlanResourceChangeCalled   bool
    70  	PlanResourceChangeResponse providers.PlanResourceChangeResponse
    71  	PlanResourceChangeRequest  providers.PlanResourceChangeRequest
    72  	PlanResourceChangeFn       func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse
    73  
    74  	ApplyResourceChangeCalled   bool
    75  	ApplyResourceChangeResponse providers.ApplyResourceChangeResponse
    76  	ApplyResourceChangeRequest  providers.ApplyResourceChangeRequest
    77  	ApplyResourceChangeFn       func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse
    78  
    79  	ImportResourceStateCalled   bool
    80  	ImportResourceStateResponse providers.ImportResourceStateResponse
    81  	ImportResourceStateRequest  providers.ImportResourceStateRequest
    82  	ImportResourceStateFn       func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse
    83  	// Legacy return type for existing tests, which will be shimmed into an
    84  	// ImportResourceStateResponse if set
    85  	ImportStateReturn []*InstanceState
    86  
    87  	ReadDataSourceCalled   bool
    88  	ReadDataSourceResponse providers.ReadDataSourceResponse
    89  	ReadDataSourceRequest  providers.ReadDataSourceRequest
    90  	ReadDataSourceFn       func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse
    91  
    92  	CloseCalled bool
    93  	CloseError  error
    94  }
    95  
    96  func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
    97  	p.Lock()
    98  	defer p.Unlock()
    99  	p.GetSchemaCalled = true
   100  	return p.getSchema()
   101  }
   102  
   103  func (p *MockProvider) getSchema() providers.GetProviderSchemaResponse {
   104  	// This version of getSchema doesn't do any locking, so it's suitable to
   105  	// call from other methods of this mock as long as they are already
   106  	// holding the lock.
   107  
   108  	ret := providers.GetProviderSchemaResponse{
   109  		Provider:      providers.Schema{},
   110  		DataSources:   map[string]providers.Schema{},
   111  		ResourceTypes: map[string]providers.Schema{},
   112  	}
   113  	if p.GetSchemaReturn != nil {
   114  		ret.Provider.Block = p.GetSchemaReturn.Provider
   115  		ret.ProviderMeta.Block = p.GetSchemaReturn.ProviderMeta
   116  		for n, s := range p.GetSchemaReturn.DataSources {
   117  			ret.DataSources[n] = providers.Schema{
   118  				Block: s,
   119  			}
   120  		}
   121  		for n, s := range p.GetSchemaReturn.ResourceTypes {
   122  			ret.ResourceTypes[n] = providers.Schema{
   123  				Version: int64(p.GetSchemaReturn.ResourceTypeSchemaVersions[n]),
   124  				Block:   s,
   125  			}
   126  		}
   127  	}
   128  
   129  	return ret
   130  }
   131  
   132  func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
   133  	p.Lock()
   134  	defer p.Unlock()
   135  
   136  	p.ValidateProviderConfigCalled = true
   137  	p.ValidateProviderConfigRequest = r
   138  	if p.ValidateProviderConfigFn != nil {
   139  		return p.ValidateProviderConfigFn(r)
   140  	}
   141  	return p.ValidateProviderConfigResponse
   142  }
   143  
   144  func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
   145  	p.Lock()
   146  	defer p.Unlock()
   147  
   148  	p.ValidateResourceConfigCalled = true
   149  	p.ValidateResourceConfigRequest = r
   150  
   151  	if p.ValidateResourceConfigFn != nil {
   152  		return p.ValidateResourceConfigFn(r)
   153  	}
   154  
   155  	return p.ValidateResourceConfigResponse
   156  }
   157  
   158  func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
   159  	p.Lock()
   160  	defer p.Unlock()
   161  
   162  	p.ValidateDataResourceConfigCalled = true
   163  	p.ValidateDataResourceConfigRequest = r
   164  
   165  	if p.ValidateDataResourceConfigFn != nil {
   166  		return p.ValidateDataResourceConfigFn(r)
   167  	}
   168  
   169  	return p.ValidateDataResourceConfigResponse
   170  }
   171  
   172  func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
   173  	p.Lock()
   174  	defer p.Unlock()
   175  
   176  	schemas := p.getSchema()
   177  	schema := schemas.ResourceTypes[r.TypeName]
   178  	schemaType := schema.Block.ImpliedType()
   179  
   180  	p.UpgradeResourceStateCalled = true
   181  	p.UpgradeResourceStateRequest = r
   182  
   183  	if p.UpgradeResourceStateFn != nil {
   184  		return p.UpgradeResourceStateFn(r)
   185  	}
   186  
   187  	resp := p.UpgradeResourceStateResponse
   188  
   189  	if resp.UpgradedState == cty.NilVal {
   190  		switch {
   191  		case r.RawStateFlatmap != nil:
   192  			v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType)
   193  			if err != nil {
   194  				resp.Diagnostics = resp.Diagnostics.Append(err)
   195  				return resp
   196  			}
   197  			resp.UpgradedState = v
   198  		case len(r.RawStateJSON) > 0:
   199  			v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType)
   200  
   201  			if err != nil {
   202  				resp.Diagnostics = resp.Diagnostics.Append(err)
   203  				return resp
   204  			}
   205  			resp.UpgradedState = v
   206  		}
   207  	}
   208  	return resp
   209  }
   210  
   211  func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
   212  	p.Lock()
   213  	defer p.Unlock()
   214  
   215  	p.ConfigureProviderCalled = true
   216  	p.ConfigureProviderRequest = r
   217  
   218  	if p.ConfigureProviderFn != nil {
   219  		return p.ConfigureProviderFn(r)
   220  	}
   221  
   222  	return p.ConfigureProviderResponse
   223  }
   224  
   225  func (p *MockProvider) Stop() error {
   226  	// We intentionally don't lock in this one because the whole point of this
   227  	// method is to be called concurrently with another operation that can
   228  	// be cancelled.  The provider itself is responsible for handling
   229  	// any concurrency concerns in this case.
   230  
   231  	p.StopCalled = true
   232  	if p.StopFn != nil {
   233  		return p.StopFn()
   234  	}
   235  
   236  	return p.StopResponse
   237  }
   238  
   239  func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) providers.ReadResourceResponse {
   240  	p.Lock()
   241  	defer p.Unlock()
   242  
   243  	p.ReadResourceCalled = true
   244  	p.ReadResourceRequest = r
   245  
   246  	if p.ReadResourceFn != nil {
   247  		return p.ReadResourceFn(r)
   248  	}
   249  
   250  	resp := p.ReadResourceResponse
   251  	if resp.NewState != cty.NilVal {
   252  		// make sure the NewState fits the schema
   253  		// This isn't always the case for the existing tests
   254  		newState, err := p.GetSchemaReturn.ResourceTypes[r.TypeName].CoerceValue(resp.NewState)
   255  		if err != nil {
   256  			panic(err)
   257  		}
   258  		resp.NewState = newState
   259  		return resp
   260  	}
   261  
   262  	// just return the same state we received
   263  	resp.NewState = r.PriorState
   264  	return resp
   265  }
   266  
   267  func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
   268  	p.Lock()
   269  	defer p.Unlock()
   270  
   271  	p.PlanResourceChangeCalled = true
   272  	p.PlanResourceChangeRequest = r
   273  
   274  	if p.PlanResourceChangeFn != nil {
   275  		return p.PlanResourceChangeFn(r)
   276  	}
   277  
   278  	return p.PlanResourceChangeResponse
   279  }
   280  
   281  func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
   282  	p.Lock()
   283  	p.ApplyResourceChangeCalled = true
   284  	p.ApplyResourceChangeRequest = r
   285  	p.Unlock()
   286  
   287  	if p.ApplyResourceChangeFn != nil {
   288  		return p.ApplyResourceChangeFn(r)
   289  	}
   290  
   291  	return p.ApplyResourceChangeResponse
   292  }
   293  
   294  func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
   295  	p.Lock()
   296  	defer p.Unlock()
   297  
   298  	if p.ImportStateReturn != nil {
   299  		for _, is := range p.ImportStateReturn {
   300  			if is.Attributes == nil {
   301  				is.Attributes = make(map[string]string)
   302  			}
   303  			is.Attributes["id"] = is.ID
   304  
   305  			typeName := is.Ephemeral.Type
   306  			// Use the requested type if the resource has no type of it's own.
   307  			// We still return the empty type, which will error, but this prevents a panic.
   308  			if typeName == "" {
   309  				typeName = r.TypeName
   310  			}
   311  
   312  			schema := p.GetSchemaReturn.ResourceTypes[typeName]
   313  			if schema == nil {
   314  				panic("no schema found for " + typeName)
   315  			}
   316  
   317  			private, err := json.Marshal(is.Meta)
   318  			if err != nil {
   319  				panic(err)
   320  			}
   321  
   322  			state, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, schema.ImpliedType())
   323  			if err != nil {
   324  				panic(err)
   325  			}
   326  
   327  			state, err = schema.CoerceValue(state)
   328  			if err != nil {
   329  				panic(err)
   330  			}
   331  
   332  			p.ImportResourceStateResponse.ImportedResources = append(
   333  				p.ImportResourceStateResponse.ImportedResources,
   334  				providers.ImportedResource{
   335  					TypeName: is.Ephemeral.Type,
   336  					State:    state,
   337  					Private:  private,
   338  				})
   339  		}
   340  	}
   341  
   342  	p.ImportResourceStateCalled = true
   343  	p.ImportResourceStateRequest = r
   344  	if p.ImportResourceStateFn != nil {
   345  		return p.ImportResourceStateFn(r)
   346  	}
   347  
   348  	return p.ImportResourceStateResponse
   349  }
   350  
   351  func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
   352  	p.Lock()
   353  	defer p.Unlock()
   354  
   355  	p.ReadDataSourceCalled = true
   356  	p.ReadDataSourceRequest = r
   357  
   358  	if p.ReadDataSourceFn != nil {
   359  		return p.ReadDataSourceFn(r)
   360  	}
   361  
   362  	return p.ReadDataSourceResponse
   363  }
   364  
   365  func (p *MockProvider) GetFunctions() providers.GetFunctionsResponse {
   366  	panic("Not Implemented")
   367  }
   368  
   369  func (p *MockProvider) CallFunction(r providers.CallFunctionRequest) providers.CallFunctionResponse {
   370  	panic("Not Implemented")
   371  }
   372  
   373  func (p *MockProvider) Close() error {
   374  	p.CloseCalled = true
   375  	return p.CloseError
   376  }