github.com/nevins-b/terraform@v0.3.8-0.20170215184714-bbae22007d5a/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_countModuleStatic(t *testing.T) {
  1481  	m := testModule(t, "plan-count-module-static")
  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(`
  1498  DIFF:
  1499  
  1500  module.child:
  1501    CREATE: aws_instance.foo.0
  1502    CREATE: aws_instance.foo.1
  1503    CREATE: aws_instance.foo.2
  1504  
  1505  STATE:
  1506  
  1507  <no state>
  1508  `)
  1509  	if actual != expected {
  1510  		t.Fatalf("bad:\n%s", actual)
  1511  	}
  1512  }
  1513  
  1514  func TestContext2Plan_countModuleStaticGrandchild(t *testing.T) {
  1515  	m := testModule(t, "plan-count-module-static-grandchild")
  1516  	p := testProvider("aws")
  1517  	p.DiffFn = testDiffFn
  1518  	ctx := testContext2(t, &ContextOpts{
  1519  		Module: m,
  1520  		Providers: map[string]ResourceProviderFactory{
  1521  			"aws": testProviderFuncFixed(p),
  1522  		},
  1523  	})
  1524  
  1525  	plan, err := ctx.Plan()
  1526  	if err != nil {
  1527  		t.Fatalf("err: %s", err)
  1528  	}
  1529  
  1530  	actual := strings.TrimSpace(plan.String())
  1531  	expected := strings.TrimSpace(`
  1532  DIFF:
  1533  
  1534  module.child.child:
  1535    CREATE: aws_instance.foo.0
  1536    CREATE: aws_instance.foo.1
  1537    CREATE: aws_instance.foo.2
  1538  
  1539  STATE:
  1540  
  1541  <no state>
  1542  `)
  1543  	if actual != expected {
  1544  		t.Fatalf("bad:\n%s", actual)
  1545  	}
  1546  }
  1547  
  1548  func TestContext2Plan_countIndex(t *testing.T) {
  1549  	m := testModule(t, "plan-count-index")
  1550  	p := testProvider("aws")
  1551  	p.DiffFn = testDiffFn
  1552  	ctx := testContext2(t, &ContextOpts{
  1553  		Module: m,
  1554  		Providers: map[string]ResourceProviderFactory{
  1555  			"aws": testProviderFuncFixed(p),
  1556  		},
  1557  	})
  1558  
  1559  	plan, err := ctx.Plan()
  1560  	if err != nil {
  1561  		t.Fatalf("err: %s", err)
  1562  	}
  1563  
  1564  	actual := strings.TrimSpace(plan.String())
  1565  	expected := strings.TrimSpace(testTerraformPlanCountIndexStr)
  1566  	if actual != expected {
  1567  		t.Fatalf("bad:\n%s", actual)
  1568  	}
  1569  }
  1570  
  1571  func TestContext2Plan_countIndexZero(t *testing.T) {
  1572  	m := testModule(t, "plan-count-index-zero")
  1573  	p := testProvider("aws")
  1574  	p.DiffFn = testDiffFn
  1575  	ctx := testContext2(t, &ContextOpts{
  1576  		Module: m,
  1577  		Providers: map[string]ResourceProviderFactory{
  1578  			"aws": testProviderFuncFixed(p),
  1579  		},
  1580  	})
  1581  
  1582  	plan, err := ctx.Plan()
  1583  	if err != nil {
  1584  		t.Fatalf("err: %s", err)
  1585  	}
  1586  
  1587  	actual := strings.TrimSpace(plan.String())
  1588  	expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr)
  1589  	if actual != expected {
  1590  		t.Fatalf("bad:\n%s", actual)
  1591  	}
  1592  }
  1593  
  1594  func TestContext2Plan_countVar(t *testing.T) {
  1595  	m := testModule(t, "plan-count-var")
  1596  	p := testProvider("aws")
  1597  	p.DiffFn = testDiffFn
  1598  	ctx := testContext2(t, &ContextOpts{
  1599  		Module: m,
  1600  		Providers: map[string]ResourceProviderFactory{
  1601  			"aws": testProviderFuncFixed(p),
  1602  		},
  1603  		Variables: map[string]interface{}{
  1604  			"count": "3",
  1605  		},
  1606  	})
  1607  
  1608  	plan, err := ctx.Plan()
  1609  	if err != nil {
  1610  		t.Fatalf("err: %s", err)
  1611  	}
  1612  
  1613  	actual := strings.TrimSpace(plan.String())
  1614  	expected := strings.TrimSpace(testTerraformPlanCountVarStr)
  1615  	if actual != expected {
  1616  		t.Fatalf("bad:\n%s", actual)
  1617  	}
  1618  }
  1619  
  1620  func TestContext2Plan_countZero(t *testing.T) {
  1621  	m := testModule(t, "plan-count-zero")
  1622  	p := testProvider("aws")
  1623  	p.DiffFn = testDiffFn
  1624  	ctx := testContext2(t, &ContextOpts{
  1625  		Module: m,
  1626  		Providers: map[string]ResourceProviderFactory{
  1627  			"aws": testProviderFuncFixed(p),
  1628  		},
  1629  	})
  1630  
  1631  	plan, err := ctx.Plan()
  1632  	if err != nil {
  1633  		t.Fatalf("err: %s", err)
  1634  	}
  1635  
  1636  	actual := strings.TrimSpace(plan.String())
  1637  	expected := strings.TrimSpace(testTerraformPlanCountZeroStr)
  1638  	if actual != expected {
  1639  		t.Logf("expected:\n%s", expected)
  1640  		t.Fatalf("bad:\n%s", actual)
  1641  	}
  1642  }
  1643  
  1644  func TestContext2Plan_countOneIndex(t *testing.T) {
  1645  	m := testModule(t, "plan-count-one-index")
  1646  	p := testProvider("aws")
  1647  	p.DiffFn = testDiffFn
  1648  	ctx := testContext2(t, &ContextOpts{
  1649  		Module: m,
  1650  		Providers: map[string]ResourceProviderFactory{
  1651  			"aws": testProviderFuncFixed(p),
  1652  		},
  1653  	})
  1654  
  1655  	plan, err := ctx.Plan()
  1656  	if err != nil {
  1657  		t.Fatalf("err: %s", err)
  1658  	}
  1659  
  1660  	actual := strings.TrimSpace(plan.String())
  1661  	expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr)
  1662  	if actual != expected {
  1663  		t.Fatalf("bad:\n%s", actual)
  1664  	}
  1665  }
  1666  
  1667  func TestContext2Plan_countDecreaseToOne(t *testing.T) {
  1668  	m := testModule(t, "plan-count-dec")
  1669  	p := testProvider("aws")
  1670  	p.DiffFn = testDiffFn
  1671  	s := &State{
  1672  		Modules: []*ModuleState{
  1673  			&ModuleState{
  1674  				Path: rootModulePath,
  1675  				Resources: map[string]*ResourceState{
  1676  					"aws_instance.foo.0": &ResourceState{
  1677  						Type: "aws_instance",
  1678  						Primary: &InstanceState{
  1679  							ID: "bar",
  1680  							Attributes: map[string]string{
  1681  								"foo":  "foo",
  1682  								"type": "aws_instance",
  1683  							},
  1684  						},
  1685  					},
  1686  					"aws_instance.foo.1": &ResourceState{
  1687  						Type: "aws_instance",
  1688  						Primary: &InstanceState{
  1689  							ID: "bar",
  1690  						},
  1691  					},
  1692  					"aws_instance.foo.2": &ResourceState{
  1693  						Type: "aws_instance",
  1694  						Primary: &InstanceState{
  1695  							ID: "bar",
  1696  						},
  1697  					},
  1698  				},
  1699  			},
  1700  		},
  1701  	}
  1702  	ctx := testContext2(t, &ContextOpts{
  1703  		Module: m,
  1704  		Providers: map[string]ResourceProviderFactory{
  1705  			"aws": testProviderFuncFixed(p),
  1706  		},
  1707  		State: s,
  1708  	})
  1709  
  1710  	plan, err := ctx.Plan()
  1711  	if err != nil {
  1712  		t.Fatalf("err: %s", err)
  1713  	}
  1714  
  1715  	actual := strings.TrimSpace(plan.String())
  1716  	expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr)
  1717  	if actual != expected {
  1718  		t.Fatalf("bad:\n%s", actual)
  1719  	}
  1720  }
  1721  
  1722  func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
  1723  	m := testModule(t, "plan-count-inc")
  1724  	p := testProvider("aws")
  1725  	p.DiffFn = testDiffFn
  1726  	s := &State{
  1727  		Modules: []*ModuleState{
  1728  			&ModuleState{
  1729  				Path: rootModulePath,
  1730  				Resources: map[string]*ResourceState{
  1731  					"aws_instance.foo": &ResourceState{
  1732  						Type: "aws_instance",
  1733  						Primary: &InstanceState{
  1734  							ID: "bar",
  1735  							Attributes: map[string]string{
  1736  								"foo":  "foo",
  1737  								"type": "aws_instance",
  1738  							},
  1739  						},
  1740  					},
  1741  				},
  1742  			},
  1743  		},
  1744  	}
  1745  	ctx := testContext2(t, &ContextOpts{
  1746  		Module: m,
  1747  		Providers: map[string]ResourceProviderFactory{
  1748  			"aws": testProviderFuncFixed(p),
  1749  		},
  1750  		State: s,
  1751  	})
  1752  
  1753  	plan, err := ctx.Plan()
  1754  	if err != nil {
  1755  		t.Fatalf("err: %s", err)
  1756  	}
  1757  
  1758  	actual := strings.TrimSpace(plan.String())
  1759  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr)
  1760  	if actual != expected {
  1761  		t.Fatalf("bad:\n%s", actual)
  1762  	}
  1763  }
  1764  
  1765  func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
  1766  	m := testModule(t, "plan-count-inc")
  1767  	p := testProvider("aws")
  1768  	p.DiffFn = testDiffFn
  1769  	s := &State{
  1770  		Modules: []*ModuleState{
  1771  			&ModuleState{
  1772  				Path: rootModulePath,
  1773  				Resources: map[string]*ResourceState{
  1774  					"aws_instance.foo.0": &ResourceState{
  1775  						Type: "aws_instance",
  1776  						Primary: &InstanceState{
  1777  							ID: "bar",
  1778  							Attributes: map[string]string{
  1779  								"foo":  "foo",
  1780  								"type": "aws_instance",
  1781  							},
  1782  						},
  1783  					},
  1784  				},
  1785  			},
  1786  		},
  1787  	}
  1788  	ctx := testContext2(t, &ContextOpts{
  1789  		Module: m,
  1790  		Providers: map[string]ResourceProviderFactory{
  1791  			"aws": testProviderFuncFixed(p),
  1792  		},
  1793  		State: s,
  1794  	})
  1795  
  1796  	plan, err := ctx.Plan()
  1797  	if err != nil {
  1798  		t.Fatalf("err: %s", err)
  1799  	}
  1800  
  1801  	actual := strings.TrimSpace(plan.String())
  1802  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr)
  1803  	if actual != expected {
  1804  		t.Fatalf("bad:\n%s", actual)
  1805  	}
  1806  }
  1807  
  1808  // https://github.com/PeoplePerHour/terraform/pull/11
  1809  //
  1810  // This tests a case where both a "resource" and "resource.0" are in
  1811  // the state file, which apparently is a reasonable backwards compatibility
  1812  // concern found in the above 3rd party repo.
  1813  func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
  1814  	m := testModule(t, "plan-count-inc")
  1815  	p := testProvider("aws")
  1816  	p.DiffFn = testDiffFn
  1817  	s := &State{
  1818  		Modules: []*ModuleState{
  1819  			&ModuleState{
  1820  				Path: rootModulePath,
  1821  				Resources: map[string]*ResourceState{
  1822  					"aws_instance.foo": &ResourceState{
  1823  						Type: "aws_instance",
  1824  						Primary: &InstanceState{
  1825  							ID: "bar",
  1826  							Attributes: map[string]string{
  1827  								"foo":  "foo",
  1828  								"type": "aws_instance",
  1829  							},
  1830  						},
  1831  					},
  1832  					"aws_instance.foo.0": &ResourceState{
  1833  						Type: "aws_instance",
  1834  						Primary: &InstanceState{
  1835  							ID: "bar",
  1836  							Attributes: map[string]string{
  1837  								"foo":  "foo",
  1838  								"type": "aws_instance",
  1839  							},
  1840  						},
  1841  					},
  1842  				},
  1843  			},
  1844  		},
  1845  	}
  1846  	ctx := testContext2(t, &ContextOpts{
  1847  		Module: m,
  1848  		Providers: map[string]ResourceProviderFactory{
  1849  			"aws": testProviderFuncFixed(p),
  1850  		},
  1851  		State: s,
  1852  	})
  1853  
  1854  	plan, err := ctx.Plan()
  1855  	if err != nil {
  1856  		t.Fatalf("err: %s", err)
  1857  	}
  1858  
  1859  	actual := strings.TrimSpace(plan.String())
  1860  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr)
  1861  	if actual != expected {
  1862  		t.Fatalf("bad:\n%s", actual)
  1863  	}
  1864  }
  1865  
  1866  func TestContext2Plan_destroy(t *testing.T) {
  1867  	m := testModule(t, "plan-destroy")
  1868  	p := testProvider("aws")
  1869  	p.DiffFn = testDiffFn
  1870  	s := &State{
  1871  		Modules: []*ModuleState{
  1872  			&ModuleState{
  1873  				Path: rootModulePath,
  1874  				Resources: map[string]*ResourceState{
  1875  					"aws_instance.one": &ResourceState{
  1876  						Type: "aws_instance",
  1877  						Primary: &InstanceState{
  1878  							ID: "bar",
  1879  						},
  1880  					},
  1881  					"aws_instance.two": &ResourceState{
  1882  						Type: "aws_instance",
  1883  						Primary: &InstanceState{
  1884  							ID: "baz",
  1885  						},
  1886  					},
  1887  				},
  1888  			},
  1889  		},
  1890  	}
  1891  	ctx := testContext2(t, &ContextOpts{
  1892  		Module: m,
  1893  		Providers: map[string]ResourceProviderFactory{
  1894  			"aws": testProviderFuncFixed(p),
  1895  		},
  1896  		State:   s,
  1897  		Destroy: true,
  1898  	})
  1899  
  1900  	plan, err := ctx.Plan()
  1901  	if err != nil {
  1902  		t.Fatalf("err: %s", err)
  1903  	}
  1904  
  1905  	if len(plan.Diff.RootModule().Resources) != 2 {
  1906  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1907  	}
  1908  
  1909  	actual := strings.TrimSpace(plan.String())
  1910  	expected := strings.TrimSpace(testTerraformPlanDestroyStr)
  1911  	if actual != expected {
  1912  		t.Fatalf("bad:\n%s", actual)
  1913  	}
  1914  }
  1915  
  1916  func TestContext2Plan_moduleDestroy(t *testing.T) {
  1917  	m := testModule(t, "plan-module-destroy")
  1918  	p := testProvider("aws")
  1919  	p.DiffFn = testDiffFn
  1920  	s := &State{
  1921  		Modules: []*ModuleState{
  1922  			&ModuleState{
  1923  				Path: rootModulePath,
  1924  				Resources: map[string]*ResourceState{
  1925  					"aws_instance.foo": &ResourceState{
  1926  						Type: "aws_instance",
  1927  						Primary: &InstanceState{
  1928  							ID: "bar",
  1929  						},
  1930  					},
  1931  				},
  1932  			},
  1933  			&ModuleState{
  1934  				Path: []string{"root", "child"},
  1935  				Resources: map[string]*ResourceState{
  1936  					"aws_instance.foo": &ResourceState{
  1937  						Type: "aws_instance",
  1938  						Primary: &InstanceState{
  1939  							ID: "bar",
  1940  						},
  1941  					},
  1942  				},
  1943  			},
  1944  		},
  1945  	}
  1946  	ctx := testContext2(t, &ContextOpts{
  1947  		Module: m,
  1948  		Providers: map[string]ResourceProviderFactory{
  1949  			"aws": testProviderFuncFixed(p),
  1950  		},
  1951  		State:   s,
  1952  		Destroy: true,
  1953  	})
  1954  
  1955  	plan, err := ctx.Plan()
  1956  	if err != nil {
  1957  		t.Fatalf("err: %s", err)
  1958  	}
  1959  
  1960  	actual := strings.TrimSpace(plan.String())
  1961  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr)
  1962  	if actual != expected {
  1963  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1964  	}
  1965  }
  1966  
  1967  // GH-1835
  1968  func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
  1969  	m := testModule(t, "plan-module-destroy-gh-1835")
  1970  	p := testProvider("aws")
  1971  	p.DiffFn = testDiffFn
  1972  	s := &State{
  1973  		Modules: []*ModuleState{
  1974  			&ModuleState{
  1975  				Path: []string{"root", "a_module"},
  1976  				Resources: map[string]*ResourceState{
  1977  					"aws_instance.a": &ResourceState{
  1978  						Type: "aws_instance",
  1979  						Primary: &InstanceState{
  1980  							ID: "a",
  1981  						},
  1982  					},
  1983  				},
  1984  			},
  1985  			&ModuleState{
  1986  				Path: []string{"root", "b_module"},
  1987  				Resources: map[string]*ResourceState{
  1988  					"aws_instance.b": &ResourceState{
  1989  						Type: "aws_instance",
  1990  						Primary: &InstanceState{
  1991  							ID: "b",
  1992  						},
  1993  					},
  1994  				},
  1995  			},
  1996  		},
  1997  	}
  1998  	ctx := testContext2(t, &ContextOpts{
  1999  		Module: m,
  2000  		Providers: map[string]ResourceProviderFactory{
  2001  			"aws": testProviderFuncFixed(p),
  2002  		},
  2003  		State:   s,
  2004  		Destroy: true,
  2005  	})
  2006  
  2007  	plan, err := ctx.Plan()
  2008  	if err != nil {
  2009  		t.Fatalf("err: %s", err)
  2010  	}
  2011  
  2012  	actual := strings.TrimSpace(plan.String())
  2013  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr)
  2014  	if actual != expected {
  2015  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2016  	}
  2017  }
  2018  
  2019  func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
  2020  	m := testModule(t, "plan-module-destroy-multivar")
  2021  	p := testProvider("aws")
  2022  	p.DiffFn = testDiffFn
  2023  	s := &State{
  2024  		Modules: []*ModuleState{
  2025  			&ModuleState{
  2026  				Path:      rootModulePath,
  2027  				Resources: map[string]*ResourceState{},
  2028  			},
  2029  			&ModuleState{
  2030  				Path: []string{"root", "child"},
  2031  				Resources: map[string]*ResourceState{
  2032  					"aws_instance.foo.0": &ResourceState{
  2033  						Type: "aws_instance",
  2034  						Primary: &InstanceState{
  2035  							ID: "bar0",
  2036  						},
  2037  					},
  2038  					"aws_instance.foo.1": &ResourceState{
  2039  						Type: "aws_instance",
  2040  						Primary: &InstanceState{
  2041  							ID: "bar1",
  2042  						},
  2043  					},
  2044  				},
  2045  			},
  2046  		},
  2047  	}
  2048  	ctx := testContext2(t, &ContextOpts{
  2049  		Module: m,
  2050  		Providers: map[string]ResourceProviderFactory{
  2051  			"aws": testProviderFuncFixed(p),
  2052  		},
  2053  		State:   s,
  2054  		Destroy: true,
  2055  	})
  2056  
  2057  	plan, err := ctx.Plan()
  2058  	if err != nil {
  2059  		t.Fatalf("err: %s", err)
  2060  	}
  2061  
  2062  	actual := strings.TrimSpace(plan.String())
  2063  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr)
  2064  	if actual != expected {
  2065  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2066  	}
  2067  }
  2068  
  2069  func TestContext2Plan_pathVar(t *testing.T) {
  2070  	cwd, err := os.Getwd()
  2071  	if err != nil {
  2072  		t.Fatalf("err: %s", err)
  2073  	}
  2074  
  2075  	m := testModule(t, "plan-path-var")
  2076  	p := testProvider("aws")
  2077  	p.DiffFn = testDiffFn
  2078  	ctx := testContext2(t, &ContextOpts{
  2079  		Module: m,
  2080  		Providers: map[string]ResourceProviderFactory{
  2081  			"aws": testProviderFuncFixed(p),
  2082  		},
  2083  	})
  2084  
  2085  	plan, err := ctx.Plan()
  2086  	if err != nil {
  2087  		t.Fatalf("err: %s", err)
  2088  	}
  2089  
  2090  	actual := strings.TrimSpace(plan.String())
  2091  	expected := strings.TrimSpace(testTerraformPlanPathVarStr)
  2092  
  2093  	// Warning: this ordering REALLY matters for this test. The
  2094  	// order is: cwd, module, root.
  2095  	expected = fmt.Sprintf(
  2096  		expected,
  2097  		cwd,
  2098  		m.Config().Dir,
  2099  		m.Config().Dir)
  2100  
  2101  	if actual != expected {
  2102  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2103  	}
  2104  }
  2105  
  2106  func TestContext2Plan_diffVar(t *testing.T) {
  2107  	m := testModule(t, "plan-diffvar")
  2108  	p := testProvider("aws")
  2109  	s := &State{
  2110  		Modules: []*ModuleState{
  2111  			&ModuleState{
  2112  				Path: rootModulePath,
  2113  				Resources: map[string]*ResourceState{
  2114  					"aws_instance.foo": &ResourceState{
  2115  						Primary: &InstanceState{
  2116  							ID: "bar",
  2117  							Attributes: map[string]string{
  2118  								"num": "2",
  2119  							},
  2120  						},
  2121  					},
  2122  				},
  2123  			},
  2124  		},
  2125  	}
  2126  	ctx := testContext2(t, &ContextOpts{
  2127  		Module: m,
  2128  		Providers: map[string]ResourceProviderFactory{
  2129  			"aws": testProviderFuncFixed(p),
  2130  		},
  2131  		State: s,
  2132  	})
  2133  
  2134  	p.DiffFn = func(
  2135  		info *InstanceInfo,
  2136  		s *InstanceState,
  2137  		c *ResourceConfig) (*InstanceDiff, error) {
  2138  		if s.ID != "bar" {
  2139  			return testDiffFn(info, s, c)
  2140  		}
  2141  
  2142  		return &InstanceDiff{
  2143  			Attributes: map[string]*ResourceAttrDiff{
  2144  				"num": &ResourceAttrDiff{
  2145  					Old: "2",
  2146  					New: "3",
  2147  				},
  2148  			},
  2149  		}, nil
  2150  	}
  2151  
  2152  	plan, err := ctx.Plan()
  2153  	if err != nil {
  2154  		t.Fatalf("err: %s", err)
  2155  	}
  2156  
  2157  	actual := strings.TrimSpace(plan.String())
  2158  	expected := strings.TrimSpace(testTerraformPlanDiffVarStr)
  2159  	if actual != expected {
  2160  		t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected)
  2161  	}
  2162  }
  2163  
  2164  func TestContext2Plan_hook(t *testing.T) {
  2165  	m := testModule(t, "plan-good")
  2166  	h := new(MockHook)
  2167  	p := testProvider("aws")
  2168  	p.DiffFn = testDiffFn
  2169  	ctx := testContext2(t, &ContextOpts{
  2170  		Module: m,
  2171  		Hooks:  []Hook{h},
  2172  		Providers: map[string]ResourceProviderFactory{
  2173  			"aws": testProviderFuncFixed(p),
  2174  		},
  2175  	})
  2176  
  2177  	_, err := ctx.Plan()
  2178  	if err != nil {
  2179  		t.Fatalf("err: %s", err)
  2180  	}
  2181  
  2182  	if !h.PreDiffCalled {
  2183  		t.Fatal("should be called")
  2184  	}
  2185  	if !h.PostDiffCalled {
  2186  		t.Fatal("should be called")
  2187  	}
  2188  }
  2189  
  2190  func TestContext2Plan_orphan(t *testing.T) {
  2191  	m := testModule(t, "plan-orphan")
  2192  	p := testProvider("aws")
  2193  	p.DiffFn = testDiffFn
  2194  	s := &State{
  2195  		Modules: []*ModuleState{
  2196  			&ModuleState{
  2197  				Path: rootModulePath,
  2198  				Resources: map[string]*ResourceState{
  2199  					"aws_instance.baz": &ResourceState{
  2200  						Type: "aws_instance",
  2201  						Primary: &InstanceState{
  2202  							ID: "bar",
  2203  						},
  2204  					},
  2205  				},
  2206  			},
  2207  		},
  2208  	}
  2209  	ctx := testContext2(t, &ContextOpts{
  2210  		Module: m,
  2211  		Providers: map[string]ResourceProviderFactory{
  2212  			"aws": testProviderFuncFixed(p),
  2213  		},
  2214  		State: s,
  2215  	})
  2216  
  2217  	plan, err := ctx.Plan()
  2218  	if err != nil {
  2219  		t.Fatalf("err: %s", err)
  2220  	}
  2221  
  2222  	actual := strings.TrimSpace(plan.String())
  2223  	expected := strings.TrimSpace(testTerraformPlanOrphanStr)
  2224  	if actual != expected {
  2225  		t.Fatalf("bad:\n%s", actual)
  2226  	}
  2227  }
  2228  
  2229  // This tests that configurations with UUIDs don't produce errors.
  2230  // For shadows, this would produce errors since a UUID changes every time.
  2231  func TestContext2Plan_shadowUuid(t *testing.T) {
  2232  	m := testModule(t, "plan-shadow-uuid")
  2233  	p := testProvider("aws")
  2234  	p.DiffFn = testDiffFn
  2235  	ctx := testContext2(t, &ContextOpts{
  2236  		Module: m,
  2237  		Providers: map[string]ResourceProviderFactory{
  2238  			"aws": testProviderFuncFixed(p),
  2239  		},
  2240  	})
  2241  
  2242  	_, err := ctx.Plan()
  2243  	if err != nil {
  2244  		t.Fatalf("err: %s", err)
  2245  	}
  2246  }
  2247  
  2248  func TestContext2Plan_state(t *testing.T) {
  2249  	m := testModule(t, "plan-good")
  2250  	p := testProvider("aws")
  2251  	p.DiffFn = testDiffFn
  2252  	s := &State{
  2253  		Modules: []*ModuleState{
  2254  			&ModuleState{
  2255  				Path: rootModulePath,
  2256  				Resources: map[string]*ResourceState{
  2257  					"aws_instance.foo": &ResourceState{
  2258  						Primary: &InstanceState{
  2259  							ID: "bar",
  2260  						},
  2261  					},
  2262  				},
  2263  			},
  2264  		},
  2265  	}
  2266  	ctx := testContext2(t, &ContextOpts{
  2267  		Module: m,
  2268  		Providers: map[string]ResourceProviderFactory{
  2269  			"aws": testProviderFuncFixed(p),
  2270  		},
  2271  		State: s,
  2272  	})
  2273  
  2274  	plan, err := ctx.Plan()
  2275  	if err != nil {
  2276  		t.Fatalf("err: %s", err)
  2277  	}
  2278  
  2279  	if len(plan.Diff.RootModule().Resources) < 2 {
  2280  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2281  	}
  2282  
  2283  	actual := strings.TrimSpace(plan.String())
  2284  	expected := strings.TrimSpace(testTerraformPlanStateStr)
  2285  	if actual != expected {
  2286  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2287  	}
  2288  }
  2289  
  2290  func TestContext2Plan_taint(t *testing.T) {
  2291  	m := testModule(t, "plan-taint")
  2292  	p := testProvider("aws")
  2293  	p.DiffFn = testDiffFn
  2294  	s := &State{
  2295  		Modules: []*ModuleState{
  2296  			&ModuleState{
  2297  				Path: rootModulePath,
  2298  				Resources: map[string]*ResourceState{
  2299  					"aws_instance.foo": &ResourceState{
  2300  						Type: "aws_instance",
  2301  						Primary: &InstanceState{
  2302  							ID:         "bar",
  2303  							Attributes: map[string]string{"num": "2"},
  2304  						},
  2305  					},
  2306  					"aws_instance.bar": &ResourceState{
  2307  						Type: "aws_instance",
  2308  						Primary: &InstanceState{
  2309  							ID:      "baz",
  2310  							Tainted: true,
  2311  						},
  2312  					},
  2313  				},
  2314  			},
  2315  		},
  2316  	}
  2317  	ctx := testContext2(t, &ContextOpts{
  2318  		Module: m,
  2319  		Providers: map[string]ResourceProviderFactory{
  2320  			"aws": testProviderFuncFixed(p),
  2321  		},
  2322  		State: s,
  2323  	})
  2324  
  2325  	plan, err := ctx.Plan()
  2326  	if err != nil {
  2327  		t.Fatalf("err: %s", err)
  2328  	}
  2329  
  2330  	actual := strings.TrimSpace(plan.String())
  2331  	expected := strings.TrimSpace(testTerraformPlanTaintStr)
  2332  	if actual != expected {
  2333  		t.Fatalf("bad:\n%s", actual)
  2334  	}
  2335  }
  2336  
  2337  func TestContext2Apply_taintIgnoreChanges(t *testing.T) {
  2338  	m := testModule(t, "plan-taint-ignore-changes")
  2339  	p := testProvider("aws")
  2340  	p.ApplyFn = testApplyFn
  2341  	p.DiffFn = testDiffFn
  2342  	s := &State{
  2343  		Modules: []*ModuleState{
  2344  			&ModuleState{
  2345  				Path: rootModulePath,
  2346  				Resources: map[string]*ResourceState{
  2347  					"aws_instance.foo": &ResourceState{
  2348  						Type: "aws_instance",
  2349  						Primary: &InstanceState{
  2350  							ID: "foo",
  2351  							Attributes: map[string]string{
  2352  								"vars": "foo",
  2353  								"type": "aws_instance",
  2354  							},
  2355  							Tainted: true,
  2356  						},
  2357  					},
  2358  				},
  2359  			},
  2360  		},
  2361  	}
  2362  	ctx := testContext2(t, &ContextOpts{
  2363  		Module: m,
  2364  		Providers: map[string]ResourceProviderFactory{
  2365  			"aws": testProviderFuncFixed(p),
  2366  		},
  2367  		State: s,
  2368  	})
  2369  
  2370  	plan, err := ctx.Plan()
  2371  	if err != nil {
  2372  		t.Fatalf("err: %s", err)
  2373  	}
  2374  
  2375  	actual := strings.TrimSpace(plan.String())
  2376  	expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr)
  2377  	if actual != expected {
  2378  		t.Fatalf("bad:\n%s", actual)
  2379  	}
  2380  }
  2381  
  2382  // Fails about 50% of the time before the fix for GH-4982, covers the fix.
  2383  func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
  2384  	m := testModule(t, "plan-taint-interpolated-count")
  2385  	p := testProvider("aws")
  2386  	p.DiffFn = testDiffFn
  2387  	s := &State{
  2388  		Modules: []*ModuleState{
  2389  			&ModuleState{
  2390  				Path: rootModulePath,
  2391  				Resources: map[string]*ResourceState{
  2392  					"aws_instance.foo.0": &ResourceState{
  2393  						Type: "aws_instance",
  2394  						Primary: &InstanceState{
  2395  							ID:      "bar",
  2396  							Tainted: true,
  2397  						},
  2398  					},
  2399  					"aws_instance.foo.1": &ResourceState{
  2400  						Type:    "aws_instance",
  2401  						Primary: &InstanceState{ID: "bar"},
  2402  					},
  2403  					"aws_instance.foo.2": &ResourceState{
  2404  						Type:    "aws_instance",
  2405  						Primary: &InstanceState{ID: "bar"},
  2406  					},
  2407  				},
  2408  			},
  2409  		},
  2410  	}
  2411  	ctx := testContext2(t, &ContextOpts{
  2412  		Module: m,
  2413  		Providers: map[string]ResourceProviderFactory{
  2414  			"aws": testProviderFuncFixed(p),
  2415  		},
  2416  		State: s,
  2417  	})
  2418  
  2419  	for i := 0; i < 100; i++ {
  2420  		plan, err := ctx.Plan()
  2421  		if err != nil {
  2422  			t.Fatalf("err: %s", err)
  2423  		}
  2424  
  2425  		actual := strings.TrimSpace(plan.String())
  2426  		expected := strings.TrimSpace(`
  2427  DIFF:
  2428  
  2429  DESTROY/CREATE: aws_instance.foo.0
  2430    type: "" => "aws_instance"
  2431  
  2432  STATE:
  2433  
  2434  aws_instance.foo.0: (tainted)
  2435    ID = bar
  2436  aws_instance.foo.1:
  2437    ID = bar
  2438  aws_instance.foo.2:
  2439    ID = bar
  2440  		`)
  2441  		if actual != expected {
  2442  			t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected)
  2443  		}
  2444  	}
  2445  }
  2446  
  2447  func TestContext2Plan_targeted(t *testing.T) {
  2448  	m := testModule(t, "plan-targeted")
  2449  	p := testProvider("aws")
  2450  	p.DiffFn = testDiffFn
  2451  	ctx := testContext2(t, &ContextOpts{
  2452  		Module: m,
  2453  		Providers: map[string]ResourceProviderFactory{
  2454  			"aws": testProviderFuncFixed(p),
  2455  		},
  2456  		Targets: []string{"aws_instance.foo"},
  2457  	})
  2458  
  2459  	plan, err := ctx.Plan()
  2460  	if err != nil {
  2461  		t.Fatalf("err: %s", err)
  2462  	}
  2463  
  2464  	actual := strings.TrimSpace(plan.String())
  2465  	expected := strings.TrimSpace(`
  2466  DIFF:
  2467  
  2468  CREATE: aws_instance.foo
  2469    num:  "" => "2"
  2470    type: "" => "aws_instance"
  2471  
  2472  STATE:
  2473  
  2474  <no state>
  2475  	`)
  2476  	if actual != expected {
  2477  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2478  	}
  2479  }
  2480  
  2481  // Test that targeting a module properly plans any inputs that depend
  2482  // on another module.
  2483  func TestContext2Plan_targetedCrossModule(t *testing.T) {
  2484  	m := testModule(t, "plan-targeted-cross-module")
  2485  	p := testProvider("aws")
  2486  	p.DiffFn = testDiffFn
  2487  	ctx := testContext2(t, &ContextOpts{
  2488  		Module: m,
  2489  		Providers: map[string]ResourceProviderFactory{
  2490  			"aws": testProviderFuncFixed(p),
  2491  		},
  2492  		Targets: []string{"module.B"},
  2493  	})
  2494  
  2495  	plan, err := ctx.Plan()
  2496  	if err != nil {
  2497  		t.Fatalf("err: %s", err)
  2498  	}
  2499  
  2500  	actual := strings.TrimSpace(plan.String())
  2501  	expected := strings.TrimSpace(`
  2502  DIFF:
  2503  
  2504  module.A:
  2505    CREATE: aws_instance.foo
  2506      foo:  "" => "bar"
  2507      type: "" => "aws_instance"
  2508  module.B:
  2509    CREATE: aws_instance.bar
  2510      foo:  "" => "<computed>"
  2511      type: "" => "aws_instance"
  2512  
  2513  STATE:
  2514  
  2515  <no state>
  2516  	`)
  2517  	if actual != expected {
  2518  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2519  	}
  2520  }
  2521  
  2522  func TestContext2Plan_targetedOrphan(t *testing.T) {
  2523  	m := testModule(t, "plan-targeted-orphan")
  2524  	p := testProvider("aws")
  2525  	p.DiffFn = testDiffFn
  2526  	ctx := testContext2(t, &ContextOpts{
  2527  		Module: m,
  2528  		Providers: map[string]ResourceProviderFactory{
  2529  			"aws": testProviderFuncFixed(p),
  2530  		},
  2531  		State: &State{
  2532  			Modules: []*ModuleState{
  2533  				&ModuleState{
  2534  					Path: rootModulePath,
  2535  					Resources: map[string]*ResourceState{
  2536  						"aws_instance.orphan": &ResourceState{
  2537  							Type: "aws_instance",
  2538  							Primary: &InstanceState{
  2539  								ID: "i-789xyz",
  2540  							},
  2541  						},
  2542  						"aws_instance.nottargeted": &ResourceState{
  2543  							Type: "aws_instance",
  2544  							Primary: &InstanceState{
  2545  								ID: "i-abc123",
  2546  							},
  2547  						},
  2548  					},
  2549  				},
  2550  			},
  2551  		},
  2552  		Destroy: true,
  2553  		Targets: []string{"aws_instance.orphan"},
  2554  	})
  2555  
  2556  	plan, err := ctx.Plan()
  2557  	if err != nil {
  2558  		t.Fatalf("err: %s", err)
  2559  	}
  2560  
  2561  	actual := strings.TrimSpace(plan.String())
  2562  	expected := strings.TrimSpace(`DIFF:
  2563  
  2564  DESTROY: aws_instance.orphan
  2565  
  2566  STATE:
  2567  
  2568  aws_instance.nottargeted:
  2569    ID = i-abc123
  2570  aws_instance.orphan:
  2571    ID = i-789xyz
  2572  `)
  2573  	if actual != expected {
  2574  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2575  	}
  2576  }
  2577  
  2578  // https://github.com/hashicorp/terraform/issues/2538
  2579  func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
  2580  	m := testModule(t, "plan-targeted-module-orphan")
  2581  	p := testProvider("aws")
  2582  	p.DiffFn = testDiffFn
  2583  	ctx := testContext2(t, &ContextOpts{
  2584  		Module: m,
  2585  		Providers: map[string]ResourceProviderFactory{
  2586  			"aws": testProviderFuncFixed(p),
  2587  		},
  2588  		State: &State{
  2589  			Modules: []*ModuleState{
  2590  				&ModuleState{
  2591  					Path: []string{"root", "child"},
  2592  					Resources: map[string]*ResourceState{
  2593  						"aws_instance.orphan": &ResourceState{
  2594  							Type: "aws_instance",
  2595  							Primary: &InstanceState{
  2596  								ID: "i-789xyz",
  2597  							},
  2598  						},
  2599  						"aws_instance.nottargeted": &ResourceState{
  2600  							Type: "aws_instance",
  2601  							Primary: &InstanceState{
  2602  								ID: "i-abc123",
  2603  							},
  2604  						},
  2605  					},
  2606  				},
  2607  			},
  2608  		},
  2609  		Destroy: true,
  2610  		Targets: []string{"module.child.aws_instance.orphan"},
  2611  	})
  2612  
  2613  	plan, err := ctx.Plan()
  2614  	if err != nil {
  2615  		t.Fatalf("err: %s", err)
  2616  	}
  2617  
  2618  	actual := strings.TrimSpace(plan.String())
  2619  	expected := strings.TrimSpace(`DIFF:
  2620  
  2621  module.child:
  2622    DESTROY: aws_instance.orphan
  2623  
  2624  STATE:
  2625  
  2626  module.child:
  2627    aws_instance.nottargeted:
  2628      ID = i-abc123
  2629    aws_instance.orphan:
  2630      ID = i-789xyz
  2631  `)
  2632  	if actual != expected {
  2633  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2634  	}
  2635  }
  2636  
  2637  func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
  2638  	m := testModule(t, "plan-targeted-module-untargeted-variable")
  2639  	p := testProvider("aws")
  2640  	p.DiffFn = testDiffFn
  2641  	ctx := testContext2(t, &ContextOpts{
  2642  		Module: m,
  2643  		Providers: map[string]ResourceProviderFactory{
  2644  			"aws": testProviderFuncFixed(p),
  2645  		},
  2646  		Targets: []string{"aws_instance.blue", "module.blue_mod"},
  2647  	})
  2648  
  2649  	plan, err := ctx.Plan()
  2650  	if err != nil {
  2651  		t.Fatalf("err: %s", err)
  2652  	}
  2653  
  2654  	actual := strings.TrimSpace(plan.String())
  2655  	expected := strings.TrimSpace(`
  2656  DIFF:
  2657  
  2658  CREATE: aws_instance.blue
  2659  
  2660  module.blue_mod:
  2661    CREATE: aws_instance.mod
  2662      type:  "" => "aws_instance"
  2663      value: "" => "<computed>"
  2664  
  2665  STATE:
  2666  
  2667  <no state>
  2668  `)
  2669  	if actual != expected {
  2670  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2671  	}
  2672  }
  2673  
  2674  // https://github.com/hashicorp/terraform/issues/4515
  2675  func TestContext2Plan_targetedOverTen(t *testing.T) {
  2676  	m := testModule(t, "plan-targeted-over-ten")
  2677  	p := testProvider("aws")
  2678  	p.DiffFn = testDiffFn
  2679  
  2680  	resources := make(map[string]*ResourceState)
  2681  	var expectedState []string
  2682  	for i := 0; i < 13; i++ {
  2683  		key := fmt.Sprintf("aws_instance.foo.%d", i)
  2684  		id := fmt.Sprintf("i-abc%d", i)
  2685  		resources[key] = &ResourceState{
  2686  			Type:    "aws_instance",
  2687  			Primary: &InstanceState{ID: id},
  2688  		}
  2689  		expectedState = append(expectedState,
  2690  			fmt.Sprintf("%s:\n  ID = %s\n", key, id))
  2691  	}
  2692  	ctx := testContext2(t, &ContextOpts{
  2693  		Module: m,
  2694  		Providers: map[string]ResourceProviderFactory{
  2695  			"aws": testProviderFuncFixed(p),
  2696  		},
  2697  		State: &State{
  2698  			Modules: []*ModuleState{
  2699  				&ModuleState{
  2700  					Path:      rootModulePath,
  2701  					Resources: resources,
  2702  				},
  2703  			},
  2704  		},
  2705  		Targets: []string{"aws_instance.foo[1]"},
  2706  	})
  2707  
  2708  	plan, err := ctx.Plan()
  2709  	if err != nil {
  2710  		t.Fatalf("err: %s", err)
  2711  	}
  2712  
  2713  	actual := strings.TrimSpace(plan.String())
  2714  	sort.Strings(expectedState)
  2715  	expected := strings.TrimSpace(`
  2716  DIFF:
  2717  
  2718  
  2719  
  2720  STATE:
  2721  
  2722  aws_instance.foo.0:
  2723    ID = i-abc0
  2724  aws_instance.foo.1:
  2725    ID = i-abc1
  2726  aws_instance.foo.10:
  2727    ID = i-abc10
  2728  aws_instance.foo.11:
  2729    ID = i-abc11
  2730  aws_instance.foo.12:
  2731    ID = i-abc12
  2732  aws_instance.foo.2:
  2733    ID = i-abc2
  2734  aws_instance.foo.3:
  2735    ID = i-abc3
  2736  aws_instance.foo.4:
  2737    ID = i-abc4
  2738  aws_instance.foo.5:
  2739    ID = i-abc5
  2740  aws_instance.foo.6:
  2741    ID = i-abc6
  2742  aws_instance.foo.7:
  2743    ID = i-abc7
  2744  aws_instance.foo.8:
  2745    ID = i-abc8
  2746  aws_instance.foo.9:
  2747    ID = i-abc9
  2748  	`)
  2749  	if actual != expected {
  2750  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2751  	}
  2752  }
  2753  
  2754  func TestContext2Plan_provider(t *testing.T) {
  2755  	m := testModule(t, "plan-provider")
  2756  	p := testProvider("aws")
  2757  	p.DiffFn = testDiffFn
  2758  
  2759  	var value interface{}
  2760  	p.ConfigureFn = func(c *ResourceConfig) error {
  2761  		value, _ = c.Get("foo")
  2762  		return nil
  2763  	}
  2764  
  2765  	ctx := testContext2(t, &ContextOpts{
  2766  		Module: m,
  2767  		Providers: map[string]ResourceProviderFactory{
  2768  			"aws": testProviderFuncFixed(p),
  2769  		},
  2770  		Variables: map[string]interface{}{
  2771  			"foo": "bar",
  2772  		},
  2773  	})
  2774  
  2775  	if _, err := ctx.Plan(); err != nil {
  2776  		t.Fatalf("err: %s", err)
  2777  	}
  2778  
  2779  	if value != "bar" {
  2780  		t.Fatalf("bad: %#v", value)
  2781  	}
  2782  }
  2783  
  2784  func TestContext2Plan_varListErr(t *testing.T) {
  2785  	m := testModule(t, "plan-var-list-err")
  2786  	p := testProvider("aws")
  2787  	ctx := testContext2(t, &ContextOpts{
  2788  		Module: m,
  2789  		Providers: map[string]ResourceProviderFactory{
  2790  			"aws": testProviderFuncFixed(p),
  2791  		},
  2792  	})
  2793  
  2794  	_, err := ctx.Plan()
  2795  
  2796  	if err == nil {
  2797  		t.Fatal("should error")
  2798  	}
  2799  }
  2800  
  2801  func TestContext2Plan_ignoreChanges(t *testing.T) {
  2802  	m := testModule(t, "plan-ignore-changes")
  2803  	p := testProvider("aws")
  2804  	p.DiffFn = testDiffFn
  2805  	s := &State{
  2806  		Modules: []*ModuleState{
  2807  			&ModuleState{
  2808  				Path: rootModulePath,
  2809  				Resources: map[string]*ResourceState{
  2810  					"aws_instance.foo": &ResourceState{
  2811  						Primary: &InstanceState{
  2812  							ID:         "bar",
  2813  							Attributes: map[string]string{"ami": "ami-abcd1234"},
  2814  						},
  2815  					},
  2816  				},
  2817  			},
  2818  		},
  2819  	}
  2820  	ctx := testContext2(t, &ContextOpts{
  2821  		Module: m,
  2822  		Providers: map[string]ResourceProviderFactory{
  2823  			"aws": testProviderFuncFixed(p),
  2824  		},
  2825  		Variables: map[string]interface{}{
  2826  			"foo": "ami-1234abcd",
  2827  		},
  2828  		State: s,
  2829  	})
  2830  
  2831  	plan, err := ctx.Plan()
  2832  	if err != nil {
  2833  		t.Fatalf("err: %s", err)
  2834  	}
  2835  
  2836  	if len(plan.Diff.RootModule().Resources) < 1 {
  2837  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2838  	}
  2839  
  2840  	actual := strings.TrimSpace(plan.String())
  2841  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr)
  2842  	if actual != expected {
  2843  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2844  	}
  2845  }
  2846  
  2847  func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
  2848  	m := testModule(t, "plan-ignore-changes-wildcard")
  2849  	p := testProvider("aws")
  2850  	p.DiffFn = testDiffFn
  2851  	s := &State{
  2852  		Modules: []*ModuleState{
  2853  			&ModuleState{
  2854  				Path: rootModulePath,
  2855  				Resources: map[string]*ResourceState{
  2856  					"aws_instance.foo": &ResourceState{
  2857  						Primary: &InstanceState{
  2858  							ID: "bar",
  2859  							Attributes: map[string]string{
  2860  								"ami":           "ami-abcd1234",
  2861  								"instance_type": "t2.micro",
  2862  							},
  2863  						},
  2864  					},
  2865  				},
  2866  			},
  2867  		},
  2868  	}
  2869  	ctx := testContext2(t, &ContextOpts{
  2870  		Module: m,
  2871  		Providers: map[string]ResourceProviderFactory{
  2872  			"aws": testProviderFuncFixed(p),
  2873  		},
  2874  		Variables: map[string]interface{}{
  2875  			"foo": "ami-1234abcd",
  2876  			"bar": "t2.small",
  2877  		},
  2878  		State: s,
  2879  	})
  2880  
  2881  	plan, err := ctx.Plan()
  2882  	if err != nil {
  2883  		t.Fatalf("err: %s", err)
  2884  	}
  2885  
  2886  	if len(plan.Diff.RootModule().Resources) > 0 {
  2887  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2888  	}
  2889  
  2890  	actual := strings.TrimSpace(plan.String())
  2891  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr)
  2892  	if actual != expected {
  2893  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2894  	}
  2895  }
  2896  
  2897  func TestContext2Plan_moduleMapLiteral(t *testing.T) {
  2898  	m := testModule(t, "plan-module-map-literal")
  2899  	p := testProvider("aws")
  2900  	p.ApplyFn = testApplyFn
  2901  	p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  2902  		// Here we verify that both the populated and empty map literals made it
  2903  		// through to the resource attributes
  2904  		val, _ := c.Get("tags")
  2905  		m, ok := val.(map[string]interface{})
  2906  		if !ok {
  2907  			t.Fatalf("Tags attr not map: %#v", val)
  2908  		}
  2909  		if m["foo"] != "bar" {
  2910  			t.Fatalf("Bad value in tags attr: %#v", m)
  2911  		}
  2912  		{
  2913  			val, _ := c.Get("meta")
  2914  			m, ok := val.(map[string]interface{})
  2915  			if !ok {
  2916  				t.Fatalf("Meta attr not map: %#v", val)
  2917  			}
  2918  			if len(m) != 0 {
  2919  				t.Fatalf("Meta attr not empty: %#v", val)
  2920  			}
  2921  		}
  2922  		return nil, nil
  2923  	}
  2924  	ctx := testContext2(t, &ContextOpts{
  2925  		Module: m,
  2926  		Providers: map[string]ResourceProviderFactory{
  2927  			"aws": testProviderFuncFixed(p),
  2928  		},
  2929  	})
  2930  
  2931  	if _, err := ctx.Plan(); err != nil {
  2932  		t.Fatalf("err: %s", err)
  2933  	}
  2934  }
  2935  
  2936  func TestContext2Plan_computedValueInMap(t *testing.T) {
  2937  	m := testModule(t, "plan-computed-value-in-map")
  2938  	p := testProvider("aws")
  2939  	p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  2940  		switch info.Type {
  2941  		case "aws_computed_source":
  2942  			return &InstanceDiff{
  2943  				Attributes: map[string]*ResourceAttrDiff{
  2944  					"computed_read_only": &ResourceAttrDiff{
  2945  						NewComputed: true,
  2946  					},
  2947  				},
  2948  			}, nil
  2949  		}
  2950  
  2951  		return testDiffFn(info, state, c)
  2952  	}
  2953  	ctx := testContext2(t, &ContextOpts{
  2954  		Module: m,
  2955  		Providers: map[string]ResourceProviderFactory{
  2956  			"aws": testProviderFuncFixed(p),
  2957  		},
  2958  	})
  2959  
  2960  	if _, err := ctx.Plan(); err != nil {
  2961  		t.Fatalf("err: %s", err)
  2962  	}
  2963  
  2964  	plan, err := ctx.Plan()
  2965  	if err != nil {
  2966  		t.Fatalf("err: %s", err)
  2967  	}
  2968  
  2969  	actual := strings.TrimSpace(plan.String())
  2970  	expected := strings.TrimSpace(testTerraformPlanComputedValueInMap)
  2971  	if actual != expected {
  2972  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2973  	}
  2974  }
  2975  
  2976  func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
  2977  	m := testModule(t, "plan-module-variable-from-splat")
  2978  	p := testProvider("aws")
  2979  	p.DiffFn = testDiffFn
  2980  	ctx := testContext2(t, &ContextOpts{
  2981  		Module: m,
  2982  		Providers: map[string]ResourceProviderFactory{
  2983  			"aws": testProviderFuncFixed(p),
  2984  		},
  2985  	})
  2986  
  2987  	if _, err := ctx.Plan(); err != nil {
  2988  		t.Fatalf("err: %s", err)
  2989  	}
  2990  
  2991  	plan, err := ctx.Plan()
  2992  	if err != nil {
  2993  		t.Fatalf("err: %s", err)
  2994  	}
  2995  
  2996  	actual := strings.TrimSpace(plan.String())
  2997  	expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat)
  2998  	if actual != expected {
  2999  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3000  	}
  3001  }
  3002  
  3003  func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
  3004  	m := testModule(t, "plan-cdb-depends-datasource")
  3005  	p := testProvider("aws")
  3006  	p.DiffFn = testDiffFn
  3007  	ctx := testContext2(t, &ContextOpts{
  3008  		Module: m,
  3009  		Providers: map[string]ResourceProviderFactory{
  3010  			"aws": testProviderFuncFixed(p),
  3011  		},
  3012  	})
  3013  
  3014  	plan, err := ctx.Plan()
  3015  	if err != nil {
  3016  		t.Fatalf("err: %s", err)
  3017  	}
  3018  
  3019  	if got := len(plan.Diff.Modules); got != 1 {
  3020  		t.Fatalf("got %d modules; want 1", got)
  3021  	}
  3022  
  3023  	moduleDiff := plan.Diff.Modules[0]
  3024  
  3025  	if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok {
  3026  		t.Fatalf("missing diff for aws_instance.foo.0")
  3027  	}
  3028  	if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok {
  3029  		t.Fatalf("missing diff for aws_instance.foo.1")
  3030  	}
  3031  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok {
  3032  		t.Fatalf("missing diff for data.aws_vpc.bar.0")
  3033  	}
  3034  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok {
  3035  		t.Fatalf("missing diff for data.aws_vpc.bar.1")
  3036  	}
  3037  }
  3038  
  3039  // interpolated lists need to be stored in the original order.
  3040  func TestContext2Plan_listOrder(t *testing.T) {
  3041  	m := testModule(t, "plan-list-order")
  3042  	p := testProvider("aws")
  3043  	p.ApplyFn = testApplyFn
  3044  	p.DiffFn = testDiffFn
  3045  	ctx := testContext2(t, &ContextOpts{
  3046  		Module: m,
  3047  		Providers: map[string]ResourceProviderFactory{
  3048  			"aws": testProviderFuncFixed(p),
  3049  		},
  3050  	})
  3051  
  3052  	plan, err := ctx.Plan()
  3053  	if err != nil {
  3054  		t.Fatalf("err: %s", err)
  3055  	}
  3056  
  3057  	rDiffs := plan.Diff.Modules[0].Resources
  3058  	rDiffA := rDiffs["aws_instance.a"]
  3059  	rDiffB := rDiffs["aws_instance.b"]
  3060  
  3061  	if !rDiffA.Equal(rDiffB) {
  3062  		t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan)
  3063  	}
  3064  }