don't lose Private state data during copy
Fix the scope of the private data copy in DeepCopy. Make sure Dependencies matches nil vs empty so that Equal compares correctly between copied states
This commit is contained in:
parent
dcab82e897
commit
ac2219ba6e
|
@ -15,6 +15,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
|
||||||
|
@ -1389,7 +1390,7 @@ func TestApply_backup(t *testing.T) {
|
||||||
|
|
||||||
actual := backupState.RootModule().Resources["test_instance.foo"]
|
actual := backupState.RootModule().Resources["test_instance.foo"]
|
||||||
expected := originalState.RootModule().Resources["test_instance.foo"]
|
expected := originalState.RootModule().Resources["test_instance.foo"]
|
||||||
if !cmp.Equal(actual, expected) {
|
if !cmp.Equal(actual, expected, cmpopts.EquateEmpty()) {
|
||||||
t.Fatalf(
|
t.Fatalf(
|
||||||
"wrong aws_instance.foo state\n%s",
|
"wrong aws_instance.foo state\n%s",
|
||||||
cmp.Diff(expected, actual, cmp.Transformer("bytesAsString", func(b []byte) string {
|
cmp.Diff(expected, actual, cmp.Transformer("bytesAsString", func(b []byte) string {
|
||||||
|
|
|
@ -7,8 +7,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hashicorp/terraform/internal/initwd"
|
|
||||||
"github.com/hashicorp/terraform/registry"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -21,6 +19,9 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/internal/initwd"
|
||||||
|
"github.com/hashicorp/terraform/registry"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/configs"
|
"github.com/hashicorp/terraform/configs"
|
||||||
"github.com/hashicorp/terraform/configs/configload"
|
"github.com/hashicorp/terraform/configs/configload"
|
||||||
|
@ -266,7 +267,10 @@ func testState() *states.State {
|
||||||
Type: "test",
|
Type: "test",
|
||||||
}.Absolute(addrs.RootModuleInstance),
|
}.Absolute(addrs.RootModuleInstance),
|
||||||
)
|
)
|
||||||
})
|
// DeepCopy is used here to ensure our synthetic state matches exactly
|
||||||
|
// with a state that will have been copied during the command
|
||||||
|
// operation, and all fields have been copied correctly.
|
||||||
|
}).DeepCopy()
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeStateForTesting is a helper that writes the given naked state to the
|
// writeStateForTesting is a helper that writes the given naked state to the
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
|
||||||
|
@ -557,8 +559,8 @@ func TestRefresh_backup(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
newState := testStateRead(t, statePath)
|
newState := testStateRead(t, statePath)
|
||||||
if !reflect.DeepEqual(newState, state) {
|
if !cmp.Equal(newState, state, cmpopts.EquateEmpty()) {
|
||||||
t.Fatalf("bad: %#v", newState)
|
t.Fatalf("got:\n%s\nexpected:\n%s\n", newState, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
newState = testStateRead(t, outPath)
|
newState = testStateRead(t, outPath)
|
||||||
|
|
|
@ -147,7 +147,7 @@ func (obj *ResourceInstanceObjectSrc) DeepCopy() *ResourceInstanceObjectSrc {
|
||||||
|
|
||||||
var private []byte
|
var private []byte
|
||||||
if obj.Private != nil {
|
if obj.Private != nil {
|
||||||
private := make([]byte, len(obj.Private))
|
private = make([]byte, len(obj.Private))
|
||||||
copy(private, obj.Private)
|
copy(private, obj.Private)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,14 +181,17 @@ func (obj *ResourceInstanceObject) DeepCopy() *ResourceInstanceObject {
|
||||||
|
|
||||||
var private []byte
|
var private []byte
|
||||||
if obj.Private != nil {
|
if obj.Private != nil {
|
||||||
private := make([]byte, len(obj.Private))
|
private = make([]byte, len(obj.Private))
|
||||||
copy(private, obj.Private)
|
copy(private, obj.Private)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some addrs.Referencable implementations are technically mutable, but
|
// Some addrs.Referenceable implementations are technically mutable, but
|
||||||
// we treat them as immutable by convention and so we don't deep-copy here.
|
// we treat them as immutable by convention and so we don't deep-copy here.
|
||||||
dependencies := make([]addrs.Referenceable, len(obj.Dependencies))
|
var dependencies []addrs.Referenceable
|
||||||
copy(dependencies, obj.Dependencies)
|
if obj.Dependencies != nil {
|
||||||
|
dependencies = make([]addrs.Referenceable, len(obj.Dependencies))
|
||||||
|
copy(dependencies, obj.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
return &ResourceInstanceObject{
|
return &ResourceInstanceObject{
|
||||||
Value: obj.Value,
|
Value: obj.Value,
|
||||||
|
|
|
@ -115,3 +115,62 @@ func TestState(t *testing.T) {
|
||||||
t.Error(problem)
|
t.Error(problem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateDeepCopy(t *testing.T) {
|
||||||
|
state := NewState()
|
||||||
|
|
||||||
|
rootModule := state.RootModule()
|
||||||
|
if rootModule == nil {
|
||||||
|
t.Errorf("root module is nil; want valid object")
|
||||||
|
}
|
||||||
|
|
||||||
|
rootModule.SetLocalValue("foo", cty.StringVal("foo value"))
|
||||||
|
rootModule.SetOutputValue("bar", cty.StringVal("bar value"), false)
|
||||||
|
rootModule.SetOutputValue("secret", cty.StringVal("secret value"), true)
|
||||||
|
rootModule.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "baz",
|
||||||
|
}.Instance(addrs.IntKey(0)),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
Private: []byte("private data"),
|
||||||
|
Dependencies: []addrs.Referenceable{},
|
||||||
|
},
|
||||||
|
addrs.ProviderConfig{
|
||||||
|
Type: "test",
|
||||||
|
}.Absolute(addrs.RootModuleInstance),
|
||||||
|
)
|
||||||
|
rootModule.SetResourceInstanceCurrent(
|
||||||
|
addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "bar",
|
||||||
|
}.Instance(addrs.IntKey(0)),
|
||||||
|
&ResourceInstanceObjectSrc{
|
||||||
|
Status: ObjectReady,
|
||||||
|
SchemaVersion: 1,
|
||||||
|
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
|
||||||
|
Private: []byte("private data"),
|
||||||
|
Dependencies: []addrs.Referenceable{addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_thing",
|
||||||
|
Name: "baz",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
addrs.ProviderConfig{
|
||||||
|
Type: "test",
|
||||||
|
}.Absolute(addrs.RootModuleInstance),
|
||||||
|
)
|
||||||
|
|
||||||
|
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
||||||
|
childModule.SetOutputValue("pizza", cty.StringVal("hawaiian"), false)
|
||||||
|
|
||||||
|
stateCopy := state.DeepCopy()
|
||||||
|
if !state.Equal(stateCopy) {
|
||||||
|
t.Fatalf("\nexpected:\n%q\ngot:\n%q\n", state, stateCopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue