2017-01-19 05:47:56 +01:00
|
|
|
package local
|
|
|
|
|
|
|
|
import (
|
2017-05-25 15:18:42 +02:00
|
|
|
"sync"
|
2017-01-19 05:47:56 +01:00
|
|
|
"testing"
|
2017-05-25 15:18:42 +02:00
|
|
|
"time"
|
2017-01-19 05:47:56 +01:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/state"
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestStateHook_impl(t *testing.T) {
|
|
|
|
var _ terraform.Hook = new(StateHook)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStateHook(t *testing.T) {
|
|
|
|
is := &state.InmemState{}
|
|
|
|
var hook terraform.Hook = &StateHook{State: is}
|
|
|
|
|
|
|
|
s := state.TestStateInitial()
|
|
|
|
action, err := hook.PostStateUpdate(s)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("bad: %v", action)
|
|
|
|
}
|
|
|
|
if !is.State().Equal(s) {
|
|
|
|
t.Fatalf("bad state: %#v", is.State())
|
|
|
|
}
|
|
|
|
}
|
2017-05-25 15:18:42 +02:00
|
|
|
|
|
|
|
// testPersistState stores the state on WriteState, and
|
|
|
|
type testPersistState struct {
|
|
|
|
*state.InmemState
|
|
|
|
|
|
|
|
mu sync.Mutex
|
|
|
|
persisted bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *testPersistState) WriteState(state *terraform.State) error {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
s.persisted = false
|
|
|
|
return s.InmemState.WriteState(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *testPersistState) PersistState() error {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
s.persisted = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify that StateHook calls PersistState if the last call was more than
|
|
|
|
// persistStateHookInterval
|
|
|
|
func TestStateHookPersist(t *testing.T) {
|
|
|
|
is := &testPersistState{
|
|
|
|
InmemState: &state.InmemState{},
|
|
|
|
}
|
|
|
|
hook := &StateHook{State: is}
|
|
|
|
|
|
|
|
s := state.TestStateInitial()
|
|
|
|
hook.PostStateUpdate(s)
|
|
|
|
|
|
|
|
// the first call should persist, since the last time was zero
|
|
|
|
if !is.persisted {
|
|
|
|
t.Fatal("PersistState not called")
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Serial++
|
|
|
|
hook.PostStateUpdate(s)
|
|
|
|
|
|
|
|
// this call should not have persisted
|
|
|
|
if is.persisted {
|
|
|
|
t.Fatal("PostStateUpdate called PersistState early")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !is.State().Equal(s) {
|
|
|
|
t.Fatalf("bad state: %#v", is.State())
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the last call back to before our interval
|
|
|
|
hook.lastPersist = time.Now().Add(-2 * persistStateHookInterval)
|
|
|
|
|
|
|
|
s.Serial++
|
|
|
|
hook.PostStateUpdate(s)
|
|
|
|
|
|
|
|
if !is.persisted {
|
|
|
|
t.Fatal("PersistState not called")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !is.State().Equal(s) {
|
|
|
|
t.Fatalf("bad state: %#v", is.State())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify that the satet hook is safe for concurrent use
|
|
|
|
func TestStateHookRace(t *testing.T) {
|
|
|
|
is := &state.InmemState{}
|
|
|
|
var hook terraform.Hook = &StateHook{State: is}
|
|
|
|
|
|
|
|
s := state.TestStateInitial()
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
action, err := hook.PostStateUpdate(s)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
if action != terraform.HookActionContinue {
|
|
|
|
t.Fatalf("bad: %v", action)
|
|
|
|
}
|
|
|
|
if !is.State().Equal(s) {
|
|
|
|
t.Fatalf("bad state: %#v", is.State())
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|