diff --git a/state/testing.go b/state/testing.go index be948d409..482615991 100644 --- a/state/testing.go +++ b/state/testing.go @@ -10,125 +10,126 @@ import ( // TestState is a helper for testing state implementations. It is expected // that the given implementation is pre-loaded with the TestStateInitial // state. -func TestState(t *testing.T, s interface{}) { - reader, ok := s.(StateReader) - if !ok { - t.Fatalf("must at least be a StateReader") +func TestState(t *testing.T, s State) { + if err := s.RefreshState(); err != nil { + t.Fatalf("err: %s", err) } - // If it implements refresh, refresh - if rs, ok := s.(StateRefresher); ok { - if err := rs.RefreshState(); err != nil { - t.Fatalf("err: %s", err) - } - } - - // current will track our current state - current := TestStateInitial() - - // Check that the initial state is correct - if state := reader.State(); !current.Equal(state) { - t.Fatalf("not initial:\n%#v\n\n%#v", state, current) + // Check that the initial state is correct. + // These do have different Lineages, but we will replace current below. + initial := TestStateInitial() + if state := s.State(); !state.Equal(initial) { + t.Fatalf("state does not match expected initial state:\n%#v\n\n%#v", state, initial) } // Now we've proven that the state we're starting with is an initial // state, we'll complete our work here with that state, since otherwise // further writes would violate the invariant that we only try to write // states that share the same lineage as what was initially written. - current = reader.State() + current := s.State() // Write a new state and verify that we have it - if ws, ok := s.(StateWriter); ok { - current.AddModuleState(&terraform.ModuleState{ - Path: []string{"root"}, - Outputs: map[string]*terraform.OutputState{ - "bar": &terraform.OutputState{ - Type: "string", - Sensitive: false, - Value: "baz", - }, + current.AddModuleState(&terraform.ModuleState{ + Path: []string{"root"}, + Outputs: map[string]*terraform.OutputState{ + "bar": &terraform.OutputState{ + Type: "string", + Sensitive: false, + Value: "baz", }, - }) + }, + }) - if err := ws.WriteState(current); err != nil { - t.Fatalf("err: %s", err) - } + if err := s.WriteState(current); err != nil { + t.Fatalf("err: %s", err) + } - if actual := reader.State(); !actual.Equal(current) { - t.Fatalf("bad:\n%#v\n\n%#v", actual, current) - } + if actual := s.State(); !actual.Equal(current) { + t.Fatalf("bad:\n%#v\n\n%#v", actual, current) } // Test persistence - if ps, ok := s.(StatePersister); ok { - if err := ps.PersistState(); err != nil { - t.Fatalf("err: %s", err) - } - - // Refresh if we got it - if rs, ok := s.(StateRefresher); ok { - if err := rs.RefreshState(); err != nil { - t.Fatalf("err: %s", err) - } - } - - // Just set the serials the same... Then compare. - actual := reader.State() - if !actual.Equal(current) { - t.Fatalf("bad: %#v\n\n%#v", actual, current) - } + if err := s.PersistState(); err != nil { + t.Fatalf("err: %s", err) } - // If we can write and persist then verify that the serial - // is only incremented on change. - writer, writeOk := s.(StateWriter) - persister, persistOk := s.(StatePersister) - if writeOk && persistOk { - // Same serial - serial := reader.State().Serial - if err := writer.WriteState(current); err != nil { - t.Fatalf("err: %s", err) - } - if err := persister.PersistState(); err != nil { - t.Fatalf("err: %s", err) - } + // Refresh if we got it + if err := s.RefreshState(); err != nil { + t.Fatalf("err: %s", err) + } - if reader.State().Serial != serial { - t.Fatalf("serial changed after persisting with no changes: got %d, want %d", reader.State().Serial, serial) - } + if s.State().Lineage != current.Lineage { + t.Fatalf("Lineage changed from %s to %s", s.State().Lineage, current.Lineage) + } - // Change the serial - current = current.DeepCopy() - current.Modules = []*terraform.ModuleState{ - &terraform.ModuleState{ - Path: []string{"root", "somewhere"}, - Outputs: map[string]*terraform.OutputState{ - "serialCheck": &terraform.OutputState{ - Type: "string", - Sensitive: false, - Value: "true", - }, + // Just set the serials the same... Then compare. + actual := s.State() + if !actual.Equal(current) { + t.Fatalf("bad: %#v\n\n%#v", actual, current) + } + + // Same serial + serial := s.State().Serial + if err := s.WriteState(current); err != nil { + t.Fatalf("err: %s", err) + } + if err := s.PersistState(); err != nil { + t.Fatalf("err: %s", err) + } + + if s.State().Serial != serial { + t.Fatalf("serial changed after persisting with no changes: got %d, want %d", s.State().Serial, serial) + } + + // Change the serial + current = current.DeepCopy() + current.Modules = []*terraform.ModuleState{ + &terraform.ModuleState{ + Path: []string{"root", "somewhere"}, + Outputs: map[string]*terraform.OutputState{ + "serialCheck": &terraform.OutputState{ + Type: "string", + Sensitive: false, + Value: "true", }, }, - } - if err := writer.WriteState(current); err != nil { - t.Fatalf("err: %s", err) - } - if err := persister.PersistState(); err != nil { - t.Fatalf("err: %s", err) - } + }, + } + if err := s.WriteState(current); err != nil { + t.Fatalf("err: %s", err) + } + if err := s.PersistState(); err != nil { + t.Fatalf("err: %s", err) + } - if reader.State().Serial <= serial { - t.Fatalf("serial incorrect after persisting with changes: got %d, want > %d", reader.State().Serial, serial) - } + if s.State().Serial <= serial { + t.Fatalf("serial incorrect after persisting with changes: got %d, want > %d", s.State().Serial, serial) + } - // Check that State() returns a copy by modifying the copy and comparing - // to the current state. - stateCopy := reader.State() - stateCopy.Serial++ - if reflect.DeepEqual(stateCopy, current) { - t.Fatal("State() should return a copy") - } + if s.State().Version != current.Version { + t.Fatalf("Version changed from %d to %d", s.State().Version, current.Version) + } + + if s.State().TFVersion != current.TFVersion { + t.Fatalf("TFVersion changed from %s to %s", s.State().TFVersion, current.TFVersion) + } + + // verify that Lineage doesn't change along with Serial, or during copying. + if s.State().Lineage != current.Lineage { + t.Fatalf("Lineage changed from %s to %s", s.State().Lineage, current.Lineage) + } + + // Check that State() returns a copy by modifying the copy and comparing + // to the current state. + stateCopy := s.State() + stateCopy.Serial++ + if reflect.DeepEqual(stateCopy, s.State()) { + t.Fatal("State() should return a copy") + } + + // our current expected state should also marhsal identically to the persisted state + if current.MarshalEqual(s.State()) { + t.Fatalf("Persisted state altered unexpectedly. Expected: %#v\b Got: %#v", current, s.State()) } }