github.com/jrasell/terraform@v0.6.17-0.20160523115548-2652f5232949/terraform/context_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  func TestNewContextState(t *testing.T) {
    11  	cases := map[string]struct {
    12  		Input *ContextOpts
    13  		Err   bool
    14  	}{
    15  		"empty TFVersion": {
    16  			&ContextOpts{
    17  				State: &State{},
    18  			},
    19  			false,
    20  		},
    21  
    22  		"past TFVersion": {
    23  			&ContextOpts{
    24  				State: &State{TFVersion: "0.1.2"},
    25  			},
    26  			false,
    27  		},
    28  
    29  		"equal TFVersion": {
    30  			&ContextOpts{
    31  				State: &State{TFVersion: Version},
    32  			},
    33  			false,
    34  		},
    35  
    36  		"future TFVersion": {
    37  			&ContextOpts{
    38  				State: &State{TFVersion: "99.99.99"},
    39  			},
    40  			true,
    41  		},
    42  
    43  		"future TFVersion, allowed": {
    44  			&ContextOpts{
    45  				State:              &State{TFVersion: "99.99.99"},
    46  				StateFutureAllowed: true,
    47  			},
    48  			false,
    49  		},
    50  	}
    51  
    52  	for k, tc := range cases {
    53  		ctx, err := NewContext(tc.Input)
    54  		if (err != nil) != tc.Err {
    55  			t.Fatalf("%s: err: %s", k, err)
    56  		}
    57  		if err != nil {
    58  			continue
    59  		}
    60  
    61  		// Version should always be set to our current
    62  		if ctx.state.TFVersion != Version {
    63  			t.Fatalf("%s: state not set to current version", k)
    64  		}
    65  	}
    66  }
    67  
    68  func testContext2(t *testing.T, opts *ContextOpts) *Context {
    69  	ctx, err := NewContext(opts)
    70  	if err != nil {
    71  		t.Fatalf("err: %s", err)
    72  	}
    73  
    74  	return ctx
    75  }
    76  
    77  func testApplyFn(
    78  	info *InstanceInfo,
    79  	s *InstanceState,
    80  	d *InstanceDiff) (*InstanceState, error) {
    81  	if d.Destroy {
    82  		return nil, nil
    83  	}
    84  
    85  	id := "foo"
    86  	if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed {
    87  		id = idAttr.New
    88  	}
    89  
    90  	result := &InstanceState{
    91  		ID:         id,
    92  		Attributes: make(map[string]string),
    93  	}
    94  
    95  	// Copy all the prior attributes
    96  	for k, v := range s.Attributes {
    97  		result.Attributes[k] = v
    98  	}
    99  
   100  	if d != nil {
   101  		result = result.MergeDiff(d)
   102  	}
   103  	return result, nil
   104  }
   105  
   106  func testDiffFn(
   107  	info *InstanceInfo,
   108  	s *InstanceState,
   109  	c *ResourceConfig) (*InstanceDiff, error) {
   110  	var diff InstanceDiff
   111  	diff.Attributes = make(map[string]*ResourceAttrDiff)
   112  
   113  	for k, v := range c.Raw {
   114  		if _, ok := v.(string); !ok {
   115  			continue
   116  		}
   117  
   118  		// Ignore __-prefixed keys since they're used for magic
   119  		if k[0] == '_' && k[1] == '_' {
   120  			continue
   121  		}
   122  
   123  		if k == "nil" {
   124  			return nil, nil
   125  		}
   126  
   127  		// This key is used for other purposes
   128  		if k == "compute_value" {
   129  			continue
   130  		}
   131  
   132  		if k == "compute" {
   133  			attrDiff := &ResourceAttrDiff{
   134  				Old:         "",
   135  				New:         "",
   136  				NewComputed: true,
   137  			}
   138  
   139  			if cv, ok := c.Config["compute_value"]; ok {
   140  				if cv.(string) == "1" {
   141  					attrDiff.NewComputed = false
   142  					attrDiff.New = fmt.Sprintf("computed_%s", v.(string))
   143  				}
   144  			}
   145  
   146  			diff.Attributes[v.(string)] = attrDiff
   147  			continue
   148  		}
   149  
   150  		// If this key is not computed, then look it up in the
   151  		// cleaned config.
   152  		found := false
   153  		for _, ck := range c.ComputedKeys {
   154  			if ck == k {
   155  				found = true
   156  				break
   157  			}
   158  		}
   159  		if !found {
   160  			v = c.Config[k]
   161  		}
   162  
   163  		attrDiff := &ResourceAttrDiff{
   164  			Old: "",
   165  			New: v.(string),
   166  		}
   167  
   168  		if k == "require_new" {
   169  			attrDiff.RequiresNew = true
   170  		}
   171  		if _, ok := c.Raw["__"+k+"_requires_new"]; ok {
   172  			attrDiff.RequiresNew = true
   173  		}
   174  		diff.Attributes[k] = attrDiff
   175  	}
   176  
   177  	for _, k := range c.ComputedKeys {
   178  		diff.Attributes[k] = &ResourceAttrDiff{
   179  			Old:         "",
   180  			NewComputed: true,
   181  		}
   182  	}
   183  
   184  	for k, v := range diff.Attributes {
   185  		if v.NewComputed {
   186  			continue
   187  		}
   188  
   189  		old, ok := s.Attributes[k]
   190  		if !ok {
   191  			continue
   192  		}
   193  		if old == v.New {
   194  			delete(diff.Attributes, k)
   195  		}
   196  	}
   197  
   198  	if !diff.Empty() {
   199  		diff.Attributes["type"] = &ResourceAttrDiff{
   200  			Old: "",
   201  			New: info.Type,
   202  		}
   203  	}
   204  
   205  	return &diff, nil
   206  }
   207  
   208  func testProvider(prefix string) *MockResourceProvider {
   209  	p := new(MockResourceProvider)
   210  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   211  		return s, nil
   212  	}
   213  	p.ResourcesReturn = []ResourceType{
   214  		ResourceType{
   215  			Name: fmt.Sprintf("%s_instance", prefix),
   216  		},
   217  	}
   218  
   219  	return p
   220  }
   221  
   222  func testProvisioner() *MockResourceProvisioner {
   223  	p := new(MockResourceProvisioner)
   224  	return p
   225  }
   226  
   227  func checkStateString(t *testing.T, state *State, expected string) {
   228  	actual := strings.TrimSpace(state.String())
   229  	expected = strings.TrimSpace(expected)
   230  
   231  	if actual != expected {
   232  		t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
   233  	}
   234  }
   235  
   236  func resourceState(resourceType, resourceID string) *ResourceState {
   237  	return &ResourceState{
   238  		Type: resourceType,
   239  		Primary: &InstanceState{
   240  			ID: resourceID,
   241  		},
   242  	}
   243  }
   244  
   245  // Test helper that gives a function 3 seconds to finish, assumes deadlock and
   246  // fails test if it does not.
   247  func testCheckDeadlock(t *testing.T, f func()) {
   248  	timeout := make(chan bool, 1)
   249  	done := make(chan bool, 1)
   250  	go func() {
   251  		time.Sleep(3 * time.Second)
   252  		timeout <- true
   253  	}()
   254  	go func(f func(), done chan bool) {
   255  		defer func() { done <- true }()
   256  		f()
   257  	}(f, done)
   258  	select {
   259  	case <-timeout:
   260  		t.Fatalf("timed out! probably deadlock")
   261  	case <-done:
   262  		// ok
   263  	}
   264  }
   265  
   266  const testContextGraph = `
   267  root: root
   268  aws_instance.bar
   269    aws_instance.bar -> provider.aws
   270  aws_instance.foo
   271    aws_instance.foo -> provider.aws
   272  provider.aws
   273  root
   274    root -> aws_instance.bar
   275    root -> aws_instance.foo
   276  `
   277  
   278  const testContextRefreshModuleStr = `
   279  aws_instance.web: (1 tainted)
   280    ID = <not created>
   281    Tainted ID 1 = bar
   282  
   283  module.child:
   284    aws_instance.web:
   285      ID = new
   286  `
   287  
   288  const testContextRefreshOutputStr = `
   289  aws_instance.web:
   290    ID = foo
   291    foo = bar
   292  
   293  Outputs:
   294  
   295  foo = bar
   296  `
   297  
   298  const testContextRefreshOutputPartialStr = `
   299  <no state>
   300  `
   301  
   302  const testContextRefreshTaintedStr = `
   303  aws_instance.web: (1 tainted)
   304    ID = <not created>
   305    Tainted ID 1 = foo
   306  `