github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/states/statemgr/testing.go (about)

     1  package statemgr
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/davecgh/go-spew/spew"
     8  	"github.com/zclconf/go-cty/cty"
     9  
    10  	"github.com/hashicorp/terraform/internal/addrs"
    11  	"github.com/hashicorp/terraform/internal/states"
    12  	"github.com/hashicorp/terraform/internal/states/statefile"
    13  )
    14  
    15  // TestFull is a helper for testing full state manager implementations. It
    16  // expects that the given implementation is pre-loaded with a snapshot of the
    17  // result from TestFullInitialState.
    18  //
    19  // If the given state manager also implements PersistentMeta, this function
    20  // will test that the snapshot metadata changes as expected between calls
    21  // to the methods of Persistent.
    22  func TestFull(t *testing.T, s Full) {
    23  	t.Helper()
    24  
    25  	if err := s.RefreshState(); err != nil {
    26  		t.Fatalf("err: %s", err)
    27  	}
    28  
    29  	// Check that the initial state is correct.
    30  	// These do have different Lineages, but we will replace current below.
    31  	initial := TestFullInitialState()
    32  	if state := s.State(); !state.Equal(initial) {
    33  		t.Fatalf("state does not match expected initial state\n\ngot:\n%s\nwant:\n%s", spew.Sdump(state), spew.Sdump(initial))
    34  	}
    35  
    36  	var initialMeta SnapshotMeta
    37  	if sm, ok := s.(PersistentMeta); ok {
    38  		initialMeta = sm.StateSnapshotMeta()
    39  	}
    40  
    41  	// Now we've proven that the state we're starting with is an initial
    42  	// state, we'll complete our work here with that state, since otherwise
    43  	// further writes would violate the invariant that we only try to write
    44  	// states that share the same lineage as what was initially written.
    45  	current := s.State()
    46  
    47  	// Write a new state and verify that we have it
    48  	current.RootModule().SetOutputValue("bar", cty.StringVal("baz"), false)
    49  
    50  	if err := s.WriteState(current); err != nil {
    51  		t.Fatalf("err: %s", err)
    52  	}
    53  
    54  	if actual := s.State(); !actual.Equal(current) {
    55  		t.Fatalf("bad:\n%#v\n\n%#v", actual, current)
    56  	}
    57  
    58  	// Test persistence
    59  	if err := s.PersistState(nil); err != nil {
    60  		t.Fatalf("err: %s", err)
    61  	}
    62  
    63  	// Refresh if we got it
    64  	if err := s.RefreshState(); err != nil {
    65  		t.Fatalf("err: %s", err)
    66  	}
    67  
    68  	var newMeta SnapshotMeta
    69  	if sm, ok := s.(PersistentMeta); ok {
    70  		newMeta = sm.StateSnapshotMeta()
    71  		if got, want := newMeta.Lineage, initialMeta.Lineage; got != want {
    72  			t.Errorf("Lineage changed from %q to %q", want, got)
    73  		}
    74  		if after, before := newMeta.Serial, initialMeta.Serial; after == before {
    75  			t.Errorf("Serial didn't change from %d after new module added", before)
    76  		}
    77  	}
    78  
    79  	// Same serial
    80  	serial := newMeta.Serial
    81  	if err := s.WriteState(current); err != nil {
    82  		t.Fatalf("err: %s", err)
    83  	}
    84  	if err := s.PersistState(nil); err != nil {
    85  		t.Fatalf("err: %s", err)
    86  	}
    87  
    88  	if sm, ok := s.(PersistentMeta); ok {
    89  		newMeta = sm.StateSnapshotMeta()
    90  		if newMeta.Serial != serial {
    91  			t.Fatalf("serial changed after persisting with no changes: got %d, want %d", newMeta.Serial, serial)
    92  		}
    93  	}
    94  
    95  	if sm, ok := s.(PersistentMeta); ok {
    96  		newMeta = sm.StateSnapshotMeta()
    97  	}
    98  
    99  	// Change the serial
   100  	current = current.DeepCopy()
   101  	current.EnsureModule(addrs.RootModuleInstance).SetOutputValue(
   102  		"serialCheck", cty.StringVal("true"), false,
   103  	)
   104  	if err := s.WriteState(current); err != nil {
   105  		t.Fatalf("err: %s", err)
   106  	}
   107  	if err := s.PersistState(nil); err != nil {
   108  		t.Fatalf("err: %s", err)
   109  	}
   110  
   111  	if sm, ok := s.(PersistentMeta); ok {
   112  		oldMeta := newMeta
   113  		newMeta = sm.StateSnapshotMeta()
   114  
   115  		if newMeta.Serial <= serial {
   116  			t.Fatalf("serial incorrect after persisting with changes: got %d, want > %d", newMeta.Serial, serial)
   117  		}
   118  
   119  		if newMeta.TerraformVersion != oldMeta.TerraformVersion {
   120  			t.Fatalf("TFVersion changed from %s to %s", oldMeta.TerraformVersion, newMeta.TerraformVersion)
   121  		}
   122  
   123  		// verify that Lineage doesn't change along with Serial, or during copying.
   124  		if newMeta.Lineage != oldMeta.Lineage {
   125  			t.Fatalf("Lineage changed from %q to %q", oldMeta.Lineage, newMeta.Lineage)
   126  		}
   127  	}
   128  
   129  	// Check that State() returns a copy by modifying the copy and comparing
   130  	// to the current state.
   131  	stateCopy := s.State()
   132  	stateCopy.EnsureModule(addrs.RootModuleInstance.Child("another", addrs.NoKey))
   133  	if reflect.DeepEqual(stateCopy, s.State()) {
   134  		t.Fatal("State() should return a copy")
   135  	}
   136  
   137  	// our current expected state should also marshal identically to the persisted state
   138  	if !statefile.StatesMarshalEqual(current, s.State()) {
   139  		t.Fatalf("Persisted state altered unexpectedly.\n\ngot:\n%s\nwant:\n%s", spew.Sdump(s.State()), spew.Sdump(current))
   140  	}
   141  }
   142  
   143  // TestFullInitialState is a state that should be snapshotted into a
   144  // full state manager before passing it into TestFull.
   145  func TestFullInitialState() *states.State {
   146  	state := states.NewState()
   147  	childMod := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   148  	rAddr := addrs.Resource{
   149  		Mode: addrs.ManagedResourceMode,
   150  		Type: "null_resource",
   151  		Name: "foo",
   152  	}
   153  	providerAddr := addrs.AbsProviderConfig{
   154  		Provider: addrs.NewDefaultProvider(rAddr.ImpliedProvider()),
   155  		Module:   addrs.RootModule,
   156  	}
   157  	childMod.SetResourceProvider(rAddr, providerAddr)
   158  
   159  	state.RootModule().SetOutputValue("sensitive_output", cty.StringVal("it's a secret"), true)
   160  	state.RootModule().SetOutputValue("nonsensitive_output", cty.StringVal("hello, world!"), false)
   161  
   162  	return state
   163  }