github.com/bradfeehan/terraform@v0.7.0-rc3.0.20170529055808-34b45c5ad841/backend/local/hook_state_test.go (about)

     1  package local
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/terraform/state"
     9  	"github.com/hashicorp/terraform/terraform"
    10  )
    11  
    12  func TestStateHook_impl(t *testing.T) {
    13  	var _ terraform.Hook = new(StateHook)
    14  }
    15  
    16  func TestStateHook(t *testing.T) {
    17  	is := &state.InmemState{}
    18  	var hook terraform.Hook = &StateHook{State: is}
    19  
    20  	s := state.TestStateInitial()
    21  	action, err := hook.PostStateUpdate(s)
    22  	if err != nil {
    23  		t.Fatalf("err: %s", err)
    24  	}
    25  	if action != terraform.HookActionContinue {
    26  		t.Fatalf("bad: %v", action)
    27  	}
    28  	if !is.State().Equal(s) {
    29  		t.Fatalf("bad state: %#v", is.State())
    30  	}
    31  }
    32  
    33  // testPersistState stores the state on WriteState, and
    34  type testPersistState struct {
    35  	*state.InmemState
    36  
    37  	mu        sync.Mutex
    38  	persisted bool
    39  }
    40  
    41  func (s *testPersistState) WriteState(state *terraform.State) error {
    42  	s.mu.Lock()
    43  	defer s.mu.Unlock()
    44  
    45  	s.persisted = false
    46  	return s.InmemState.WriteState(state)
    47  }
    48  
    49  func (s *testPersistState) PersistState() error {
    50  	s.mu.Lock()
    51  	defer s.mu.Unlock()
    52  
    53  	s.persisted = true
    54  	return nil
    55  }
    56  
    57  // verify that StateHook calls PersistState if the last call was more than
    58  // persistStateHookInterval
    59  func TestStateHookPersist(t *testing.T) {
    60  	is := &testPersistState{
    61  		InmemState: &state.InmemState{},
    62  	}
    63  	hook := &StateHook{State: is}
    64  
    65  	s := state.TestStateInitial()
    66  	hook.PostStateUpdate(s)
    67  
    68  	// the first call should persist, since the last time was zero
    69  	if !is.persisted {
    70  		t.Fatal("PersistState not called")
    71  	}
    72  
    73  	s.Serial++
    74  	hook.PostStateUpdate(s)
    75  
    76  	// this call should not have persisted
    77  	if is.persisted {
    78  		t.Fatal("PostStateUpdate called PersistState early")
    79  	}
    80  
    81  	if !is.State().Equal(s) {
    82  		t.Fatalf("bad state: %#v", is.State())
    83  	}
    84  
    85  	// set the last call back to before our interval
    86  	hook.lastPersist = time.Now().Add(-2 * persistStateHookInterval)
    87  
    88  	s.Serial++
    89  	hook.PostStateUpdate(s)
    90  
    91  	if !is.persisted {
    92  		t.Fatal("PersistState not called")
    93  	}
    94  
    95  	if !is.State().Equal(s) {
    96  		t.Fatalf("bad state: %#v", is.State())
    97  	}
    98  }
    99  
   100  // verify that the satet hook is safe for concurrent use
   101  func TestStateHookRace(t *testing.T) {
   102  	is := &state.InmemState{}
   103  	var hook terraform.Hook = &StateHook{State: is}
   104  
   105  	s := state.TestStateInitial()
   106  
   107  	var wg sync.WaitGroup
   108  
   109  	for i := 0; i < 100; i++ {
   110  		wg.Add(1)
   111  		go func() {
   112  			defer wg.Done()
   113  			action, err := hook.PostStateUpdate(s)
   114  			if err != nil {
   115  				t.Fatalf("err: %s", err)
   116  			}
   117  			if action != terraform.HookActionContinue {
   118  				t.Fatalf("bad: %v", action)
   119  			}
   120  			if !is.State().Equal(s) {
   121  				t.Fatalf("bad state: %#v", is.State())
   122  			}
   123  		}()
   124  	}
   125  	wg.Wait()
   126  }