github.com/magodo/terraform@v0.11.12-beta1/state/testing.go (about)

     1  package state
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/hashicorp/terraform/terraform"
     8  )
     9  
    10  // TestState is a helper for testing state implementations. It is expected
    11  // that the given implementation is pre-loaded with the TestStateInitial
    12  // state.
    13  func TestState(t *testing.T, s State) {
    14  	t.Helper()
    15  
    16  	if err := s.RefreshState(); err != nil {
    17  		t.Fatalf("err: %s", err)
    18  	}
    19  
    20  	// Check that the initial state is correct.
    21  	// These do have different Lineages, but we will replace current below.
    22  	initial := TestStateInitial()
    23  	if state := s.State(); !state.Equal(initial) {
    24  		t.Fatalf("state does not match expected initial state:\n%#v\n\n%#v", state, initial)
    25  	}
    26  
    27  	// Now we've proven that the state we're starting with is an initial
    28  	// state, we'll complete our work here with that state, since otherwise
    29  	// further writes would violate the invariant that we only try to write
    30  	// states that share the same lineage as what was initially written.
    31  	current := s.State()
    32  
    33  	// Write a new state and verify that we have it
    34  	current.AddModuleState(&terraform.ModuleState{
    35  		Path: []string{"root"},
    36  		Outputs: map[string]*terraform.OutputState{
    37  			"bar": &terraform.OutputState{
    38  				Type:      "string",
    39  				Sensitive: false,
    40  				Value:     "baz",
    41  			},
    42  		},
    43  	})
    44  
    45  	if err := s.WriteState(current); err != nil {
    46  		t.Fatalf("err: %s", err)
    47  	}
    48  
    49  	if actual := s.State(); !actual.Equal(current) {
    50  		t.Fatalf("bad:\n%#v\n\n%#v", actual, current)
    51  	}
    52  
    53  	// Test persistence
    54  	if err := s.PersistState(); err != nil {
    55  		t.Fatalf("err: %s", err)
    56  	}
    57  
    58  	// Refresh if we got it
    59  	if err := s.RefreshState(); err != nil {
    60  		t.Fatalf("err: %s", err)
    61  	}
    62  
    63  	if s.State().Lineage != current.Lineage {
    64  		t.Fatalf("Lineage changed from %s to %s", s.State().Lineage, current.Lineage)
    65  	}
    66  
    67  	// Just set the serials the same... Then compare.
    68  	actual := s.State()
    69  	if !actual.Equal(current) {
    70  		t.Fatalf("bad: %#v\n\n%#v", actual, current)
    71  	}
    72  
    73  	// Same serial
    74  	serial := s.State().Serial
    75  	if err := s.WriteState(current); err != nil {
    76  		t.Fatalf("err: %s", err)
    77  	}
    78  	if err := s.PersistState(); err != nil {
    79  		t.Fatalf("err: %s", err)
    80  	}
    81  
    82  	if s.State().Serial != serial {
    83  		t.Fatalf("serial changed after persisting with no changes: got %d, want %d", s.State().Serial, serial)
    84  	}
    85  
    86  	// Change the serial
    87  	current = current.DeepCopy()
    88  	current.Modules = []*terraform.ModuleState{
    89  		&terraform.ModuleState{
    90  			Path: []string{"root", "somewhere"},
    91  			Outputs: map[string]*terraform.OutputState{
    92  				"serialCheck": &terraform.OutputState{
    93  					Type:      "string",
    94  					Sensitive: false,
    95  					Value:     "true",
    96  				},
    97  			},
    98  		},
    99  	}
   100  	if err := s.WriteState(current); err != nil {
   101  		t.Fatalf("err: %s", err)
   102  	}
   103  	if err := s.PersistState(); err != nil {
   104  		t.Fatalf("err: %s", err)
   105  	}
   106  
   107  	if s.State().Serial <= serial {
   108  		t.Fatalf("serial incorrect after persisting with changes: got %d, want > %d", s.State().Serial, serial)
   109  	}
   110  
   111  	if s.State().Version != current.Version {
   112  		t.Fatalf("Version changed from %d to %d", s.State().Version, current.Version)
   113  	}
   114  
   115  	if s.State().TFVersion != current.TFVersion {
   116  		t.Fatalf("TFVersion changed from %s to %s", s.State().TFVersion, current.TFVersion)
   117  	}
   118  
   119  	// verify that Lineage doesn't change along with Serial, or during copying.
   120  	if s.State().Lineage != current.Lineage {
   121  		t.Fatalf("Lineage changed from %s to %s", s.State().Lineage, current.Lineage)
   122  	}
   123  
   124  	// Check that State() returns a copy by modifying the copy and comparing
   125  	// to the current state.
   126  	stateCopy := s.State()
   127  	stateCopy.Serial++
   128  	if reflect.DeepEqual(stateCopy, s.State()) {
   129  		t.Fatal("State() should return a copy")
   130  	}
   131  
   132  	// our current expected state should also marhsal identically to the persisted state
   133  	if current.MarshalEqual(s.State()) {
   134  		t.Fatalf("Persisted state altered unexpectedly. Expected: %#v\b Got: %#v", current, s.State())
   135  	}
   136  }
   137  
   138  // TestStateInitial is the initial state that a State should have
   139  // for TestState.
   140  func TestStateInitial() *terraform.State {
   141  	initial := &terraform.State{
   142  		Modules: []*terraform.ModuleState{
   143  			&terraform.ModuleState{
   144  				Path: []string{"root", "child"},
   145  				Outputs: map[string]*terraform.OutputState{
   146  					"foo": &terraform.OutputState{
   147  						Type:      "string",
   148  						Sensitive: false,
   149  						Value:     "bar",
   150  					},
   151  				},
   152  			},
   153  		},
   154  	}
   155  
   156  	initial.Init()
   157  
   158  	return initial
   159  }