github.com/keshavdv/terraform@v0.7.0-rc2.0.20160711232630-d69256dcb425/state/testing.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/hashicorp/terraform/terraform"
     9  )
    10  
    11  // TestState is a helper for testing state implementations. It is expected
    12  // that the given implementation is pre-loaded with the TestStateInitial
    13  // state.
    14  func TestState(t *testing.T, s interface{}) {
    15  	reader, ok := s.(StateReader)
    16  	if !ok {
    17  		t.Fatalf("must at least be a StateReader")
    18  	}
    19  
    20  	// If it implements refresh, refresh
    21  	if rs, ok := s.(StateRefresher); ok {
    22  		if err := rs.RefreshState(); err != nil {
    23  			t.Fatalf("err: %s", err)
    24  		}
    25  	}
    26  
    27  	// current will track our current state
    28  	current := TestStateInitial()
    29  
    30  	// Check that the initial state is correct
    31  	if state := reader.State(); !current.Equal(state) {
    32  		t.Fatalf("not initial: %#v\n\n%#v", state, current)
    33  	}
    34  
    35  	// Write a new state and verify that we have it
    36  	if ws, ok := s.(StateWriter); ok {
    37  		current.Modules = append(current.Modules, &terraform.ModuleState{
    38  			Path: []string{"root"},
    39  			Outputs: map[string]*terraform.OutputState{
    40  				"bar": &terraform.OutputState{
    41  					Type:      "string",
    42  					Sensitive: false,
    43  					Value:     "baz",
    44  				},
    45  			},
    46  		})
    47  
    48  		if err := ws.WriteState(current); err != nil {
    49  			t.Fatalf("err: %s", err)
    50  		}
    51  
    52  		if actual := reader.State(); !actual.Equal(current) {
    53  			t.Fatalf("bad: %#v\n\n%#v", actual, current)
    54  		}
    55  	}
    56  
    57  	// Test persistence
    58  	if ps, ok := s.(StatePersister); ok {
    59  		if err := ps.PersistState(); err != nil {
    60  			t.Fatalf("err: %s", err)
    61  		}
    62  
    63  		// Refresh if we got it
    64  		if rs, ok := s.(StateRefresher); ok {
    65  			if err := rs.RefreshState(); err != nil {
    66  				t.Fatalf("err: %s", err)
    67  			}
    68  		}
    69  
    70  		// Just set the serials the same... Then compare.
    71  		actual := reader.State()
    72  		if !actual.Equal(current) {
    73  			t.Fatalf("bad: %#v\n\n%#v", actual, current)
    74  		}
    75  	}
    76  
    77  	// If we can write and persist then verify that the serial
    78  	// is only implemented on change.
    79  	writer, writeOk := s.(StateWriter)
    80  	persister, persistOk := s.(StatePersister)
    81  	if writeOk && persistOk {
    82  		// Same serial
    83  		serial := current.Serial
    84  		if err := writer.WriteState(current); err != nil {
    85  			t.Fatalf("err: %s", err)
    86  		}
    87  		if err := persister.PersistState(); err != nil {
    88  			t.Fatalf("err: %s", err)
    89  		}
    90  
    91  		if reader.State().Serial != serial {
    92  			t.Fatalf("bad: expected %d, got %d", serial, reader.State().Serial)
    93  		}
    94  
    95  		// Change the serial
    96  		currentCopy := *current
    97  		current = &currentCopy
    98  		current.Modules = []*terraform.ModuleState{
    99  			&terraform.ModuleState{
   100  				Path: []string{"root", "somewhere"},
   101  				Outputs: map[string]*terraform.OutputState{
   102  					"serialCheck": &terraform.OutputState{
   103  						Type:      "string",
   104  						Sensitive: false,
   105  						Value:     "true",
   106  					},
   107  				},
   108  			},
   109  		}
   110  		if err := writer.WriteState(current); err != nil {
   111  			t.Fatalf("err: %s", err)
   112  		}
   113  		if err := persister.PersistState(); err != nil {
   114  			t.Fatalf("err: %s", err)
   115  		}
   116  
   117  		if reader.State().Serial <= serial {
   118  			t.Fatalf("bad: expected %d, got %d", serial, reader.State().Serial)
   119  		}
   120  
   121  		// Check that State() returns a copy by modifying the copy and comparing
   122  		// to the current state.
   123  		stateCopy := reader.State()
   124  		stateCopy.Serial++
   125  		if reflect.DeepEqual(stateCopy, current) {
   126  			t.Fatal("State() should return a copy")
   127  		}
   128  	}
   129  }
   130  
   131  // TestStateInitial is the initial state that a State should have
   132  // for TestState.
   133  func TestStateInitial() *terraform.State {
   134  	initial := &terraform.State{
   135  		Modules: []*terraform.ModuleState{
   136  			&terraform.ModuleState{
   137  				Path: []string{"root", "child"},
   138  				Outputs: map[string]*terraform.OutputState{
   139  					"foo": &terraform.OutputState{
   140  						Type:      "string",
   141  						Sensitive: false,
   142  						Value:     "bar",
   143  					},
   144  				},
   145  			},
   146  		},
   147  	}
   148  
   149  	var scratch bytes.Buffer
   150  	terraform.WriteState(initial, &scratch)
   151  	return initial
   152  }