mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
532 lines
12 KiB
Go
532 lines
12 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestShadowResourceProvider_impl(t *testing.T) {
|
|
var _ Shadow = new(shadowResourceProviderShadow)
|
|
}
|
|
|
|
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.Fatalf("bad: %s", err)
|
|
}
|
|
if err := shadow.ShadowError(); err == nil {
|
|
t.Fatal("should 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.Fatalf("bad: %s", err)
|
|
}
|
|
if err := shadow.ShadowError(); err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderConfigure(t *testing.T) {
|
|
mock := new(MockResourceProvider)
|
|
real, shadow := newShadowResourceProvider(mock)
|
|
|
|
// Test values
|
|
config := testResourceConfig(t, map[string]interface{}{
|
|
"foo": "bar",
|
|
})
|
|
returnErr := fmt.Errorf("bar")
|
|
|
|
// Configure the mock
|
|
mock.ConfigureReturnError = returnErr
|
|
|
|
// Verify that it blocks until the real func is called
|
|
var err error
|
|
doneCh := make(chan struct{})
|
|
go func() {
|
|
defer close(doneCh)
|
|
err = shadow.Configure(config)
|
|
}()
|
|
|
|
select {
|
|
case <-doneCh:
|
|
t.Fatal("should block until finished")
|
|
case <-time.After(10 * time.Millisecond):
|
|
}
|
|
|
|
// Call the real func
|
|
realErr := real.Configure(config)
|
|
if !reflect.DeepEqual(realErr, returnErr) {
|
|
t.Fatalf("bad: %#v", realErr)
|
|
}
|
|
|
|
// The shadow should finish now
|
|
<-doneCh
|
|
|
|
// Verify the shadow returned the same values
|
|
if !reflect.DeepEqual(err, returnErr) {
|
|
t.Fatalf("bad: %#v", err)
|
|
}
|
|
|
|
// Verify we have no errors
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderConfigure_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.Configure(config)
|
|
|
|
// Call the shadow with another
|
|
shadow.Configure(configBad)
|
|
|
|
// Verify we have an error
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
if err := shadow.ShadowError(); err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderApply(t *testing.T) {
|
|
mock := new(MockResourceProvider)
|
|
real, shadow := newShadowResourceProvider(mock)
|
|
|
|
// Test values
|
|
info := &InstanceInfo{Id: "foo"}
|
|
state := &InstanceState{ID: "foo"}
|
|
diff := &InstanceDiff{Destroy: true}
|
|
mockResult := &InstanceState{ID: "bar"}
|
|
|
|
// Configure the mock
|
|
mock.ApplyReturn = mockResult
|
|
|
|
// Verify that it blocks until the real func is called
|
|
var result *InstanceState
|
|
var err error
|
|
doneCh := make(chan struct{})
|
|
go func() {
|
|
defer close(doneCh)
|
|
result, err = shadow.Apply(info, state, diff)
|
|
}()
|
|
|
|
select {
|
|
case <-doneCh:
|
|
t.Fatal("should block until finished")
|
|
case <-time.After(10 * time.Millisecond):
|
|
}
|
|
|
|
// Call the real func
|
|
realResult, realErr := real.Apply(info, state, diff)
|
|
if !realResult.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", realResult)
|
|
}
|
|
if realErr != nil {
|
|
t.Fatalf("bad: %#v", realErr)
|
|
}
|
|
|
|
// The shadow should finish now
|
|
<-doneCh
|
|
|
|
// Verify the shadow returned the same values
|
|
if !result.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", result)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("bad: %#v", err)
|
|
}
|
|
|
|
// Verify we have no errors
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderApply_modifyDiff(t *testing.T) {
|
|
mock := new(MockResourceProvider)
|
|
real, shadow := newShadowResourceProvider(mock)
|
|
|
|
// Test values
|
|
info := &InstanceInfo{Id: "foo"}
|
|
state := &InstanceState{ID: "foo"}
|
|
diff := &InstanceDiff{}
|
|
mockResult := &InstanceState{ID: "foo"}
|
|
|
|
// Configure the mock
|
|
mock.ApplyFn = func(
|
|
info *InstanceInfo,
|
|
s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
d.Destroy = true
|
|
return s, nil
|
|
}
|
|
|
|
// Call the real func
|
|
realResult, realErr := real.Apply(info, state.DeepCopy(), diff.DeepCopy())
|
|
if !realResult.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", realResult)
|
|
}
|
|
if realErr != nil {
|
|
t.Fatalf("bad: %#v", realErr)
|
|
}
|
|
|
|
// Verify the shadow returned the same values
|
|
result, err := shadow.Apply(info, state.DeepCopy(), diff.DeepCopy())
|
|
if !result.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", result)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("bad: %#v", err)
|
|
}
|
|
|
|
// Verify we have no errors
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
if err := shadow.ShadowError(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderApply_modifyState(t *testing.T) {
|
|
mock := new(MockResourceProvider)
|
|
real, shadow := newShadowResourceProvider(mock)
|
|
|
|
// Test values
|
|
info := &InstanceInfo{Id: "foo"}
|
|
state := &InstanceState{ID: ""}
|
|
diff := &InstanceDiff{}
|
|
mockResult := &InstanceState{ID: "foo"}
|
|
|
|
// Configure the mock
|
|
mock.ApplyFn = func(
|
|
info *InstanceInfo,
|
|
s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
s.ID = "foo"
|
|
return s, nil
|
|
}
|
|
|
|
// Call the real func
|
|
realResult, realErr := real.Apply(info, state.DeepCopy(), diff)
|
|
if !realResult.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", realResult)
|
|
}
|
|
if realErr != nil {
|
|
t.Fatalf("bad: %#v", realErr)
|
|
}
|
|
|
|
// Verify the shadow returned the same values
|
|
result, err := shadow.Apply(info, state.DeepCopy(), diff)
|
|
if !result.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", result)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("bad: %#v", err)
|
|
}
|
|
|
|
// Verify we have no errors
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
if err := shadow.ShadowError(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderDiff(t *testing.T) {
|
|
mock := new(MockResourceProvider)
|
|
real, shadow := newShadowResourceProvider(mock)
|
|
|
|
// Test values
|
|
info := &InstanceInfo{Id: "foo"}
|
|
state := &InstanceState{ID: "foo"}
|
|
desired := testResourceConfig(t, map[string]interface{}{"foo": "bar"})
|
|
mockResult := &InstanceDiff{Destroy: true}
|
|
|
|
// Configure the mock
|
|
mock.DiffReturn = mockResult
|
|
|
|
// Verify that it blocks until the real func is called
|
|
var result *InstanceDiff
|
|
var err error
|
|
doneCh := make(chan struct{})
|
|
go func() {
|
|
defer close(doneCh)
|
|
result, err = shadow.Diff(info, state, desired)
|
|
}()
|
|
|
|
select {
|
|
case <-doneCh:
|
|
t.Fatal("should block until finished")
|
|
case <-time.After(10 * time.Millisecond):
|
|
}
|
|
|
|
// Call the real func
|
|
realResult, realErr := real.Diff(info, state, desired)
|
|
if !reflect.DeepEqual(realResult, mockResult) {
|
|
t.Fatalf("bad: %#v", realResult)
|
|
}
|
|
if realErr != nil {
|
|
t.Fatalf("bad: %#v", realErr)
|
|
}
|
|
|
|
// The shadow should finish now
|
|
<-doneCh
|
|
|
|
// Verify the shadow returned the same values
|
|
if !reflect.DeepEqual(result, mockResult) {
|
|
t.Fatalf("bad: %#v", result)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("bad: %#v", err)
|
|
}
|
|
|
|
// Verify we have no errors
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestShadowResourceProviderRefresh(t *testing.T) {
|
|
mock := new(MockResourceProvider)
|
|
real, shadow := newShadowResourceProvider(mock)
|
|
|
|
// Test values
|
|
info := &InstanceInfo{Id: "foo"}
|
|
state := &InstanceState{ID: "foo"}
|
|
mockResult := &InstanceState{ID: "bar"}
|
|
|
|
// Configure the mock
|
|
mock.RefreshReturn = mockResult
|
|
|
|
// Verify that it blocks until the real func is called
|
|
var result *InstanceState
|
|
var err error
|
|
doneCh := make(chan struct{})
|
|
go func() {
|
|
defer close(doneCh)
|
|
result, err = shadow.Refresh(info, state)
|
|
}()
|
|
|
|
select {
|
|
case <-doneCh:
|
|
t.Fatal("should block until finished")
|
|
case <-time.After(10 * time.Millisecond):
|
|
}
|
|
|
|
// Call the real func
|
|
realResult, realErr := real.Refresh(info, state)
|
|
if !realResult.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", realResult)
|
|
}
|
|
if realErr != nil {
|
|
t.Fatalf("bad: %#v", realErr)
|
|
}
|
|
|
|
// The shadow should finish now
|
|
<-doneCh
|
|
|
|
// Verify the shadow returned the same values
|
|
if !result.Equal(mockResult) {
|
|
t.Fatalf("bad: %#v", result)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("bad: %#v", err)
|
|
}
|
|
|
|
// Verify we have no errors
|
|
if err := shadow.CloseShadow(); err != nil {
|
|
t.Fatalf("bad: %s", err)
|
|
}
|
|
}
|