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 }