github.com/jameswoolfenden/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 }