terraform/terraform/provisioner_mock.go

155 lines
4.2 KiB
Go

package terraform
import (
"fmt"
"sync"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
"github.com/hashicorp/terraform/provisioners"
)
var _ provisioners.Interface = (*MockProvisioner)(nil)
// MockProvisioner implements provisioners.Interface but mocks out all the
// calls for testing purposes.
type MockProvisioner struct {
sync.Mutex
// Anything you want, in case you need to store extra data with the mock.
Meta interface{}
GetSchemaCalled bool
GetSchemaResponse provisioners.GetSchemaResponse
ValidateProvisionerConfigCalled bool
ValidateProvisionerConfigRequest provisioners.ValidateProvisionerConfigRequest
ValidateProvisionerConfigResponse provisioners.ValidateProvisionerConfigResponse
ValidateProvisionerConfigFn func(provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse
ProvisionResourceCalled bool
ProvisionResourceRequest provisioners.ProvisionResourceRequest
ProvisionResourceResponse provisioners.ProvisionResourceResponse
ProvisionResourceFn func(provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse
StopCalled bool
StopResponse error
StopFn func() error
CloseCalled bool
CloseResponse error
CloseFn func() error
// Legacy callbacks: if these are set, we will shim incoming calls for
// new-style methods to these old-fashioned terraform.ResourceProvider
// mock callbacks, for the benefit of older tests that were written against
// the old mock API.
ApplyFn func(rs *InstanceState, c *ResourceConfig) error
}
func (p *MockProvisioner) GetSchema() provisioners.GetSchemaResponse {
p.Lock()
defer p.Unlock()
p.GetSchemaCalled = true
return p.getSchema()
}
// getSchema is the implementation of GetSchema, which can be called from other
// methods on MockProvisioner that may already be holding the lock.
func (p *MockProvisioner) getSchema() provisioners.GetSchemaResponse {
return p.GetSchemaResponse
}
func (p *MockProvisioner) ValidateProvisionerConfig(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
p.Lock()
defer p.Unlock()
p.ValidateProvisionerConfigCalled = true
p.ValidateProvisionerConfigRequest = r
if p.ValidateProvisionerConfigFn != nil {
return p.ValidateProvisionerConfigFn(r)
}
return p.ValidateProvisionerConfigResponse
}
func (p *MockProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequest) provisioners.ProvisionResourceResponse {
p.Lock()
defer p.Unlock()
p.ProvisionResourceCalled = true
p.ProvisionResourceRequest = r
if p.ApplyFn != nil {
if !r.Config.IsKnown() {
panic(fmt.Sprintf("cannot provision with unknown value: %#v", r.Config))
}
schema := p.getSchema()
rc := NewResourceConfigShimmed(r.Config, schema.Provisioner)
connVal := r.Connection
connMap := map[string]string{}
if !connVal.IsNull() && connVal.IsKnown() {
for it := connVal.ElementIterator(); it.Next(); {
ak, av := it.Element()
name := ak.AsString()
if !av.IsKnown() || av.IsNull() {
continue
}
av, _ = convert.Convert(av, cty.String)
connMap[name] = av.AsString()
}
}
// We no longer pass the full instance state to a provisioner, so we'll
// construct a partial one that should be good enough for what existing
// test mocks need.
is := &InstanceState{
Ephemeral: EphemeralState{
ConnInfo: connMap,
},
}
var resp provisioners.ProvisionResourceResponse
err := p.ApplyFn(is, rc)
if err != nil {
resp.Diagnostics = resp.Diagnostics.Append(err)
}
return resp
}
if p.ProvisionResourceFn != nil {
fn := p.ProvisionResourceFn
p.Unlock()
return fn(r)
}
return p.ProvisionResourceResponse
}
func (p *MockProvisioner) 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 provisioner 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 *MockProvisioner) Close() error {
p.Lock()
defer p.Unlock()
p.CloseCalled = true
if p.CloseFn != nil {
return p.CloseFn()
}
return p.CloseResponse
}