github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/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  
   536  					l.Lock()
   537  					defer l.Unlock()
   538  					calls = append(calls, v.(string))
   539  					return testDiffFn(info, state, c)
   540  				}
   541  				return p, nil
   542  			},
   543  		},
   544  	})
   545  
   546  	_, err := ctx.Plan()
   547  	if err != nil {
   548  		t.Fatalf("err: %s", err)
   549  	}
   550  
   551  	actual := calls
   552  	sort.Strings(actual)
   553  	expected := []string{"child", "root"}
   554  	if !reflect.DeepEqual(actual, expected) {
   555  		t.Fatalf("bad: %#v", actual)
   556  	}
   557  }
   558  
   559  // This tests (for GH-11282) that deeply nested modules properly inherit
   560  // configuration.
   561  func TestContext2Plan_moduleProviderInheritDeep(t *testing.T) {
   562  	var l sync.Mutex
   563  
   564  	m := testModule(t, "plan-module-provider-inherit-deep")
   565  	ctx := testContext2(t, &ContextOpts{
   566  		Module: m,
   567  		Providers: map[string]ResourceProviderFactory{
   568  			"aws": func() (ResourceProvider, error) {
   569  				l.Lock()
   570  				defer l.Unlock()
   571  
   572  				var from string
   573  				p := testProvider("aws")
   574  				p.ConfigureFn = func(c *ResourceConfig) error {
   575  					v, ok := c.Get("from")
   576  					if !ok || v.(string) != "root" {
   577  						return fmt.Errorf("bad")
   578  					}
   579  
   580  					from = v.(string)
   581  					return nil
   582  				}
   583  
   584  				p.DiffFn = func(
   585  					info *InstanceInfo,
   586  					state *InstanceState,
   587  					c *ResourceConfig) (*InstanceDiff, error) {
   588  					if from != "root" {
   589  						return nil, fmt.Errorf("bad resource")
   590  					}
   591  
   592  					return testDiffFn(info, state, c)
   593  				}
   594  				return p, nil
   595  			},
   596  		},
   597  	})
   598  
   599  	_, err := ctx.Plan()
   600  	if err != nil {
   601  		t.Fatalf("err: %s", err)
   602  	}
   603  }
   604  
   605  func TestContext2Plan_moduleProviderDefaults(t *testing.T) {
   606  	var l sync.Mutex
   607  	var calls []string
   608  	toCount := 0
   609  
   610  	m := testModule(t, "plan-module-provider-defaults")
   611  	ctx := testContext2(t, &ContextOpts{
   612  		Module: m,
   613  		Providers: map[string]ResourceProviderFactory{
   614  			"aws": func() (ResourceProvider, error) {
   615  				l.Lock()
   616  				defer l.Unlock()
   617  
   618  				p := testProvider("aws")
   619  				p.ConfigureFn = func(c *ResourceConfig) error {
   620  					if v, ok := c.Get("from"); !ok || v.(string) != "root" {
   621  						return fmt.Errorf("bad")
   622  					}
   623  					if v, ok := c.Get("to"); ok && v.(string) == "child" {
   624  						toCount++
   625  					}
   626  
   627  					return nil
   628  				}
   629  				p.DiffFn = func(
   630  					info *InstanceInfo,
   631  					state *InstanceState,
   632  					c *ResourceConfig) (*InstanceDiff, error) {
   633  					v, _ := c.Get("from")
   634  
   635  					l.Lock()
   636  					defer l.Unlock()
   637  					calls = append(calls, v.(string))
   638  					return testDiffFn(info, state, c)
   639  				}
   640  				return p, nil
   641  			},
   642  		},
   643  	})
   644  
   645  	_, err := ctx.Plan()
   646  	if err != nil {
   647  		t.Fatalf("err: %s", err)
   648  	}
   649  
   650  	if toCount != 1 {
   651  		t.Fatalf(
   652  			"provider in child didn't set proper config\n\n"+
   653  				"toCount: %d", toCount)
   654  	}
   655  
   656  	actual := calls
   657  	sort.Strings(actual)
   658  	expected := []string{"child", "root"}
   659  	if !reflect.DeepEqual(actual, expected) {
   660  		t.Fatalf("bad: %#v", actual)
   661  	}
   662  }
   663  
   664  func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
   665  	var l sync.Mutex
   666  	var calls []string
   667  
   668  	m := testModule(t, "plan-module-provider-defaults-var")
   669  	ctx := testContext2(t, &ContextOpts{
   670  		Module: m,
   671  		Providers: map[string]ResourceProviderFactory{
   672  			"aws": func() (ResourceProvider, error) {
   673  				l.Lock()
   674  				defer l.Unlock()
   675  
   676  				p := testProvider("aws")
   677  				p.ConfigureFn = func(c *ResourceConfig) error {
   678  					var buf bytes.Buffer
   679  					if v, ok := c.Get("from"); ok {
   680  						buf.WriteString(v.(string) + "\n")
   681  					}
   682  					if v, ok := c.Get("to"); ok {
   683  						buf.WriteString(v.(string) + "\n")
   684  					}
   685  
   686  					l.Lock()
   687  					defer l.Unlock()
   688  					calls = append(calls, buf.String())
   689  					return nil
   690  				}
   691  				p.DiffFn = testDiffFn
   692  				return p, nil
   693  			},
   694  		},
   695  		Variables: map[string]interface{}{
   696  			"foo": "root",
   697  		},
   698  	})
   699  
   700  	_, err := ctx.Plan()
   701  	if err != nil {
   702  		t.Fatalf("err: %s", err)
   703  	}
   704  
   705  	expected := []string{
   706  		"root\n",
   707  		"root\nchild\n",
   708  	}
   709  	if !reflect.DeepEqual(calls, expected) {
   710  		t.Fatalf("BAD: %#v", calls)
   711  	}
   712  }
   713  
   714  func TestContext2Plan_moduleProviderVar(t *testing.T) {
   715  	m := testModule(t, "plan-module-provider-var")
   716  	p := testProvider("aws")
   717  	p.DiffFn = testDiffFn
   718  	ctx := testContext2(t, &ContextOpts{
   719  		Module: m,
   720  		Providers: map[string]ResourceProviderFactory{
   721  			"aws": testProviderFuncFixed(p),
   722  		},
   723  	})
   724  
   725  	plan, err := ctx.Plan()
   726  	if err != nil {
   727  		t.Fatalf("err: %s", err)
   728  	}
   729  
   730  	actual := strings.TrimSpace(plan.String())
   731  	expected := strings.TrimSpace(testTerraformPlanModuleProviderVarStr)
   732  	if actual != expected {
   733  		t.Fatalf("bad:\n%s", actual)
   734  	}
   735  }
   736  
   737  func TestContext2Plan_moduleVar(t *testing.T) {
   738  	m := testModule(t, "plan-module-var")
   739  	p := testProvider("aws")
   740  	p.DiffFn = testDiffFn
   741  	ctx := testContext2(t, &ContextOpts{
   742  		Module: m,
   743  		Providers: map[string]ResourceProviderFactory{
   744  			"aws": testProviderFuncFixed(p),
   745  		},
   746  	})
   747  
   748  	plan, err := ctx.Plan()
   749  	if err != nil {
   750  		t.Fatalf("err: %s", err)
   751  	}
   752  
   753  	actual := strings.TrimSpace(plan.String())
   754  	expected := strings.TrimSpace(testTerraformPlanModuleVarStr)
   755  	if actual != expected {
   756  		t.Fatalf("bad:\n%s", actual)
   757  	}
   758  }
   759  
   760  func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) {
   761  	m := testModule(t, "plan-module-wrong-var-type")
   762  	p := testProvider("aws")
   763  	p.DiffFn = testDiffFn
   764  	ctx := testContext2(t, &ContextOpts{
   765  		Module: m,
   766  		Providers: map[string]ResourceProviderFactory{
   767  			"aws": testProviderFuncFixed(p),
   768  		},
   769  	})
   770  
   771  	_, err := ctx.Plan()
   772  	if err == nil {
   773  		t.Fatalf("should error")
   774  	}
   775  }
   776  
   777  func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) {
   778  	m := testModule(t, "plan-module-wrong-var-type-nested")
   779  	p := testProvider("aws")
   780  	p.DiffFn = testDiffFn
   781  	ctx := testContext2(t, &ContextOpts{
   782  		Module: m,
   783  		Providers: map[string]ResourceProviderFactory{
   784  			"aws": testProviderFuncFixed(p),
   785  		},
   786  	})
   787  
   788  	_, err := ctx.Plan()
   789  	if err == nil {
   790  		t.Fatalf("should error")
   791  	}
   792  }
   793  
   794  func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) {
   795  	m := testModule(t, "plan-module-var-with-default-value")
   796  	p := testProvider("null")
   797  	p.DiffFn = testDiffFn
   798  	ctx := testContext2(t, &ContextOpts{
   799  		Module: m,
   800  		Providers: map[string]ResourceProviderFactory{
   801  			"null": testProviderFuncFixed(p),
   802  		},
   803  	})
   804  
   805  	_, err := ctx.Plan()
   806  	if err != nil {
   807  		t.Fatalf("bad: %s", err)
   808  	}
   809  }
   810  
   811  func TestContext2Plan_moduleVarComputed(t *testing.T) {
   812  	m := testModule(t, "plan-module-var-computed")
   813  	p := testProvider("aws")
   814  	p.DiffFn = testDiffFn
   815  	ctx := testContext2(t, &ContextOpts{
   816  		Module: m,
   817  		Providers: map[string]ResourceProviderFactory{
   818  			"aws": testProviderFuncFixed(p),
   819  		},
   820  	})
   821  
   822  	plan, err := ctx.Plan()
   823  	if err != nil {
   824  		t.Fatalf("err: %s", err)
   825  	}
   826  
   827  	actual := strings.TrimSpace(plan.String())
   828  	expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr)
   829  	if actual != expected {
   830  		t.Fatalf("bad:\n%s", actual)
   831  	}
   832  }
   833  
   834  func TestContext2Plan_nil(t *testing.T) {
   835  	m := testModule(t, "plan-nil")
   836  	p := testProvider("aws")
   837  	p.DiffFn = testDiffFn
   838  	ctx := testContext2(t, &ContextOpts{
   839  		Module: m,
   840  		Providers: map[string]ResourceProviderFactory{
   841  			"aws": testProviderFuncFixed(p),
   842  		},
   843  		State: &State{
   844  			Modules: []*ModuleState{
   845  				&ModuleState{
   846  					Path: rootModulePath,
   847  					Resources: map[string]*ResourceState{
   848  						"aws_instance.foo": &ResourceState{
   849  							Type: "aws_instance",
   850  							Primary: &InstanceState{
   851  								ID: "bar",
   852  							},
   853  						},
   854  					},
   855  				},
   856  			},
   857  		},
   858  	})
   859  
   860  	plan, err := ctx.Plan()
   861  	if err != nil {
   862  		t.Fatalf("err: %s", err)
   863  	}
   864  	if len(plan.Diff.RootModule().Resources) != 0 {
   865  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
   866  	}
   867  }
   868  
   869  func TestContext2Plan_preventDestroy_bad(t *testing.T) {
   870  	m := testModule(t, "plan-prevent-destroy-bad")
   871  	p := testProvider("aws")
   872  	p.DiffFn = testDiffFn
   873  	ctx := testContext2(t, &ContextOpts{
   874  		Module: m,
   875  		Providers: map[string]ResourceProviderFactory{
   876  			"aws": testProviderFuncFixed(p),
   877  		},
   878  		State: &State{
   879  			Modules: []*ModuleState{
   880  				&ModuleState{
   881  					Path: rootModulePath,
   882  					Resources: map[string]*ResourceState{
   883  						"aws_instance.foo": &ResourceState{
   884  							Type: "aws_instance",
   885  							Primary: &InstanceState{
   886  								ID: "i-abc123",
   887  							},
   888  						},
   889  					},
   890  				},
   891  			},
   892  		},
   893  	})
   894  
   895  	plan, err := ctx.Plan()
   896  
   897  	expectedErr := "aws_instance.foo: the plan would destroy"
   898  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
   899  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
   900  			expectedErr, err, plan)
   901  	}
   902  }
   903  
   904  func TestContext2Plan_preventDestroy_good(t *testing.T) {
   905  	m := testModule(t, "plan-prevent-destroy-good")
   906  	p := testProvider("aws")
   907  	p.DiffFn = testDiffFn
   908  	ctx := testContext2(t, &ContextOpts{
   909  		Module: m,
   910  		Providers: map[string]ResourceProviderFactory{
   911  			"aws": testProviderFuncFixed(p),
   912  		},
   913  		State: &State{
   914  			Modules: []*ModuleState{
   915  				&ModuleState{
   916  					Path: rootModulePath,
   917  					Resources: map[string]*ResourceState{
   918  						"aws_instance.foo": &ResourceState{
   919  							Type: "aws_instance",
   920  							Primary: &InstanceState{
   921  								ID: "i-abc123",
   922  							},
   923  						},
   924  					},
   925  				},
   926  			},
   927  		},
   928  	})
   929  
   930  	plan, err := ctx.Plan()
   931  	if err != nil {
   932  		t.Fatalf("err: %s", err)
   933  	}
   934  	if !plan.Diff.Empty() {
   935  		t.Fatalf("Expected empty plan, got %s", plan.String())
   936  	}
   937  }
   938  
   939  func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
   940  	m := testModule(t, "plan-prevent-destroy-count-bad")
   941  	p := testProvider("aws")
   942  	p.DiffFn = testDiffFn
   943  	ctx := testContext2(t, &ContextOpts{
   944  		Module: m,
   945  		Providers: map[string]ResourceProviderFactory{
   946  			"aws": testProviderFuncFixed(p),
   947  		},
   948  		State: &State{
   949  			Modules: []*ModuleState{
   950  				&ModuleState{
   951  					Path: rootModulePath,
   952  					Resources: map[string]*ResourceState{
   953  						"aws_instance.foo.0": &ResourceState{
   954  							Type: "aws_instance",
   955  							Primary: &InstanceState{
   956  								ID: "i-abc123",
   957  							},
   958  						},
   959  						"aws_instance.foo.1": &ResourceState{
   960  							Type: "aws_instance",
   961  							Primary: &InstanceState{
   962  								ID: "i-abc345",
   963  							},
   964  						},
   965  					},
   966  				},
   967  			},
   968  		},
   969  	})
   970  
   971  	plan, err := ctx.Plan()
   972  
   973  	expectedErr := "aws_instance.foo.1: the plan would destroy"
   974  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
   975  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
   976  			expectedErr, err, plan)
   977  	}
   978  }
   979  
   980  func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
   981  	m := testModule(t, "plan-prevent-destroy-count-good")
   982  	p := testProvider("aws")
   983  	p.DiffFn = testDiffFn
   984  	ctx := testContext2(t, &ContextOpts{
   985  		Module: m,
   986  		Providers: map[string]ResourceProviderFactory{
   987  			"aws": testProviderFuncFixed(p),
   988  		},
   989  		State: &State{
   990  			Modules: []*ModuleState{
   991  				&ModuleState{
   992  					Path: rootModulePath,
   993  					Resources: map[string]*ResourceState{
   994  						"aws_instance.foo.0": &ResourceState{
   995  							Type: "aws_instance",
   996  							Primary: &InstanceState{
   997  								ID: "i-abc123",
   998  							},
   999  						},
  1000  						"aws_instance.foo.1": &ResourceState{
  1001  							Type: "aws_instance",
  1002  							Primary: &InstanceState{
  1003  								ID: "i-abc345",
  1004  							},
  1005  						},
  1006  					},
  1007  				},
  1008  			},
  1009  		},
  1010  	})
  1011  
  1012  	plan, err := ctx.Plan()
  1013  	if err != nil {
  1014  		t.Fatalf("err: %s", err)
  1015  	}
  1016  	if plan.Diff.Empty() {
  1017  		t.Fatalf("Expected non-empty plan, got %s", plan.String())
  1018  	}
  1019  }
  1020  
  1021  func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) {
  1022  	m := testModule(t, "plan-prevent-destroy-count-good")
  1023  	p := testProvider("aws")
  1024  	p.DiffFn = testDiffFn
  1025  	ctx := testContext2(t, &ContextOpts{
  1026  		Module: m,
  1027  		Providers: map[string]ResourceProviderFactory{
  1028  			"aws": testProviderFuncFixed(p),
  1029  		},
  1030  		State: &State{
  1031  			Modules: []*ModuleState{
  1032  				&ModuleState{
  1033  					Path: rootModulePath,
  1034  					Resources: map[string]*ResourceState{
  1035  						"aws_instance.foo.0": &ResourceState{
  1036  							Type: "aws_instance",
  1037  							Primary: &InstanceState{
  1038  								ID: "i-abc123",
  1039  								Attributes: map[string]string{
  1040  									"current": "0",
  1041  									"type":    "aws_instance",
  1042  								},
  1043  							},
  1044  						},
  1045  					},
  1046  				},
  1047  			},
  1048  		},
  1049  	})
  1050  
  1051  	plan, err := ctx.Plan()
  1052  	if err != nil {
  1053  		t.Fatalf("err: %s", err)
  1054  	}
  1055  	if !plan.Diff.Empty() {
  1056  		t.Fatalf("Expected empty plan, got %s", plan.String())
  1057  	}
  1058  }
  1059  
  1060  func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
  1061  	m := testModule(t, "plan-prevent-destroy-good")
  1062  	p := testProvider("aws")
  1063  	p.DiffFn = testDiffFn
  1064  	ctx := testContext2(t, &ContextOpts{
  1065  		Module: m,
  1066  		Providers: map[string]ResourceProviderFactory{
  1067  			"aws": testProviderFuncFixed(p),
  1068  		},
  1069  		State: &State{
  1070  			Modules: []*ModuleState{
  1071  				&ModuleState{
  1072  					Path: rootModulePath,
  1073  					Resources: map[string]*ResourceState{
  1074  						"aws_instance.foo": &ResourceState{
  1075  							Type: "aws_instance",
  1076  							Primary: &InstanceState{
  1077  								ID: "i-abc123",
  1078  							},
  1079  						},
  1080  					},
  1081  				},
  1082  			},
  1083  		},
  1084  		Destroy: true,
  1085  	})
  1086  
  1087  	plan, err := ctx.Plan()
  1088  
  1089  	expectedErr := "aws_instance.foo: the plan would destroy"
  1090  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  1091  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
  1092  			expectedErr, err, plan)
  1093  	}
  1094  }
  1095  
  1096  func TestContext2Plan_provisionerCycle(t *testing.T) {
  1097  	m := testModule(t, "plan-provisioner-cycle")
  1098  	p := testProvider("aws")
  1099  	p.DiffFn = testDiffFn
  1100  	pr := testProvisioner()
  1101  	ctx := testContext2(t, &ContextOpts{
  1102  		Module: m,
  1103  		Providers: map[string]ResourceProviderFactory{
  1104  			"aws": testProviderFuncFixed(p),
  1105  		},
  1106  		Provisioners: map[string]ResourceProvisionerFactory{
  1107  			"local-exec": testProvisionerFuncFixed(pr),
  1108  		},
  1109  	})
  1110  
  1111  	_, err := ctx.Plan()
  1112  	if err == nil {
  1113  		t.Fatalf("should error")
  1114  	}
  1115  }
  1116  
  1117  func TestContext2Plan_computed(t *testing.T) {
  1118  	m := testModule(t, "plan-computed")
  1119  	p := testProvider("aws")
  1120  	p.DiffFn = testDiffFn
  1121  	ctx := testContext2(t, &ContextOpts{
  1122  		Module: m,
  1123  		Providers: map[string]ResourceProviderFactory{
  1124  			"aws": testProviderFuncFixed(p),
  1125  		},
  1126  	})
  1127  
  1128  	plan, err := ctx.Plan()
  1129  	if err != nil {
  1130  		t.Fatalf("err: %s", err)
  1131  	}
  1132  
  1133  	actual := strings.TrimSpace(plan.String())
  1134  	expected := strings.TrimSpace(testTerraformPlanComputedStr)
  1135  	if actual != expected {
  1136  		t.Fatalf("bad:\n%s", actual)
  1137  	}
  1138  }
  1139  
  1140  func TestContext2Plan_computedDataResource(t *testing.T) {
  1141  	m := testModule(t, "plan-computed-data-resource")
  1142  	p := testProvider("aws")
  1143  	p.DiffFn = testDiffFn
  1144  	ctx := testContext2(t, &ContextOpts{
  1145  		Module: m,
  1146  		Providers: map[string]ResourceProviderFactory{
  1147  			"aws": testProviderFuncFixed(p),
  1148  		},
  1149  	})
  1150  
  1151  	plan, err := ctx.Plan()
  1152  	if err != nil {
  1153  		t.Fatalf("err: %s", err)
  1154  	}
  1155  
  1156  	if got := len(plan.Diff.Modules); got != 1 {
  1157  		t.Fatalf("got %d modules; want 1", got)
  1158  	}
  1159  
  1160  	moduleDiff := plan.Diff.Modules[0]
  1161  
  1162  	if _, ok := moduleDiff.Resources["aws_instance.foo"]; !ok {
  1163  		t.Fatalf("missing diff for aws_instance.foo")
  1164  	}
  1165  	iDiff, ok := moduleDiff.Resources["data.aws_vpc.bar"]
  1166  	if !ok {
  1167  		t.Fatalf("missing diff for data.aws_vpc.bar")
  1168  	}
  1169  
  1170  	expectedDiff := &InstanceDiff{
  1171  		Attributes: map[string]*ResourceAttrDiff{
  1172  			"id": {
  1173  				NewComputed: true,
  1174  				RequiresNew: true,
  1175  				Type:        DiffAttrOutput,
  1176  			},
  1177  		},
  1178  	}
  1179  	if same, _ := expectedDiff.Same(iDiff); !same {
  1180  		t.Fatalf(
  1181  			"incorrect diff for data.aws_vpc.bar\ngot:  %#v\nwant: %#v",
  1182  			iDiff, expectedDiff,
  1183  		)
  1184  	}
  1185  }
  1186  
  1187  func TestContext2Plan_computedDataCountResource(t *testing.T) {
  1188  	m := testModule(t, "plan-computed-data-count")
  1189  	p := testProvider("aws")
  1190  	p.DiffFn = testDiffFn
  1191  	ctx := testContext2(t, &ContextOpts{
  1192  		Module: m,
  1193  		Providers: map[string]ResourceProviderFactory{
  1194  			"aws": testProviderFuncFixed(p),
  1195  		},
  1196  	})
  1197  
  1198  	plan, err := ctx.Plan()
  1199  	if err != nil {
  1200  		t.Fatalf("err: %s", err)
  1201  	}
  1202  
  1203  	if got := len(plan.Diff.Modules); got != 1 {
  1204  		t.Fatalf("got %d modules; want 1", got)
  1205  	}
  1206  
  1207  	moduleDiff := plan.Diff.Modules[0]
  1208  
  1209  	// make sure we created 3 "bar"s
  1210  	for i := 0; i < 3; i++ {
  1211  		resource := fmt.Sprintf("data.aws_vpc.bar.%d", i)
  1212  		if _, ok := moduleDiff.Resources[resource]; !ok {
  1213  			t.Fatalf("missing diff for %s", resource)
  1214  		}
  1215  	}
  1216  }
  1217  
  1218  // Higher level test at TestResource_dataSourceListPlanPanic
  1219  func TestContext2Plan_dataSourceTypeMismatch(t *testing.T) {
  1220  	m := testModule(t, "plan-data-source-type-mismatch")
  1221  	p := testProvider("aws")
  1222  	p.ValidateResourceFn = func(t string, c *ResourceConfig) (ws []string, es []error) {
  1223  		// Emulate the type checking behavior of helper/schema based validation
  1224  		if t == "aws_instance" {
  1225  			ami, _ := c.Get("ami")
  1226  			switch a := ami.(type) {
  1227  			case string:
  1228  				// ok
  1229  			default:
  1230  				es = append(es, fmt.Errorf("Expected ami to be string, got %T", a))
  1231  			}
  1232  		}
  1233  		return
  1234  	}
  1235  	p.DiffFn = func(
  1236  		info *InstanceInfo,
  1237  		state *InstanceState,
  1238  		c *ResourceConfig) (*InstanceDiff, error) {
  1239  		if info.Type == "aws_instance" {
  1240  			// If we get to the diff, we should be able to assume types
  1241  			ami, _ := c.Get("ami")
  1242  			_ = ami.(string)
  1243  		}
  1244  		return nil, nil
  1245  	}
  1246  	ctx := testContext2(t, &ContextOpts{
  1247  		Module: m,
  1248  		// Pretend like we ran a Refresh and the AZs data source was populated.
  1249  		State: &State{
  1250  			Modules: []*ModuleState{
  1251  				&ModuleState{
  1252  					Path: rootModulePath,
  1253  					Resources: map[string]*ResourceState{
  1254  						"data.aws_availability_zones.azs": &ResourceState{
  1255  							Type: "aws_availability_zones",
  1256  							Primary: &InstanceState{
  1257  								ID: "i-abc123",
  1258  								Attributes: map[string]string{
  1259  									"names.#": "2",
  1260  									"names.0": "us-east-1a",
  1261  									"names.1": "us-east-1b",
  1262  								},
  1263  							},
  1264  						},
  1265  					},
  1266  				},
  1267  			},
  1268  		},
  1269  		Providers: map[string]ResourceProviderFactory{
  1270  			"aws": testProviderFuncFixed(p),
  1271  		},
  1272  	})
  1273  
  1274  	_, err := ctx.Plan()
  1275  
  1276  	if err == nil {
  1277  		t.Fatalf("Expected err, got none!")
  1278  	}
  1279  	expected := "Expected ami to be string"
  1280  	if !strings.Contains(err.Error(), expected) {
  1281  		t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", err, expected)
  1282  	}
  1283  }
  1284  
  1285  func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
  1286  	m := testModule(t, "plan-data-resource-becomes-computed")
  1287  	p := testProvider("aws")
  1288  
  1289  	p.DiffFn = func(info *InstanceInfo, state *InstanceState, config *ResourceConfig) (*InstanceDiff, error) {
  1290  		if info.Type != "aws_instance" {
  1291  			t.Fatalf("don't know how to diff %s", info.Id)
  1292  			return nil, nil
  1293  		}
  1294  
  1295  		return &InstanceDiff{
  1296  			Attributes: map[string]*ResourceAttrDiff{
  1297  				"computed": &ResourceAttrDiff{
  1298  					Old:         "",
  1299  					New:         "",
  1300  					NewComputed: true,
  1301  				},
  1302  			},
  1303  		}, nil
  1304  	}
  1305  	p.ReadDataDiffReturn = &InstanceDiff{
  1306  		Attributes: map[string]*ResourceAttrDiff{
  1307  			"foo": &ResourceAttrDiff{
  1308  				Old:         "",
  1309  				New:         "",
  1310  				NewComputed: true,
  1311  			},
  1312  		},
  1313  	}
  1314  
  1315  	ctx := testContext2(t, &ContextOpts{
  1316  		Module: m,
  1317  		Providers: map[string]ResourceProviderFactory{
  1318  			"aws": testProviderFuncFixed(p),
  1319  		},
  1320  		State: &State{
  1321  			Modules: []*ModuleState{
  1322  				&ModuleState{
  1323  					Path: rootModulePath,
  1324  					Resources: map[string]*ResourceState{
  1325  						"data.aws_data_resource.foo": &ResourceState{
  1326  							Type: "aws_data_resource",
  1327  							Primary: &InstanceState{
  1328  								ID: "i-abc123",
  1329  								Attributes: map[string]string{
  1330  									"id":    "i-abc123",
  1331  									"value": "baz",
  1332  								},
  1333  							},
  1334  						},
  1335  					},
  1336  				},
  1337  			},
  1338  		},
  1339  	})
  1340  
  1341  	plan, err := ctx.Plan()
  1342  	if err != nil {
  1343  		t.Fatalf("err: %s", err)
  1344  	}
  1345  
  1346  	if got := len(plan.Diff.Modules); got != 1 {
  1347  		t.Fatalf("got %d modules; want 1", got)
  1348  	}
  1349  
  1350  	if !p.ReadDataDiffCalled {
  1351  		t.Fatal("ReadDataDiff wasn't called, but should've been")
  1352  	}
  1353  	if got, want := p.ReadDataDiffInfo.Id, "data.aws_data_resource.foo"; got != want {
  1354  		t.Fatalf("ReadDataDiff info id is %s; want %s", got, want)
  1355  	}
  1356  
  1357  	moduleDiff := plan.Diff.Modules[0]
  1358  
  1359  	iDiff, ok := moduleDiff.Resources["data.aws_data_resource.foo"]
  1360  	if !ok {
  1361  		t.Fatalf("missing diff for data.aws_data_resource.foo")
  1362  	}
  1363  
  1364  	// This is added by the diff but we want to verify that we got
  1365  	// the same diff as above minus the dynamic stuff.
  1366  	delete(iDiff.Attributes, "id")
  1367  
  1368  	if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same {
  1369  		t.Fatalf(
  1370  			"incorrect diff for data.data_resource.foo\ngot:  %#v\nwant: %#v",
  1371  			iDiff, p.ReadDataDiffReturn,
  1372  		)
  1373  	}
  1374  }
  1375  
  1376  func TestContext2Plan_computedList(t *testing.T) {
  1377  	m := testModule(t, "plan-computed-list")
  1378  	p := testProvider("aws")
  1379  	p.DiffFn = testDiffFn
  1380  	ctx := testContext2(t, &ContextOpts{
  1381  		Module: m,
  1382  		Providers: map[string]ResourceProviderFactory{
  1383  			"aws": testProviderFuncFixed(p),
  1384  		},
  1385  	})
  1386  
  1387  	plan, err := ctx.Plan()
  1388  	if err != nil {
  1389  		t.Fatalf("err: %s", err)
  1390  	}
  1391  
  1392  	actual := strings.TrimSpace(plan.String())
  1393  	expected := strings.TrimSpace(testTerraformPlanComputedListStr)
  1394  	if actual != expected {
  1395  		t.Fatalf("bad:\n%s", actual)
  1396  	}
  1397  }
  1398  
  1399  // GH-8695. This tests that you can index into a computed list on a
  1400  // splatted resource.
  1401  func TestContext2Plan_computedMultiIndex(t *testing.T) {
  1402  	m := testModule(t, "plan-computed-multi-index")
  1403  	p := testProvider("aws")
  1404  	p.DiffFn = testDiffFn
  1405  	ctx := testContext2(t, &ContextOpts{
  1406  		Module: m,
  1407  		Providers: map[string]ResourceProviderFactory{
  1408  			"aws": testProviderFuncFixed(p),
  1409  		},
  1410  	})
  1411  
  1412  	plan, err := ctx.Plan()
  1413  	if err != nil {
  1414  		t.Fatalf("err: %s", err)
  1415  	}
  1416  
  1417  	actual := strings.TrimSpace(plan.String())
  1418  	expected := strings.TrimSpace(testTerraformPlanComputedMultiIndexStr)
  1419  	if actual != expected {
  1420  		t.Fatalf("bad:\n%s", actual)
  1421  	}
  1422  }
  1423  
  1424  func TestContext2Plan_count(t *testing.T) {
  1425  	m := testModule(t, "plan-count")
  1426  	p := testProvider("aws")
  1427  	p.DiffFn = testDiffFn
  1428  	ctx := testContext2(t, &ContextOpts{
  1429  		Module: m,
  1430  		Providers: map[string]ResourceProviderFactory{
  1431  			"aws": testProviderFuncFixed(p),
  1432  		},
  1433  	})
  1434  
  1435  	plan, err := ctx.Plan()
  1436  	if err != nil {
  1437  		t.Fatalf("err: %s", err)
  1438  	}
  1439  
  1440  	if len(plan.Diff.RootModule().Resources) < 6 {
  1441  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1442  	}
  1443  
  1444  	actual := strings.TrimSpace(plan.String())
  1445  	expected := strings.TrimSpace(testTerraformPlanCountStr)
  1446  	if actual != expected {
  1447  		t.Fatalf("bad:\n%s", actual)
  1448  	}
  1449  }
  1450  
  1451  func TestContext2Plan_countComputed(t *testing.T) {
  1452  	m := testModule(t, "plan-count-computed")
  1453  	p := testProvider("aws")
  1454  	p.DiffFn = testDiffFn
  1455  	ctx := testContext2(t, &ContextOpts{
  1456  		Module: m,
  1457  		Providers: map[string]ResourceProviderFactory{
  1458  			"aws": testProviderFuncFixed(p),
  1459  		},
  1460  	})
  1461  
  1462  	_, err := ctx.Plan()
  1463  	if err == nil {
  1464  		t.Fatal("should error")
  1465  	}
  1466  }
  1467  
  1468  func TestContext2Plan_countComputedModule(t *testing.T) {
  1469  	m := testModule(t, "plan-count-computed-module")
  1470  	p := testProvider("aws")
  1471  	p.DiffFn = testDiffFn
  1472  	ctx := testContext2(t, &ContextOpts{
  1473  		Module: m,
  1474  		Providers: map[string]ResourceProviderFactory{
  1475  			"aws": testProviderFuncFixed(p),
  1476  		},
  1477  	})
  1478  
  1479  	_, err := ctx.Plan()
  1480  
  1481  	expectedErr := "aws_instance.bar: value of 'count'"
  1482  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  1483  		t.Fatalf("expected err would contain %q\nerr: %s\n",
  1484  			expectedErr, err)
  1485  	}
  1486  }
  1487  
  1488  func TestContext2Plan_countModuleStatic(t *testing.T) {
  1489  	m := testModule(t, "plan-count-module-static")
  1490  	p := testProvider("aws")
  1491  	p.DiffFn = testDiffFn
  1492  	ctx := testContext2(t, &ContextOpts{
  1493  		Module: m,
  1494  		Providers: map[string]ResourceProviderFactory{
  1495  			"aws": testProviderFuncFixed(p),
  1496  		},
  1497  	})
  1498  
  1499  	plan, err := ctx.Plan()
  1500  	if err != nil {
  1501  		t.Fatalf("err: %s", err)
  1502  	}
  1503  
  1504  	actual := strings.TrimSpace(plan.String())
  1505  	expected := strings.TrimSpace(`
  1506  DIFF:
  1507  
  1508  module.child:
  1509    CREATE: aws_instance.foo.0
  1510    CREATE: aws_instance.foo.1
  1511    CREATE: aws_instance.foo.2
  1512  
  1513  STATE:
  1514  
  1515  <no state>
  1516  `)
  1517  	if actual != expected {
  1518  		t.Fatalf("bad:\n%s", actual)
  1519  	}
  1520  }
  1521  
  1522  func TestContext2Plan_countModuleStaticGrandchild(t *testing.T) {
  1523  	m := testModule(t, "plan-count-module-static-grandchild")
  1524  	p := testProvider("aws")
  1525  	p.DiffFn = testDiffFn
  1526  	ctx := testContext2(t, &ContextOpts{
  1527  		Module: m,
  1528  		Providers: map[string]ResourceProviderFactory{
  1529  			"aws": testProviderFuncFixed(p),
  1530  		},
  1531  	})
  1532  
  1533  	plan, err := ctx.Plan()
  1534  	if err != nil {
  1535  		t.Fatalf("err: %s", err)
  1536  	}
  1537  
  1538  	actual := strings.TrimSpace(plan.String())
  1539  	expected := strings.TrimSpace(`
  1540  DIFF:
  1541  
  1542  module.child.child:
  1543    CREATE: aws_instance.foo.0
  1544    CREATE: aws_instance.foo.1
  1545    CREATE: aws_instance.foo.2
  1546  
  1547  STATE:
  1548  
  1549  <no state>
  1550  `)
  1551  	if actual != expected {
  1552  		t.Fatalf("bad:\n%s", actual)
  1553  	}
  1554  }
  1555  
  1556  func TestContext2Plan_countIndex(t *testing.T) {
  1557  	m := testModule(t, "plan-count-index")
  1558  	p := testProvider("aws")
  1559  	p.DiffFn = testDiffFn
  1560  	ctx := testContext2(t, &ContextOpts{
  1561  		Module: m,
  1562  		Providers: map[string]ResourceProviderFactory{
  1563  			"aws": testProviderFuncFixed(p),
  1564  		},
  1565  	})
  1566  
  1567  	plan, err := ctx.Plan()
  1568  	if err != nil {
  1569  		t.Fatalf("err: %s", err)
  1570  	}
  1571  
  1572  	actual := strings.TrimSpace(plan.String())
  1573  	expected := strings.TrimSpace(testTerraformPlanCountIndexStr)
  1574  	if actual != expected {
  1575  		t.Fatalf("bad:\n%s", actual)
  1576  	}
  1577  }
  1578  
  1579  func TestContext2Plan_countIndexZero(t *testing.T) {
  1580  	m := testModule(t, "plan-count-index-zero")
  1581  	p := testProvider("aws")
  1582  	p.DiffFn = testDiffFn
  1583  	ctx := testContext2(t, &ContextOpts{
  1584  		Module: m,
  1585  		Providers: map[string]ResourceProviderFactory{
  1586  			"aws": testProviderFuncFixed(p),
  1587  		},
  1588  	})
  1589  
  1590  	plan, err := ctx.Plan()
  1591  	if err != nil {
  1592  		t.Fatalf("err: %s", err)
  1593  	}
  1594  
  1595  	actual := strings.TrimSpace(plan.String())
  1596  	expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr)
  1597  	if actual != expected {
  1598  		t.Fatalf("bad:\n%s", actual)
  1599  	}
  1600  }
  1601  
  1602  func TestContext2Plan_countVar(t *testing.T) {
  1603  	m := testModule(t, "plan-count-var")
  1604  	p := testProvider("aws")
  1605  	p.DiffFn = testDiffFn
  1606  	ctx := testContext2(t, &ContextOpts{
  1607  		Module: m,
  1608  		Providers: map[string]ResourceProviderFactory{
  1609  			"aws": testProviderFuncFixed(p),
  1610  		},
  1611  		Variables: map[string]interface{}{
  1612  			"count": "3",
  1613  		},
  1614  	})
  1615  
  1616  	plan, err := ctx.Plan()
  1617  	if err != nil {
  1618  		t.Fatalf("err: %s", err)
  1619  	}
  1620  
  1621  	actual := strings.TrimSpace(plan.String())
  1622  	expected := strings.TrimSpace(testTerraformPlanCountVarStr)
  1623  	if actual != expected {
  1624  		t.Fatalf("bad:\n%s", actual)
  1625  	}
  1626  }
  1627  
  1628  func TestContext2Plan_countZero(t *testing.T) {
  1629  	m := testModule(t, "plan-count-zero")
  1630  	p := testProvider("aws")
  1631  	p.DiffFn = testDiffFn
  1632  	ctx := testContext2(t, &ContextOpts{
  1633  		Module: m,
  1634  		Providers: map[string]ResourceProviderFactory{
  1635  			"aws": testProviderFuncFixed(p),
  1636  		},
  1637  	})
  1638  
  1639  	plan, err := ctx.Plan()
  1640  	if err != nil {
  1641  		t.Fatalf("err: %s", err)
  1642  	}
  1643  
  1644  	actual := strings.TrimSpace(plan.String())
  1645  	expected := strings.TrimSpace(testTerraformPlanCountZeroStr)
  1646  	if actual != expected {
  1647  		t.Logf("expected:\n%s", expected)
  1648  		t.Fatalf("bad:\n%s", actual)
  1649  	}
  1650  }
  1651  
  1652  func TestContext2Plan_countOneIndex(t *testing.T) {
  1653  	m := testModule(t, "plan-count-one-index")
  1654  	p := testProvider("aws")
  1655  	p.DiffFn = testDiffFn
  1656  	ctx := testContext2(t, &ContextOpts{
  1657  		Module: m,
  1658  		Providers: map[string]ResourceProviderFactory{
  1659  			"aws": testProviderFuncFixed(p),
  1660  		},
  1661  	})
  1662  
  1663  	plan, err := ctx.Plan()
  1664  	if err != nil {
  1665  		t.Fatalf("err: %s", err)
  1666  	}
  1667  
  1668  	actual := strings.TrimSpace(plan.String())
  1669  	expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr)
  1670  	if actual != expected {
  1671  		t.Fatalf("bad:\n%s", actual)
  1672  	}
  1673  }
  1674  
  1675  func TestContext2Plan_countDecreaseToOne(t *testing.T) {
  1676  	m := testModule(t, "plan-count-dec")
  1677  	p := testProvider("aws")
  1678  	p.DiffFn = testDiffFn
  1679  	s := &State{
  1680  		Modules: []*ModuleState{
  1681  			&ModuleState{
  1682  				Path: rootModulePath,
  1683  				Resources: map[string]*ResourceState{
  1684  					"aws_instance.foo.0": &ResourceState{
  1685  						Type: "aws_instance",
  1686  						Primary: &InstanceState{
  1687  							ID: "bar",
  1688  							Attributes: map[string]string{
  1689  								"foo":  "foo",
  1690  								"type": "aws_instance",
  1691  							},
  1692  						},
  1693  					},
  1694  					"aws_instance.foo.1": &ResourceState{
  1695  						Type: "aws_instance",
  1696  						Primary: &InstanceState{
  1697  							ID: "bar",
  1698  						},
  1699  					},
  1700  					"aws_instance.foo.2": &ResourceState{
  1701  						Type: "aws_instance",
  1702  						Primary: &InstanceState{
  1703  							ID: "bar",
  1704  						},
  1705  					},
  1706  				},
  1707  			},
  1708  		},
  1709  	}
  1710  	ctx := testContext2(t, &ContextOpts{
  1711  		Module: m,
  1712  		Providers: map[string]ResourceProviderFactory{
  1713  			"aws": testProviderFuncFixed(p),
  1714  		},
  1715  		State: s,
  1716  	})
  1717  
  1718  	plan, err := ctx.Plan()
  1719  	if err != nil {
  1720  		t.Fatalf("err: %s", err)
  1721  	}
  1722  
  1723  	actual := strings.TrimSpace(plan.String())
  1724  	expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr)
  1725  	if actual != expected {
  1726  		t.Fatalf("bad:\n%s", actual)
  1727  	}
  1728  }
  1729  
  1730  func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
  1731  	m := testModule(t, "plan-count-inc")
  1732  	p := testProvider("aws")
  1733  	p.DiffFn = testDiffFn
  1734  	s := &State{
  1735  		Modules: []*ModuleState{
  1736  			&ModuleState{
  1737  				Path: rootModulePath,
  1738  				Resources: map[string]*ResourceState{
  1739  					"aws_instance.foo": &ResourceState{
  1740  						Type: "aws_instance",
  1741  						Primary: &InstanceState{
  1742  							ID: "bar",
  1743  							Attributes: map[string]string{
  1744  								"foo":  "foo",
  1745  								"type": "aws_instance",
  1746  							},
  1747  						},
  1748  					},
  1749  				},
  1750  			},
  1751  		},
  1752  	}
  1753  	ctx := testContext2(t, &ContextOpts{
  1754  		Module: m,
  1755  		Providers: map[string]ResourceProviderFactory{
  1756  			"aws": testProviderFuncFixed(p),
  1757  		},
  1758  		State: s,
  1759  	})
  1760  
  1761  	plan, err := ctx.Plan()
  1762  	if err != nil {
  1763  		t.Fatalf("err: %s", err)
  1764  	}
  1765  
  1766  	actual := strings.TrimSpace(plan.String())
  1767  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr)
  1768  	if actual != expected {
  1769  		t.Fatalf("bad:\n%s", actual)
  1770  	}
  1771  }
  1772  
  1773  func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
  1774  	m := testModule(t, "plan-count-inc")
  1775  	p := testProvider("aws")
  1776  	p.DiffFn = testDiffFn
  1777  	s := &State{
  1778  		Modules: []*ModuleState{
  1779  			&ModuleState{
  1780  				Path: rootModulePath,
  1781  				Resources: map[string]*ResourceState{
  1782  					"aws_instance.foo.0": &ResourceState{
  1783  						Type: "aws_instance",
  1784  						Primary: &InstanceState{
  1785  							ID: "bar",
  1786  							Attributes: map[string]string{
  1787  								"foo":  "foo",
  1788  								"type": "aws_instance",
  1789  							},
  1790  						},
  1791  					},
  1792  				},
  1793  			},
  1794  		},
  1795  	}
  1796  	ctx := testContext2(t, &ContextOpts{
  1797  		Module: m,
  1798  		Providers: map[string]ResourceProviderFactory{
  1799  			"aws": testProviderFuncFixed(p),
  1800  		},
  1801  		State: s,
  1802  	})
  1803  
  1804  	plan, err := ctx.Plan()
  1805  	if err != nil {
  1806  		t.Fatalf("err: %s", err)
  1807  	}
  1808  
  1809  	actual := strings.TrimSpace(plan.String())
  1810  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr)
  1811  	if actual != expected {
  1812  		t.Fatalf("bad:\n%s", actual)
  1813  	}
  1814  }
  1815  
  1816  // https://github.com/PeoplePerHour/terraform/pull/11
  1817  //
  1818  // This tests a case where both a "resource" and "resource.0" are in
  1819  // the state file, which apparently is a reasonable backwards compatibility
  1820  // concern found in the above 3rd party repo.
  1821  func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
  1822  	m := testModule(t, "plan-count-inc")
  1823  	p := testProvider("aws")
  1824  	p.DiffFn = testDiffFn
  1825  	s := &State{
  1826  		Modules: []*ModuleState{
  1827  			&ModuleState{
  1828  				Path: rootModulePath,
  1829  				Resources: map[string]*ResourceState{
  1830  					"aws_instance.foo": &ResourceState{
  1831  						Type: "aws_instance",
  1832  						Primary: &InstanceState{
  1833  							ID: "bar",
  1834  							Attributes: map[string]string{
  1835  								"foo":  "foo",
  1836  								"type": "aws_instance",
  1837  							},
  1838  						},
  1839  					},
  1840  					"aws_instance.foo.0": &ResourceState{
  1841  						Type: "aws_instance",
  1842  						Primary: &InstanceState{
  1843  							ID: "bar",
  1844  							Attributes: map[string]string{
  1845  								"foo":  "foo",
  1846  								"type": "aws_instance",
  1847  							},
  1848  						},
  1849  					},
  1850  				},
  1851  			},
  1852  		},
  1853  	}
  1854  	ctx := testContext2(t, &ContextOpts{
  1855  		Module: m,
  1856  		Providers: map[string]ResourceProviderFactory{
  1857  			"aws": testProviderFuncFixed(p),
  1858  		},
  1859  		State: s,
  1860  	})
  1861  
  1862  	plan, err := ctx.Plan()
  1863  	if err != nil {
  1864  		t.Fatalf("err: %s", err)
  1865  	}
  1866  
  1867  	actual := strings.TrimSpace(plan.String())
  1868  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr)
  1869  	if actual != expected {
  1870  		t.Fatalf("bad:\n%s", actual)
  1871  	}
  1872  }
  1873  
  1874  // A common pattern in TF configs is to have a set of resources with the same
  1875  // count and to use count.index to create correspondences between them:
  1876  //
  1877  //    foo_id = "${foo.bar.*.id[count.index]}"
  1878  //
  1879  // This test is for the situation where some instances already exist and the
  1880  // count is increased. In that case, we should see only the create diffs
  1881  // for the new instances and not any update diffs for the existing ones.
  1882  func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
  1883  	m := testModule(t, "plan-count-splat-reference")
  1884  	p := testProvider("aws")
  1885  	p.DiffFn = testDiffFn
  1886  	s := &State{
  1887  		Modules: []*ModuleState{
  1888  			&ModuleState{
  1889  				Path: rootModulePath,
  1890  				Resources: map[string]*ResourceState{
  1891  					"aws_instance.foo.0": &ResourceState{
  1892  						Type: "aws_instance",
  1893  						Primary: &InstanceState{
  1894  							ID: "bar",
  1895  							Attributes: map[string]string{
  1896  								"name": "foo 0",
  1897  							},
  1898  						},
  1899  					},
  1900  					"aws_instance.foo.1": &ResourceState{
  1901  						Type: "aws_instance",
  1902  						Primary: &InstanceState{
  1903  							ID: "bar",
  1904  							Attributes: map[string]string{
  1905  								"name": "foo 1",
  1906  							},
  1907  						},
  1908  					},
  1909  					"aws_instance.bar.0": &ResourceState{
  1910  						Type: "aws_instance",
  1911  						Primary: &InstanceState{
  1912  							ID: "bar",
  1913  							Attributes: map[string]string{
  1914  								"foo_name": "foo 0",
  1915  							},
  1916  						},
  1917  					},
  1918  					"aws_instance.bar.1": &ResourceState{
  1919  						Type: "aws_instance",
  1920  						Primary: &InstanceState{
  1921  							ID: "bar",
  1922  							Attributes: map[string]string{
  1923  								"foo_name": "foo 1",
  1924  							},
  1925  						},
  1926  					},
  1927  				},
  1928  			},
  1929  		},
  1930  	}
  1931  	ctx := testContext2(t, &ContextOpts{
  1932  		Module: m,
  1933  		Providers: map[string]ResourceProviderFactory{
  1934  			"aws": testProviderFuncFixed(p),
  1935  		},
  1936  		State: s,
  1937  	})
  1938  
  1939  	plan, err := ctx.Plan()
  1940  	if err != nil {
  1941  		t.Fatalf("err: %s", err)
  1942  	}
  1943  
  1944  	actual := strings.TrimSpace(plan.String())
  1945  	expected := strings.TrimSpace(`
  1946  DIFF:
  1947  
  1948  CREATE: aws_instance.bar.2
  1949    foo_name: "" => "foo 2"
  1950    type:     "" => "aws_instance"
  1951  CREATE: aws_instance.foo.2
  1952    name: "" => "foo 2"
  1953    type: "" => "aws_instance"
  1954  
  1955  STATE:
  1956  
  1957  aws_instance.bar.0:
  1958    ID = bar
  1959    foo_name = foo 0
  1960  aws_instance.bar.1:
  1961    ID = bar
  1962    foo_name = foo 1
  1963  aws_instance.foo.0:
  1964    ID = bar
  1965    name = foo 0
  1966  aws_instance.foo.1:
  1967    ID = bar
  1968    name = foo 1
  1969  `)
  1970  	if actual != expected {
  1971  		t.Fatalf("bad:\n%s", actual)
  1972  	}
  1973  }
  1974  
  1975  func TestContext2Plan_destroy(t *testing.T) {
  1976  	m := testModule(t, "plan-destroy")
  1977  	p := testProvider("aws")
  1978  	p.DiffFn = testDiffFn
  1979  	s := &State{
  1980  		Modules: []*ModuleState{
  1981  			&ModuleState{
  1982  				Path: rootModulePath,
  1983  				Resources: map[string]*ResourceState{
  1984  					"aws_instance.one": &ResourceState{
  1985  						Type: "aws_instance",
  1986  						Primary: &InstanceState{
  1987  							ID: "bar",
  1988  						},
  1989  					},
  1990  					"aws_instance.two": &ResourceState{
  1991  						Type: "aws_instance",
  1992  						Primary: &InstanceState{
  1993  							ID: "baz",
  1994  						},
  1995  					},
  1996  				},
  1997  			},
  1998  		},
  1999  	}
  2000  	ctx := testContext2(t, &ContextOpts{
  2001  		Module: m,
  2002  		Providers: map[string]ResourceProviderFactory{
  2003  			"aws": testProviderFuncFixed(p),
  2004  		},
  2005  		State:   s,
  2006  		Destroy: true,
  2007  	})
  2008  
  2009  	plan, err := ctx.Plan()
  2010  	if err != nil {
  2011  		t.Fatalf("err: %s", err)
  2012  	}
  2013  
  2014  	if len(plan.Diff.RootModule().Resources) != 2 {
  2015  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2016  	}
  2017  
  2018  	actual := strings.TrimSpace(plan.String())
  2019  	expected := strings.TrimSpace(testTerraformPlanDestroyStr)
  2020  	if actual != expected {
  2021  		t.Fatalf("bad:\n%s", actual)
  2022  	}
  2023  }
  2024  
  2025  func TestContext2Plan_moduleDestroy(t *testing.T) {
  2026  	m := testModule(t, "plan-module-destroy")
  2027  	p := testProvider("aws")
  2028  	p.DiffFn = testDiffFn
  2029  	s := &State{
  2030  		Modules: []*ModuleState{
  2031  			&ModuleState{
  2032  				Path: rootModulePath,
  2033  				Resources: map[string]*ResourceState{
  2034  					"aws_instance.foo": &ResourceState{
  2035  						Type: "aws_instance",
  2036  						Primary: &InstanceState{
  2037  							ID: "bar",
  2038  						},
  2039  					},
  2040  				},
  2041  			},
  2042  			&ModuleState{
  2043  				Path: []string{"root", "child"},
  2044  				Resources: map[string]*ResourceState{
  2045  					"aws_instance.foo": &ResourceState{
  2046  						Type: "aws_instance",
  2047  						Primary: &InstanceState{
  2048  							ID: "bar",
  2049  						},
  2050  					},
  2051  				},
  2052  			},
  2053  		},
  2054  	}
  2055  	ctx := testContext2(t, &ContextOpts{
  2056  		Module: m,
  2057  		Providers: map[string]ResourceProviderFactory{
  2058  			"aws": testProviderFuncFixed(p),
  2059  		},
  2060  		State:   s,
  2061  		Destroy: true,
  2062  	})
  2063  
  2064  	plan, err := ctx.Plan()
  2065  	if err != nil {
  2066  		t.Fatalf("err: %s", err)
  2067  	}
  2068  
  2069  	actual := strings.TrimSpace(plan.String())
  2070  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr)
  2071  	if actual != expected {
  2072  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2073  	}
  2074  }
  2075  
  2076  // GH-1835
  2077  func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
  2078  	m := testModule(t, "plan-module-destroy-gh-1835")
  2079  	p := testProvider("aws")
  2080  	p.DiffFn = testDiffFn
  2081  	s := &State{
  2082  		Modules: []*ModuleState{
  2083  			&ModuleState{
  2084  				Path: []string{"root", "a_module"},
  2085  				Resources: map[string]*ResourceState{
  2086  					"aws_instance.a": &ResourceState{
  2087  						Type: "aws_instance",
  2088  						Primary: &InstanceState{
  2089  							ID: "a",
  2090  						},
  2091  					},
  2092  				},
  2093  			},
  2094  			&ModuleState{
  2095  				Path: []string{"root", "b_module"},
  2096  				Resources: map[string]*ResourceState{
  2097  					"aws_instance.b": &ResourceState{
  2098  						Type: "aws_instance",
  2099  						Primary: &InstanceState{
  2100  							ID: "b",
  2101  						},
  2102  					},
  2103  				},
  2104  			},
  2105  		},
  2106  	}
  2107  	ctx := testContext2(t, &ContextOpts{
  2108  		Module: m,
  2109  		Providers: map[string]ResourceProviderFactory{
  2110  			"aws": testProviderFuncFixed(p),
  2111  		},
  2112  		State:   s,
  2113  		Destroy: true,
  2114  	})
  2115  
  2116  	plan, err := ctx.Plan()
  2117  	if err != nil {
  2118  		t.Fatalf("err: %s", err)
  2119  	}
  2120  
  2121  	actual := strings.TrimSpace(plan.String())
  2122  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr)
  2123  	if actual != expected {
  2124  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2125  	}
  2126  }
  2127  
  2128  func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
  2129  	m := testModule(t, "plan-module-destroy-multivar")
  2130  	p := testProvider("aws")
  2131  	p.DiffFn = testDiffFn
  2132  	s := &State{
  2133  		Modules: []*ModuleState{
  2134  			&ModuleState{
  2135  				Path:      rootModulePath,
  2136  				Resources: map[string]*ResourceState{},
  2137  			},
  2138  			&ModuleState{
  2139  				Path: []string{"root", "child"},
  2140  				Resources: map[string]*ResourceState{
  2141  					"aws_instance.foo.0": &ResourceState{
  2142  						Type: "aws_instance",
  2143  						Primary: &InstanceState{
  2144  							ID: "bar0",
  2145  						},
  2146  					},
  2147  					"aws_instance.foo.1": &ResourceState{
  2148  						Type: "aws_instance",
  2149  						Primary: &InstanceState{
  2150  							ID: "bar1",
  2151  						},
  2152  					},
  2153  				},
  2154  			},
  2155  		},
  2156  	}
  2157  	ctx := testContext2(t, &ContextOpts{
  2158  		Module: m,
  2159  		Providers: map[string]ResourceProviderFactory{
  2160  			"aws": testProviderFuncFixed(p),
  2161  		},
  2162  		State:   s,
  2163  		Destroy: true,
  2164  	})
  2165  
  2166  	plan, err := ctx.Plan()
  2167  	if err != nil {
  2168  		t.Fatalf("err: %s", err)
  2169  	}
  2170  
  2171  	actual := strings.TrimSpace(plan.String())
  2172  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr)
  2173  	if actual != expected {
  2174  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2175  	}
  2176  }
  2177  
  2178  func TestContext2Plan_pathVar(t *testing.T) {
  2179  	cwd, err := os.Getwd()
  2180  	if err != nil {
  2181  		t.Fatalf("err: %s", err)
  2182  	}
  2183  
  2184  	m := testModule(t, "plan-path-var")
  2185  	p := testProvider("aws")
  2186  	p.DiffFn = testDiffFn
  2187  	ctx := testContext2(t, &ContextOpts{
  2188  		Module: m,
  2189  		Providers: map[string]ResourceProviderFactory{
  2190  			"aws": testProviderFuncFixed(p),
  2191  		},
  2192  	})
  2193  
  2194  	plan, err := ctx.Plan()
  2195  	if err != nil {
  2196  		t.Fatalf("err: %s", err)
  2197  	}
  2198  
  2199  	actual := strings.TrimSpace(plan.String())
  2200  	expected := strings.TrimSpace(testTerraformPlanPathVarStr)
  2201  
  2202  	// Warning: this ordering REALLY matters for this test. The
  2203  	// order is: cwd, module, root.
  2204  	expected = fmt.Sprintf(
  2205  		expected,
  2206  		cwd,
  2207  		m.Config().Dir,
  2208  		m.Config().Dir)
  2209  
  2210  	if actual != expected {
  2211  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2212  	}
  2213  }
  2214  
  2215  func TestContext2Plan_diffVar(t *testing.T) {
  2216  	m := testModule(t, "plan-diffvar")
  2217  	p := testProvider("aws")
  2218  	s := &State{
  2219  		Modules: []*ModuleState{
  2220  			&ModuleState{
  2221  				Path: rootModulePath,
  2222  				Resources: map[string]*ResourceState{
  2223  					"aws_instance.foo": &ResourceState{
  2224  						Primary: &InstanceState{
  2225  							ID: "bar",
  2226  							Attributes: map[string]string{
  2227  								"num": "2",
  2228  							},
  2229  						},
  2230  					},
  2231  				},
  2232  			},
  2233  		},
  2234  	}
  2235  	ctx := testContext2(t, &ContextOpts{
  2236  		Module: m,
  2237  		Providers: map[string]ResourceProviderFactory{
  2238  			"aws": testProviderFuncFixed(p),
  2239  		},
  2240  		State: s,
  2241  	})
  2242  
  2243  	p.DiffFn = func(
  2244  		info *InstanceInfo,
  2245  		s *InstanceState,
  2246  		c *ResourceConfig) (*InstanceDiff, error) {
  2247  		if s.ID != "bar" {
  2248  			return testDiffFn(info, s, c)
  2249  		}
  2250  
  2251  		return &InstanceDiff{
  2252  			Attributes: map[string]*ResourceAttrDiff{
  2253  				"num": &ResourceAttrDiff{
  2254  					Old: "2",
  2255  					New: "3",
  2256  				},
  2257  			},
  2258  		}, nil
  2259  	}
  2260  
  2261  	plan, err := ctx.Plan()
  2262  	if err != nil {
  2263  		t.Fatalf("err: %s", err)
  2264  	}
  2265  
  2266  	actual := strings.TrimSpace(plan.String())
  2267  	expected := strings.TrimSpace(testTerraformPlanDiffVarStr)
  2268  	if actual != expected {
  2269  		t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected)
  2270  	}
  2271  }
  2272  
  2273  func TestContext2Plan_hook(t *testing.T) {
  2274  	m := testModule(t, "plan-good")
  2275  	h := new(MockHook)
  2276  	p := testProvider("aws")
  2277  	p.DiffFn = testDiffFn
  2278  	ctx := testContext2(t, &ContextOpts{
  2279  		Module: m,
  2280  		Hooks:  []Hook{h},
  2281  		Providers: map[string]ResourceProviderFactory{
  2282  			"aws": testProviderFuncFixed(p),
  2283  		},
  2284  	})
  2285  
  2286  	_, err := ctx.Plan()
  2287  	if err != nil {
  2288  		t.Fatalf("err: %s", err)
  2289  	}
  2290  
  2291  	if !h.PreDiffCalled {
  2292  		t.Fatal("should be called")
  2293  	}
  2294  	if !h.PostDiffCalled {
  2295  		t.Fatal("should be called")
  2296  	}
  2297  }
  2298  
  2299  func TestContext2Plan_orphan(t *testing.T) {
  2300  	m := testModule(t, "plan-orphan")
  2301  	p := testProvider("aws")
  2302  	p.DiffFn = testDiffFn
  2303  	s := &State{
  2304  		Modules: []*ModuleState{
  2305  			&ModuleState{
  2306  				Path: rootModulePath,
  2307  				Resources: map[string]*ResourceState{
  2308  					"aws_instance.baz": &ResourceState{
  2309  						Type: "aws_instance",
  2310  						Primary: &InstanceState{
  2311  							ID: "bar",
  2312  						},
  2313  					},
  2314  				},
  2315  			},
  2316  		},
  2317  	}
  2318  	ctx := testContext2(t, &ContextOpts{
  2319  		Module: m,
  2320  		Providers: map[string]ResourceProviderFactory{
  2321  			"aws": testProviderFuncFixed(p),
  2322  		},
  2323  		State: s,
  2324  	})
  2325  
  2326  	plan, err := ctx.Plan()
  2327  	if err != nil {
  2328  		t.Fatalf("err: %s", err)
  2329  	}
  2330  
  2331  	actual := strings.TrimSpace(plan.String())
  2332  	expected := strings.TrimSpace(testTerraformPlanOrphanStr)
  2333  	if actual != expected {
  2334  		t.Fatalf("bad:\n%s", actual)
  2335  	}
  2336  }
  2337  
  2338  // This tests that configurations with UUIDs don't produce errors.
  2339  // For shadows, this would produce errors since a UUID changes every time.
  2340  func TestContext2Plan_shadowUuid(t *testing.T) {
  2341  	m := testModule(t, "plan-shadow-uuid")
  2342  	p := testProvider("aws")
  2343  	p.DiffFn = testDiffFn
  2344  	ctx := testContext2(t, &ContextOpts{
  2345  		Module: m,
  2346  		Providers: map[string]ResourceProviderFactory{
  2347  			"aws": testProviderFuncFixed(p),
  2348  		},
  2349  	})
  2350  
  2351  	_, err := ctx.Plan()
  2352  	if err != nil {
  2353  		t.Fatalf("err: %s", err)
  2354  	}
  2355  }
  2356  
  2357  func TestContext2Plan_state(t *testing.T) {
  2358  	m := testModule(t, "plan-good")
  2359  	p := testProvider("aws")
  2360  	p.DiffFn = testDiffFn
  2361  	s := &State{
  2362  		Modules: []*ModuleState{
  2363  			&ModuleState{
  2364  				Path: rootModulePath,
  2365  				Resources: map[string]*ResourceState{
  2366  					"aws_instance.foo": &ResourceState{
  2367  						Primary: &InstanceState{
  2368  							ID: "bar",
  2369  						},
  2370  					},
  2371  				},
  2372  			},
  2373  		},
  2374  	}
  2375  	ctx := testContext2(t, &ContextOpts{
  2376  		Module: m,
  2377  		Providers: map[string]ResourceProviderFactory{
  2378  			"aws": testProviderFuncFixed(p),
  2379  		},
  2380  		State: s,
  2381  	})
  2382  
  2383  	plan, err := ctx.Plan()
  2384  	if err != nil {
  2385  		t.Fatalf("err: %s", err)
  2386  	}
  2387  
  2388  	if len(plan.Diff.RootModule().Resources) < 2 {
  2389  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2390  	}
  2391  
  2392  	actual := strings.TrimSpace(plan.String())
  2393  	expected := strings.TrimSpace(testTerraformPlanStateStr)
  2394  	if actual != expected {
  2395  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2396  	}
  2397  }
  2398  
  2399  func TestContext2Plan_taint(t *testing.T) {
  2400  	m := testModule(t, "plan-taint")
  2401  	p := testProvider("aws")
  2402  	p.DiffFn = testDiffFn
  2403  	s := &State{
  2404  		Modules: []*ModuleState{
  2405  			&ModuleState{
  2406  				Path: rootModulePath,
  2407  				Resources: map[string]*ResourceState{
  2408  					"aws_instance.foo": &ResourceState{
  2409  						Type: "aws_instance",
  2410  						Primary: &InstanceState{
  2411  							ID:         "bar",
  2412  							Attributes: map[string]string{"num": "2"},
  2413  						},
  2414  					},
  2415  					"aws_instance.bar": &ResourceState{
  2416  						Type: "aws_instance",
  2417  						Primary: &InstanceState{
  2418  							ID:      "baz",
  2419  							Tainted: true,
  2420  						},
  2421  					},
  2422  				},
  2423  			},
  2424  		},
  2425  	}
  2426  	ctx := testContext2(t, &ContextOpts{
  2427  		Module: m,
  2428  		Providers: map[string]ResourceProviderFactory{
  2429  			"aws": testProviderFuncFixed(p),
  2430  		},
  2431  		State: s,
  2432  	})
  2433  
  2434  	plan, err := ctx.Plan()
  2435  	if err != nil {
  2436  		t.Fatalf("err: %s", err)
  2437  	}
  2438  
  2439  	actual := strings.TrimSpace(plan.String())
  2440  	expected := strings.TrimSpace(testTerraformPlanTaintStr)
  2441  	if actual != expected {
  2442  		t.Fatalf("bad:\n%s", actual)
  2443  	}
  2444  }
  2445  
  2446  func TestContext2Apply_taintIgnoreChanges(t *testing.T) {
  2447  	m := testModule(t, "plan-taint-ignore-changes")
  2448  	p := testProvider("aws")
  2449  	p.ApplyFn = testApplyFn
  2450  	p.DiffFn = testDiffFn
  2451  	s := &State{
  2452  		Modules: []*ModuleState{
  2453  			&ModuleState{
  2454  				Path: rootModulePath,
  2455  				Resources: map[string]*ResourceState{
  2456  					"aws_instance.foo": &ResourceState{
  2457  						Type: "aws_instance",
  2458  						Primary: &InstanceState{
  2459  							ID: "foo",
  2460  							Attributes: map[string]string{
  2461  								"vars": "foo",
  2462  								"type": "aws_instance",
  2463  							},
  2464  							Tainted: true,
  2465  						},
  2466  					},
  2467  				},
  2468  			},
  2469  		},
  2470  	}
  2471  	ctx := testContext2(t, &ContextOpts{
  2472  		Module: m,
  2473  		Providers: map[string]ResourceProviderFactory{
  2474  			"aws": testProviderFuncFixed(p),
  2475  		},
  2476  		State: s,
  2477  	})
  2478  
  2479  	plan, err := ctx.Plan()
  2480  	if err != nil {
  2481  		t.Fatalf("err: %s", err)
  2482  	}
  2483  
  2484  	actual := strings.TrimSpace(plan.String())
  2485  	expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr)
  2486  	if actual != expected {
  2487  		t.Fatalf("bad:\n%s", actual)
  2488  	}
  2489  }
  2490  
  2491  // Fails about 50% of the time before the fix for GH-4982, covers the fix.
  2492  func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
  2493  	m := testModule(t, "plan-taint-interpolated-count")
  2494  	p := testProvider("aws")
  2495  	p.DiffFn = testDiffFn
  2496  	s := &State{
  2497  		Modules: []*ModuleState{
  2498  			&ModuleState{
  2499  				Path: rootModulePath,
  2500  				Resources: map[string]*ResourceState{
  2501  					"aws_instance.foo.0": &ResourceState{
  2502  						Type: "aws_instance",
  2503  						Primary: &InstanceState{
  2504  							ID:      "bar",
  2505  							Tainted: true,
  2506  						},
  2507  					},
  2508  					"aws_instance.foo.1": &ResourceState{
  2509  						Type:    "aws_instance",
  2510  						Primary: &InstanceState{ID: "bar"},
  2511  					},
  2512  					"aws_instance.foo.2": &ResourceState{
  2513  						Type:    "aws_instance",
  2514  						Primary: &InstanceState{ID: "bar"},
  2515  					},
  2516  				},
  2517  			},
  2518  		},
  2519  	}
  2520  	ctx := testContext2(t, &ContextOpts{
  2521  		Module: m,
  2522  		Providers: map[string]ResourceProviderFactory{
  2523  			"aws": testProviderFuncFixed(p),
  2524  		},
  2525  		State: s,
  2526  	})
  2527  
  2528  	for i := 0; i < 100; i++ {
  2529  		plan, err := ctx.Plan()
  2530  		if err != nil {
  2531  			t.Fatalf("err: %s", err)
  2532  		}
  2533  
  2534  		actual := strings.TrimSpace(plan.String())
  2535  		expected := strings.TrimSpace(`
  2536  DIFF:
  2537  
  2538  DESTROY/CREATE: aws_instance.foo.0
  2539    type: "" => "aws_instance"
  2540  
  2541  STATE:
  2542  
  2543  aws_instance.foo.0: (tainted)
  2544    ID = bar
  2545  aws_instance.foo.1:
  2546    ID = bar
  2547  aws_instance.foo.2:
  2548    ID = bar
  2549  		`)
  2550  		if actual != expected {
  2551  			t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected)
  2552  		}
  2553  	}
  2554  }
  2555  
  2556  func TestContext2Plan_targeted(t *testing.T) {
  2557  	m := testModule(t, "plan-targeted")
  2558  	p := testProvider("aws")
  2559  	p.DiffFn = testDiffFn
  2560  	ctx := testContext2(t, &ContextOpts{
  2561  		Module: m,
  2562  		Providers: map[string]ResourceProviderFactory{
  2563  			"aws": testProviderFuncFixed(p),
  2564  		},
  2565  		Targets: []string{"aws_instance.foo"},
  2566  	})
  2567  
  2568  	plan, err := ctx.Plan()
  2569  	if err != nil {
  2570  		t.Fatalf("err: %s", err)
  2571  	}
  2572  
  2573  	actual := strings.TrimSpace(plan.String())
  2574  	expected := strings.TrimSpace(`
  2575  DIFF:
  2576  
  2577  CREATE: aws_instance.foo
  2578    num:  "" => "2"
  2579    type: "" => "aws_instance"
  2580  
  2581  STATE:
  2582  
  2583  <no state>
  2584  	`)
  2585  	if actual != expected {
  2586  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2587  	}
  2588  }
  2589  
  2590  // Test that targeting a module properly plans any inputs that depend
  2591  // on another module.
  2592  func TestContext2Plan_targetedCrossModule(t *testing.T) {
  2593  	m := testModule(t, "plan-targeted-cross-module")
  2594  	p := testProvider("aws")
  2595  	p.DiffFn = testDiffFn
  2596  	ctx := testContext2(t, &ContextOpts{
  2597  		Module: m,
  2598  		Providers: map[string]ResourceProviderFactory{
  2599  			"aws": testProviderFuncFixed(p),
  2600  		},
  2601  		Targets: []string{"module.B"},
  2602  	})
  2603  
  2604  	plan, err := ctx.Plan()
  2605  	if err != nil {
  2606  		t.Fatalf("err: %s", err)
  2607  	}
  2608  
  2609  	actual := strings.TrimSpace(plan.String())
  2610  	expected := strings.TrimSpace(`
  2611  DIFF:
  2612  
  2613  module.A:
  2614    CREATE: aws_instance.foo
  2615      foo:  "" => "bar"
  2616      type: "" => "aws_instance"
  2617  module.B:
  2618    CREATE: aws_instance.bar
  2619      foo:  "" => "<computed>"
  2620      type: "" => "aws_instance"
  2621  
  2622  STATE:
  2623  
  2624  <no state>
  2625  	`)
  2626  	if actual != expected {
  2627  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2628  	}
  2629  }
  2630  
  2631  func TestContext2Plan_targetedModuleWithProvider(t *testing.T) {
  2632  	m := testModule(t, "plan-targeted-module-with-provider")
  2633  	p := testProvider("null")
  2634  	p.DiffFn = testDiffFn
  2635  	ctx := testContext2(t, &ContextOpts{
  2636  		Module: m,
  2637  		Providers: map[string]ResourceProviderFactory{
  2638  			"null": testProviderFuncFixed(p),
  2639  		},
  2640  		Targets: []string{"module.child2"},
  2641  	})
  2642  
  2643  	plan, err := ctx.Plan()
  2644  	if err != nil {
  2645  		t.Fatalf("err: %s", err)
  2646  	}
  2647  
  2648  	actual := strings.TrimSpace(plan.String())
  2649  	expected := strings.TrimSpace(`
  2650  DIFF:
  2651  
  2652  module.child2:
  2653    CREATE: null_resource.foo
  2654  
  2655  STATE:
  2656  
  2657  <no state>
  2658  	`)
  2659  	if actual != expected {
  2660  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2661  	}
  2662  }
  2663  
  2664  func TestContext2Plan_targetedOrphan(t *testing.T) {
  2665  	m := testModule(t, "plan-targeted-orphan")
  2666  	p := testProvider("aws")
  2667  	p.DiffFn = testDiffFn
  2668  	ctx := testContext2(t, &ContextOpts{
  2669  		Module: m,
  2670  		Providers: map[string]ResourceProviderFactory{
  2671  			"aws": testProviderFuncFixed(p),
  2672  		},
  2673  		State: &State{
  2674  			Modules: []*ModuleState{
  2675  				&ModuleState{
  2676  					Path: rootModulePath,
  2677  					Resources: map[string]*ResourceState{
  2678  						"aws_instance.orphan": &ResourceState{
  2679  							Type: "aws_instance",
  2680  							Primary: &InstanceState{
  2681  								ID: "i-789xyz",
  2682  							},
  2683  						},
  2684  						"aws_instance.nottargeted": &ResourceState{
  2685  							Type: "aws_instance",
  2686  							Primary: &InstanceState{
  2687  								ID: "i-abc123",
  2688  							},
  2689  						},
  2690  					},
  2691  				},
  2692  			},
  2693  		},
  2694  		Destroy: true,
  2695  		Targets: []string{"aws_instance.orphan"},
  2696  	})
  2697  
  2698  	plan, err := ctx.Plan()
  2699  	if err != nil {
  2700  		t.Fatalf("err: %s", err)
  2701  	}
  2702  
  2703  	actual := strings.TrimSpace(plan.String())
  2704  	expected := strings.TrimSpace(`DIFF:
  2705  
  2706  DESTROY: aws_instance.orphan
  2707  
  2708  STATE:
  2709  
  2710  aws_instance.nottargeted:
  2711    ID = i-abc123
  2712  aws_instance.orphan:
  2713    ID = i-789xyz
  2714  `)
  2715  	if actual != expected {
  2716  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2717  	}
  2718  }
  2719  
  2720  // https://github.com/hashicorp/terraform/issues/2538
  2721  func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
  2722  	m := testModule(t, "plan-targeted-module-orphan")
  2723  	p := testProvider("aws")
  2724  	p.DiffFn = testDiffFn
  2725  	ctx := testContext2(t, &ContextOpts{
  2726  		Module: m,
  2727  		Providers: map[string]ResourceProviderFactory{
  2728  			"aws": testProviderFuncFixed(p),
  2729  		},
  2730  		State: &State{
  2731  			Modules: []*ModuleState{
  2732  				&ModuleState{
  2733  					Path: []string{"root", "child"},
  2734  					Resources: map[string]*ResourceState{
  2735  						"aws_instance.orphan": &ResourceState{
  2736  							Type: "aws_instance",
  2737  							Primary: &InstanceState{
  2738  								ID: "i-789xyz",
  2739  							},
  2740  						},
  2741  						"aws_instance.nottargeted": &ResourceState{
  2742  							Type: "aws_instance",
  2743  							Primary: &InstanceState{
  2744  								ID: "i-abc123",
  2745  							},
  2746  						},
  2747  					},
  2748  				},
  2749  			},
  2750  		},
  2751  		Destroy: true,
  2752  		Targets: []string{"module.child.aws_instance.orphan"},
  2753  	})
  2754  
  2755  	plan, err := ctx.Plan()
  2756  	if err != nil {
  2757  		t.Fatalf("err: %s", err)
  2758  	}
  2759  
  2760  	actual := strings.TrimSpace(plan.String())
  2761  	expected := strings.TrimSpace(`DIFF:
  2762  
  2763  module.child:
  2764    DESTROY: aws_instance.orphan
  2765  
  2766  STATE:
  2767  
  2768  module.child:
  2769    aws_instance.nottargeted:
  2770      ID = i-abc123
  2771    aws_instance.orphan:
  2772      ID = i-789xyz
  2773  `)
  2774  	if actual != expected {
  2775  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2776  	}
  2777  }
  2778  
  2779  func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
  2780  	m := testModule(t, "plan-targeted-module-untargeted-variable")
  2781  	p := testProvider("aws")
  2782  	p.DiffFn = testDiffFn
  2783  	ctx := testContext2(t, &ContextOpts{
  2784  		Module: m,
  2785  		Providers: map[string]ResourceProviderFactory{
  2786  			"aws": testProviderFuncFixed(p),
  2787  		},
  2788  		Targets: []string{"aws_instance.blue", "module.blue_mod"},
  2789  	})
  2790  
  2791  	plan, err := ctx.Plan()
  2792  	if err != nil {
  2793  		t.Fatalf("err: %s", err)
  2794  	}
  2795  
  2796  	actual := strings.TrimSpace(plan.String())
  2797  	expected := strings.TrimSpace(`
  2798  DIFF:
  2799  
  2800  CREATE: aws_instance.blue
  2801  
  2802  module.blue_mod:
  2803    CREATE: aws_instance.mod
  2804      type:  "" => "aws_instance"
  2805      value: "" => "<computed>"
  2806  
  2807  STATE:
  2808  
  2809  <no state>
  2810  `)
  2811  	if actual != expected {
  2812  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2813  	}
  2814  }
  2815  
  2816  // https://github.com/hashicorp/terraform/issues/4515
  2817  func TestContext2Plan_targetedOverTen(t *testing.T) {
  2818  	m := testModule(t, "plan-targeted-over-ten")
  2819  	p := testProvider("aws")
  2820  	p.DiffFn = testDiffFn
  2821  
  2822  	resources := make(map[string]*ResourceState)
  2823  	var expectedState []string
  2824  	for i := 0; i < 13; i++ {
  2825  		key := fmt.Sprintf("aws_instance.foo.%d", i)
  2826  		id := fmt.Sprintf("i-abc%d", i)
  2827  		resources[key] = &ResourceState{
  2828  			Type:    "aws_instance",
  2829  			Primary: &InstanceState{ID: id},
  2830  		}
  2831  		expectedState = append(expectedState,
  2832  			fmt.Sprintf("%s:\n  ID = %s\n", key, id))
  2833  	}
  2834  	ctx := testContext2(t, &ContextOpts{
  2835  		Module: m,
  2836  		Providers: map[string]ResourceProviderFactory{
  2837  			"aws": testProviderFuncFixed(p),
  2838  		},
  2839  		State: &State{
  2840  			Modules: []*ModuleState{
  2841  				&ModuleState{
  2842  					Path:      rootModulePath,
  2843  					Resources: resources,
  2844  				},
  2845  			},
  2846  		},
  2847  		Targets: []string{"aws_instance.foo[1]"},
  2848  	})
  2849  
  2850  	plan, err := ctx.Plan()
  2851  	if err != nil {
  2852  		t.Fatalf("err: %s", err)
  2853  	}
  2854  
  2855  	actual := strings.TrimSpace(plan.String())
  2856  	sort.Strings(expectedState)
  2857  	expected := strings.TrimSpace(`
  2858  DIFF:
  2859  
  2860  
  2861  
  2862  STATE:
  2863  
  2864  aws_instance.foo.0:
  2865    ID = i-abc0
  2866  aws_instance.foo.1:
  2867    ID = i-abc1
  2868  aws_instance.foo.2:
  2869    ID = i-abc2
  2870  aws_instance.foo.3:
  2871    ID = i-abc3
  2872  aws_instance.foo.4:
  2873    ID = i-abc4
  2874  aws_instance.foo.5:
  2875    ID = i-abc5
  2876  aws_instance.foo.6:
  2877    ID = i-abc6
  2878  aws_instance.foo.7:
  2879    ID = i-abc7
  2880  aws_instance.foo.8:
  2881    ID = i-abc8
  2882  aws_instance.foo.9:
  2883    ID = i-abc9
  2884  aws_instance.foo.10:
  2885    ID = i-abc10
  2886  aws_instance.foo.11:
  2887    ID = i-abc11
  2888  aws_instance.foo.12:
  2889    ID = i-abc12
  2890  	`)
  2891  	if actual != expected {
  2892  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2893  	}
  2894  }
  2895  
  2896  func TestContext2Plan_provider(t *testing.T) {
  2897  	m := testModule(t, "plan-provider")
  2898  	p := testProvider("aws")
  2899  	p.DiffFn = testDiffFn
  2900  
  2901  	var value interface{}
  2902  	p.ConfigureFn = func(c *ResourceConfig) error {
  2903  		value, _ = c.Get("foo")
  2904  		return nil
  2905  	}
  2906  
  2907  	ctx := testContext2(t, &ContextOpts{
  2908  		Module: m,
  2909  		Providers: map[string]ResourceProviderFactory{
  2910  			"aws": testProviderFuncFixed(p),
  2911  		},
  2912  		Variables: map[string]interface{}{
  2913  			"foo": "bar",
  2914  		},
  2915  	})
  2916  
  2917  	if _, err := ctx.Plan(); err != nil {
  2918  		t.Fatalf("err: %s", err)
  2919  	}
  2920  
  2921  	if value != "bar" {
  2922  		t.Fatalf("bad: %#v", value)
  2923  	}
  2924  }
  2925  
  2926  func TestContext2Plan_varListErr(t *testing.T) {
  2927  	m := testModule(t, "plan-var-list-err")
  2928  	p := testProvider("aws")
  2929  	ctx := testContext2(t, &ContextOpts{
  2930  		Module: m,
  2931  		Providers: map[string]ResourceProviderFactory{
  2932  			"aws": testProviderFuncFixed(p),
  2933  		},
  2934  	})
  2935  
  2936  	_, err := ctx.Plan()
  2937  
  2938  	if err == nil {
  2939  		t.Fatal("should error")
  2940  	}
  2941  }
  2942  
  2943  func TestContext2Plan_ignoreChanges(t *testing.T) {
  2944  	m := testModule(t, "plan-ignore-changes")
  2945  	p := testProvider("aws")
  2946  	p.DiffFn = testDiffFn
  2947  	s := &State{
  2948  		Modules: []*ModuleState{
  2949  			&ModuleState{
  2950  				Path: rootModulePath,
  2951  				Resources: map[string]*ResourceState{
  2952  					"aws_instance.foo": &ResourceState{
  2953  						Primary: &InstanceState{
  2954  							ID:         "bar",
  2955  							Attributes: map[string]string{"ami": "ami-abcd1234"},
  2956  						},
  2957  					},
  2958  				},
  2959  			},
  2960  		},
  2961  	}
  2962  	ctx := testContext2(t, &ContextOpts{
  2963  		Module: m,
  2964  		Providers: map[string]ResourceProviderFactory{
  2965  			"aws": testProviderFuncFixed(p),
  2966  		},
  2967  		Variables: map[string]interface{}{
  2968  			"foo": "ami-1234abcd",
  2969  		},
  2970  		State: s,
  2971  	})
  2972  
  2973  	plan, err := ctx.Plan()
  2974  	if err != nil {
  2975  		t.Fatalf("err: %s", err)
  2976  	}
  2977  
  2978  	if len(plan.Diff.RootModule().Resources) < 1 {
  2979  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2980  	}
  2981  
  2982  	actual := strings.TrimSpace(plan.String())
  2983  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr)
  2984  	if actual != expected {
  2985  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2986  	}
  2987  }
  2988  
  2989  func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
  2990  	m := testModule(t, "plan-ignore-changes-wildcard")
  2991  	p := testProvider("aws")
  2992  	p.DiffFn = testDiffFn
  2993  	s := &State{
  2994  		Modules: []*ModuleState{
  2995  			&ModuleState{
  2996  				Path: rootModulePath,
  2997  				Resources: map[string]*ResourceState{
  2998  					"aws_instance.foo": &ResourceState{
  2999  						Primary: &InstanceState{
  3000  							ID: "bar",
  3001  							Attributes: map[string]string{
  3002  								"ami":           "ami-abcd1234",
  3003  								"instance_type": "t2.micro",
  3004  							},
  3005  						},
  3006  					},
  3007  				},
  3008  			},
  3009  		},
  3010  	}
  3011  	ctx := testContext2(t, &ContextOpts{
  3012  		Module: m,
  3013  		Providers: map[string]ResourceProviderFactory{
  3014  			"aws": testProviderFuncFixed(p),
  3015  		},
  3016  		Variables: map[string]interface{}{
  3017  			"foo": "ami-1234abcd",
  3018  			"bar": "t2.small",
  3019  		},
  3020  		State: s,
  3021  	})
  3022  
  3023  	plan, err := ctx.Plan()
  3024  	if err != nil {
  3025  		t.Fatalf("err: %s", err)
  3026  	}
  3027  
  3028  	if len(plan.Diff.RootModule().Resources) > 0 {
  3029  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  3030  	}
  3031  
  3032  	actual := strings.TrimSpace(plan.String())
  3033  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr)
  3034  	if actual != expected {
  3035  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3036  	}
  3037  }
  3038  
  3039  func TestContext2Plan_moduleMapLiteral(t *testing.T) {
  3040  	m := testModule(t, "plan-module-map-literal")
  3041  	p := testProvider("aws")
  3042  	p.ApplyFn = testApplyFn
  3043  	p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  3044  		// Here we verify that both the populated and empty map literals made it
  3045  		// through to the resource attributes
  3046  		val, _ := c.Get("tags")
  3047  		m, ok := val.(map[string]interface{})
  3048  		if !ok {
  3049  			t.Fatalf("Tags attr not map: %#v", val)
  3050  		}
  3051  		if m["foo"] != "bar" {
  3052  			t.Fatalf("Bad value in tags attr: %#v", m)
  3053  		}
  3054  		{
  3055  			val, _ := c.Get("meta")
  3056  			m, ok := val.(map[string]interface{})
  3057  			if !ok {
  3058  				t.Fatalf("Meta attr not map: %#v", val)
  3059  			}
  3060  			if len(m) != 0 {
  3061  				t.Fatalf("Meta attr not empty: %#v", val)
  3062  			}
  3063  		}
  3064  		return nil, nil
  3065  	}
  3066  	ctx := testContext2(t, &ContextOpts{
  3067  		Module: m,
  3068  		Providers: map[string]ResourceProviderFactory{
  3069  			"aws": testProviderFuncFixed(p),
  3070  		},
  3071  	})
  3072  
  3073  	if _, err := ctx.Plan(); err != nil {
  3074  		t.Fatalf("err: %s", err)
  3075  	}
  3076  }
  3077  
  3078  func TestContext2Plan_computedValueInMap(t *testing.T) {
  3079  	m := testModule(t, "plan-computed-value-in-map")
  3080  	p := testProvider("aws")
  3081  	p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  3082  		switch info.Type {
  3083  		case "aws_computed_source":
  3084  			return &InstanceDiff{
  3085  				Attributes: map[string]*ResourceAttrDiff{
  3086  					"computed_read_only": &ResourceAttrDiff{
  3087  						NewComputed: true,
  3088  					},
  3089  				},
  3090  			}, nil
  3091  		}
  3092  
  3093  		return testDiffFn(info, state, c)
  3094  	}
  3095  	ctx := testContext2(t, &ContextOpts{
  3096  		Module: m,
  3097  		Providers: map[string]ResourceProviderFactory{
  3098  			"aws": testProviderFuncFixed(p),
  3099  		},
  3100  	})
  3101  
  3102  	if _, err := ctx.Plan(); err != nil {
  3103  		t.Fatalf("err: %s", err)
  3104  	}
  3105  
  3106  	plan, err := ctx.Plan()
  3107  	if err != nil {
  3108  		t.Fatalf("err: %s", err)
  3109  	}
  3110  
  3111  	actual := strings.TrimSpace(plan.String())
  3112  	expected := strings.TrimSpace(testTerraformPlanComputedValueInMap)
  3113  	if actual != expected {
  3114  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3115  	}
  3116  }
  3117  
  3118  func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
  3119  	m := testModule(t, "plan-module-variable-from-splat")
  3120  	p := testProvider("aws")
  3121  	p.DiffFn = testDiffFn
  3122  	ctx := testContext2(t, &ContextOpts{
  3123  		Module: m,
  3124  		Providers: map[string]ResourceProviderFactory{
  3125  			"aws": testProviderFuncFixed(p),
  3126  		},
  3127  	})
  3128  
  3129  	if _, err := ctx.Plan(); err != nil {
  3130  		t.Fatalf("err: %s", err)
  3131  	}
  3132  
  3133  	plan, err := ctx.Plan()
  3134  	if err != nil {
  3135  		t.Fatalf("err: %s", err)
  3136  	}
  3137  
  3138  	actual := strings.TrimSpace(plan.String())
  3139  	expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat)
  3140  	if actual != expected {
  3141  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3142  	}
  3143  }
  3144  
  3145  func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
  3146  	m := testModule(t, "plan-cdb-depends-datasource")
  3147  	p := testProvider("aws")
  3148  	p.DiffFn = testDiffFn
  3149  	ctx := testContext2(t, &ContextOpts{
  3150  		Module: m,
  3151  		Providers: map[string]ResourceProviderFactory{
  3152  			"aws": testProviderFuncFixed(p),
  3153  		},
  3154  	})
  3155  
  3156  	plan, err := ctx.Plan()
  3157  	if err != nil {
  3158  		t.Fatalf("err: %s", err)
  3159  	}
  3160  
  3161  	if got := len(plan.Diff.Modules); got != 1 {
  3162  		t.Fatalf("got %d modules; want 1", got)
  3163  	}
  3164  
  3165  	moduleDiff := plan.Diff.Modules[0]
  3166  
  3167  	if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok {
  3168  		t.Fatalf("missing diff for aws_instance.foo.0")
  3169  	}
  3170  	if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok {
  3171  		t.Fatalf("missing diff for aws_instance.foo.1")
  3172  	}
  3173  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok {
  3174  		t.Fatalf("missing diff for data.aws_vpc.bar.0")
  3175  	}
  3176  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok {
  3177  		t.Fatalf("missing diff for data.aws_vpc.bar.1")
  3178  	}
  3179  }
  3180  
  3181  // interpolated lists need to be stored in the original order.
  3182  func TestContext2Plan_listOrder(t *testing.T) {
  3183  	m := testModule(t, "plan-list-order")
  3184  	p := testProvider("aws")
  3185  	p.ApplyFn = testApplyFn
  3186  	p.DiffFn = testDiffFn
  3187  	ctx := testContext2(t, &ContextOpts{
  3188  		Module: m,
  3189  		Providers: map[string]ResourceProviderFactory{
  3190  			"aws": testProviderFuncFixed(p),
  3191  		},
  3192  	})
  3193  
  3194  	plan, err := ctx.Plan()
  3195  	if err != nil {
  3196  		t.Fatalf("err: %s", err)
  3197  	}
  3198  
  3199  	rDiffs := plan.Diff.Modules[0].Resources
  3200  	rDiffA := rDiffs["aws_instance.a"]
  3201  	rDiffB := rDiffs["aws_instance.b"]
  3202  
  3203  	if !rDiffA.Equal(rDiffB) {
  3204  		t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan)
  3205  	}
  3206  }
  3207  
  3208  // Make sure ignore-changes doesn't interfere with set/list/map diffs.
  3209  // If a resource was being replaced by a RequiresNew attribute that gets
  3210  // ignored, we need to filter the diff properly to properly update rather than
  3211  // replace.
  3212  func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
  3213  	m := testModule(t, "plan-ignore-changes-with-flatmaps")
  3214  	p := testProvider("aws")
  3215  	p.DiffFn = testDiffFn
  3216  	s := &State{
  3217  		Modules: []*ModuleState{
  3218  			&ModuleState{
  3219  				Path: rootModulePath,
  3220  				Resources: map[string]*ResourceState{
  3221  					"aws_instance.foo": &ResourceState{
  3222  						Type: "aws_instance",
  3223  						Primary: &InstanceState{
  3224  							ID: "bar",
  3225  							Attributes: map[string]string{
  3226  								"user_data":   "x",
  3227  								"require_new": "",
  3228  								"set.#":       "1",
  3229  								"set.0.a":     "1",
  3230  								"lst.#":       "1",
  3231  								"lst.0":       "j",
  3232  							},
  3233  						},
  3234  					},
  3235  				},
  3236  			},
  3237  		},
  3238  	}
  3239  	ctx := testContext2(t, &ContextOpts{
  3240  		Module: m,
  3241  		Providers: map[string]ResourceProviderFactory{
  3242  			"aws": testProviderFuncFixed(p),
  3243  		},
  3244  		State: s,
  3245  	})
  3246  
  3247  	plan, err := ctx.Plan()
  3248  	if err != nil {
  3249  		t.Fatalf("err: %s", err)
  3250  	}
  3251  
  3252  	actual := strings.TrimSpace(plan.Diff.String())
  3253  	expected := strings.TrimSpace(testTFPlanDiffIgnoreChangesWithFlatmaps)
  3254  	if actual != expected {
  3255  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3256  	}
  3257  }
  3258  
  3259  // TestContext2Plan_resourceNestedCount ensures resource sets that depend on
  3260  // the count of another resource set (ie: count of a data source that depends
  3261  // on another data source's instance count - data.x.foo.*.id) get properly
  3262  // normalized to the indexes they should be. This case comes up when there is
  3263  // an existing state (after an initial apply).
  3264  func TestContext2Plan_resourceNestedCount(t *testing.T) {
  3265  	m := testModule(t, "nested-resource-count-plan")
  3266  	p := testProvider("aws")
  3267  	p.DiffFn = testDiffFn
  3268  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
  3269  		return is, nil
  3270  	}
  3271  	s := &State{
  3272  		Modules: []*ModuleState{
  3273  			&ModuleState{
  3274  				Path: rootModulePath,
  3275  				Resources: map[string]*ResourceState{
  3276  					"aws_instance.foo.0": &ResourceState{
  3277  						Type: "aws_instance",
  3278  						Primary: &InstanceState{
  3279  							ID: "foo0",
  3280  							Attributes: map[string]string{
  3281  								"id": "foo0",
  3282  							},
  3283  						},
  3284  					},
  3285  					"aws_instance.foo.1": &ResourceState{
  3286  						Type: "aws_instance",
  3287  						Primary: &InstanceState{
  3288  							ID: "foo1",
  3289  							Attributes: map[string]string{
  3290  								"id": "foo1",
  3291  							},
  3292  						},
  3293  					},
  3294  					"aws_instance.bar.0": &ResourceState{
  3295  						Type:         "aws_instance",
  3296  						Dependencies: []string{"aws_instance.foo.*"},
  3297  						Primary: &InstanceState{
  3298  							ID: "bar0",
  3299  							Attributes: map[string]string{
  3300  								"id": "bar0",
  3301  							},
  3302  						},
  3303  					},
  3304  					"aws_instance.bar.1": &ResourceState{
  3305  						Type:         "aws_instance",
  3306  						Dependencies: []string{"aws_instance.foo.*"},
  3307  						Primary: &InstanceState{
  3308  							ID: "bar1",
  3309  							Attributes: map[string]string{
  3310  								"id": "bar1",
  3311  							},
  3312  						},
  3313  					},
  3314  					"aws_instance.baz.0": &ResourceState{
  3315  						Type:         "aws_instance",
  3316  						Dependencies: []string{"aws_instance.bar.*"},
  3317  						Primary: &InstanceState{
  3318  							ID: "baz0",
  3319  							Attributes: map[string]string{
  3320  								"id": "baz0",
  3321  							},
  3322  						},
  3323  					},
  3324  					"aws_instance.baz.1": &ResourceState{
  3325  						Type:         "aws_instance",
  3326  						Dependencies: []string{"aws_instance.bar.*"},
  3327  						Primary: &InstanceState{
  3328  							ID: "baz1",
  3329  							Attributes: map[string]string{
  3330  								"id": "baz1",
  3331  							},
  3332  						},
  3333  					},
  3334  				},
  3335  			},
  3336  		},
  3337  	}
  3338  	ctx := testContext2(t, &ContextOpts{
  3339  		Module: m,
  3340  		Providers: map[string]ResourceProviderFactory{
  3341  			"aws": testProviderFuncFixed(p),
  3342  		},
  3343  		State: s,
  3344  	})
  3345  
  3346  	w, e := ctx.Validate()
  3347  	if len(w) > 0 {
  3348  		t.Fatalf("warnings generated on validate: %#v", w)
  3349  	}
  3350  	if len(e) > 0 {
  3351  		t.Fatalf("errors generated on validate: %#v", e)
  3352  	}
  3353  
  3354  	_, err := ctx.Refresh()
  3355  	if err != nil {
  3356  		t.Fatalf("refresh err: %s", err)
  3357  	}
  3358  
  3359  	plan, err := ctx.Plan()
  3360  	if err != nil {
  3361  		t.Fatalf("plan err: %s", err)
  3362  	}
  3363  
  3364  	actual := strings.TrimSpace(plan.String())
  3365  	expected := strings.TrimSpace(`
  3366  DIFF:
  3367  
  3368  
  3369  
  3370  STATE:
  3371  
  3372  aws_instance.bar.0:
  3373    ID = bar0
  3374  
  3375    Dependencies:
  3376      aws_instance.foo.*
  3377  aws_instance.bar.1:
  3378    ID = bar1
  3379  
  3380    Dependencies:
  3381      aws_instance.foo.*
  3382  aws_instance.baz.0:
  3383    ID = baz0
  3384  
  3385    Dependencies:
  3386      aws_instance.bar.*
  3387  aws_instance.baz.1:
  3388    ID = baz1
  3389  
  3390    Dependencies:
  3391      aws_instance.bar.*
  3392  aws_instance.foo.0:
  3393    ID = foo0
  3394  aws_instance.foo.1:
  3395    ID = foo1
  3396  `)
  3397  	if actual != expected {
  3398  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3399  	}
  3400  }