github.com/pbthorste/terraform@v0.8.6-0.20170127005045-deb56bd93da2/terraform/context_plan_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"sort"
     9  	"strings"
    10  	"sync"
    11  	"testing"
    12  )
    13  
    14  func TestContext2Plan_basic(t *testing.T) {
    15  	m := testModule(t, "plan-good")
    16  	p := testProvider("aws")
    17  	p.DiffFn = testDiffFn
    18  	ctx := testContext2(t, &ContextOpts{
    19  		Module: m,
    20  		Providers: map[string]ResourceProviderFactory{
    21  			"aws": testProviderFuncFixed(p),
    22  		},
    23  	})
    24  
    25  	plan, err := ctx.Plan()
    26  	if err != nil {
    27  		t.Fatalf("err: %s", err)
    28  	}
    29  
    30  	if len(plan.Diff.RootModule().Resources) < 2 {
    31  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
    32  	}
    33  
    34  	actual := strings.TrimSpace(plan.String())
    35  	expected := strings.TrimSpace(testTerraformPlanStr)
    36  	if actual != expected {
    37  		t.Fatalf("bad:\n%s", actual)
    38  	}
    39  }
    40  
    41  func TestContext2Plan_createBefore_deposed(t *testing.T) {
    42  	m := testModule(t, "plan-cbd")
    43  	p := testProvider("aws")
    44  	p.DiffFn = testDiffFn
    45  
    46  	s := &State{
    47  		Modules: []*ModuleState{
    48  			&ModuleState{
    49  				Path: []string{"root"},
    50  				Resources: map[string]*ResourceState{
    51  					"aws_instance.foo": &ResourceState{
    52  						Type: "aws_instance",
    53  						Primary: &InstanceState{
    54  							ID: "baz",
    55  						},
    56  						Deposed: []*InstanceState{
    57  							&InstanceState{ID: "foo"},
    58  						},
    59  					},
    60  				},
    61  			},
    62  		},
    63  	}
    64  
    65  	ctx := testContext2(t, &ContextOpts{
    66  		Module: m,
    67  		Providers: map[string]ResourceProviderFactory{
    68  			"aws": testProviderFuncFixed(p),
    69  		},
    70  		State: s,
    71  	})
    72  
    73  	plan, err := ctx.Plan()
    74  	if err != nil {
    75  		t.Fatalf("err: %s", err)
    76  	}
    77  
    78  	actual := strings.TrimSpace(plan.String())
    79  	expected := strings.TrimSpace(`
    80  DIFF:
    81  
    82  DESTROY: aws_instance.foo (deposed only)
    83  
    84  STATE:
    85  
    86  aws_instance.foo: (1 deposed)
    87    ID = baz
    88    Deposed ID 1 = foo
    89  		`)
    90  	if actual != expected {
    91  		t.Fatalf("expected:\n%s, got:\n%s", expected, actual)
    92  	}
    93  }
    94  
    95  func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
    96  	m := testModule(t, "plan-cbd-maintain-root")
    97  	p := testProvider("aws")
    98  	p.DiffFn = testDiffFn
    99  	ctx := testContext2(t, &ContextOpts{
   100  		Module: m,
   101  		Providers: map[string]ResourceProviderFactory{
   102  			"aws": testProviderFuncFixed(p),
   103  		},
   104  		Variables: map[string]interface{}{
   105  			"in": "a,b,c",
   106  		},
   107  	})
   108  
   109  	plan, err := ctx.Plan()
   110  	if err != nil {
   111  		t.Fatalf("err: %s", err)
   112  	}
   113  
   114  	actual := strings.TrimSpace(plan.String())
   115  	expected := strings.TrimSpace(`
   116  DIFF:
   117  
   118  CREATE: aws_instance.bar.0
   119  CREATE: aws_instance.bar.1
   120  CREATE: aws_instance.foo.0
   121  CREATE: aws_instance.foo.1
   122  
   123  STATE:
   124  
   125  <no state>
   126  		`)
   127  	if actual != expected {
   128  		t.Fatalf("expected:\n%s, got:\n%s", expected, actual)
   129  	}
   130  }
   131  
   132  func TestContext2Plan_emptyDiff(t *testing.T) {
   133  	m := testModule(t, "plan-empty")
   134  	p := testProvider("aws")
   135  	p.DiffFn = func(
   136  		info *InstanceInfo,
   137  		s *InstanceState,
   138  		c *ResourceConfig) (*InstanceDiff, error) {
   139  		return nil, nil
   140  	}
   141  
   142  	ctx := testContext2(t, &ContextOpts{
   143  		Module: m,
   144  		Providers: map[string]ResourceProviderFactory{
   145  			"aws": testProviderFuncFixed(p),
   146  		},
   147  	})
   148  
   149  	plan, err := ctx.Plan()
   150  	if err != nil {
   151  		t.Fatalf("err: %s", err)
   152  	}
   153  
   154  	actual := strings.TrimSpace(plan.String())
   155  	expected := strings.TrimSpace(testTerraformPlanEmptyStr)
   156  	if actual != expected {
   157  		t.Fatalf("bad:\n%s", actual)
   158  	}
   159  }
   160  
   161  func TestContext2Plan_escapedVar(t *testing.T) {
   162  	m := testModule(t, "plan-escaped-var")
   163  	p := testProvider("aws")
   164  	p.DiffFn = testDiffFn
   165  	ctx := testContext2(t, &ContextOpts{
   166  		Module: m,
   167  		Providers: map[string]ResourceProviderFactory{
   168  			"aws": testProviderFuncFixed(p),
   169  		},
   170  	})
   171  
   172  	plan, err := ctx.Plan()
   173  	if err != nil {
   174  		t.Fatalf("err: %s", err)
   175  	}
   176  
   177  	actual := strings.TrimSpace(plan.String())
   178  	expected := strings.TrimSpace(testTerraformPlanEscapedVarStr)
   179  	if actual != expected {
   180  		t.Fatalf("bad:\n%s", actual)
   181  	}
   182  }
   183  
   184  func TestContext2Plan_minimal(t *testing.T) {
   185  	m := testModule(t, "plan-empty")
   186  	p := testProvider("aws")
   187  	p.DiffFn = testDiffFn
   188  	ctx := testContext2(t, &ContextOpts{
   189  		Module: m,
   190  		Providers: map[string]ResourceProviderFactory{
   191  			"aws": testProviderFuncFixed(p),
   192  		},
   193  	})
   194  
   195  	plan, err := ctx.Plan()
   196  	if err != nil {
   197  		t.Fatalf("err: %s", err)
   198  	}
   199  
   200  	actual := strings.TrimSpace(plan.String())
   201  	expected := strings.TrimSpace(testTerraformPlanEmptyStr)
   202  	if actual != expected {
   203  		t.Fatalf("bad:\n%s", actual)
   204  	}
   205  }
   206  
   207  func TestContext2Plan_modules(t *testing.T) {
   208  	m := testModule(t, "plan-modules")
   209  	p := testProvider("aws")
   210  	p.DiffFn = testDiffFn
   211  	ctx := testContext2(t, &ContextOpts{
   212  		Module: m,
   213  		Providers: map[string]ResourceProviderFactory{
   214  			"aws": testProviderFuncFixed(p),
   215  		},
   216  	})
   217  
   218  	plan, err := ctx.Plan()
   219  	if err != nil {
   220  		t.Fatalf("err: %s", err)
   221  	}
   222  
   223  	actual := strings.TrimSpace(plan.String())
   224  	expected := strings.TrimSpace(testTerraformPlanModulesStr)
   225  	if actual != expected {
   226  		t.Fatalf("bad:\n%s", actual)
   227  	}
   228  }
   229  
   230  // GH-1475
   231  func TestContext2Plan_moduleCycle(t *testing.T) {
   232  	m := testModule(t, "plan-module-cycle")
   233  	p := testProvider("aws")
   234  	p.DiffFn = testDiffFn
   235  	ctx := testContext2(t, &ContextOpts{
   236  		Module: m,
   237  		Providers: map[string]ResourceProviderFactory{
   238  			"aws": testProviderFuncFixed(p),
   239  		},
   240  	})
   241  
   242  	plan, err := ctx.Plan()
   243  	if err != nil {
   244  		t.Fatalf("err: %s", err)
   245  	}
   246  
   247  	actual := strings.TrimSpace(plan.String())
   248  	expected := strings.TrimSpace(testTerraformPlanModuleCycleStr)
   249  	if actual != expected {
   250  		t.Fatalf("bad:\n%s", actual)
   251  	}
   252  }
   253  
   254  func TestContext2Plan_moduleDeadlock(t *testing.T) {
   255  	testCheckDeadlock(t, func() {
   256  		m := testModule(t, "plan-module-deadlock")
   257  		p := testProvider("aws")
   258  		p.DiffFn = testDiffFn
   259  
   260  		ctx := testContext2(t, &ContextOpts{
   261  			Module: m,
   262  			Providers: map[string]ResourceProviderFactory{
   263  				"aws": testProviderFuncFixed(p),
   264  			},
   265  		})
   266  
   267  		plan, err := ctx.Plan()
   268  		if err != nil {
   269  			t.Fatalf("err: %s", err)
   270  		}
   271  
   272  		actual := strings.TrimSpace(plan.String())
   273  		expected := strings.TrimSpace(`
   274  DIFF:
   275  
   276  module.child:
   277    CREATE: aws_instance.foo.0
   278    CREATE: aws_instance.foo.1
   279    CREATE: aws_instance.foo.2
   280  
   281  STATE:
   282  
   283  <no state>
   284  		`)
   285  		if actual != expected {
   286  			t.Fatalf("expected:\n%sgot:\n%s", expected, actual)
   287  		}
   288  	})
   289  }
   290  
   291  func TestContext2Plan_moduleInput(t *testing.T) {
   292  	m := testModule(t, "plan-module-input")
   293  	p := testProvider("aws")
   294  	p.DiffFn = testDiffFn
   295  	ctx := testContext2(t, &ContextOpts{
   296  		Module: m,
   297  		Providers: map[string]ResourceProviderFactory{
   298  			"aws": testProviderFuncFixed(p),
   299  		},
   300  	})
   301  
   302  	plan, err := ctx.Plan()
   303  	if err != nil {
   304  		t.Fatalf("err: %s", err)
   305  	}
   306  
   307  	actual := strings.TrimSpace(plan.String())
   308  	expected := strings.TrimSpace(testTerraformPlanModuleInputStr)
   309  	if actual != expected {
   310  		t.Fatalf("bad:\n%s", actual)
   311  	}
   312  }
   313  
   314  func TestContext2Plan_moduleInputComputed(t *testing.T) {
   315  	m := testModule(t, "plan-module-input-computed")
   316  	p := testProvider("aws")
   317  	p.DiffFn = testDiffFn
   318  	ctx := testContext2(t, &ContextOpts{
   319  		Module: m,
   320  		Providers: map[string]ResourceProviderFactory{
   321  			"aws": testProviderFuncFixed(p),
   322  		},
   323  	})
   324  
   325  	plan, err := ctx.Plan()
   326  	if err != nil {
   327  		t.Fatalf("err: %s", err)
   328  	}
   329  
   330  	actual := strings.TrimSpace(plan.String())
   331  	expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr)
   332  	if actual != expected {
   333  		t.Fatalf("bad:\n%s", actual)
   334  	}
   335  }
   336  
   337  func TestContext2Plan_moduleInputFromVar(t *testing.T) {
   338  	m := testModule(t, "plan-module-input-var")
   339  	p := testProvider("aws")
   340  	p.DiffFn = testDiffFn
   341  	ctx := testContext2(t, &ContextOpts{
   342  		Module: m,
   343  		Providers: map[string]ResourceProviderFactory{
   344  			"aws": testProviderFuncFixed(p),
   345  		},
   346  		Variables: map[string]interface{}{
   347  			"foo": "52",
   348  		},
   349  	})
   350  
   351  	plan, err := ctx.Plan()
   352  	if err != nil {
   353  		t.Fatalf("err: %s", err)
   354  	}
   355  
   356  	actual := strings.TrimSpace(plan.String())
   357  	expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr)
   358  	if actual != expected {
   359  		t.Fatalf("bad:\n%s", actual)
   360  	}
   361  }
   362  
   363  func TestContext2Plan_moduleMultiVar(t *testing.T) {
   364  	m := testModule(t, "plan-module-multi-var")
   365  	p := testProvider("aws")
   366  	p.DiffFn = testDiffFn
   367  	ctx := testContext2(t, &ContextOpts{
   368  		Module: m,
   369  		Providers: map[string]ResourceProviderFactory{
   370  			"aws": testProviderFuncFixed(p),
   371  		},
   372  	})
   373  
   374  	plan, err := ctx.Plan()
   375  	if err != nil {
   376  		t.Fatalf("err: %s", err)
   377  	}
   378  
   379  	actual := strings.TrimSpace(plan.String())
   380  	expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr)
   381  	if actual != expected {
   382  		t.Fatalf("bad:\n%s", actual)
   383  	}
   384  }
   385  
   386  func TestContext2Plan_moduleOrphans(t *testing.T) {
   387  	m := testModule(t, "plan-modules-remove")
   388  	p := testProvider("aws")
   389  	p.DiffFn = testDiffFn
   390  	s := &State{
   391  		Modules: []*ModuleState{
   392  			&ModuleState{
   393  				Path: []string{"root", "child"},
   394  				Resources: map[string]*ResourceState{
   395  					"aws_instance.foo": &ResourceState{
   396  						Type: "aws_instance",
   397  						Primary: &InstanceState{
   398  							ID: "baz",
   399  						},
   400  					},
   401  				},
   402  			},
   403  		},
   404  	}
   405  	ctx := testContext2(t, &ContextOpts{
   406  		Module: m,
   407  		Providers: map[string]ResourceProviderFactory{
   408  			"aws": testProviderFuncFixed(p),
   409  		},
   410  		State: s,
   411  	})
   412  
   413  	plan, err := ctx.Plan()
   414  	if err != nil {
   415  		t.Fatalf("err: %s", err)
   416  	}
   417  
   418  	actual := strings.TrimSpace(plan.String())
   419  	expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr)
   420  	if actual != expected {
   421  		t.Fatalf("bad:\n%s", actual)
   422  	}
   423  }
   424  
   425  // https://github.com/hashicorp/terraform/issues/3114
   426  func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
   427  	m := testModule(t, "plan-modules-remove-provisioners")
   428  	p := testProvider("aws")
   429  	pr := testProvisioner()
   430  	p.DiffFn = testDiffFn
   431  	s := &State{
   432  		Modules: []*ModuleState{
   433  			&ModuleState{
   434  				Path: []string{"root"},
   435  				Resources: map[string]*ResourceState{
   436  					"aws_instance.top": &ResourceState{
   437  						Type: "aws_instance",
   438  						Primary: &InstanceState{
   439  							ID: "top",
   440  						},
   441  					},
   442  				},
   443  			},
   444  			&ModuleState{
   445  				Path: []string{"root", "parent", "childone"},
   446  				Resources: map[string]*ResourceState{
   447  					"aws_instance.foo": &ResourceState{
   448  						Type: "aws_instance",
   449  						Primary: &InstanceState{
   450  							ID: "baz",
   451  						},
   452  					},
   453  				},
   454  			},
   455  			&ModuleState{
   456  				Path: []string{"root", "parent", "childtwo"},
   457  				Resources: map[string]*ResourceState{
   458  					"aws_instance.foo": &ResourceState{
   459  						Type: "aws_instance",
   460  						Primary: &InstanceState{
   461  							ID: "baz",
   462  						},
   463  					},
   464  				},
   465  			},
   466  		},
   467  	}
   468  	ctx := testContext2(t, &ContextOpts{
   469  		Module: m,
   470  		Providers: map[string]ResourceProviderFactory{
   471  			"aws": testProviderFuncFixed(p),
   472  		},
   473  		Provisioners: map[string]ResourceProvisionerFactory{
   474  			"shell": testProvisionerFuncFixed(pr),
   475  		},
   476  		State: s,
   477  	})
   478  
   479  	plan, err := ctx.Plan()
   480  	if err != nil {
   481  		t.Fatalf("err: %s", err)
   482  	}
   483  
   484  	actual := strings.TrimSpace(plan.String())
   485  	expected := strings.TrimSpace(`
   486  DIFF:
   487  
   488  module.parent.childone:
   489    DESTROY: aws_instance.foo
   490  module.parent.childtwo:
   491    DESTROY: aws_instance.foo
   492  
   493  STATE:
   494  
   495  aws_instance.top:
   496    ID = top
   497  
   498  module.parent.childone:
   499    aws_instance.foo:
   500      ID = baz
   501  module.parent.childtwo:
   502    aws_instance.foo:
   503      ID = baz
   504  	`)
   505  	if actual != expected {
   506  		t.Fatalf("bad:\n%s", actual)
   507  	}
   508  }
   509  
   510  func TestContext2Plan_moduleProviderInherit(t *testing.T) {
   511  	var l sync.Mutex
   512  	var calls []string
   513  
   514  	m := testModule(t, "plan-module-provider-inherit")
   515  	ctx := testContext2(t, &ContextOpts{
   516  		Module: m,
   517  		Providers: map[string]ResourceProviderFactory{
   518  			"aws": func() (ResourceProvider, error) {
   519  				l.Lock()
   520  				defer l.Unlock()
   521  
   522  				p := testProvider("aws")
   523  				p.ConfigureFn = func(c *ResourceConfig) error {
   524  					if v, ok := c.Get("from"); !ok || v.(string) != "root" {
   525  						return fmt.Errorf("bad")
   526  					}
   527  
   528  					return nil
   529  				}
   530  				p.DiffFn = func(
   531  					info *InstanceInfo,
   532  					state *InstanceState,
   533  					c *ResourceConfig) (*InstanceDiff, error) {
   534  					v, _ := c.Get("from")
   535  					calls = append(calls, v.(string))
   536  					return testDiffFn(info, state, c)
   537  				}
   538  				return p, nil
   539  			},
   540  		},
   541  	})
   542  
   543  	_, err := ctx.Plan()
   544  	if err != nil {
   545  		t.Fatalf("err: %s", err)
   546  	}
   547  
   548  	actual := calls
   549  	sort.Strings(actual)
   550  	expected := []string{"child", "root"}
   551  	if !reflect.DeepEqual(actual, expected) {
   552  		t.Fatalf("bad: %#v", actual)
   553  	}
   554  }
   555  
   556  // This tests (for GH-11282) that deeply nested modules properly inherit
   557  // configuration.
   558  func TestContext2Plan_moduleProviderInheritDeep(t *testing.T) {
   559  	var l sync.Mutex
   560  
   561  	m := testModule(t, "plan-module-provider-inherit-deep")
   562  	ctx := testContext2(t, &ContextOpts{
   563  		Module: m,
   564  		Providers: map[string]ResourceProviderFactory{
   565  			"aws": func() (ResourceProvider, error) {
   566  				l.Lock()
   567  				defer l.Unlock()
   568  
   569  				var from string
   570  				p := testProvider("aws")
   571  				p.ConfigureFn = func(c *ResourceConfig) error {
   572  					v, ok := c.Get("from")
   573  					if !ok || v.(string) != "root" {
   574  						return fmt.Errorf("bad")
   575  					}
   576  
   577  					from = v.(string)
   578  					return nil
   579  				}
   580  
   581  				p.DiffFn = func(
   582  					info *InstanceInfo,
   583  					state *InstanceState,
   584  					c *ResourceConfig) (*InstanceDiff, error) {
   585  					if from != "root" {
   586  						return nil, fmt.Errorf("bad resource")
   587  					}
   588  
   589  					return testDiffFn(info, state, c)
   590  				}
   591  				return p, nil
   592  			},
   593  		},
   594  	})
   595  
   596  	_, err := ctx.Plan()
   597  	if err != nil {
   598  		t.Fatalf("err: %s", err)
   599  	}
   600  }
   601  
   602  func TestContext2Plan_moduleProviderDefaults(t *testing.T) {
   603  	var l sync.Mutex
   604  	var calls []string
   605  	toCount := 0
   606  
   607  	m := testModule(t, "plan-module-provider-defaults")
   608  	ctx := testContext2(t, &ContextOpts{
   609  		Module: m,
   610  		Providers: map[string]ResourceProviderFactory{
   611  			"aws": func() (ResourceProvider, error) {
   612  				l.Lock()
   613  				defer l.Unlock()
   614  
   615  				p := testProvider("aws")
   616  				p.ConfigureFn = func(c *ResourceConfig) error {
   617  					if v, ok := c.Get("from"); !ok || v.(string) != "root" {
   618  						return fmt.Errorf("bad")
   619  					}
   620  					if v, ok := c.Get("to"); ok && v.(string) == "child" {
   621  						toCount++
   622  					}
   623  
   624  					return nil
   625  				}
   626  				p.DiffFn = func(
   627  					info *InstanceInfo,
   628  					state *InstanceState,
   629  					c *ResourceConfig) (*InstanceDiff, error) {
   630  					v, _ := c.Get("from")
   631  					calls = append(calls, v.(string))
   632  					return testDiffFn(info, state, c)
   633  				}
   634  				return p, nil
   635  			},
   636  		},
   637  	})
   638  
   639  	_, err := ctx.Plan()
   640  	if err != nil {
   641  		t.Fatalf("err: %s", err)
   642  	}
   643  
   644  	if toCount != 1 {
   645  		t.Fatalf(
   646  			"provider in child didn't set proper config\n\n"+
   647  				"toCount: %d", toCount)
   648  	}
   649  
   650  	actual := calls
   651  	sort.Strings(actual)
   652  	expected := []string{"child", "root"}
   653  	if !reflect.DeepEqual(actual, expected) {
   654  		t.Fatalf("bad: %#v", actual)
   655  	}
   656  }
   657  
   658  func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
   659  	var l sync.Mutex
   660  	var calls []string
   661  
   662  	m := testModule(t, "plan-module-provider-defaults-var")
   663  	ctx := testContext2(t, &ContextOpts{
   664  		Module: m,
   665  		Providers: map[string]ResourceProviderFactory{
   666  			"aws": func() (ResourceProvider, error) {
   667  				l.Lock()
   668  				defer l.Unlock()
   669  
   670  				p := testProvider("aws")
   671  				p.ConfigureFn = func(c *ResourceConfig) error {
   672  					var buf bytes.Buffer
   673  					if v, ok := c.Get("from"); ok {
   674  						buf.WriteString(v.(string) + "\n")
   675  					}
   676  					if v, ok := c.Get("to"); ok {
   677  						buf.WriteString(v.(string) + "\n")
   678  					}
   679  
   680  					calls = append(calls, buf.String())
   681  					return nil
   682  				}
   683  				p.DiffFn = testDiffFn
   684  				return p, nil
   685  			},
   686  		},
   687  		Variables: map[string]interface{}{
   688  			"foo": "root",
   689  		},
   690  	})
   691  
   692  	_, err := ctx.Plan()
   693  	if err != nil {
   694  		t.Fatalf("err: %s", err)
   695  	}
   696  
   697  	expected := []string{
   698  		"root\n",
   699  		"root\nchild\n",
   700  	}
   701  	if !reflect.DeepEqual(calls, expected) {
   702  		t.Fatalf("BAD: %#v", calls)
   703  	}
   704  }
   705  
   706  func TestContext2Plan_moduleProviderVar(t *testing.T) {
   707  	m := testModule(t, "plan-module-provider-var")
   708  	p := testProvider("aws")
   709  	p.DiffFn = testDiffFn
   710  	ctx := testContext2(t, &ContextOpts{
   711  		Module: m,
   712  		Providers: map[string]ResourceProviderFactory{
   713  			"aws": testProviderFuncFixed(p),
   714  		},
   715  	})
   716  
   717  	plan, err := ctx.Plan()
   718  	if err != nil {
   719  		t.Fatalf("err: %s", err)
   720  	}
   721  
   722  	actual := strings.TrimSpace(plan.String())
   723  	expected := strings.TrimSpace(testTerraformPlanModuleProviderVarStr)
   724  	if actual != expected {
   725  		t.Fatalf("bad:\n%s", actual)
   726  	}
   727  }
   728  
   729  func TestContext2Plan_moduleVar(t *testing.T) {
   730  	m := testModule(t, "plan-module-var")
   731  	p := testProvider("aws")
   732  	p.DiffFn = testDiffFn
   733  	ctx := testContext2(t, &ContextOpts{
   734  		Module: m,
   735  		Providers: map[string]ResourceProviderFactory{
   736  			"aws": testProviderFuncFixed(p),
   737  		},
   738  	})
   739  
   740  	plan, err := ctx.Plan()
   741  	if err != nil {
   742  		t.Fatalf("err: %s", err)
   743  	}
   744  
   745  	actual := strings.TrimSpace(plan.String())
   746  	expected := strings.TrimSpace(testTerraformPlanModuleVarStr)
   747  	if actual != expected {
   748  		t.Fatalf("bad:\n%s", actual)
   749  	}
   750  }
   751  
   752  func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) {
   753  	m := testModule(t, "plan-module-wrong-var-type")
   754  	p := testProvider("aws")
   755  	p.DiffFn = testDiffFn
   756  	ctx := testContext2(t, &ContextOpts{
   757  		Module: m,
   758  		Providers: map[string]ResourceProviderFactory{
   759  			"aws": testProviderFuncFixed(p),
   760  		},
   761  	})
   762  
   763  	_, err := ctx.Plan()
   764  	if err == nil {
   765  		t.Fatalf("should error")
   766  	}
   767  }
   768  
   769  func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) {
   770  	m := testModule(t, "plan-module-wrong-var-type-nested")
   771  	p := testProvider("aws")
   772  	p.DiffFn = testDiffFn
   773  	ctx := testContext2(t, &ContextOpts{
   774  		Module: m,
   775  		Providers: map[string]ResourceProviderFactory{
   776  			"aws": testProviderFuncFixed(p),
   777  		},
   778  	})
   779  
   780  	_, err := ctx.Plan()
   781  	if err == nil {
   782  		t.Fatalf("should error")
   783  	}
   784  }
   785  
   786  func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) {
   787  	m := testModule(t, "plan-module-var-with-default-value")
   788  	p := testProvider("null")
   789  	p.DiffFn = testDiffFn
   790  	ctx := testContext2(t, &ContextOpts{
   791  		Module: m,
   792  		Providers: map[string]ResourceProviderFactory{
   793  			"null": testProviderFuncFixed(p),
   794  		},
   795  	})
   796  
   797  	_, err := ctx.Plan()
   798  	if err != nil {
   799  		t.Fatalf("bad: %s", err)
   800  	}
   801  }
   802  
   803  func TestContext2Plan_moduleVarComputed(t *testing.T) {
   804  	m := testModule(t, "plan-module-var-computed")
   805  	p := testProvider("aws")
   806  	p.DiffFn = testDiffFn
   807  	ctx := testContext2(t, &ContextOpts{
   808  		Module: m,
   809  		Providers: map[string]ResourceProviderFactory{
   810  			"aws": testProviderFuncFixed(p),
   811  		},
   812  	})
   813  
   814  	plan, err := ctx.Plan()
   815  	if err != nil {
   816  		t.Fatalf("err: %s", err)
   817  	}
   818  
   819  	actual := strings.TrimSpace(plan.String())
   820  	expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr)
   821  	if actual != expected {
   822  		t.Fatalf("bad:\n%s", actual)
   823  	}
   824  }
   825  
   826  func TestContext2Plan_nil(t *testing.T) {
   827  	m := testModule(t, "plan-nil")
   828  	p := testProvider("aws")
   829  	p.DiffFn = testDiffFn
   830  	ctx := testContext2(t, &ContextOpts{
   831  		Module: m,
   832  		Providers: map[string]ResourceProviderFactory{
   833  			"aws": testProviderFuncFixed(p),
   834  		},
   835  		State: &State{
   836  			Modules: []*ModuleState{
   837  				&ModuleState{
   838  					Path: rootModulePath,
   839  					Resources: map[string]*ResourceState{
   840  						"aws_instance.foo": &ResourceState{
   841  							Type: "aws_instance",
   842  							Primary: &InstanceState{
   843  								ID: "bar",
   844  							},
   845  						},
   846  					},
   847  				},
   848  			},
   849  		},
   850  	})
   851  
   852  	plan, err := ctx.Plan()
   853  	if err != nil {
   854  		t.Fatalf("err: %s", err)
   855  	}
   856  	if len(plan.Diff.RootModule().Resources) != 0 {
   857  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
   858  	}
   859  }
   860  
   861  func TestContext2Plan_preventDestroy_bad(t *testing.T) {
   862  	m := testModule(t, "plan-prevent-destroy-bad")
   863  	p := testProvider("aws")
   864  	p.DiffFn = testDiffFn
   865  	ctx := testContext2(t, &ContextOpts{
   866  		Module: m,
   867  		Providers: map[string]ResourceProviderFactory{
   868  			"aws": testProviderFuncFixed(p),
   869  		},
   870  		State: &State{
   871  			Modules: []*ModuleState{
   872  				&ModuleState{
   873  					Path: rootModulePath,
   874  					Resources: map[string]*ResourceState{
   875  						"aws_instance.foo": &ResourceState{
   876  							Type: "aws_instance",
   877  							Primary: &InstanceState{
   878  								ID: "i-abc123",
   879  							},
   880  						},
   881  					},
   882  				},
   883  			},
   884  		},
   885  	})
   886  
   887  	plan, err := ctx.Plan()
   888  
   889  	expectedErr := "aws_instance.foo: the plan would destroy"
   890  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
   891  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
   892  			expectedErr, err, plan)
   893  	}
   894  }
   895  
   896  func TestContext2Plan_preventDestroy_good(t *testing.T) {
   897  	m := testModule(t, "plan-prevent-destroy-good")
   898  	p := testProvider("aws")
   899  	p.DiffFn = testDiffFn
   900  	ctx := testContext2(t, &ContextOpts{
   901  		Module: m,
   902  		Providers: map[string]ResourceProviderFactory{
   903  			"aws": testProviderFuncFixed(p),
   904  		},
   905  		State: &State{
   906  			Modules: []*ModuleState{
   907  				&ModuleState{
   908  					Path: rootModulePath,
   909  					Resources: map[string]*ResourceState{
   910  						"aws_instance.foo": &ResourceState{
   911  							Type: "aws_instance",
   912  							Primary: &InstanceState{
   913  								ID: "i-abc123",
   914  							},
   915  						},
   916  					},
   917  				},
   918  			},
   919  		},
   920  	})
   921  
   922  	plan, err := ctx.Plan()
   923  	if err != nil {
   924  		t.Fatalf("err: %s", err)
   925  	}
   926  	if !plan.Diff.Empty() {
   927  		t.Fatalf("Expected empty plan, got %s", plan.String())
   928  	}
   929  }
   930  
   931  func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
   932  	m := testModule(t, "plan-prevent-destroy-count-bad")
   933  	p := testProvider("aws")
   934  	p.DiffFn = testDiffFn
   935  	ctx := testContext2(t, &ContextOpts{
   936  		Module: m,
   937  		Providers: map[string]ResourceProviderFactory{
   938  			"aws": testProviderFuncFixed(p),
   939  		},
   940  		State: &State{
   941  			Modules: []*ModuleState{
   942  				&ModuleState{
   943  					Path: rootModulePath,
   944  					Resources: map[string]*ResourceState{
   945  						"aws_instance.foo.0": &ResourceState{
   946  							Type: "aws_instance",
   947  							Primary: &InstanceState{
   948  								ID: "i-abc123",
   949  							},
   950  						},
   951  						"aws_instance.foo.1": &ResourceState{
   952  							Type: "aws_instance",
   953  							Primary: &InstanceState{
   954  								ID: "i-abc345",
   955  							},
   956  						},
   957  					},
   958  				},
   959  			},
   960  		},
   961  	})
   962  
   963  	plan, err := ctx.Plan()
   964  
   965  	expectedErr := "aws_instance.foo.1: the plan would destroy"
   966  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
   967  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
   968  			expectedErr, err, plan)
   969  	}
   970  }
   971  
   972  func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
   973  	m := testModule(t, "plan-prevent-destroy-count-good")
   974  	p := testProvider("aws")
   975  	p.DiffFn = testDiffFn
   976  	ctx := testContext2(t, &ContextOpts{
   977  		Module: m,
   978  		Providers: map[string]ResourceProviderFactory{
   979  			"aws": testProviderFuncFixed(p),
   980  		},
   981  		State: &State{
   982  			Modules: []*ModuleState{
   983  				&ModuleState{
   984  					Path: rootModulePath,
   985  					Resources: map[string]*ResourceState{
   986  						"aws_instance.foo.0": &ResourceState{
   987  							Type: "aws_instance",
   988  							Primary: &InstanceState{
   989  								ID: "i-abc123",
   990  							},
   991  						},
   992  						"aws_instance.foo.1": &ResourceState{
   993  							Type: "aws_instance",
   994  							Primary: &InstanceState{
   995  								ID: "i-abc345",
   996  							},
   997  						},
   998  					},
   999  				},
  1000  			},
  1001  		},
  1002  	})
  1003  
  1004  	plan, err := ctx.Plan()
  1005  	if err != nil {
  1006  		t.Fatalf("err: %s", err)
  1007  	}
  1008  	if plan.Diff.Empty() {
  1009  		t.Fatalf("Expected non-empty plan, got %s", plan.String())
  1010  	}
  1011  }
  1012  
  1013  func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) {
  1014  	m := testModule(t, "plan-prevent-destroy-count-good")
  1015  	p := testProvider("aws")
  1016  	p.DiffFn = testDiffFn
  1017  	ctx := testContext2(t, &ContextOpts{
  1018  		Module: m,
  1019  		Providers: map[string]ResourceProviderFactory{
  1020  			"aws": testProviderFuncFixed(p),
  1021  		},
  1022  		State: &State{
  1023  			Modules: []*ModuleState{
  1024  				&ModuleState{
  1025  					Path: rootModulePath,
  1026  					Resources: map[string]*ResourceState{
  1027  						"aws_instance.foo.0": &ResourceState{
  1028  							Type: "aws_instance",
  1029  							Primary: &InstanceState{
  1030  								ID: "i-abc123",
  1031  								Attributes: map[string]string{
  1032  									"current": "0",
  1033  									"type":    "aws_instance",
  1034  								},
  1035  							},
  1036  						},
  1037  					},
  1038  				},
  1039  			},
  1040  		},
  1041  	})
  1042  
  1043  	plan, err := ctx.Plan()
  1044  	if err != nil {
  1045  		t.Fatalf("err: %s", err)
  1046  	}
  1047  	if !plan.Diff.Empty() {
  1048  		t.Fatalf("Expected empty plan, got %s", plan.String())
  1049  	}
  1050  }
  1051  
  1052  func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
  1053  	m := testModule(t, "plan-prevent-destroy-good")
  1054  	p := testProvider("aws")
  1055  	p.DiffFn = testDiffFn
  1056  	ctx := testContext2(t, &ContextOpts{
  1057  		Module: m,
  1058  		Providers: map[string]ResourceProviderFactory{
  1059  			"aws": testProviderFuncFixed(p),
  1060  		},
  1061  		State: &State{
  1062  			Modules: []*ModuleState{
  1063  				&ModuleState{
  1064  					Path: rootModulePath,
  1065  					Resources: map[string]*ResourceState{
  1066  						"aws_instance.foo": &ResourceState{
  1067  							Type: "aws_instance",
  1068  							Primary: &InstanceState{
  1069  								ID: "i-abc123",
  1070  							},
  1071  						},
  1072  					},
  1073  				},
  1074  			},
  1075  		},
  1076  		Destroy: true,
  1077  	})
  1078  
  1079  	plan, err := ctx.Plan()
  1080  
  1081  	expectedErr := "aws_instance.foo: the plan would destroy"
  1082  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  1083  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
  1084  			expectedErr, err, plan)
  1085  	}
  1086  }
  1087  
  1088  func TestContext2Plan_provisionerCycle(t *testing.T) {
  1089  	m := testModule(t, "plan-provisioner-cycle")
  1090  	p := testProvider("aws")
  1091  	p.DiffFn = testDiffFn
  1092  	pr := testProvisioner()
  1093  	ctx := testContext2(t, &ContextOpts{
  1094  		Module: m,
  1095  		Providers: map[string]ResourceProviderFactory{
  1096  			"aws": testProviderFuncFixed(p),
  1097  		},
  1098  		Provisioners: map[string]ResourceProvisionerFactory{
  1099  			"local-exec": testProvisionerFuncFixed(pr),
  1100  		},
  1101  	})
  1102  
  1103  	_, err := ctx.Plan()
  1104  	if err == nil {
  1105  		t.Fatalf("should error")
  1106  	}
  1107  }
  1108  
  1109  func TestContext2Plan_computed(t *testing.T) {
  1110  	m := testModule(t, "plan-computed")
  1111  	p := testProvider("aws")
  1112  	p.DiffFn = testDiffFn
  1113  	ctx := testContext2(t, &ContextOpts{
  1114  		Module: m,
  1115  		Providers: map[string]ResourceProviderFactory{
  1116  			"aws": testProviderFuncFixed(p),
  1117  		},
  1118  	})
  1119  
  1120  	plan, err := ctx.Plan()
  1121  	if err != nil {
  1122  		t.Fatalf("err: %s", err)
  1123  	}
  1124  
  1125  	actual := strings.TrimSpace(plan.String())
  1126  	expected := strings.TrimSpace(testTerraformPlanComputedStr)
  1127  	if actual != expected {
  1128  		t.Fatalf("bad:\n%s", actual)
  1129  	}
  1130  }
  1131  
  1132  func TestContext2Plan_computedDataResource(t *testing.T) {
  1133  	m := testModule(t, "plan-computed-data-resource")
  1134  	p := testProvider("aws")
  1135  	p.DiffFn = testDiffFn
  1136  	ctx := testContext2(t, &ContextOpts{
  1137  		Module: m,
  1138  		Providers: map[string]ResourceProviderFactory{
  1139  			"aws": testProviderFuncFixed(p),
  1140  		},
  1141  	})
  1142  
  1143  	plan, err := ctx.Plan()
  1144  	if err != nil {
  1145  		t.Fatalf("err: %s", err)
  1146  	}
  1147  
  1148  	if got := len(plan.Diff.Modules); got != 1 {
  1149  		t.Fatalf("got %d modules; want 1", got)
  1150  	}
  1151  
  1152  	moduleDiff := plan.Diff.Modules[0]
  1153  
  1154  	if _, ok := moduleDiff.Resources["aws_instance.foo"]; !ok {
  1155  		t.Fatalf("missing diff for aws_instance.foo")
  1156  	}
  1157  	iDiff, ok := moduleDiff.Resources["data.aws_vpc.bar"]
  1158  	if !ok {
  1159  		t.Fatalf("missing diff for data.aws_vpc.bar")
  1160  	}
  1161  
  1162  	expectedDiff := &InstanceDiff{
  1163  		Attributes: map[string]*ResourceAttrDiff{
  1164  			"id": {
  1165  				NewComputed: true,
  1166  				RequiresNew: true,
  1167  				Type:        DiffAttrOutput,
  1168  			},
  1169  		},
  1170  	}
  1171  	if same, _ := expectedDiff.Same(iDiff); !same {
  1172  		t.Fatalf(
  1173  			"incorrect diff for data.aws_vpc.bar\ngot:  %#v\nwant: %#v",
  1174  			iDiff, expectedDiff,
  1175  		)
  1176  	}
  1177  }
  1178  
  1179  func TestContext2Plan_computedDataCountResource(t *testing.T) {
  1180  	m := testModule(t, "plan-computed-data-count")
  1181  	p := testProvider("aws")
  1182  	p.DiffFn = testDiffFn
  1183  	ctx := testContext2(t, &ContextOpts{
  1184  		Module: m,
  1185  		Providers: map[string]ResourceProviderFactory{
  1186  			"aws": testProviderFuncFixed(p),
  1187  		},
  1188  	})
  1189  
  1190  	plan, err := ctx.Plan()
  1191  	if err != nil {
  1192  		t.Fatalf("err: %s", err)
  1193  	}
  1194  
  1195  	if got := len(plan.Diff.Modules); got != 1 {
  1196  		t.Fatalf("got %d modules; want 1", got)
  1197  	}
  1198  
  1199  	moduleDiff := plan.Diff.Modules[0]
  1200  
  1201  	// make sure we created 3 "bar"s
  1202  	for i := 0; i < 3; i++ {
  1203  		resource := fmt.Sprintf("data.aws_vpc.bar.%d", i)
  1204  		if _, ok := moduleDiff.Resources[resource]; !ok {
  1205  			t.Fatalf("missing diff for %s", resource)
  1206  		}
  1207  	}
  1208  }
  1209  
  1210  // Higher level test at TestResource_dataSourceListPlanPanic
  1211  func TestContext2Plan_dataSourceTypeMismatch(t *testing.T) {
  1212  	m := testModule(t, "plan-data-source-type-mismatch")
  1213  	p := testProvider("aws")
  1214  	p.ValidateResourceFn = func(t string, c *ResourceConfig) (ws []string, es []error) {
  1215  		// Emulate the type checking behavior of helper/schema based validation
  1216  		if t == "aws_instance" {
  1217  			ami, _ := c.Get("ami")
  1218  			switch a := ami.(type) {
  1219  			case string:
  1220  				// ok
  1221  			default:
  1222  				es = append(es, fmt.Errorf("Expected ami to be string, got %T", a))
  1223  			}
  1224  		}
  1225  		return
  1226  	}
  1227  	p.DiffFn = func(
  1228  		info *InstanceInfo,
  1229  		state *InstanceState,
  1230  		c *ResourceConfig) (*InstanceDiff, error) {
  1231  		if info.Type == "aws_instance" {
  1232  			// If we get to the diff, we should be able to assume types
  1233  			ami, _ := c.Get("ami")
  1234  			_ = ami.(string)
  1235  		}
  1236  		return nil, nil
  1237  	}
  1238  	ctx := testContext2(t, &ContextOpts{
  1239  		Module: m,
  1240  		// Pretend like we ran a Refresh and the AZs data source was populated.
  1241  		State: &State{
  1242  			Modules: []*ModuleState{
  1243  				&ModuleState{
  1244  					Path: rootModulePath,
  1245  					Resources: map[string]*ResourceState{
  1246  						"data.aws_availability_zones.azs": &ResourceState{
  1247  							Type: "aws_availability_zones",
  1248  							Primary: &InstanceState{
  1249  								ID: "i-abc123",
  1250  								Attributes: map[string]string{
  1251  									"names.#": "2",
  1252  									"names.0": "us-east-1a",
  1253  									"names.1": "us-east-1b",
  1254  								},
  1255  							},
  1256  						},
  1257  					},
  1258  				},
  1259  			},
  1260  		},
  1261  		Providers: map[string]ResourceProviderFactory{
  1262  			"aws": testProviderFuncFixed(p),
  1263  		},
  1264  	})
  1265  
  1266  	_, err := ctx.Plan()
  1267  
  1268  	if err == nil {
  1269  		t.Fatalf("Expected err, got none!")
  1270  	}
  1271  	expected := "Expected ami to be string"
  1272  	if !strings.Contains(err.Error(), expected) {
  1273  		t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", err, expected)
  1274  	}
  1275  }
  1276  
  1277  func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
  1278  	m := testModule(t, "plan-data-resource-becomes-computed")
  1279  	p := testProvider("aws")
  1280  
  1281  	p.DiffFn = func(info *InstanceInfo, state *InstanceState, config *ResourceConfig) (*InstanceDiff, error) {
  1282  		if info.Type != "aws_instance" {
  1283  			t.Fatalf("don't know how to diff %s", info.Id)
  1284  			return nil, nil
  1285  		}
  1286  
  1287  		return &InstanceDiff{
  1288  			Attributes: map[string]*ResourceAttrDiff{
  1289  				"computed": &ResourceAttrDiff{
  1290  					Old:         "",
  1291  					New:         "",
  1292  					NewComputed: true,
  1293  				},
  1294  			},
  1295  		}, nil
  1296  	}
  1297  	p.ReadDataDiffReturn = &InstanceDiff{
  1298  		Attributes: map[string]*ResourceAttrDiff{
  1299  			"foo": &ResourceAttrDiff{
  1300  				Old:         "",
  1301  				New:         "",
  1302  				NewComputed: true,
  1303  			},
  1304  		},
  1305  	}
  1306  
  1307  	ctx := testContext2(t, &ContextOpts{
  1308  		Module: m,
  1309  		Providers: map[string]ResourceProviderFactory{
  1310  			"aws": testProviderFuncFixed(p),
  1311  		},
  1312  		State: &State{
  1313  			Modules: []*ModuleState{
  1314  				&ModuleState{
  1315  					Path: rootModulePath,
  1316  					Resources: map[string]*ResourceState{
  1317  						"data.aws_data_resource.foo": &ResourceState{
  1318  							Type: "aws_data_resource",
  1319  							Primary: &InstanceState{
  1320  								ID: "i-abc123",
  1321  								Attributes: map[string]string{
  1322  									"id":    "i-abc123",
  1323  									"value": "baz",
  1324  								},
  1325  							},
  1326  						},
  1327  					},
  1328  				},
  1329  			},
  1330  		},
  1331  	})
  1332  
  1333  	plan, err := ctx.Plan()
  1334  	if err != nil {
  1335  		t.Fatalf("err: %s", err)
  1336  	}
  1337  
  1338  	if got := len(plan.Diff.Modules); got != 1 {
  1339  		t.Fatalf("got %d modules; want 1", got)
  1340  	}
  1341  
  1342  	if !p.ReadDataDiffCalled {
  1343  		t.Fatal("ReadDataDiff wasn't called, but should've been")
  1344  	}
  1345  	if got, want := p.ReadDataDiffInfo.Id, "data.aws_data_resource.foo"; got != want {
  1346  		t.Fatalf("ReadDataDiff info id is %s; want %s", got, want)
  1347  	}
  1348  
  1349  	moduleDiff := plan.Diff.Modules[0]
  1350  
  1351  	iDiff, ok := moduleDiff.Resources["data.aws_data_resource.foo"]
  1352  	if !ok {
  1353  		t.Fatalf("missing diff for data.aws_data_resource.foo")
  1354  	}
  1355  
  1356  	// This is added by the diff but we want to verify that we got
  1357  	// the same diff as above minus the dynamic stuff.
  1358  	delete(iDiff.Attributes, "id")
  1359  
  1360  	if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same {
  1361  		t.Fatalf(
  1362  			"incorrect diff for data.data_resource.foo\ngot:  %#v\nwant: %#v",
  1363  			iDiff, p.ReadDataDiffReturn,
  1364  		)
  1365  	}
  1366  }
  1367  
  1368  func TestContext2Plan_computedList(t *testing.T) {
  1369  	m := testModule(t, "plan-computed-list")
  1370  	p := testProvider("aws")
  1371  	p.DiffFn = testDiffFn
  1372  	ctx := testContext2(t, &ContextOpts{
  1373  		Module: m,
  1374  		Providers: map[string]ResourceProviderFactory{
  1375  			"aws": testProviderFuncFixed(p),
  1376  		},
  1377  	})
  1378  
  1379  	plan, err := ctx.Plan()
  1380  	if err != nil {
  1381  		t.Fatalf("err: %s", err)
  1382  	}
  1383  
  1384  	actual := strings.TrimSpace(plan.String())
  1385  	expected := strings.TrimSpace(testTerraformPlanComputedListStr)
  1386  	if actual != expected {
  1387  		t.Fatalf("bad:\n%s", actual)
  1388  	}
  1389  }
  1390  
  1391  // GH-8695. This tests that you can index into a computed list on a
  1392  // splatted resource.
  1393  func TestContext2Plan_computedMultiIndex(t *testing.T) {
  1394  	m := testModule(t, "plan-computed-multi-index")
  1395  	p := testProvider("aws")
  1396  	p.DiffFn = testDiffFn
  1397  	ctx := testContext2(t, &ContextOpts{
  1398  		Module: m,
  1399  		Providers: map[string]ResourceProviderFactory{
  1400  			"aws": testProviderFuncFixed(p),
  1401  		},
  1402  	})
  1403  
  1404  	plan, err := ctx.Plan()
  1405  	if err != nil {
  1406  		t.Fatalf("err: %s", err)
  1407  	}
  1408  
  1409  	actual := strings.TrimSpace(plan.String())
  1410  	expected := strings.TrimSpace(testTerraformPlanComputedMultiIndexStr)
  1411  	if actual != expected {
  1412  		t.Fatalf("bad:\n%s", actual)
  1413  	}
  1414  }
  1415  
  1416  func TestContext2Plan_count(t *testing.T) {
  1417  	m := testModule(t, "plan-count")
  1418  	p := testProvider("aws")
  1419  	p.DiffFn = testDiffFn
  1420  	ctx := testContext2(t, &ContextOpts{
  1421  		Module: m,
  1422  		Providers: map[string]ResourceProviderFactory{
  1423  			"aws": testProviderFuncFixed(p),
  1424  		},
  1425  	})
  1426  
  1427  	plan, err := ctx.Plan()
  1428  	if err != nil {
  1429  		t.Fatalf("err: %s", err)
  1430  	}
  1431  
  1432  	if len(plan.Diff.RootModule().Resources) < 6 {
  1433  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1434  	}
  1435  
  1436  	actual := strings.TrimSpace(plan.String())
  1437  	expected := strings.TrimSpace(testTerraformPlanCountStr)
  1438  	if actual != expected {
  1439  		t.Fatalf("bad:\n%s", actual)
  1440  	}
  1441  }
  1442  
  1443  func TestContext2Plan_countComputed(t *testing.T) {
  1444  	m := testModule(t, "plan-count-computed")
  1445  	p := testProvider("aws")
  1446  	p.DiffFn = testDiffFn
  1447  	ctx := testContext2(t, &ContextOpts{
  1448  		Module: m,
  1449  		Providers: map[string]ResourceProviderFactory{
  1450  			"aws": testProviderFuncFixed(p),
  1451  		},
  1452  	})
  1453  
  1454  	_, err := ctx.Plan()
  1455  	if err == nil {
  1456  		t.Fatal("should error")
  1457  	}
  1458  }
  1459  
  1460  func TestContext2Plan_countComputedModule(t *testing.T) {
  1461  	m := testModule(t, "plan-count-computed-module")
  1462  	p := testProvider("aws")
  1463  	p.DiffFn = testDiffFn
  1464  	ctx := testContext2(t, &ContextOpts{
  1465  		Module: m,
  1466  		Providers: map[string]ResourceProviderFactory{
  1467  			"aws": testProviderFuncFixed(p),
  1468  		},
  1469  	})
  1470  
  1471  	_, err := ctx.Plan()
  1472  
  1473  	expectedErr := "aws_instance.bar: value of 'count'"
  1474  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  1475  		t.Fatalf("expected err would contain %q\nerr: %s\n",
  1476  			expectedErr, err)
  1477  	}
  1478  }
  1479  
  1480  func TestContext2Plan_countIndex(t *testing.T) {
  1481  	m := testModule(t, "plan-count-index")
  1482  	p := testProvider("aws")
  1483  	p.DiffFn = testDiffFn
  1484  	ctx := testContext2(t, &ContextOpts{
  1485  		Module: m,
  1486  		Providers: map[string]ResourceProviderFactory{
  1487  			"aws": testProviderFuncFixed(p),
  1488  		},
  1489  	})
  1490  
  1491  	plan, err := ctx.Plan()
  1492  	if err != nil {
  1493  		t.Fatalf("err: %s", err)
  1494  	}
  1495  
  1496  	actual := strings.TrimSpace(plan.String())
  1497  	expected := strings.TrimSpace(testTerraformPlanCountIndexStr)
  1498  	if actual != expected {
  1499  		t.Fatalf("bad:\n%s", actual)
  1500  	}
  1501  }
  1502  
  1503  func TestContext2Plan_countIndexZero(t *testing.T) {
  1504  	m := testModule(t, "plan-count-index-zero")
  1505  	p := testProvider("aws")
  1506  	p.DiffFn = testDiffFn
  1507  	ctx := testContext2(t, &ContextOpts{
  1508  		Module: m,
  1509  		Providers: map[string]ResourceProviderFactory{
  1510  			"aws": testProviderFuncFixed(p),
  1511  		},
  1512  	})
  1513  
  1514  	plan, err := ctx.Plan()
  1515  	if err != nil {
  1516  		t.Fatalf("err: %s", err)
  1517  	}
  1518  
  1519  	actual := strings.TrimSpace(plan.String())
  1520  	expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr)
  1521  	if actual != expected {
  1522  		t.Fatalf("bad:\n%s", actual)
  1523  	}
  1524  }
  1525  
  1526  func TestContext2Plan_countVar(t *testing.T) {
  1527  	m := testModule(t, "plan-count-var")
  1528  	p := testProvider("aws")
  1529  	p.DiffFn = testDiffFn
  1530  	ctx := testContext2(t, &ContextOpts{
  1531  		Module: m,
  1532  		Providers: map[string]ResourceProviderFactory{
  1533  			"aws": testProviderFuncFixed(p),
  1534  		},
  1535  		Variables: map[string]interface{}{
  1536  			"count": "3",
  1537  		},
  1538  	})
  1539  
  1540  	plan, err := ctx.Plan()
  1541  	if err != nil {
  1542  		t.Fatalf("err: %s", err)
  1543  	}
  1544  
  1545  	actual := strings.TrimSpace(plan.String())
  1546  	expected := strings.TrimSpace(testTerraformPlanCountVarStr)
  1547  	if actual != expected {
  1548  		t.Fatalf("bad:\n%s", actual)
  1549  	}
  1550  }
  1551  
  1552  func TestContext2Plan_countZero(t *testing.T) {
  1553  	m := testModule(t, "plan-count-zero")
  1554  	p := testProvider("aws")
  1555  	p.DiffFn = testDiffFn
  1556  	ctx := testContext2(t, &ContextOpts{
  1557  		Module: m,
  1558  		Providers: map[string]ResourceProviderFactory{
  1559  			"aws": testProviderFuncFixed(p),
  1560  		},
  1561  	})
  1562  
  1563  	plan, err := ctx.Plan()
  1564  	if err != nil {
  1565  		t.Fatalf("err: %s", err)
  1566  	}
  1567  
  1568  	actual := strings.TrimSpace(plan.String())
  1569  	expected := strings.TrimSpace(testTerraformPlanCountZeroStr)
  1570  	if actual != expected {
  1571  		t.Logf("expected:\n%s", expected)
  1572  		t.Fatalf("bad:\n%s", actual)
  1573  	}
  1574  }
  1575  
  1576  func TestContext2Plan_countOneIndex(t *testing.T) {
  1577  	m := testModule(t, "plan-count-one-index")
  1578  	p := testProvider("aws")
  1579  	p.DiffFn = testDiffFn
  1580  	ctx := testContext2(t, &ContextOpts{
  1581  		Module: m,
  1582  		Providers: map[string]ResourceProviderFactory{
  1583  			"aws": testProviderFuncFixed(p),
  1584  		},
  1585  	})
  1586  
  1587  	plan, err := ctx.Plan()
  1588  	if err != nil {
  1589  		t.Fatalf("err: %s", err)
  1590  	}
  1591  
  1592  	actual := strings.TrimSpace(plan.String())
  1593  	expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr)
  1594  	if actual != expected {
  1595  		t.Fatalf("bad:\n%s", actual)
  1596  	}
  1597  }
  1598  
  1599  func TestContext2Plan_countDecreaseToOne(t *testing.T) {
  1600  	m := testModule(t, "plan-count-dec")
  1601  	p := testProvider("aws")
  1602  	p.DiffFn = testDiffFn
  1603  	s := &State{
  1604  		Modules: []*ModuleState{
  1605  			&ModuleState{
  1606  				Path: rootModulePath,
  1607  				Resources: map[string]*ResourceState{
  1608  					"aws_instance.foo.0": &ResourceState{
  1609  						Type: "aws_instance",
  1610  						Primary: &InstanceState{
  1611  							ID: "bar",
  1612  							Attributes: map[string]string{
  1613  								"foo":  "foo",
  1614  								"type": "aws_instance",
  1615  							},
  1616  						},
  1617  					},
  1618  					"aws_instance.foo.1": &ResourceState{
  1619  						Type: "aws_instance",
  1620  						Primary: &InstanceState{
  1621  							ID: "bar",
  1622  						},
  1623  					},
  1624  					"aws_instance.foo.2": &ResourceState{
  1625  						Type: "aws_instance",
  1626  						Primary: &InstanceState{
  1627  							ID: "bar",
  1628  						},
  1629  					},
  1630  				},
  1631  			},
  1632  		},
  1633  	}
  1634  	ctx := testContext2(t, &ContextOpts{
  1635  		Module: m,
  1636  		Providers: map[string]ResourceProviderFactory{
  1637  			"aws": testProviderFuncFixed(p),
  1638  		},
  1639  		State: s,
  1640  	})
  1641  
  1642  	plan, err := ctx.Plan()
  1643  	if err != nil {
  1644  		t.Fatalf("err: %s", err)
  1645  	}
  1646  
  1647  	actual := strings.TrimSpace(plan.String())
  1648  	expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr)
  1649  	if actual != expected {
  1650  		t.Fatalf("bad:\n%s", actual)
  1651  	}
  1652  }
  1653  
  1654  func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
  1655  	m := testModule(t, "plan-count-inc")
  1656  	p := testProvider("aws")
  1657  	p.DiffFn = testDiffFn
  1658  	s := &State{
  1659  		Modules: []*ModuleState{
  1660  			&ModuleState{
  1661  				Path: rootModulePath,
  1662  				Resources: map[string]*ResourceState{
  1663  					"aws_instance.foo": &ResourceState{
  1664  						Type: "aws_instance",
  1665  						Primary: &InstanceState{
  1666  							ID: "bar",
  1667  							Attributes: map[string]string{
  1668  								"foo":  "foo",
  1669  								"type": "aws_instance",
  1670  							},
  1671  						},
  1672  					},
  1673  				},
  1674  			},
  1675  		},
  1676  	}
  1677  	ctx := testContext2(t, &ContextOpts{
  1678  		Module: m,
  1679  		Providers: map[string]ResourceProviderFactory{
  1680  			"aws": testProviderFuncFixed(p),
  1681  		},
  1682  		State: s,
  1683  	})
  1684  
  1685  	plan, err := ctx.Plan()
  1686  	if err != nil {
  1687  		t.Fatalf("err: %s", err)
  1688  	}
  1689  
  1690  	actual := strings.TrimSpace(plan.String())
  1691  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr)
  1692  	if actual != expected {
  1693  		t.Fatalf("bad:\n%s", actual)
  1694  	}
  1695  }
  1696  
  1697  func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
  1698  	m := testModule(t, "plan-count-inc")
  1699  	p := testProvider("aws")
  1700  	p.DiffFn = testDiffFn
  1701  	s := &State{
  1702  		Modules: []*ModuleState{
  1703  			&ModuleState{
  1704  				Path: rootModulePath,
  1705  				Resources: map[string]*ResourceState{
  1706  					"aws_instance.foo.0": &ResourceState{
  1707  						Type: "aws_instance",
  1708  						Primary: &InstanceState{
  1709  							ID: "bar",
  1710  							Attributes: map[string]string{
  1711  								"foo":  "foo",
  1712  								"type": "aws_instance",
  1713  							},
  1714  						},
  1715  					},
  1716  				},
  1717  			},
  1718  		},
  1719  	}
  1720  	ctx := testContext2(t, &ContextOpts{
  1721  		Module: m,
  1722  		Providers: map[string]ResourceProviderFactory{
  1723  			"aws": testProviderFuncFixed(p),
  1724  		},
  1725  		State: s,
  1726  	})
  1727  
  1728  	plan, err := ctx.Plan()
  1729  	if err != nil {
  1730  		t.Fatalf("err: %s", err)
  1731  	}
  1732  
  1733  	actual := strings.TrimSpace(plan.String())
  1734  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr)
  1735  	if actual != expected {
  1736  		t.Fatalf("bad:\n%s", actual)
  1737  	}
  1738  }
  1739  
  1740  // https://github.com/PeoplePerHour/terraform/pull/11
  1741  //
  1742  // This tests a case where both a "resource" and "resource.0" are in
  1743  // the state file, which apparently is a reasonable backwards compatibility
  1744  // concern found in the above 3rd party repo.
  1745  func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
  1746  	m := testModule(t, "plan-count-inc")
  1747  	p := testProvider("aws")
  1748  	p.DiffFn = testDiffFn
  1749  	s := &State{
  1750  		Modules: []*ModuleState{
  1751  			&ModuleState{
  1752  				Path: rootModulePath,
  1753  				Resources: map[string]*ResourceState{
  1754  					"aws_instance.foo": &ResourceState{
  1755  						Type: "aws_instance",
  1756  						Primary: &InstanceState{
  1757  							ID: "bar",
  1758  							Attributes: map[string]string{
  1759  								"foo":  "foo",
  1760  								"type": "aws_instance",
  1761  							},
  1762  						},
  1763  					},
  1764  					"aws_instance.foo.0": &ResourceState{
  1765  						Type: "aws_instance",
  1766  						Primary: &InstanceState{
  1767  							ID: "bar",
  1768  							Attributes: map[string]string{
  1769  								"foo":  "foo",
  1770  								"type": "aws_instance",
  1771  							},
  1772  						},
  1773  					},
  1774  				},
  1775  			},
  1776  		},
  1777  	}
  1778  	ctx := testContext2(t, &ContextOpts{
  1779  		Module: m,
  1780  		Providers: map[string]ResourceProviderFactory{
  1781  			"aws": testProviderFuncFixed(p),
  1782  		},
  1783  		State: s,
  1784  	})
  1785  
  1786  	plan, err := ctx.Plan()
  1787  	if err != nil {
  1788  		t.Fatalf("err: %s", err)
  1789  	}
  1790  
  1791  	actual := strings.TrimSpace(plan.String())
  1792  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr)
  1793  	if actual != expected {
  1794  		t.Fatalf("bad:\n%s", actual)
  1795  	}
  1796  }
  1797  
  1798  func TestContext2Plan_destroy(t *testing.T) {
  1799  	m := testModule(t, "plan-destroy")
  1800  	p := testProvider("aws")
  1801  	p.DiffFn = testDiffFn
  1802  	s := &State{
  1803  		Modules: []*ModuleState{
  1804  			&ModuleState{
  1805  				Path: rootModulePath,
  1806  				Resources: map[string]*ResourceState{
  1807  					"aws_instance.one": &ResourceState{
  1808  						Type: "aws_instance",
  1809  						Primary: &InstanceState{
  1810  							ID: "bar",
  1811  						},
  1812  					},
  1813  					"aws_instance.two": &ResourceState{
  1814  						Type: "aws_instance",
  1815  						Primary: &InstanceState{
  1816  							ID: "baz",
  1817  						},
  1818  					},
  1819  				},
  1820  			},
  1821  		},
  1822  	}
  1823  	ctx := testContext2(t, &ContextOpts{
  1824  		Module: m,
  1825  		Providers: map[string]ResourceProviderFactory{
  1826  			"aws": testProviderFuncFixed(p),
  1827  		},
  1828  		State:   s,
  1829  		Destroy: true,
  1830  	})
  1831  
  1832  	plan, err := ctx.Plan()
  1833  	if err != nil {
  1834  		t.Fatalf("err: %s", err)
  1835  	}
  1836  
  1837  	if len(plan.Diff.RootModule().Resources) != 2 {
  1838  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1839  	}
  1840  
  1841  	actual := strings.TrimSpace(plan.String())
  1842  	expected := strings.TrimSpace(testTerraformPlanDestroyStr)
  1843  	if actual != expected {
  1844  		t.Fatalf("bad:\n%s", actual)
  1845  	}
  1846  }
  1847  
  1848  func TestContext2Plan_moduleDestroy(t *testing.T) {
  1849  	m := testModule(t, "plan-module-destroy")
  1850  	p := testProvider("aws")
  1851  	p.DiffFn = testDiffFn
  1852  	s := &State{
  1853  		Modules: []*ModuleState{
  1854  			&ModuleState{
  1855  				Path: rootModulePath,
  1856  				Resources: map[string]*ResourceState{
  1857  					"aws_instance.foo": &ResourceState{
  1858  						Type: "aws_instance",
  1859  						Primary: &InstanceState{
  1860  							ID: "bar",
  1861  						},
  1862  					},
  1863  				},
  1864  			},
  1865  			&ModuleState{
  1866  				Path: []string{"root", "child"},
  1867  				Resources: map[string]*ResourceState{
  1868  					"aws_instance.foo": &ResourceState{
  1869  						Type: "aws_instance",
  1870  						Primary: &InstanceState{
  1871  							ID: "bar",
  1872  						},
  1873  					},
  1874  				},
  1875  			},
  1876  		},
  1877  	}
  1878  	ctx := testContext2(t, &ContextOpts{
  1879  		Module: m,
  1880  		Providers: map[string]ResourceProviderFactory{
  1881  			"aws": testProviderFuncFixed(p),
  1882  		},
  1883  		State:   s,
  1884  		Destroy: true,
  1885  	})
  1886  
  1887  	plan, err := ctx.Plan()
  1888  	if err != nil {
  1889  		t.Fatalf("err: %s", err)
  1890  	}
  1891  
  1892  	actual := strings.TrimSpace(plan.String())
  1893  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr)
  1894  	if actual != expected {
  1895  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1896  	}
  1897  }
  1898  
  1899  // GH-1835
  1900  func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
  1901  	m := testModule(t, "plan-module-destroy-gh-1835")
  1902  	p := testProvider("aws")
  1903  	p.DiffFn = testDiffFn
  1904  	s := &State{
  1905  		Modules: []*ModuleState{
  1906  			&ModuleState{
  1907  				Path: []string{"root", "a_module"},
  1908  				Resources: map[string]*ResourceState{
  1909  					"aws_instance.a": &ResourceState{
  1910  						Type: "aws_instance",
  1911  						Primary: &InstanceState{
  1912  							ID: "a",
  1913  						},
  1914  					},
  1915  				},
  1916  			},
  1917  			&ModuleState{
  1918  				Path: []string{"root", "b_module"},
  1919  				Resources: map[string]*ResourceState{
  1920  					"aws_instance.b": &ResourceState{
  1921  						Type: "aws_instance",
  1922  						Primary: &InstanceState{
  1923  							ID: "b",
  1924  						},
  1925  					},
  1926  				},
  1927  			},
  1928  		},
  1929  	}
  1930  	ctx := testContext2(t, &ContextOpts{
  1931  		Module: m,
  1932  		Providers: map[string]ResourceProviderFactory{
  1933  			"aws": testProviderFuncFixed(p),
  1934  		},
  1935  		State:   s,
  1936  		Destroy: true,
  1937  	})
  1938  
  1939  	plan, err := ctx.Plan()
  1940  	if err != nil {
  1941  		t.Fatalf("err: %s", err)
  1942  	}
  1943  
  1944  	actual := strings.TrimSpace(plan.String())
  1945  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr)
  1946  	if actual != expected {
  1947  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1948  	}
  1949  }
  1950  
  1951  func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
  1952  	m := testModule(t, "plan-module-destroy-multivar")
  1953  	p := testProvider("aws")
  1954  	p.DiffFn = testDiffFn
  1955  	s := &State{
  1956  		Modules: []*ModuleState{
  1957  			&ModuleState{
  1958  				Path:      rootModulePath,
  1959  				Resources: map[string]*ResourceState{},
  1960  			},
  1961  			&ModuleState{
  1962  				Path: []string{"root", "child"},
  1963  				Resources: map[string]*ResourceState{
  1964  					"aws_instance.foo.0": &ResourceState{
  1965  						Type: "aws_instance",
  1966  						Primary: &InstanceState{
  1967  							ID: "bar0",
  1968  						},
  1969  					},
  1970  					"aws_instance.foo.1": &ResourceState{
  1971  						Type: "aws_instance",
  1972  						Primary: &InstanceState{
  1973  							ID: "bar1",
  1974  						},
  1975  					},
  1976  				},
  1977  			},
  1978  		},
  1979  	}
  1980  	ctx := testContext2(t, &ContextOpts{
  1981  		Module: m,
  1982  		Providers: map[string]ResourceProviderFactory{
  1983  			"aws": testProviderFuncFixed(p),
  1984  		},
  1985  		State:   s,
  1986  		Destroy: true,
  1987  	})
  1988  
  1989  	plan, err := ctx.Plan()
  1990  	if err != nil {
  1991  		t.Fatalf("err: %s", err)
  1992  	}
  1993  
  1994  	actual := strings.TrimSpace(plan.String())
  1995  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr)
  1996  	if actual != expected {
  1997  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1998  	}
  1999  }
  2000  
  2001  func TestContext2Plan_pathVar(t *testing.T) {
  2002  	cwd, err := os.Getwd()
  2003  	if err != nil {
  2004  		t.Fatalf("err: %s", err)
  2005  	}
  2006  
  2007  	m := testModule(t, "plan-path-var")
  2008  	p := testProvider("aws")
  2009  	p.DiffFn = testDiffFn
  2010  	ctx := testContext2(t, &ContextOpts{
  2011  		Module: m,
  2012  		Providers: map[string]ResourceProviderFactory{
  2013  			"aws": testProviderFuncFixed(p),
  2014  		},
  2015  	})
  2016  
  2017  	plan, err := ctx.Plan()
  2018  	if err != nil {
  2019  		t.Fatalf("err: %s", err)
  2020  	}
  2021  
  2022  	actual := strings.TrimSpace(plan.String())
  2023  	expected := strings.TrimSpace(testTerraformPlanPathVarStr)
  2024  
  2025  	// Warning: this ordering REALLY matters for this test. The
  2026  	// order is: cwd, module, root.
  2027  	expected = fmt.Sprintf(
  2028  		expected,
  2029  		cwd,
  2030  		m.Config().Dir,
  2031  		m.Config().Dir)
  2032  
  2033  	if actual != expected {
  2034  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2035  	}
  2036  }
  2037  
  2038  func TestContext2Plan_diffVar(t *testing.T) {
  2039  	m := testModule(t, "plan-diffvar")
  2040  	p := testProvider("aws")
  2041  	s := &State{
  2042  		Modules: []*ModuleState{
  2043  			&ModuleState{
  2044  				Path: rootModulePath,
  2045  				Resources: map[string]*ResourceState{
  2046  					"aws_instance.foo": &ResourceState{
  2047  						Primary: &InstanceState{
  2048  							ID: "bar",
  2049  							Attributes: map[string]string{
  2050  								"num": "2",
  2051  							},
  2052  						},
  2053  					},
  2054  				},
  2055  			},
  2056  		},
  2057  	}
  2058  	ctx := testContext2(t, &ContextOpts{
  2059  		Module: m,
  2060  		Providers: map[string]ResourceProviderFactory{
  2061  			"aws": testProviderFuncFixed(p),
  2062  		},
  2063  		State: s,
  2064  	})
  2065  
  2066  	p.DiffFn = func(
  2067  		info *InstanceInfo,
  2068  		s *InstanceState,
  2069  		c *ResourceConfig) (*InstanceDiff, error) {
  2070  		if s.ID != "bar" {
  2071  			return testDiffFn(info, s, c)
  2072  		}
  2073  
  2074  		return &InstanceDiff{
  2075  			Attributes: map[string]*ResourceAttrDiff{
  2076  				"num": &ResourceAttrDiff{
  2077  					Old: "2",
  2078  					New: "3",
  2079  				},
  2080  			},
  2081  		}, nil
  2082  	}
  2083  
  2084  	plan, err := ctx.Plan()
  2085  	if err != nil {
  2086  		t.Fatalf("err: %s", err)
  2087  	}
  2088  
  2089  	actual := strings.TrimSpace(plan.String())
  2090  	expected := strings.TrimSpace(testTerraformPlanDiffVarStr)
  2091  	if actual != expected {
  2092  		t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected)
  2093  	}
  2094  }
  2095  
  2096  func TestContext2Plan_hook(t *testing.T) {
  2097  	m := testModule(t, "plan-good")
  2098  	h := new(MockHook)
  2099  	p := testProvider("aws")
  2100  	p.DiffFn = testDiffFn
  2101  	ctx := testContext2(t, &ContextOpts{
  2102  		Module: m,
  2103  		Hooks:  []Hook{h},
  2104  		Providers: map[string]ResourceProviderFactory{
  2105  			"aws": testProviderFuncFixed(p),
  2106  		},
  2107  	})
  2108  
  2109  	_, err := ctx.Plan()
  2110  	if err != nil {
  2111  		t.Fatalf("err: %s", err)
  2112  	}
  2113  
  2114  	if !h.PreDiffCalled {
  2115  		t.Fatal("should be called")
  2116  	}
  2117  	if !h.PostDiffCalled {
  2118  		t.Fatal("should be called")
  2119  	}
  2120  }
  2121  
  2122  func TestContext2Plan_orphan(t *testing.T) {
  2123  	m := testModule(t, "plan-orphan")
  2124  	p := testProvider("aws")
  2125  	p.DiffFn = testDiffFn
  2126  	s := &State{
  2127  		Modules: []*ModuleState{
  2128  			&ModuleState{
  2129  				Path: rootModulePath,
  2130  				Resources: map[string]*ResourceState{
  2131  					"aws_instance.baz": &ResourceState{
  2132  						Type: "aws_instance",
  2133  						Primary: &InstanceState{
  2134  							ID: "bar",
  2135  						},
  2136  					},
  2137  				},
  2138  			},
  2139  		},
  2140  	}
  2141  	ctx := testContext2(t, &ContextOpts{
  2142  		Module: m,
  2143  		Providers: map[string]ResourceProviderFactory{
  2144  			"aws": testProviderFuncFixed(p),
  2145  		},
  2146  		State: s,
  2147  	})
  2148  
  2149  	plan, err := ctx.Plan()
  2150  	if err != nil {
  2151  		t.Fatalf("err: %s", err)
  2152  	}
  2153  
  2154  	actual := strings.TrimSpace(plan.String())
  2155  	expected := strings.TrimSpace(testTerraformPlanOrphanStr)
  2156  	if actual != expected {
  2157  		t.Fatalf("bad:\n%s", actual)
  2158  	}
  2159  }
  2160  
  2161  // This tests that configurations with UUIDs don't produce errors.
  2162  // For shadows, this would produce errors since a UUID changes every time.
  2163  func TestContext2Plan_shadowUuid(t *testing.T) {
  2164  	m := testModule(t, "plan-shadow-uuid")
  2165  	p := testProvider("aws")
  2166  	p.DiffFn = testDiffFn
  2167  	ctx := testContext2(t, &ContextOpts{
  2168  		Module: m,
  2169  		Providers: map[string]ResourceProviderFactory{
  2170  			"aws": testProviderFuncFixed(p),
  2171  		},
  2172  	})
  2173  
  2174  	_, err := ctx.Plan()
  2175  	if err != nil {
  2176  		t.Fatalf("err: %s", err)
  2177  	}
  2178  }
  2179  
  2180  func TestContext2Plan_state(t *testing.T) {
  2181  	m := testModule(t, "plan-good")
  2182  	p := testProvider("aws")
  2183  	p.DiffFn = testDiffFn
  2184  	s := &State{
  2185  		Modules: []*ModuleState{
  2186  			&ModuleState{
  2187  				Path: rootModulePath,
  2188  				Resources: map[string]*ResourceState{
  2189  					"aws_instance.foo": &ResourceState{
  2190  						Primary: &InstanceState{
  2191  							ID: "bar",
  2192  						},
  2193  					},
  2194  				},
  2195  			},
  2196  		},
  2197  	}
  2198  	ctx := testContext2(t, &ContextOpts{
  2199  		Module: m,
  2200  		Providers: map[string]ResourceProviderFactory{
  2201  			"aws": testProviderFuncFixed(p),
  2202  		},
  2203  		State: s,
  2204  	})
  2205  
  2206  	plan, err := ctx.Plan()
  2207  	if err != nil {
  2208  		t.Fatalf("err: %s", err)
  2209  	}
  2210  
  2211  	if len(plan.Diff.RootModule().Resources) < 2 {
  2212  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2213  	}
  2214  
  2215  	actual := strings.TrimSpace(plan.String())
  2216  	expected := strings.TrimSpace(testTerraformPlanStateStr)
  2217  	if actual != expected {
  2218  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2219  	}
  2220  }
  2221  
  2222  func TestContext2Plan_taint(t *testing.T) {
  2223  	m := testModule(t, "plan-taint")
  2224  	p := testProvider("aws")
  2225  	p.DiffFn = testDiffFn
  2226  	s := &State{
  2227  		Modules: []*ModuleState{
  2228  			&ModuleState{
  2229  				Path: rootModulePath,
  2230  				Resources: map[string]*ResourceState{
  2231  					"aws_instance.foo": &ResourceState{
  2232  						Type: "aws_instance",
  2233  						Primary: &InstanceState{
  2234  							ID:         "bar",
  2235  							Attributes: map[string]string{"num": "2"},
  2236  						},
  2237  					},
  2238  					"aws_instance.bar": &ResourceState{
  2239  						Type: "aws_instance",
  2240  						Primary: &InstanceState{
  2241  							ID:      "baz",
  2242  							Tainted: true,
  2243  						},
  2244  					},
  2245  				},
  2246  			},
  2247  		},
  2248  	}
  2249  	ctx := testContext2(t, &ContextOpts{
  2250  		Module: m,
  2251  		Providers: map[string]ResourceProviderFactory{
  2252  			"aws": testProviderFuncFixed(p),
  2253  		},
  2254  		State: s,
  2255  	})
  2256  
  2257  	plan, err := ctx.Plan()
  2258  	if err != nil {
  2259  		t.Fatalf("err: %s", err)
  2260  	}
  2261  
  2262  	actual := strings.TrimSpace(plan.String())
  2263  	expected := strings.TrimSpace(testTerraformPlanTaintStr)
  2264  	if actual != expected {
  2265  		t.Fatalf("bad:\n%s", actual)
  2266  	}
  2267  }
  2268  
  2269  func TestContext2Apply_taintIgnoreChanges(t *testing.T) {
  2270  	m := testModule(t, "plan-taint-ignore-changes")
  2271  	p := testProvider("aws")
  2272  	p.ApplyFn = testApplyFn
  2273  	p.DiffFn = testDiffFn
  2274  	s := &State{
  2275  		Modules: []*ModuleState{
  2276  			&ModuleState{
  2277  				Path: rootModulePath,
  2278  				Resources: map[string]*ResourceState{
  2279  					"aws_instance.foo": &ResourceState{
  2280  						Type: "aws_instance",
  2281  						Primary: &InstanceState{
  2282  							ID: "foo",
  2283  							Attributes: map[string]string{
  2284  								"vars": "foo",
  2285  								"type": "aws_instance",
  2286  							},
  2287  							Tainted: true,
  2288  						},
  2289  					},
  2290  				},
  2291  			},
  2292  		},
  2293  	}
  2294  	ctx := testContext2(t, &ContextOpts{
  2295  		Module: m,
  2296  		Providers: map[string]ResourceProviderFactory{
  2297  			"aws": testProviderFuncFixed(p),
  2298  		},
  2299  		State: s,
  2300  	})
  2301  
  2302  	plan, err := ctx.Plan()
  2303  	if err != nil {
  2304  		t.Fatalf("err: %s", err)
  2305  	}
  2306  
  2307  	actual := strings.TrimSpace(plan.String())
  2308  	expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr)
  2309  	if actual != expected {
  2310  		t.Fatalf("bad:\n%s", actual)
  2311  	}
  2312  }
  2313  
  2314  // Fails about 50% of the time before the fix for GH-4982, covers the fix.
  2315  func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
  2316  	m := testModule(t, "plan-taint-interpolated-count")
  2317  	p := testProvider("aws")
  2318  	p.DiffFn = testDiffFn
  2319  	s := &State{
  2320  		Modules: []*ModuleState{
  2321  			&ModuleState{
  2322  				Path: rootModulePath,
  2323  				Resources: map[string]*ResourceState{
  2324  					"aws_instance.foo.0": &ResourceState{
  2325  						Type: "aws_instance",
  2326  						Primary: &InstanceState{
  2327  							ID:      "bar",
  2328  							Tainted: true,
  2329  						},
  2330  					},
  2331  					"aws_instance.foo.1": &ResourceState{
  2332  						Type:    "aws_instance",
  2333  						Primary: &InstanceState{ID: "bar"},
  2334  					},
  2335  					"aws_instance.foo.2": &ResourceState{
  2336  						Type:    "aws_instance",
  2337  						Primary: &InstanceState{ID: "bar"},
  2338  					},
  2339  				},
  2340  			},
  2341  		},
  2342  	}
  2343  	ctx := testContext2(t, &ContextOpts{
  2344  		Module: m,
  2345  		Providers: map[string]ResourceProviderFactory{
  2346  			"aws": testProviderFuncFixed(p),
  2347  		},
  2348  		State: s,
  2349  	})
  2350  
  2351  	for i := 0; i < 100; i++ {
  2352  		plan, err := ctx.Plan()
  2353  		if err != nil {
  2354  			t.Fatalf("err: %s", err)
  2355  		}
  2356  
  2357  		actual := strings.TrimSpace(plan.String())
  2358  		expected := strings.TrimSpace(`
  2359  DIFF:
  2360  
  2361  DESTROY/CREATE: aws_instance.foo.0
  2362    type: "" => "aws_instance"
  2363  
  2364  STATE:
  2365  
  2366  aws_instance.foo.0: (tainted)
  2367    ID = bar
  2368  aws_instance.foo.1:
  2369    ID = bar
  2370  aws_instance.foo.2:
  2371    ID = bar
  2372  		`)
  2373  		if actual != expected {
  2374  			t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected)
  2375  		}
  2376  	}
  2377  }
  2378  
  2379  func TestContext2Plan_targeted(t *testing.T) {
  2380  	m := testModule(t, "plan-targeted")
  2381  	p := testProvider("aws")
  2382  	p.DiffFn = testDiffFn
  2383  	ctx := testContext2(t, &ContextOpts{
  2384  		Module: m,
  2385  		Providers: map[string]ResourceProviderFactory{
  2386  			"aws": testProviderFuncFixed(p),
  2387  		},
  2388  		Targets: []string{"aws_instance.foo"},
  2389  	})
  2390  
  2391  	plan, err := ctx.Plan()
  2392  	if err != nil {
  2393  		t.Fatalf("err: %s", err)
  2394  	}
  2395  
  2396  	actual := strings.TrimSpace(plan.String())
  2397  	expected := strings.TrimSpace(`
  2398  DIFF:
  2399  
  2400  CREATE: aws_instance.foo
  2401    num:  "" => "2"
  2402    type: "" => "aws_instance"
  2403  
  2404  STATE:
  2405  
  2406  <no state>
  2407  	`)
  2408  	if actual != expected {
  2409  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2410  	}
  2411  }
  2412  
  2413  // Test that targeting a module properly plans any inputs that depend
  2414  // on another module.
  2415  func TestContext2Plan_targetedCrossModule(t *testing.T) {
  2416  	m := testModule(t, "plan-targeted-cross-module")
  2417  	p := testProvider("aws")
  2418  	p.DiffFn = testDiffFn
  2419  	ctx := testContext2(t, &ContextOpts{
  2420  		Module: m,
  2421  		Providers: map[string]ResourceProviderFactory{
  2422  			"aws": testProviderFuncFixed(p),
  2423  		},
  2424  		Targets: []string{"module.B"},
  2425  	})
  2426  
  2427  	plan, err := ctx.Plan()
  2428  	if err != nil {
  2429  		t.Fatalf("err: %s", err)
  2430  	}
  2431  
  2432  	actual := strings.TrimSpace(plan.String())
  2433  	expected := strings.TrimSpace(`
  2434  DIFF:
  2435  
  2436  module.A:
  2437    CREATE: aws_instance.foo
  2438      foo:  "" => "bar"
  2439      type: "" => "aws_instance"
  2440  module.B:
  2441    CREATE: aws_instance.bar
  2442      foo:  "" => "<computed>"
  2443      type: "" => "aws_instance"
  2444  
  2445  STATE:
  2446  
  2447  <no state>
  2448  	`)
  2449  	if actual != expected {
  2450  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2451  	}
  2452  }
  2453  
  2454  func TestContext2Plan_targetedOrphan(t *testing.T) {
  2455  	m := testModule(t, "plan-targeted-orphan")
  2456  	p := testProvider("aws")
  2457  	p.DiffFn = testDiffFn
  2458  	ctx := testContext2(t, &ContextOpts{
  2459  		Module: m,
  2460  		Providers: map[string]ResourceProviderFactory{
  2461  			"aws": testProviderFuncFixed(p),
  2462  		},
  2463  		State: &State{
  2464  			Modules: []*ModuleState{
  2465  				&ModuleState{
  2466  					Path: rootModulePath,
  2467  					Resources: map[string]*ResourceState{
  2468  						"aws_instance.orphan": &ResourceState{
  2469  							Type: "aws_instance",
  2470  							Primary: &InstanceState{
  2471  								ID: "i-789xyz",
  2472  							},
  2473  						},
  2474  						"aws_instance.nottargeted": &ResourceState{
  2475  							Type: "aws_instance",
  2476  							Primary: &InstanceState{
  2477  								ID: "i-abc123",
  2478  							},
  2479  						},
  2480  					},
  2481  				},
  2482  			},
  2483  		},
  2484  		Destroy: true,
  2485  		Targets: []string{"aws_instance.orphan"},
  2486  	})
  2487  
  2488  	plan, err := ctx.Plan()
  2489  	if err != nil {
  2490  		t.Fatalf("err: %s", err)
  2491  	}
  2492  
  2493  	actual := strings.TrimSpace(plan.String())
  2494  	expected := strings.TrimSpace(`DIFF:
  2495  
  2496  DESTROY: aws_instance.orphan
  2497  
  2498  STATE:
  2499  
  2500  aws_instance.nottargeted:
  2501    ID = i-abc123
  2502  aws_instance.orphan:
  2503    ID = i-789xyz
  2504  `)
  2505  	if actual != expected {
  2506  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2507  	}
  2508  }
  2509  
  2510  // https://github.com/hashicorp/terraform/issues/2538
  2511  func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
  2512  	m := testModule(t, "plan-targeted-module-orphan")
  2513  	p := testProvider("aws")
  2514  	p.DiffFn = testDiffFn
  2515  	ctx := testContext2(t, &ContextOpts{
  2516  		Module: m,
  2517  		Providers: map[string]ResourceProviderFactory{
  2518  			"aws": testProviderFuncFixed(p),
  2519  		},
  2520  		State: &State{
  2521  			Modules: []*ModuleState{
  2522  				&ModuleState{
  2523  					Path: []string{"root", "child"},
  2524  					Resources: map[string]*ResourceState{
  2525  						"aws_instance.orphan": &ResourceState{
  2526  							Type: "aws_instance",
  2527  							Primary: &InstanceState{
  2528  								ID: "i-789xyz",
  2529  							},
  2530  						},
  2531  						"aws_instance.nottargeted": &ResourceState{
  2532  							Type: "aws_instance",
  2533  							Primary: &InstanceState{
  2534  								ID: "i-abc123",
  2535  							},
  2536  						},
  2537  					},
  2538  				},
  2539  			},
  2540  		},
  2541  		Destroy: true,
  2542  		Targets: []string{"module.child.aws_instance.orphan"},
  2543  	})
  2544  
  2545  	plan, err := ctx.Plan()
  2546  	if err != nil {
  2547  		t.Fatalf("err: %s", err)
  2548  	}
  2549  
  2550  	actual := strings.TrimSpace(plan.String())
  2551  	expected := strings.TrimSpace(`DIFF:
  2552  
  2553  module.child:
  2554    DESTROY: aws_instance.orphan
  2555  
  2556  STATE:
  2557  
  2558  module.child:
  2559    aws_instance.nottargeted:
  2560      ID = i-abc123
  2561    aws_instance.orphan:
  2562      ID = i-789xyz
  2563  `)
  2564  	if actual != expected {
  2565  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2566  	}
  2567  }
  2568  
  2569  func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
  2570  	m := testModule(t, "plan-targeted-module-untargeted-variable")
  2571  	p := testProvider("aws")
  2572  	p.DiffFn = testDiffFn
  2573  	ctx := testContext2(t, &ContextOpts{
  2574  		Module: m,
  2575  		Providers: map[string]ResourceProviderFactory{
  2576  			"aws": testProviderFuncFixed(p),
  2577  		},
  2578  		Targets: []string{"aws_instance.blue", "module.blue_mod"},
  2579  	})
  2580  
  2581  	plan, err := ctx.Plan()
  2582  	if err != nil {
  2583  		t.Fatalf("err: %s", err)
  2584  	}
  2585  
  2586  	actual := strings.TrimSpace(plan.String())
  2587  	expected := strings.TrimSpace(`
  2588  DIFF:
  2589  
  2590  CREATE: aws_instance.blue
  2591  
  2592  module.blue_mod:
  2593    CREATE: aws_instance.mod
  2594      type:  "" => "aws_instance"
  2595      value: "" => "<computed>"
  2596  
  2597  STATE:
  2598  
  2599  <no state>
  2600  `)
  2601  	if actual != expected {
  2602  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2603  	}
  2604  }
  2605  
  2606  // https://github.com/hashicorp/terraform/issues/4515
  2607  func TestContext2Plan_targetedOverTen(t *testing.T) {
  2608  	m := testModule(t, "plan-targeted-over-ten")
  2609  	p := testProvider("aws")
  2610  	p.DiffFn = testDiffFn
  2611  
  2612  	resources := make(map[string]*ResourceState)
  2613  	var expectedState []string
  2614  	for i := 0; i < 13; i++ {
  2615  		key := fmt.Sprintf("aws_instance.foo.%d", i)
  2616  		id := fmt.Sprintf("i-abc%d", i)
  2617  		resources[key] = &ResourceState{
  2618  			Type:    "aws_instance",
  2619  			Primary: &InstanceState{ID: id},
  2620  		}
  2621  		expectedState = append(expectedState,
  2622  			fmt.Sprintf("%s:\n  ID = %s\n", key, id))
  2623  	}
  2624  	ctx := testContext2(t, &ContextOpts{
  2625  		Module: m,
  2626  		Providers: map[string]ResourceProviderFactory{
  2627  			"aws": testProviderFuncFixed(p),
  2628  		},
  2629  		State: &State{
  2630  			Modules: []*ModuleState{
  2631  				&ModuleState{
  2632  					Path:      rootModulePath,
  2633  					Resources: resources,
  2634  				},
  2635  			},
  2636  		},
  2637  		Targets: []string{"aws_instance.foo[1]"},
  2638  	})
  2639  
  2640  	plan, err := ctx.Plan()
  2641  	if err != nil {
  2642  		t.Fatalf("err: %s", err)
  2643  	}
  2644  
  2645  	actual := strings.TrimSpace(plan.String())
  2646  	sort.Strings(expectedState)
  2647  	expected := strings.TrimSpace(`
  2648  DIFF:
  2649  
  2650  
  2651  
  2652  STATE:
  2653  
  2654  aws_instance.foo.0:
  2655    ID = i-abc0
  2656  aws_instance.foo.1:
  2657    ID = i-abc1
  2658  aws_instance.foo.10:
  2659    ID = i-abc10
  2660  aws_instance.foo.11:
  2661    ID = i-abc11
  2662  aws_instance.foo.12:
  2663    ID = i-abc12
  2664  aws_instance.foo.2:
  2665    ID = i-abc2
  2666  aws_instance.foo.3:
  2667    ID = i-abc3
  2668  aws_instance.foo.4:
  2669    ID = i-abc4
  2670  aws_instance.foo.5:
  2671    ID = i-abc5
  2672  aws_instance.foo.6:
  2673    ID = i-abc6
  2674  aws_instance.foo.7:
  2675    ID = i-abc7
  2676  aws_instance.foo.8:
  2677    ID = i-abc8
  2678  aws_instance.foo.9:
  2679    ID = i-abc9
  2680  	`)
  2681  	if actual != expected {
  2682  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2683  	}
  2684  }
  2685  
  2686  func TestContext2Plan_provider(t *testing.T) {
  2687  	m := testModule(t, "plan-provider")
  2688  	p := testProvider("aws")
  2689  	p.DiffFn = testDiffFn
  2690  
  2691  	var value interface{}
  2692  	p.ConfigureFn = func(c *ResourceConfig) error {
  2693  		value, _ = c.Get("foo")
  2694  		return nil
  2695  	}
  2696  
  2697  	ctx := testContext2(t, &ContextOpts{
  2698  		Module: m,
  2699  		Providers: map[string]ResourceProviderFactory{
  2700  			"aws": testProviderFuncFixed(p),
  2701  		},
  2702  		Variables: map[string]interface{}{
  2703  			"foo": "bar",
  2704  		},
  2705  	})
  2706  
  2707  	if _, err := ctx.Plan(); err != nil {
  2708  		t.Fatalf("err: %s", err)
  2709  	}
  2710  
  2711  	if value != "bar" {
  2712  		t.Fatalf("bad: %#v", value)
  2713  	}
  2714  }
  2715  
  2716  func TestContext2Plan_varListErr(t *testing.T) {
  2717  	m := testModule(t, "plan-var-list-err")
  2718  	p := testProvider("aws")
  2719  	ctx := testContext2(t, &ContextOpts{
  2720  		Module: m,
  2721  		Providers: map[string]ResourceProviderFactory{
  2722  			"aws": testProviderFuncFixed(p),
  2723  		},
  2724  	})
  2725  
  2726  	_, err := ctx.Plan()
  2727  
  2728  	if err == nil {
  2729  		t.Fatal("should error")
  2730  	}
  2731  }
  2732  
  2733  func TestContext2Plan_ignoreChanges(t *testing.T) {
  2734  	m := testModule(t, "plan-ignore-changes")
  2735  	p := testProvider("aws")
  2736  	p.DiffFn = testDiffFn
  2737  	s := &State{
  2738  		Modules: []*ModuleState{
  2739  			&ModuleState{
  2740  				Path: rootModulePath,
  2741  				Resources: map[string]*ResourceState{
  2742  					"aws_instance.foo": &ResourceState{
  2743  						Primary: &InstanceState{
  2744  							ID:         "bar",
  2745  							Attributes: map[string]string{"ami": "ami-abcd1234"},
  2746  						},
  2747  					},
  2748  				},
  2749  			},
  2750  		},
  2751  	}
  2752  	ctx := testContext2(t, &ContextOpts{
  2753  		Module: m,
  2754  		Providers: map[string]ResourceProviderFactory{
  2755  			"aws": testProviderFuncFixed(p),
  2756  		},
  2757  		Variables: map[string]interface{}{
  2758  			"foo": "ami-1234abcd",
  2759  		},
  2760  		State: s,
  2761  	})
  2762  
  2763  	plan, err := ctx.Plan()
  2764  	if err != nil {
  2765  		t.Fatalf("err: %s", err)
  2766  	}
  2767  
  2768  	if len(plan.Diff.RootModule().Resources) < 1 {
  2769  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2770  	}
  2771  
  2772  	actual := strings.TrimSpace(plan.String())
  2773  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr)
  2774  	if actual != expected {
  2775  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2776  	}
  2777  }
  2778  
  2779  func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
  2780  	m := testModule(t, "plan-ignore-changes-wildcard")
  2781  	p := testProvider("aws")
  2782  	p.DiffFn = testDiffFn
  2783  	s := &State{
  2784  		Modules: []*ModuleState{
  2785  			&ModuleState{
  2786  				Path: rootModulePath,
  2787  				Resources: map[string]*ResourceState{
  2788  					"aws_instance.foo": &ResourceState{
  2789  						Primary: &InstanceState{
  2790  							ID: "bar",
  2791  							Attributes: map[string]string{
  2792  								"ami":           "ami-abcd1234",
  2793  								"instance_type": "t2.micro",
  2794  							},
  2795  						},
  2796  					},
  2797  				},
  2798  			},
  2799  		},
  2800  	}
  2801  	ctx := testContext2(t, &ContextOpts{
  2802  		Module: m,
  2803  		Providers: map[string]ResourceProviderFactory{
  2804  			"aws": testProviderFuncFixed(p),
  2805  		},
  2806  		Variables: map[string]interface{}{
  2807  			"foo": "ami-1234abcd",
  2808  			"bar": "t2.small",
  2809  		},
  2810  		State: s,
  2811  	})
  2812  
  2813  	plan, err := ctx.Plan()
  2814  	if err != nil {
  2815  		t.Fatalf("err: %s", err)
  2816  	}
  2817  
  2818  	if len(plan.Diff.RootModule().Resources) > 0 {
  2819  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2820  	}
  2821  
  2822  	actual := strings.TrimSpace(plan.String())
  2823  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr)
  2824  	if actual != expected {
  2825  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2826  	}
  2827  }
  2828  
  2829  func TestContext2Plan_moduleMapLiteral(t *testing.T) {
  2830  	m := testModule(t, "plan-module-map-literal")
  2831  	p := testProvider("aws")
  2832  	p.ApplyFn = testApplyFn
  2833  	p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  2834  		// Here we verify that both the populated and empty map literals made it
  2835  		// through to the resource attributes
  2836  		val, _ := c.Get("tags")
  2837  		m, ok := val.(map[string]interface{})
  2838  		if !ok {
  2839  			t.Fatalf("Tags attr not map: %#v", val)
  2840  		}
  2841  		if m["foo"] != "bar" {
  2842  			t.Fatalf("Bad value in tags attr: %#v", m)
  2843  		}
  2844  		{
  2845  			val, _ := c.Get("meta")
  2846  			m, ok := val.(map[string]interface{})
  2847  			if !ok {
  2848  				t.Fatalf("Meta attr not map: %#v", val)
  2849  			}
  2850  			if len(m) != 0 {
  2851  				t.Fatalf("Meta attr not empty: %#v", val)
  2852  			}
  2853  		}
  2854  		return nil, nil
  2855  	}
  2856  	ctx := testContext2(t, &ContextOpts{
  2857  		Module: m,
  2858  		Providers: map[string]ResourceProviderFactory{
  2859  			"aws": testProviderFuncFixed(p),
  2860  		},
  2861  	})
  2862  
  2863  	if _, err := ctx.Plan(); err != nil {
  2864  		t.Fatalf("err: %s", err)
  2865  	}
  2866  }
  2867  
  2868  func TestContext2Plan_computedValueInMap(t *testing.T) {
  2869  	m := testModule(t, "plan-computed-value-in-map")
  2870  	p := testProvider("aws")
  2871  	p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  2872  		switch info.Type {
  2873  		case "aws_computed_source":
  2874  			return &InstanceDiff{
  2875  				Attributes: map[string]*ResourceAttrDiff{
  2876  					"computed_read_only": &ResourceAttrDiff{
  2877  						NewComputed: true,
  2878  					},
  2879  				},
  2880  			}, nil
  2881  		}
  2882  
  2883  		return testDiffFn(info, state, c)
  2884  	}
  2885  	ctx := testContext2(t, &ContextOpts{
  2886  		Module: m,
  2887  		Providers: map[string]ResourceProviderFactory{
  2888  			"aws": testProviderFuncFixed(p),
  2889  		},
  2890  	})
  2891  
  2892  	if _, err := ctx.Plan(); err != nil {
  2893  		t.Fatalf("err: %s", err)
  2894  	}
  2895  
  2896  	plan, err := ctx.Plan()
  2897  	if err != nil {
  2898  		t.Fatalf("err: %s", err)
  2899  	}
  2900  
  2901  	actual := strings.TrimSpace(plan.String())
  2902  	expected := strings.TrimSpace(testTerraformPlanComputedValueInMap)
  2903  	if actual != expected {
  2904  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2905  	}
  2906  }
  2907  
  2908  func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
  2909  	m := testModule(t, "plan-module-variable-from-splat")
  2910  	p := testProvider("aws")
  2911  	p.DiffFn = testDiffFn
  2912  	ctx := testContext2(t, &ContextOpts{
  2913  		Module: m,
  2914  		Providers: map[string]ResourceProviderFactory{
  2915  			"aws": testProviderFuncFixed(p),
  2916  		},
  2917  	})
  2918  
  2919  	if _, err := ctx.Plan(); err != nil {
  2920  		t.Fatalf("err: %s", err)
  2921  	}
  2922  
  2923  	plan, err := ctx.Plan()
  2924  	if err != nil {
  2925  		t.Fatalf("err: %s", err)
  2926  	}
  2927  
  2928  	actual := strings.TrimSpace(plan.String())
  2929  	expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat)
  2930  	if actual != expected {
  2931  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2932  	}
  2933  }
  2934  
  2935  func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
  2936  	m := testModule(t, "plan-cdb-depends-datasource")
  2937  	p := testProvider("aws")
  2938  	p.DiffFn = testDiffFn
  2939  	ctx := testContext2(t, &ContextOpts{
  2940  		Module: m,
  2941  		Providers: map[string]ResourceProviderFactory{
  2942  			"aws": testProviderFuncFixed(p),
  2943  		},
  2944  	})
  2945  
  2946  	plan, err := ctx.Plan()
  2947  	if err != nil {
  2948  		t.Fatalf("err: %s", err)
  2949  	}
  2950  
  2951  	if got := len(plan.Diff.Modules); got != 1 {
  2952  		t.Fatalf("got %d modules; want 1", got)
  2953  	}
  2954  
  2955  	moduleDiff := plan.Diff.Modules[0]
  2956  
  2957  	if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok {
  2958  		t.Fatalf("missing diff for aws_instance.foo.0")
  2959  	}
  2960  	if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok {
  2961  		t.Fatalf("missing diff for aws_instance.foo.1")
  2962  	}
  2963  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok {
  2964  		t.Fatalf("missing diff for data.aws_vpc.bar.0")
  2965  	}
  2966  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok {
  2967  		t.Fatalf("missing diff for data.aws_vpc.bar.1")
  2968  	}
  2969  }
  2970  
  2971  // interpolated lists need to be stored in the original order.
  2972  func TestContext2Plan_listOrder(t *testing.T) {
  2973  	m := testModule(t, "plan-list-order")
  2974  	p := testProvider("aws")
  2975  	p.ApplyFn = testApplyFn
  2976  	p.DiffFn = testDiffFn
  2977  	ctx := testContext2(t, &ContextOpts{
  2978  		Module: m,
  2979  		Providers: map[string]ResourceProviderFactory{
  2980  			"aws": testProviderFuncFixed(p),
  2981  		},
  2982  	})
  2983  
  2984  	plan, err := ctx.Plan()
  2985  	if err != nil {
  2986  		t.Fatalf("err: %s", err)
  2987  	}
  2988  
  2989  	rDiffs := plan.Diff.Modules[0].Resources
  2990  	rDiffA := rDiffs["aws_instance.a"]
  2991  	rDiffB := rDiffs["aws_instance.b"]
  2992  
  2993  	if !rDiffA.Equal(rDiffB) {
  2994  		t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan)
  2995  	}
  2996  }