blob: abdba432460e42b028f5b7e9b3c56d3d13ed4056 [file] [log] [blame]
package terraform
import (
"encoding/json"
"sync"
"github.com/zclconf/go-cty/cty"
ctyjson "github.com/zclconf/go-cty/cty/json"
"github.com/hashicorp/terraform/internal/configs/hcl2shim"
"github.com/hashicorp/terraform/internal/providers"
)
var _ providers.Interface = (*MockProvider)(nil)
// MockProvider implements providers.Interface but mocks out all the
// calls for testing purposes.
type MockProvider struct {
sync.Mutex
// Anything you want, in case you need to store extra data with the mock.
Meta interface{}
GetSchemaCalled bool
GetSchemaReturn *ProviderSchema // This is using ProviderSchema directly rather than providers.GetProviderSchemaResponse for compatibility with old tests
ValidateProviderConfigCalled bool
ValidateProviderConfigResponse providers.ValidateProviderConfigResponse
ValidateProviderConfigRequest providers.ValidateProviderConfigRequest
ValidateProviderConfigFn func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse
ValidateResourceConfigCalled bool
ValidateResourceConfigTypeName string
ValidateResourceConfigResponse providers.ValidateResourceConfigResponse
ValidateResourceConfigRequest providers.ValidateResourceConfigRequest
ValidateResourceConfigFn func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse
ValidateDataResourceConfigCalled bool
ValidateDataResourceConfigTypeName string
ValidateDataResourceConfigResponse providers.ValidateDataResourceConfigResponse
ValidateDataResourceConfigRequest providers.ValidateDataResourceConfigRequest
ValidateDataResourceConfigFn func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse
UpgradeResourceStateCalled bool
UpgradeResourceStateTypeName string
UpgradeResourceStateResponse providers.UpgradeResourceStateResponse
UpgradeResourceStateRequest providers.UpgradeResourceStateRequest
UpgradeResourceStateFn func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse
ConfigureProviderCalled bool
ConfigureProviderResponse providers.ConfigureProviderResponse
ConfigureProviderRequest providers.ConfigureProviderRequest
ConfigureProviderFn func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse
StopCalled bool
StopFn func() error
StopResponse error
ReadResourceCalled bool
ReadResourceResponse providers.ReadResourceResponse
ReadResourceRequest providers.ReadResourceRequest
ReadResourceFn func(providers.ReadResourceRequest) providers.ReadResourceResponse
PlanResourceChangeCalled bool
PlanResourceChangeResponse providers.PlanResourceChangeResponse
PlanResourceChangeRequest providers.PlanResourceChangeRequest
PlanResourceChangeFn func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse
ApplyResourceChangeCalled bool
ApplyResourceChangeResponse providers.ApplyResourceChangeResponse
ApplyResourceChangeRequest providers.ApplyResourceChangeRequest
ApplyResourceChangeFn func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse
ImportResourceStateCalled bool
ImportResourceStateResponse providers.ImportResourceStateResponse
ImportResourceStateRequest providers.ImportResourceStateRequest
ImportResourceStateFn func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse
// Legacy return type for existing tests, which will be shimmed into an
// ImportResourceStateResponse if set
ImportStateReturn []*InstanceState
ReadDataSourceCalled bool
ReadDataSourceResponse providers.ReadDataSourceResponse
ReadDataSourceRequest providers.ReadDataSourceRequest
ReadDataSourceFn func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse
CloseCalled bool
CloseError error
}
func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
p.Lock()
defer p.Unlock()
p.GetSchemaCalled = true
return p.getSchema()
}
func (p *MockProvider) getSchema() providers.GetProviderSchemaResponse {
// This version of getSchema doesn't do any locking, so it's suitable to
// call from other methods of this mock as long as they are already
// holding the lock.
ret := providers.GetProviderSchemaResponse{
Provider: providers.Schema{},
DataSources: map[string]providers.Schema{},
ResourceTypes: map[string]providers.Schema{},
}
if p.GetSchemaReturn != nil {
ret.Provider.Block = p.GetSchemaReturn.Provider
ret.ProviderMeta.Block = p.GetSchemaReturn.ProviderMeta
for n, s := range p.GetSchemaReturn.DataSources {
ret.DataSources[n] = providers.Schema{
Block: s,
}
}
for n, s := range p.GetSchemaReturn.ResourceTypes {
ret.ResourceTypes[n] = providers.Schema{
Version: int64(p.GetSchemaReturn.ResourceTypeSchemaVersions[n]),
Block: s,
}
}
}
return ret
}
func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
p.Lock()
defer p.Unlock()
p.ValidateProviderConfigCalled = true
p.ValidateProviderConfigRequest = r
if p.ValidateProviderConfigFn != nil {
return p.ValidateProviderConfigFn(r)
}
return p.ValidateProviderConfigResponse
}
func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
p.Lock()
defer p.Unlock()
p.ValidateResourceConfigCalled = true
p.ValidateResourceConfigRequest = r
if p.ValidateResourceConfigFn != nil {
return p.ValidateResourceConfigFn(r)
}
return p.ValidateResourceConfigResponse
}
func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
p.Lock()
defer p.Unlock()
p.ValidateDataResourceConfigCalled = true
p.ValidateDataResourceConfigRequest = r
if p.ValidateDataResourceConfigFn != nil {
return p.ValidateDataResourceConfigFn(r)
}
return p.ValidateDataResourceConfigResponse
}
func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
p.Lock()
defer p.Unlock()
schemas := p.getSchema()
schema := schemas.ResourceTypes[r.TypeName]
schemaType := schema.Block.ImpliedType()
p.UpgradeResourceStateCalled = true
p.UpgradeResourceStateRequest = r
if p.UpgradeResourceStateFn != nil {
return p.UpgradeResourceStateFn(r)
}
resp := p.UpgradeResourceStateResponse
if resp.UpgradedState == cty.NilVal {
switch {
case r.RawStateFlatmap != nil:
v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType)
if err != nil {
resp.Diagnostics = resp.Diagnostics.Append(err)
return resp
}
resp.UpgradedState = v
case len(r.RawStateJSON) > 0:
v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType)
if err != nil {
resp.Diagnostics = resp.Diagnostics.Append(err)
return resp
}
resp.UpgradedState = v
}
}
return resp
}
func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
p.Lock()
defer p.Unlock()
p.ConfigureProviderCalled = true
p.ConfigureProviderRequest = r
if p.ConfigureProviderFn != nil {
return p.ConfigureProviderFn(r)
}
return p.ConfigureProviderResponse
}
func (p *MockProvider) Stop() error {
// We intentionally don't lock in this one because the whole point of this
// method is to be called concurrently with another operation that can
// be cancelled. The provider itself is responsible for handling
// any concurrency concerns in this case.
p.StopCalled = true
if p.StopFn != nil {
return p.StopFn()
}
return p.StopResponse
}
func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) providers.ReadResourceResponse {
p.Lock()
defer p.Unlock()
p.ReadResourceCalled = true
p.ReadResourceRequest = r
if p.ReadResourceFn != nil {
return p.ReadResourceFn(r)
}
resp := p.ReadResourceResponse
if resp.NewState != cty.NilVal {
// make sure the NewState fits the schema
// This isn't always the case for the existing tests
newState, err := p.GetSchemaReturn.ResourceTypes[r.TypeName].CoerceValue(resp.NewState)
if err != nil {
panic(err)
}
resp.NewState = newState
return resp
}
// just return the same state we received
resp.NewState = r.PriorState
return resp
}
func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
p.Lock()
defer p.Unlock()
p.PlanResourceChangeCalled = true
p.PlanResourceChangeRequest = r
if p.PlanResourceChangeFn != nil {
return p.PlanResourceChangeFn(r)
}
return p.PlanResourceChangeResponse
}
func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
p.Lock()
p.ApplyResourceChangeCalled = true
p.ApplyResourceChangeRequest = r
p.Unlock()
if p.ApplyResourceChangeFn != nil {
return p.ApplyResourceChangeFn(r)
}
return p.ApplyResourceChangeResponse
}
func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
p.Lock()
defer p.Unlock()
if p.ImportStateReturn != nil {
for _, is := range p.ImportStateReturn {
if is.Attributes == nil {
is.Attributes = make(map[string]string)
}
is.Attributes["id"] = is.ID
typeName := is.Ephemeral.Type
// Use the requested type if the resource has no type of it's own.
// We still return the empty type, which will error, but this prevents a panic.
if typeName == "" {
typeName = r.TypeName
}
schema := p.GetSchemaReturn.ResourceTypes[typeName]
if schema == nil {
panic("no schema found for " + typeName)
}
private, err := json.Marshal(is.Meta)
if err != nil {
panic(err)
}
state, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, schema.ImpliedType())
if err != nil {
panic(err)
}
state, err = schema.CoerceValue(state)
if err != nil {
panic(err)
}
p.ImportResourceStateResponse.ImportedResources = append(
p.ImportResourceStateResponse.ImportedResources,
providers.ImportedResource{
TypeName: is.Ephemeral.Type,
State: state,
Private: private,
})
}
}
p.ImportResourceStateCalled = true
p.ImportResourceStateRequest = r
if p.ImportResourceStateFn != nil {
return p.ImportResourceStateFn(r)
}
return p.ImportResourceStateResponse
}
func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
p.Lock()
defer p.Unlock()
p.ReadDataSourceCalled = true
p.ReadDataSourceRequest = r
if p.ReadDataSourceFn != nil {
return p.ReadDataSourceFn(r)
}
return p.ReadDataSourceResponse
}
func (p *MockProvider) Close() error {
p.CloseCalled = true
return p.CloseError
}