2015-02-21 20:52:55 +01:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
2015-02-21 21:25:10 +01:00
|
|
|
"bytes"
|
2015-02-21 20:52:55 +01:00
|
|
|
"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.
|
|
|
|
func TestState(t *testing.T, s interface{}) {
|
|
|
|
reader, ok := s.(StateReader)
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("must at least be a StateReader")
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it implements refresh, refresh
|
|
|
|
if rs, ok := s.(StateRefresher); ok {
|
|
|
|
if err := rs.RefreshState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// current will track our current state
|
2015-02-21 21:25:10 +01:00
|
|
|
current := TestStateInitial()
|
2015-02-21 20:52:55 +01:00
|
|
|
|
|
|
|
// Check that the initial state is correct
|
2015-02-24 06:26:33 +01:00
|
|
|
if state := reader.State(); !reflect.DeepEqual(state, current) {
|
2015-02-23 18:53:20 +01:00
|
|
|
t.Fatalf("not initial: %#v\n\n%#v", state, current)
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write a new state and verify that we have it
|
|
|
|
if ws, ok := s.(StateWriter); ok {
|
|
|
|
current.Modules = append(current.Modules, &terraform.ModuleState{
|
|
|
|
Path: []string{"root"},
|
|
|
|
Outputs: map[string]string{
|
|
|
|
"bar": "baz",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
if err := ws.WriteState(current); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if actual := reader.State(); !reflect.DeepEqual(actual, current) {
|
2015-02-21 21:25:10 +01:00
|
|
|
t.Fatalf("bad: %#v\n\n%#v", actual, current)
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test persistence
|
|
|
|
if ps, ok := s.(StatePersister); ok {
|
|
|
|
if err := ps.PersistState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Refresh if we got it
|
|
|
|
if rs, ok := s.(StateRefresher); ok {
|
|
|
|
if err := rs.RefreshState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-21 21:25:10 +01:00
|
|
|
// Just set the serials the same... Then compare.
|
|
|
|
actual := reader.State()
|
|
|
|
if !reflect.DeepEqual(actual, current) {
|
|
|
|
t.Fatalf("bad: %#v\n\n%#v", actual, current)
|
2015-02-21 20:52:55 +01:00
|
|
|
}
|
|
|
|
}
|
2015-02-24 06:26:33 +01:00
|
|
|
|
|
|
|
// If we can write and persist then verify that the serial
|
|
|
|
// is only implemented on change.
|
|
|
|
writer, writeOk := s.(StateWriter)
|
|
|
|
persister, persistOk := s.(StatePersister)
|
|
|
|
if writeOk && persistOk {
|
|
|
|
// Same serial
|
|
|
|
serial := current.Serial
|
|
|
|
if err := writer.WriteState(current); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if err := persister.PersistState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if reader.State().Serial != serial {
|
|
|
|
t.Fatalf("bad: expected %d, got %d", serial, reader.State().Serial)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change the serial
|
|
|
|
currentCopy := *current
|
|
|
|
current = ¤tCopy
|
|
|
|
current.Modules = []*terraform.ModuleState{
|
|
|
|
&terraform.ModuleState{
|
|
|
|
Path: []string{"root", "somewhere"},
|
|
|
|
Outputs: map[string]string{"serialCheck": "true"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if err := writer.WriteState(current); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if err := persister.PersistState(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if reader.State().Serial <= serial {
|
|
|
|
t.Fatalf("bad: expected %d, got %d", serial, reader.State().Serial)
|
|
|
|
}
|
|
|
|
}
|
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"},
|
|
|
|
Outputs: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var scratch bytes.Buffer
|
|
|
|
terraform.WriteState(initial, &scratch)
|
|
|
|
return initial
|
|
|
|
}
|