terraform: shadow resource provider tests begin

This commit is contained in:
Mitchell Hashimoto 2016-09-30 11:33:36 -07:00
parent d37bb87bf2
commit bb5f116cec
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 134 additions and 31 deletions

View File

@ -48,6 +48,9 @@ func newShadowResourceProvider(p ResourceProvider) (ResourceProvider, shadowReso
// Create the shadow that watches the real value // Create the shadow that watches the real value
shadow := &shadowResourceProviderShadow{ shadow := &shadowResourceProviderShadow{
Shared: &shared, Shared: &shared,
resources: p.Resources(),
dataSources: p.DataSources(),
} }
return real, shadow return real, shadow
@ -62,18 +65,6 @@ type shadowResourceProviderReal struct {
Shared *shadowResourceProviderShared Shared *shadowResourceProviderShared
} }
func (p *shadowResourceProviderReal) Resources() []ResourceType {
result := p.ResourceProvider.Resources()
p.Shared.Resources.SetValue(result)
return result
}
func (p *shadowResourceProviderReal) DataSources() []DataSource {
result := p.ResourceProvider.DataSources()
p.Shared.DataSources.SetValue(result)
return result
}
func (p *shadowResourceProviderReal) Close() error { func (p *shadowResourceProviderReal) Close() error {
var result error var result error
if c, ok := p.ResourceProvider.(ResourceProviderCloser); ok { if c, ok := p.ResourceProvider.(ResourceProviderCloser); ok {
@ -88,8 +79,8 @@ func (p *shadowResourceProviderReal) Input(
input UIInput, c *ResourceConfig) (*ResourceConfig, error) { input UIInput, c *ResourceConfig) (*ResourceConfig, error) {
result, err := p.ResourceProvider.Input(input, c) result, err := p.ResourceProvider.Input(input, c)
p.Shared.Input.SetValue(&shadowResourceProviderInput{ p.Shared.Input.SetValue(&shadowResourceProviderInput{
Config: c, Config: c.DeepCopy(),
Result: result, Result: result.DeepCopy(),
ResultErr: err, ResultErr: err,
}) })
@ -102,35 +93,32 @@ func (p *shadowResourceProviderReal) Input(
type shadowResourceProviderShadow struct { type shadowResourceProviderShadow struct {
Shared *shadowResourceProviderShared Shared *shadowResourceProviderShared
// Cached values that are expected to not change
resources []ResourceType
dataSources []DataSource
Error error // Error is the list of errors from the shadow Error error // Error is the list of errors from the shadow
ErrorLock sync.Mutex ErrorLock sync.Mutex
} }
type shadowResourceProviderShared struct { type shadowResourceProviderShared struct {
CloseErr shadow.Value CloseErr shadow.Value
Input shadow.Value Input shadow.Value
Resources shadow.Value
DataSources shadow.Value
} }
func (p *shadowResourceProviderShadow) CloseShadow() error { return nil } func (p *shadowResourceProviderShadow) CloseShadow() error {
// For now, just return the error. What we need to do in the future
// is marked the provider as "closed" so that any subsequent calls
// will fail out.
return p.Error
}
func (p *shadowResourceProviderShadow) Resources() []ResourceType { func (p *shadowResourceProviderShadow) Resources() []ResourceType {
v := p.Shared.Resources.Value() return p.resources
if v == nil {
return nil
}
return v.([]ResourceType)
} }
func (p *shadowResourceProviderShadow) DataSources() []DataSource { func (p *shadowResourceProviderShadow) DataSources() []DataSource {
v := p.Shared.DataSources.Value() return p.dataSources
if v == nil {
return nil
}
return v.([]DataSource)
} }
func (p *shadowResourceProviderShadow) Close() error { func (p *shadowResourceProviderShadow) Close() error {

View File

@ -0,0 +1,115 @@
package terraform
import (
"reflect"
"testing"
"time"
)
func TestShadowResourceProvider_cachedValues(t *testing.T) {
mock := new(MockResourceProvider)
real, shadow := newShadowResourceProvider(mock)
// Resources
{
actual := shadow.Resources()
expected := real.Resources()
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad:\n\n%#v\n\n%#v", actual, expected)
}
}
// DataSources
{
actual := shadow.DataSources()
expected := real.DataSources()
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad:\n\n%#v\n\n%#v", actual, expected)
}
}
}
func TestShadowResourceProviderInput(t *testing.T) {
mock := new(MockResourceProvider)
real, shadow := newShadowResourceProvider(mock)
// Test values
ui := new(MockUIInput)
config := testResourceConfig(t, map[string]interface{}{
"foo": "bar",
})
returnConfig := testResourceConfig(t, map[string]interface{}{
"bar": "baz",
})
// Configure the mock
mock.InputReturnConfig = returnConfig
// Verify that it blocks until the real input is called
var actual *ResourceConfig
var err error
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
actual, err = shadow.Input(ui, config)
}()
select {
case <-doneCh:
t.Fatal("should block until finished")
case <-time.After(10 * time.Millisecond):
}
// Call the real input
realResult, realErr := real.Input(ui, config)
if !realResult.Equal(returnConfig) {
t.Fatalf("bad: %#v", realResult)
}
if realErr != nil {
t.Fatalf("bad: %s", realErr)
}
// The shadow should finish now
<-doneCh
// Verify the shadow returned the same values
if !actual.Equal(returnConfig) {
t.Fatalf("bad: %#v", actual)
}
if err != nil {
t.Fatalf("bad: %s", err)
}
// Verify we have no errors
if err := shadow.CloseShadow(); err != nil {
t.Fatalf("bad: %s", err)
}
}
func TestShadowResourceProviderInput_badInput(t *testing.T) {
mock := new(MockResourceProvider)
real, shadow := newShadowResourceProvider(mock)
// Test values
ui := new(MockUIInput)
config := testResourceConfig(t, map[string]interface{}{
"foo": "bar",
})
configBad := testResourceConfig(t, map[string]interface{}{
"foo": "nope",
})
// Call the real with one
real.Input(ui, config)
// Call the shadow with another
_, err := shadow.Input(ui, configBad)
if err != nil {
t.Fatalf("bad: %s", err)
}
// Verify we have an error
if err := shadow.CloseShadow(); err == nil {
t.Fatal("should have error")
}
}