terraform: ResourceProvider.Validate for shadow

This commit is contained in:
Mitchell Hashimoto 2016-09-30 15:39:20 -07:00
parent bb5f116cec
commit 23204d2414
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 131 additions and 7 deletions

View File

@ -87,6 +87,17 @@ func (p *shadowResourceProviderReal) Input(
return result, err return result, err
} }
func (p *shadowResourceProviderReal) Validate(c *ResourceConfig) ([]string, []error) {
warns, errs := p.ResourceProvider.Validate(c)
p.Shared.Validate.SetValue(&shadowResourceProviderValidate{
Config: c.DeepCopy(),
ResultWarn: warns,
ResultErr: errs,
})
return warns, errs
}
// shadowResourceProviderShadow is the shadow resource provider. Function // shadowResourceProviderShadow is the shadow resource provider. Function
// calls never affect real resources. This is paired with the "real" side // calls never affect real resources. This is paired with the "real" side
// which must be called properly to enable recording. // which must be called properly to enable recording.
@ -104,6 +115,7 @@ type shadowResourceProviderShadow struct {
type shadowResourceProviderShared struct { type shadowResourceProviderShared struct {
CloseErr shadow.Value CloseErr shadow.Value
Input shadow.Value Input shadow.Value
Validate shadow.Value
} }
func (p *shadowResourceProviderShadow) CloseShadow() error { func (p *shadowResourceProviderShadow) CloseShadow() error {
@ -160,16 +172,41 @@ func (p *shadowResourceProviderShadow) Input(
return result.Result, result.ResultErr return result.Result, result.ResultErr
} }
// TODO
// TODO
// TODO
// TODO
// TODO
func (p *shadowResourceProviderShadow) Validate(c *ResourceConfig) ([]string, []error) { func (p *shadowResourceProviderShadow) Validate(c *ResourceConfig) ([]string, []error) {
// Get the result of the validate call
raw := p.Shared.Validate.Value()
if raw == nil {
return nil, nil return nil, nil
}
result, ok := raw.(*shadowResourceProviderValidate)
if !ok {
p.ErrorLock.Lock()
defer p.ErrorLock.Unlock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"Unknown 'validate' shadow value: %#v", raw))
return nil, nil
}
// Compare the parameters, which should be identical
if !c.Equal(result.Config) {
p.ErrorLock.Lock()
p.Error = multierror.Append(p.Error, fmt.Errorf(
"Validate had unequal configurations (real, then shadow):\n\n%#v\n\n%#v",
result.Config, c))
p.ErrorLock.Unlock()
}
// Return the results
return result.ResultWarn, result.ResultErr
} }
// TODO
// TODO
// TODO
// TODO
// TODO
func (p *shadowResourceProviderShadow) ValidateResource(t string, c *ResourceConfig) ([]string, []error) { func (p *shadowResourceProviderShadow) ValidateResource(t string, c *ResourceConfig) ([]string, []error) {
return nil, nil return nil, nil
} }
@ -226,3 +263,9 @@ type shadowResourceProviderInput struct {
Result *ResourceConfig Result *ResourceConfig
ResultErr error ResultErr error
} }
type shadowResourceProviderValidate struct {
Config *ResourceConfig
ResultWarn []string
ResultErr []error
}

View File

@ -1,6 +1,7 @@
package terraform package terraform
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
"time" "time"
@ -113,3 +114,83 @@ func TestShadowResourceProviderInput_badInput(t *testing.T) {
t.Fatal("should have error") t.Fatal("should have error")
} }
} }
func TestShadowResourceProviderValidate(t *testing.T) {
mock := new(MockResourceProvider)
real, shadow := newShadowResourceProvider(mock)
// Test values
config := testResourceConfig(t, map[string]interface{}{
"foo": "bar",
})
returnWarns := []string{"foo"}
returnErrs := []error{fmt.Errorf("bar")}
// Configure the mock
mock.ValidateReturnWarns = returnWarns
mock.ValidateReturnErrors = returnErrs
// Verify that it blocks until the real func is called
var warns []string
var errs []error
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
warns, errs = shadow.Validate(config)
}()
select {
case <-doneCh:
t.Fatal("should block until finished")
case <-time.After(10 * time.Millisecond):
}
// Call the real func
realWarns, realErrs := real.Validate(config)
if !reflect.DeepEqual(realWarns, returnWarns) {
t.Fatalf("bad: %#v", realWarns)
}
if !reflect.DeepEqual(realErrs, returnErrs) {
t.Fatalf("bad: %#v", realWarns)
}
// The shadow should finish now
<-doneCh
// Verify the shadow returned the same values
if !reflect.DeepEqual(warns, returnWarns) {
t.Fatalf("bad: %#v", warns)
}
if !reflect.DeepEqual(errs, returnErrs) {
t.Fatalf("bad: %#v", errs)
}
// Verify we have no errors
if err := shadow.CloseShadow(); err != nil {
t.Fatalf("bad: %s", err)
}
}
func TestShadowResourceProviderValidate_badInput(t *testing.T) {
mock := new(MockResourceProvider)
real, shadow := newShadowResourceProvider(mock)
// Test values
config := testResourceConfig(t, map[string]interface{}{
"foo": "bar",
})
configBad := testResourceConfig(t, map[string]interface{}{
"foo": "nope",
})
// Call the real with one
real.Validate(config)
// Call the shadow with another
shadow.Validate(configBad)
// Verify we have an error
if err := shadow.CloseShadow(); err == nil {
t.Fatal("should have error")
}
}