opentofu/terraform/state_v0_test.go

119 lines
2.5 KiB
Go
Raw Normal View History

2014-09-18 12:21:25 -05:00
package terraform
import (
"bytes"
"encoding/gob"
"errors"
"io"
"reflect"
"sync"
"testing"
2016-02-17 13:39:12 -06:00
"github.com/mitchellh/hashstructure"
2014-09-18 12:21:25 -05:00
)
func TestReadWriteStateV0(t *testing.T) {
state := &StateV0{
Resources: map[string]*ResourceStateV0{
"foo": &ResourceStateV0{
2014-09-18 12:21:25 -05:00
ID: "bar",
ConnInfo: map[string]string{
"type": "ssh",
"user": "root",
"password": "supersecret",
},
},
},
}
// Checksum before the write
2016-02-17 13:39:12 -06:00
chksum, err := hashstructure.Hash(state, nil)
if err != nil {
t.Fatalf("hash: %s", err)
}
2014-09-18 12:21:25 -05:00
buf := new(bytes.Buffer)
if err := testWriteStateV0(state, buf); err != nil {
2014-09-18 12:21:25 -05:00
t.Fatalf("err: %s", err)
}
// Checksum after the write
2016-02-17 13:39:12 -06:00
chksumAfter, err := hashstructure.Hash(state, nil)
if err != nil {
t.Fatalf("hash: %s", err)
}
2014-09-18 12:21:25 -05:00
if chksumAfter != chksum {
t.Fatalf("structure changed during serialization!")
}
actual, err := ReadStateV0(buf)
2014-09-18 12:21:25 -05:00
if err != nil {
t.Fatalf("err: %s", err)
}
// ReadState should not restore sensitive information!
state.Resources["foo"].ConnInfo = nil
if !reflect.DeepEqual(actual, state) {
t.Fatalf("bad: %#v", actual)
}
}
// sensitiveState is used to store sensitive state information
// that should not be serialized. This is only used temporarily
// and is restored into the state.
type sensitiveState struct {
ConnInfo map[string]map[string]string
once sync.Once
}
func (s *sensitiveState) init() {
s.once.Do(func() {
s.ConnInfo = make(map[string]map[string]string)
})
}
// testWriteStateV0 writes a state somewhere in a binary format.
2014-09-18 12:21:25 -05:00
// Only for testing now
func testWriteStateV0(d *StateV0, dst io.Writer) error {
2014-09-18 12:21:25 -05:00
// Write the magic bytes so we can determine the file format later
n, err := dst.Write([]byte(stateFormatMagic))
if err != nil {
return err
}
if n != len(stateFormatMagic) {
return errors.New("failed to write state format magic bytes")
}
// Write a version byte so we can iterate on version at some point
n, err = dst.Write([]byte{stateFormatVersion})
if err != nil {
return err
}
if n != 1 {
return errors.New("failed to write state version byte")
}
// Prevent sensitive information from being serialized
sensitive := &sensitiveState{}
sensitive.init()
for name, r := range d.Resources {
if r.ConnInfo != nil {
sensitive.ConnInfo[name] = r.ConnInfo
r.ConnInfo = nil
}
}
// Serialize the state
err = gob.NewEncoder(dst).Encode(d)
// Restore the state
for name, info := range sensitive.ConnInfo {
d.Resources[name].ConnInfo = info
}
return err
}