2015-02-21 20:52:55 +01:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
|
|
|
// TestState is a helper for testing state implementations. It is expected
|
|
|
|
// that the given implementation is pre-loaded with the TestStateInitial
|
|
|
|
// state.
|
2017-07-05 23:10:19 +02:00
|
|
|
func TestState(t *testing.T, s State) {
|
|
|
|
if err := s.RefreshState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
|
|
|
|
2017-07-05 23:10:19 +02:00
|
|
|
// Check that the initial state is correct.
|
|
|
|
// These do have different Lineages, but we will replace current below.
|
|
|
|
initial := TestStateInitial()
|
|
|
|
if state := s.State(); !state.Equal(initial) {
|
|
|
|
t.Fatalf("state does not match expected initial state:\n%#v\n\n%#v", state, initial)
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
|
|
|
|
2017-07-05 21:34:30 +02:00
|
|
|
// Now we've proven that the state we're starting with is an initial
|
|
|
|
// state, we'll complete our work here with that state, since otherwise
|
|
|
|
// further writes would violate the invariant that we only try to write
|
|
|
|
// states that share the same lineage as what was initially written.
|
2017-07-05 23:10:19 +02:00
|
|
|
current := s.State()
|
2017-07-05 21:34:30 +02:00
|
|
|
|
2015-02-21 20:52:55 +01:00
|
|
|
// Write a new state and verify that we have it
|
2017-07-05 23:10:19 +02:00
|
|
|
current.AddModuleState(&terraform.ModuleState{
|
|
|
|
Path: []string{"root"},
|
|
|
|
Outputs: map[string]*terraform.OutputState{
|
|
|
|
"bar": &terraform.OutputState{
|
|
|
|
Type: "string",
|
|
|
|
Sensitive: false,
|
|
|
|
Value: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
if err := s.WriteState(current); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if actual := s.State(); !actual.Equal(current) {
|
|
|
|
t.Fatalf("bad:\n%#v\n\n%#v", actual, current)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test persistence
|
|
|
|
if err := s.PersistState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Refresh if we got it
|
|
|
|
if err := s.RefreshState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.State().Lineage != current.Lineage {
|
|
|
|
t.Fatalf("Lineage changed from %s to %s", s.State().Lineage, current.Lineage)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just set the serials the same... Then compare.
|
|
|
|
actual := s.State()
|
|
|
|
if !actual.Equal(current) {
|
|
|
|
t.Fatalf("bad: %#v\n\n%#v", actual, current)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same serial
|
|
|
|
serial := s.State().Serial
|
|
|
|
if err := s.WriteState(current); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if err := s.PersistState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.State().Serial != serial {
|
|
|
|
t.Fatalf("serial changed after persisting with no changes: got %d, want %d", s.State().Serial, serial)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change the serial
|
|
|
|
current = current.DeepCopy()
|
|
|
|
current.Modules = []*terraform.ModuleState{
|
|
|
|
&terraform.ModuleState{
|
|
|
|
Path: []string{"root", "somewhere"},
|
2016-05-12 02:05:02 +02:00
|
|
|
Outputs: map[string]*terraform.OutputState{
|
2017-07-05 23:10:19 +02:00
|
|
|
"serialCheck": &terraform.OutputState{
|
2016-05-12 02:05:02 +02:00
|
|
|
Type: "string",
|
|
|
|
Sensitive: false,
|
2017-07-05 23:10:19 +02:00
|
|
|
Value: "true",
|
2016-05-12 02:05:02 +02:00
|
|
|
},
|
2015-02-21 20:52:55 +01:00
|
|
|
},
|
2017-07-05 23:10:19 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
if err := s.WriteState(current); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if err := s.PersistState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
2015-02-21 20:52:55 +01:00
|
|
|
|
2017-07-05 23:10:19 +02:00
|
|
|
if s.State().Serial <= serial {
|
|
|
|
t.Fatalf("serial incorrect after persisting with changes: got %d, want > %d", s.State().Serial, serial)
|
|
|
|
}
|
2015-02-21 20:52:55 +01:00
|
|
|
|
2017-07-05 23:10:19 +02:00
|
|
|
if s.State().Version != current.Version {
|
|
|
|
t.Fatalf("Version changed from %d to %d", s.State().Version, current.Version)
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
|
|
|
|
2017-07-05 23:10:19 +02:00
|
|
|
if s.State().TFVersion != current.TFVersion {
|
|
|
|
t.Fatalf("TFVersion changed from %s to %s", s.State().TFVersion, current.TFVersion)
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify that Lineage doesn't change along with Serial, or during copying.
|
|
|
|
if s.State().Lineage != current.Lineage {
|
|
|
|
t.Fatalf("Lineage changed from %s to %s", s.State().Lineage, current.Lineage)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that State() returns a copy by modifying the copy and comparing
|
|
|
|
// to the current state.
|
|
|
|
stateCopy := s.State()
|
|
|
|
stateCopy.Serial++
|
|
|
|
if reflect.DeepEqual(stateCopy, s.State()) {
|
|
|
|
t.Fatal("State() should return a copy")
|
|
|
|
}
|
|
|
|
|
|
|
|
// our current expected state should also marhsal identically to the persisted state
|
|
|
|
if current.MarshalEqual(s.State()) {
|
|
|
|
t.Fatalf("Persisted state altered unexpectedly. Expected: %#v\b Got: %#v", current, s.State())
|
2015-02-24 06:26:33 +01:00
|
|
|
}
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
2015-02-21 21:25:10 +01:00
|
|
|
|
|
|
|
// TestStateInitial is the initial state that a State should have
|
|
|
|
// for TestState.
|
|
|
|
func TestStateInitial() *terraform.State {
|
|
|
|
initial := &terraform.State{
|
|
|
|
Modules: []*terraform.ModuleState{
|
|
|
|
&terraform.ModuleState{
|
|
|
|
Path: []string{"root", "child"},
|
2016-05-12 02:05:02 +02:00
|
|
|
Outputs: map[string]*terraform.OutputState{
|
|
|
|
"foo": &terraform.OutputState{
|
|
|
|
Type: "string",
|
|
|
|
Sensitive: false,
|
|
|
|
Value: "bar",
|
|
|
|
},
|
2015-02-21 21:25:10 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2016-08-10 21:47:25 +02:00
|
|
|
initial.Init()
|
|
|
|
|
2015-02-21 21:25:10 +01:00
|
|
|
return initial
|
|
|
|
}
|