github.com/archgrove/terraform@v0.9.5-0.20170502093151-adb789f0f8d2/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  func TestContext2Plan_destroy(t *testing.T) {
  1875  	m := testModule(t, "plan-destroy")
  1876  	p := testProvider("aws")
  1877  	p.DiffFn = testDiffFn
  1878  	s := &State{
  1879  		Modules: []*ModuleState{
  1880  			&ModuleState{
  1881  				Path: rootModulePath,
  1882  				Resources: map[string]*ResourceState{
  1883  					"aws_instance.one": &ResourceState{
  1884  						Type: "aws_instance",
  1885  						Primary: &InstanceState{
  1886  							ID: "bar",
  1887  						},
  1888  					},
  1889  					"aws_instance.two": &ResourceState{
  1890  						Type: "aws_instance",
  1891  						Primary: &InstanceState{
  1892  							ID: "baz",
  1893  						},
  1894  					},
  1895  				},
  1896  			},
  1897  		},
  1898  	}
  1899  	ctx := testContext2(t, &ContextOpts{
  1900  		Module: m,
  1901  		Providers: map[string]ResourceProviderFactory{
  1902  			"aws": testProviderFuncFixed(p),
  1903  		},
  1904  		State:   s,
  1905  		Destroy: true,
  1906  	})
  1907  
  1908  	plan, err := ctx.Plan()
  1909  	if err != nil {
  1910  		t.Fatalf("err: %s", err)
  1911  	}
  1912  
  1913  	if len(plan.Diff.RootModule().Resources) != 2 {
  1914  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1915  	}
  1916  
  1917  	actual := strings.TrimSpace(plan.String())
  1918  	expected := strings.TrimSpace(testTerraformPlanDestroyStr)
  1919  	if actual != expected {
  1920  		t.Fatalf("bad:\n%s", actual)
  1921  	}
  1922  }
  1923  
  1924  func TestContext2Plan_moduleDestroy(t *testing.T) {
  1925  	m := testModule(t, "plan-module-destroy")
  1926  	p := testProvider("aws")
  1927  	p.DiffFn = testDiffFn
  1928  	s := &State{
  1929  		Modules: []*ModuleState{
  1930  			&ModuleState{
  1931  				Path: rootModulePath,
  1932  				Resources: map[string]*ResourceState{
  1933  					"aws_instance.foo": &ResourceState{
  1934  						Type: "aws_instance",
  1935  						Primary: &InstanceState{
  1936  							ID: "bar",
  1937  						},
  1938  					},
  1939  				},
  1940  			},
  1941  			&ModuleState{
  1942  				Path: []string{"root", "child"},
  1943  				Resources: map[string]*ResourceState{
  1944  					"aws_instance.foo": &ResourceState{
  1945  						Type: "aws_instance",
  1946  						Primary: &InstanceState{
  1947  							ID: "bar",
  1948  						},
  1949  					},
  1950  				},
  1951  			},
  1952  		},
  1953  	}
  1954  	ctx := testContext2(t, &ContextOpts{
  1955  		Module: m,
  1956  		Providers: map[string]ResourceProviderFactory{
  1957  			"aws": testProviderFuncFixed(p),
  1958  		},
  1959  		State:   s,
  1960  		Destroy: true,
  1961  	})
  1962  
  1963  	plan, err := ctx.Plan()
  1964  	if err != nil {
  1965  		t.Fatalf("err: %s", err)
  1966  	}
  1967  
  1968  	actual := strings.TrimSpace(plan.String())
  1969  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr)
  1970  	if actual != expected {
  1971  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1972  	}
  1973  }
  1974  
  1975  // GH-1835
  1976  func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
  1977  	m := testModule(t, "plan-module-destroy-gh-1835")
  1978  	p := testProvider("aws")
  1979  	p.DiffFn = testDiffFn
  1980  	s := &State{
  1981  		Modules: []*ModuleState{
  1982  			&ModuleState{
  1983  				Path: []string{"root", "a_module"},
  1984  				Resources: map[string]*ResourceState{
  1985  					"aws_instance.a": &ResourceState{
  1986  						Type: "aws_instance",
  1987  						Primary: &InstanceState{
  1988  							ID: "a",
  1989  						},
  1990  					},
  1991  				},
  1992  			},
  1993  			&ModuleState{
  1994  				Path: []string{"root", "b_module"},
  1995  				Resources: map[string]*ResourceState{
  1996  					"aws_instance.b": &ResourceState{
  1997  						Type: "aws_instance",
  1998  						Primary: &InstanceState{
  1999  							ID: "b",
  2000  						},
  2001  					},
  2002  				},
  2003  			},
  2004  		},
  2005  	}
  2006  	ctx := testContext2(t, &ContextOpts{
  2007  		Module: m,
  2008  		Providers: map[string]ResourceProviderFactory{
  2009  			"aws": testProviderFuncFixed(p),
  2010  		},
  2011  		State:   s,
  2012  		Destroy: true,
  2013  	})
  2014  
  2015  	plan, err := ctx.Plan()
  2016  	if err != nil {
  2017  		t.Fatalf("err: %s", err)
  2018  	}
  2019  
  2020  	actual := strings.TrimSpace(plan.String())
  2021  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr)
  2022  	if actual != expected {
  2023  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2024  	}
  2025  }
  2026  
  2027  func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
  2028  	m := testModule(t, "plan-module-destroy-multivar")
  2029  	p := testProvider("aws")
  2030  	p.DiffFn = testDiffFn
  2031  	s := &State{
  2032  		Modules: []*ModuleState{
  2033  			&ModuleState{
  2034  				Path:      rootModulePath,
  2035  				Resources: map[string]*ResourceState{},
  2036  			},
  2037  			&ModuleState{
  2038  				Path: []string{"root", "child"},
  2039  				Resources: map[string]*ResourceState{
  2040  					"aws_instance.foo.0": &ResourceState{
  2041  						Type: "aws_instance",
  2042  						Primary: &InstanceState{
  2043  							ID: "bar0",
  2044  						},
  2045  					},
  2046  					"aws_instance.foo.1": &ResourceState{
  2047  						Type: "aws_instance",
  2048  						Primary: &InstanceState{
  2049  							ID: "bar1",
  2050  						},
  2051  					},
  2052  				},
  2053  			},
  2054  		},
  2055  	}
  2056  	ctx := testContext2(t, &ContextOpts{
  2057  		Module: m,
  2058  		Providers: map[string]ResourceProviderFactory{
  2059  			"aws": testProviderFuncFixed(p),
  2060  		},
  2061  		State:   s,
  2062  		Destroy: true,
  2063  	})
  2064  
  2065  	plan, err := ctx.Plan()
  2066  	if err != nil {
  2067  		t.Fatalf("err: %s", err)
  2068  	}
  2069  
  2070  	actual := strings.TrimSpace(plan.String())
  2071  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr)
  2072  	if actual != expected {
  2073  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2074  	}
  2075  }
  2076  
  2077  func TestContext2Plan_pathVar(t *testing.T) {
  2078  	cwd, err := os.Getwd()
  2079  	if err != nil {
  2080  		t.Fatalf("err: %s", err)
  2081  	}
  2082  
  2083  	m := testModule(t, "plan-path-var")
  2084  	p := testProvider("aws")
  2085  	p.DiffFn = testDiffFn
  2086  	ctx := testContext2(t, &ContextOpts{
  2087  		Module: m,
  2088  		Providers: map[string]ResourceProviderFactory{
  2089  			"aws": testProviderFuncFixed(p),
  2090  		},
  2091  	})
  2092  
  2093  	plan, err := ctx.Plan()
  2094  	if err != nil {
  2095  		t.Fatalf("err: %s", err)
  2096  	}
  2097  
  2098  	actual := strings.TrimSpace(plan.String())
  2099  	expected := strings.TrimSpace(testTerraformPlanPathVarStr)
  2100  
  2101  	// Warning: this ordering REALLY matters for this test. The
  2102  	// order is: cwd, module, root.
  2103  	expected = fmt.Sprintf(
  2104  		expected,
  2105  		cwd,
  2106  		m.Config().Dir,
  2107  		m.Config().Dir)
  2108  
  2109  	if actual != expected {
  2110  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2111  	}
  2112  }
  2113  
  2114  func TestContext2Plan_diffVar(t *testing.T) {
  2115  	m := testModule(t, "plan-diffvar")
  2116  	p := testProvider("aws")
  2117  	s := &State{
  2118  		Modules: []*ModuleState{
  2119  			&ModuleState{
  2120  				Path: rootModulePath,
  2121  				Resources: map[string]*ResourceState{
  2122  					"aws_instance.foo": &ResourceState{
  2123  						Primary: &InstanceState{
  2124  							ID: "bar",
  2125  							Attributes: map[string]string{
  2126  								"num": "2",
  2127  							},
  2128  						},
  2129  					},
  2130  				},
  2131  			},
  2132  		},
  2133  	}
  2134  	ctx := testContext2(t, &ContextOpts{
  2135  		Module: m,
  2136  		Providers: map[string]ResourceProviderFactory{
  2137  			"aws": testProviderFuncFixed(p),
  2138  		},
  2139  		State: s,
  2140  	})
  2141  
  2142  	p.DiffFn = func(
  2143  		info *InstanceInfo,
  2144  		s *InstanceState,
  2145  		c *ResourceConfig) (*InstanceDiff, error) {
  2146  		if s.ID != "bar" {
  2147  			return testDiffFn(info, s, c)
  2148  		}
  2149  
  2150  		return &InstanceDiff{
  2151  			Attributes: map[string]*ResourceAttrDiff{
  2152  				"num": &ResourceAttrDiff{
  2153  					Old: "2",
  2154  					New: "3",
  2155  				},
  2156  			},
  2157  		}, nil
  2158  	}
  2159  
  2160  	plan, err := ctx.Plan()
  2161  	if err != nil {
  2162  		t.Fatalf("err: %s", err)
  2163  	}
  2164  
  2165  	actual := strings.TrimSpace(plan.String())
  2166  	expected := strings.TrimSpace(testTerraformPlanDiffVarStr)
  2167  	if actual != expected {
  2168  		t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected)
  2169  	}
  2170  }
  2171  
  2172  func TestContext2Plan_hook(t *testing.T) {
  2173  	m := testModule(t, "plan-good")
  2174  	h := new(MockHook)
  2175  	p := testProvider("aws")
  2176  	p.DiffFn = testDiffFn
  2177  	ctx := testContext2(t, &ContextOpts{
  2178  		Module: m,
  2179  		Hooks:  []Hook{h},
  2180  		Providers: map[string]ResourceProviderFactory{
  2181  			"aws": testProviderFuncFixed(p),
  2182  		},
  2183  	})
  2184  
  2185  	_, err := ctx.Plan()
  2186  	if err != nil {
  2187  		t.Fatalf("err: %s", err)
  2188  	}
  2189  
  2190  	if !h.PreDiffCalled {
  2191  		t.Fatal("should be called")
  2192  	}
  2193  	if !h.PostDiffCalled {
  2194  		t.Fatal("should be called")
  2195  	}
  2196  }
  2197  
  2198  func TestContext2Plan_orphan(t *testing.T) {
  2199  	m := testModule(t, "plan-orphan")
  2200  	p := testProvider("aws")
  2201  	p.DiffFn = testDiffFn
  2202  	s := &State{
  2203  		Modules: []*ModuleState{
  2204  			&ModuleState{
  2205  				Path: rootModulePath,
  2206  				Resources: map[string]*ResourceState{
  2207  					"aws_instance.baz": &ResourceState{
  2208  						Type: "aws_instance",
  2209  						Primary: &InstanceState{
  2210  							ID: "bar",
  2211  						},
  2212  					},
  2213  				},
  2214  			},
  2215  		},
  2216  	}
  2217  	ctx := testContext2(t, &ContextOpts{
  2218  		Module: m,
  2219  		Providers: map[string]ResourceProviderFactory{
  2220  			"aws": testProviderFuncFixed(p),
  2221  		},
  2222  		State: s,
  2223  	})
  2224  
  2225  	plan, err := ctx.Plan()
  2226  	if err != nil {
  2227  		t.Fatalf("err: %s", err)
  2228  	}
  2229  
  2230  	actual := strings.TrimSpace(plan.String())
  2231  	expected := strings.TrimSpace(testTerraformPlanOrphanStr)
  2232  	if actual != expected {
  2233  		t.Fatalf("bad:\n%s", actual)
  2234  	}
  2235  }
  2236  
  2237  // This tests that configurations with UUIDs don't produce errors.
  2238  // For shadows, this would produce errors since a UUID changes every time.
  2239  func TestContext2Plan_shadowUuid(t *testing.T) {
  2240  	m := testModule(t, "plan-shadow-uuid")
  2241  	p := testProvider("aws")
  2242  	p.DiffFn = testDiffFn
  2243  	ctx := testContext2(t, &ContextOpts{
  2244  		Module: m,
  2245  		Providers: map[string]ResourceProviderFactory{
  2246  			"aws": testProviderFuncFixed(p),
  2247  		},
  2248  	})
  2249  
  2250  	_, err := ctx.Plan()
  2251  	if err != nil {
  2252  		t.Fatalf("err: %s", err)
  2253  	}
  2254  }
  2255  
  2256  func TestContext2Plan_state(t *testing.T) {
  2257  	m := testModule(t, "plan-good")
  2258  	p := testProvider("aws")
  2259  	p.DiffFn = testDiffFn
  2260  	s := &State{
  2261  		Modules: []*ModuleState{
  2262  			&ModuleState{
  2263  				Path: rootModulePath,
  2264  				Resources: map[string]*ResourceState{
  2265  					"aws_instance.foo": &ResourceState{
  2266  						Primary: &InstanceState{
  2267  							ID: "bar",
  2268  						},
  2269  					},
  2270  				},
  2271  			},
  2272  		},
  2273  	}
  2274  	ctx := testContext2(t, &ContextOpts{
  2275  		Module: m,
  2276  		Providers: map[string]ResourceProviderFactory{
  2277  			"aws": testProviderFuncFixed(p),
  2278  		},
  2279  		State: s,
  2280  	})
  2281  
  2282  	plan, err := ctx.Plan()
  2283  	if err != nil {
  2284  		t.Fatalf("err: %s", err)
  2285  	}
  2286  
  2287  	if len(plan.Diff.RootModule().Resources) < 2 {
  2288  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2289  	}
  2290  
  2291  	actual := strings.TrimSpace(plan.String())
  2292  	expected := strings.TrimSpace(testTerraformPlanStateStr)
  2293  	if actual != expected {
  2294  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  2295  	}
  2296  }
  2297  
  2298  func TestContext2Plan_taint(t *testing.T) {
  2299  	m := testModule(t, "plan-taint")
  2300  	p := testProvider("aws")
  2301  	p.DiffFn = testDiffFn
  2302  	s := &State{
  2303  		Modules: []*ModuleState{
  2304  			&ModuleState{
  2305  				Path: rootModulePath,
  2306  				Resources: map[string]*ResourceState{
  2307  					"aws_instance.foo": &ResourceState{
  2308  						Type: "aws_instance",
  2309  						Primary: &InstanceState{
  2310  							ID:         "bar",
  2311  							Attributes: map[string]string{"num": "2"},
  2312  						},
  2313  					},
  2314  					"aws_instance.bar": &ResourceState{
  2315  						Type: "aws_instance",
  2316  						Primary: &InstanceState{
  2317  							ID:      "baz",
  2318  							Tainted: true,
  2319  						},
  2320  					},
  2321  				},
  2322  			},
  2323  		},
  2324  	}
  2325  	ctx := testContext2(t, &ContextOpts{
  2326  		Module: m,
  2327  		Providers: map[string]ResourceProviderFactory{
  2328  			"aws": testProviderFuncFixed(p),
  2329  		},
  2330  		State: s,
  2331  	})
  2332  
  2333  	plan, err := ctx.Plan()
  2334  	if err != nil {
  2335  		t.Fatalf("err: %s", err)
  2336  	}
  2337  
  2338  	actual := strings.TrimSpace(plan.String())
  2339  	expected := strings.TrimSpace(testTerraformPlanTaintStr)
  2340  	if actual != expected {
  2341  		t.Fatalf("bad:\n%s", actual)
  2342  	}
  2343  }
  2344  
  2345  func TestContext2Apply_taintIgnoreChanges(t *testing.T) {
  2346  	m := testModule(t, "plan-taint-ignore-changes")
  2347  	p := testProvider("aws")
  2348  	p.ApplyFn = testApplyFn
  2349  	p.DiffFn = testDiffFn
  2350  	s := &State{
  2351  		Modules: []*ModuleState{
  2352  			&ModuleState{
  2353  				Path: rootModulePath,
  2354  				Resources: map[string]*ResourceState{
  2355  					"aws_instance.foo": &ResourceState{
  2356  						Type: "aws_instance",
  2357  						Primary: &InstanceState{
  2358  							ID: "foo",
  2359  							Attributes: map[string]string{
  2360  								"vars": "foo",
  2361  								"type": "aws_instance",
  2362  							},
  2363  							Tainted: true,
  2364  						},
  2365  					},
  2366  				},
  2367  			},
  2368  		},
  2369  	}
  2370  	ctx := testContext2(t, &ContextOpts{
  2371  		Module: m,
  2372  		Providers: map[string]ResourceProviderFactory{
  2373  			"aws": testProviderFuncFixed(p),
  2374  		},
  2375  		State: s,
  2376  	})
  2377  
  2378  	plan, err := ctx.Plan()
  2379  	if err != nil {
  2380  		t.Fatalf("err: %s", err)
  2381  	}
  2382  
  2383  	actual := strings.TrimSpace(plan.String())
  2384  	expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr)
  2385  	if actual != expected {
  2386  		t.Fatalf("bad:\n%s", actual)
  2387  	}
  2388  }
  2389  
  2390  // Fails about 50% of the time before the fix for GH-4982, covers the fix.
  2391  func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
  2392  	m := testModule(t, "plan-taint-interpolated-count")
  2393  	p := testProvider("aws")
  2394  	p.DiffFn = testDiffFn
  2395  	s := &State{
  2396  		Modules: []*ModuleState{
  2397  			&ModuleState{
  2398  				Path: rootModulePath,
  2399  				Resources: map[string]*ResourceState{
  2400  					"aws_instance.foo.0": &ResourceState{
  2401  						Type: "aws_instance",
  2402  						Primary: &InstanceState{
  2403  							ID:      "bar",
  2404  							Tainted: true,
  2405  						},
  2406  					},
  2407  					"aws_instance.foo.1": &ResourceState{
  2408  						Type:    "aws_instance",
  2409  						Primary: &InstanceState{ID: "bar"},
  2410  					},
  2411  					"aws_instance.foo.2": &ResourceState{
  2412  						Type:    "aws_instance",
  2413  						Primary: &InstanceState{ID: "bar"},
  2414  					},
  2415  				},
  2416  			},
  2417  		},
  2418  	}
  2419  	ctx := testContext2(t, &ContextOpts{
  2420  		Module: m,
  2421  		Providers: map[string]ResourceProviderFactory{
  2422  			"aws": testProviderFuncFixed(p),
  2423  		},
  2424  		State: s,
  2425  	})
  2426  
  2427  	for i := 0; i < 100; i++ {
  2428  		plan, err := ctx.Plan()
  2429  		if err != nil {
  2430  			t.Fatalf("err: %s", err)
  2431  		}
  2432  
  2433  		actual := strings.TrimSpace(plan.String())
  2434  		expected := strings.TrimSpace(`
  2435  DIFF:
  2436  
  2437  DESTROY/CREATE: aws_instance.foo.0
  2438    type: "" => "aws_instance"
  2439  
  2440  STATE:
  2441  
  2442  aws_instance.foo.0: (tainted)
  2443    ID = bar
  2444  aws_instance.foo.1:
  2445    ID = bar
  2446  aws_instance.foo.2:
  2447    ID = bar
  2448  		`)
  2449  		if actual != expected {
  2450  			t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected)
  2451  		}
  2452  	}
  2453  }
  2454  
  2455  func TestContext2Plan_targeted(t *testing.T) {
  2456  	m := testModule(t, "plan-targeted")
  2457  	p := testProvider("aws")
  2458  	p.DiffFn = testDiffFn
  2459  	ctx := testContext2(t, &ContextOpts{
  2460  		Module: m,
  2461  		Providers: map[string]ResourceProviderFactory{
  2462  			"aws": testProviderFuncFixed(p),
  2463  		},
  2464  		Targets: []string{"aws_instance.foo"},
  2465  	})
  2466  
  2467  	plan, err := ctx.Plan()
  2468  	if err != nil {
  2469  		t.Fatalf("err: %s", err)
  2470  	}
  2471  
  2472  	actual := strings.TrimSpace(plan.String())
  2473  	expected := strings.TrimSpace(`
  2474  DIFF:
  2475  
  2476  CREATE: aws_instance.foo
  2477    num:  "" => "2"
  2478    type: "" => "aws_instance"
  2479  
  2480  STATE:
  2481  
  2482  <no state>
  2483  	`)
  2484  	if actual != expected {
  2485  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2486  	}
  2487  }
  2488  
  2489  // Test that targeting a module properly plans any inputs that depend
  2490  // on another module.
  2491  func TestContext2Plan_targetedCrossModule(t *testing.T) {
  2492  	m := testModule(t, "plan-targeted-cross-module")
  2493  	p := testProvider("aws")
  2494  	p.DiffFn = testDiffFn
  2495  	ctx := testContext2(t, &ContextOpts{
  2496  		Module: m,
  2497  		Providers: map[string]ResourceProviderFactory{
  2498  			"aws": testProviderFuncFixed(p),
  2499  		},
  2500  		Targets: []string{"module.B"},
  2501  	})
  2502  
  2503  	plan, err := ctx.Plan()
  2504  	if err != nil {
  2505  		t.Fatalf("err: %s", err)
  2506  	}
  2507  
  2508  	actual := strings.TrimSpace(plan.String())
  2509  	expected := strings.TrimSpace(`
  2510  DIFF:
  2511  
  2512  module.A:
  2513    CREATE: aws_instance.foo
  2514      foo:  "" => "bar"
  2515      type: "" => "aws_instance"
  2516  module.B:
  2517    CREATE: aws_instance.bar
  2518      foo:  "" => "<computed>"
  2519      type: "" => "aws_instance"
  2520  
  2521  STATE:
  2522  
  2523  <no state>
  2524  	`)
  2525  	if actual != expected {
  2526  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2527  	}
  2528  }
  2529  
  2530  func TestContext2Plan_targetedModuleWithProvider(t *testing.T) {
  2531  	m := testModule(t, "plan-targeted-module-with-provider")
  2532  	p := testProvider("null")
  2533  	p.DiffFn = testDiffFn
  2534  	ctx := testContext2(t, &ContextOpts{
  2535  		Module: m,
  2536  		Providers: map[string]ResourceProviderFactory{
  2537  			"null": testProviderFuncFixed(p),
  2538  		},
  2539  		Targets: []string{"module.child2"},
  2540  	})
  2541  
  2542  	plan, err := ctx.Plan()
  2543  	if err != nil {
  2544  		t.Fatalf("err: %s", err)
  2545  	}
  2546  
  2547  	actual := strings.TrimSpace(plan.String())
  2548  	expected := strings.TrimSpace(`
  2549  DIFF:
  2550  
  2551  module.child2:
  2552    CREATE: null_resource.foo
  2553  
  2554  STATE:
  2555  
  2556  <no state>
  2557  	`)
  2558  	if actual != expected {
  2559  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2560  	}
  2561  }
  2562  
  2563  func TestContext2Plan_targetedOrphan(t *testing.T) {
  2564  	m := testModule(t, "plan-targeted-orphan")
  2565  	p := testProvider("aws")
  2566  	p.DiffFn = testDiffFn
  2567  	ctx := testContext2(t, &ContextOpts{
  2568  		Module: m,
  2569  		Providers: map[string]ResourceProviderFactory{
  2570  			"aws": testProviderFuncFixed(p),
  2571  		},
  2572  		State: &State{
  2573  			Modules: []*ModuleState{
  2574  				&ModuleState{
  2575  					Path: rootModulePath,
  2576  					Resources: map[string]*ResourceState{
  2577  						"aws_instance.orphan": &ResourceState{
  2578  							Type: "aws_instance",
  2579  							Primary: &InstanceState{
  2580  								ID: "i-789xyz",
  2581  							},
  2582  						},
  2583  						"aws_instance.nottargeted": &ResourceState{
  2584  							Type: "aws_instance",
  2585  							Primary: &InstanceState{
  2586  								ID: "i-abc123",
  2587  							},
  2588  						},
  2589  					},
  2590  				},
  2591  			},
  2592  		},
  2593  		Destroy: true,
  2594  		Targets: []string{"aws_instance.orphan"},
  2595  	})
  2596  
  2597  	plan, err := ctx.Plan()
  2598  	if err != nil {
  2599  		t.Fatalf("err: %s", err)
  2600  	}
  2601  
  2602  	actual := strings.TrimSpace(plan.String())
  2603  	expected := strings.TrimSpace(`DIFF:
  2604  
  2605  DESTROY: aws_instance.orphan
  2606  
  2607  STATE:
  2608  
  2609  aws_instance.nottargeted:
  2610    ID = i-abc123
  2611  aws_instance.orphan:
  2612    ID = i-789xyz
  2613  `)
  2614  	if actual != expected {
  2615  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2616  	}
  2617  }
  2618  
  2619  // https://github.com/hashicorp/terraform/issues/2538
  2620  func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
  2621  	m := testModule(t, "plan-targeted-module-orphan")
  2622  	p := testProvider("aws")
  2623  	p.DiffFn = testDiffFn
  2624  	ctx := testContext2(t, &ContextOpts{
  2625  		Module: m,
  2626  		Providers: map[string]ResourceProviderFactory{
  2627  			"aws": testProviderFuncFixed(p),
  2628  		},
  2629  		State: &State{
  2630  			Modules: []*ModuleState{
  2631  				&ModuleState{
  2632  					Path: []string{"root", "child"},
  2633  					Resources: map[string]*ResourceState{
  2634  						"aws_instance.orphan": &ResourceState{
  2635  							Type: "aws_instance",
  2636  							Primary: &InstanceState{
  2637  								ID: "i-789xyz",
  2638  							},
  2639  						},
  2640  						"aws_instance.nottargeted": &ResourceState{
  2641  							Type: "aws_instance",
  2642  							Primary: &InstanceState{
  2643  								ID: "i-abc123",
  2644  							},
  2645  						},
  2646  					},
  2647  				},
  2648  			},
  2649  		},
  2650  		Destroy: true,
  2651  		Targets: []string{"module.child.aws_instance.orphan"},
  2652  	})
  2653  
  2654  	plan, err := ctx.Plan()
  2655  	if err != nil {
  2656  		t.Fatalf("err: %s", err)
  2657  	}
  2658  
  2659  	actual := strings.TrimSpace(plan.String())
  2660  	expected := strings.TrimSpace(`DIFF:
  2661  
  2662  module.child:
  2663    DESTROY: aws_instance.orphan
  2664  
  2665  STATE:
  2666  
  2667  module.child:
  2668    aws_instance.nottargeted:
  2669      ID = i-abc123
  2670    aws_instance.orphan:
  2671      ID = i-789xyz
  2672  `)
  2673  	if actual != expected {
  2674  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2675  	}
  2676  }
  2677  
  2678  func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
  2679  	m := testModule(t, "plan-targeted-module-untargeted-variable")
  2680  	p := testProvider("aws")
  2681  	p.DiffFn = testDiffFn
  2682  	ctx := testContext2(t, &ContextOpts{
  2683  		Module: m,
  2684  		Providers: map[string]ResourceProviderFactory{
  2685  			"aws": testProviderFuncFixed(p),
  2686  		},
  2687  		Targets: []string{"aws_instance.blue", "module.blue_mod"},
  2688  	})
  2689  
  2690  	plan, err := ctx.Plan()
  2691  	if err != nil {
  2692  		t.Fatalf("err: %s", err)
  2693  	}
  2694  
  2695  	actual := strings.TrimSpace(plan.String())
  2696  	expected := strings.TrimSpace(`
  2697  DIFF:
  2698  
  2699  CREATE: aws_instance.blue
  2700  
  2701  module.blue_mod:
  2702    CREATE: aws_instance.mod
  2703      type:  "" => "aws_instance"
  2704      value: "" => "<computed>"
  2705  
  2706  STATE:
  2707  
  2708  <no state>
  2709  `)
  2710  	if actual != expected {
  2711  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2712  	}
  2713  }
  2714  
  2715  // https://github.com/hashicorp/terraform/issues/4515
  2716  func TestContext2Plan_targetedOverTen(t *testing.T) {
  2717  	m := testModule(t, "plan-targeted-over-ten")
  2718  	p := testProvider("aws")
  2719  	p.DiffFn = testDiffFn
  2720  
  2721  	resources := make(map[string]*ResourceState)
  2722  	var expectedState []string
  2723  	for i := 0; i < 13; i++ {
  2724  		key := fmt.Sprintf("aws_instance.foo.%d", i)
  2725  		id := fmt.Sprintf("i-abc%d", i)
  2726  		resources[key] = &ResourceState{
  2727  			Type:    "aws_instance",
  2728  			Primary: &InstanceState{ID: id},
  2729  		}
  2730  		expectedState = append(expectedState,
  2731  			fmt.Sprintf("%s:\n  ID = %s\n", key, id))
  2732  	}
  2733  	ctx := testContext2(t, &ContextOpts{
  2734  		Module: m,
  2735  		Providers: map[string]ResourceProviderFactory{
  2736  			"aws": testProviderFuncFixed(p),
  2737  		},
  2738  		State: &State{
  2739  			Modules: []*ModuleState{
  2740  				&ModuleState{
  2741  					Path:      rootModulePath,
  2742  					Resources: resources,
  2743  				},
  2744  			},
  2745  		},
  2746  		Targets: []string{"aws_instance.foo[1]"},
  2747  	})
  2748  
  2749  	plan, err := ctx.Plan()
  2750  	if err != nil {
  2751  		t.Fatalf("err: %s", err)
  2752  	}
  2753  
  2754  	actual := strings.TrimSpace(plan.String())
  2755  	sort.Strings(expectedState)
  2756  	expected := strings.TrimSpace(`
  2757  DIFF:
  2758  
  2759  
  2760  
  2761  STATE:
  2762  
  2763  aws_instance.foo.0:
  2764    ID = i-abc0
  2765  aws_instance.foo.1:
  2766    ID = i-abc1
  2767  aws_instance.foo.2:
  2768    ID = i-abc2
  2769  aws_instance.foo.3:
  2770    ID = i-abc3
  2771  aws_instance.foo.4:
  2772    ID = i-abc4
  2773  aws_instance.foo.5:
  2774    ID = i-abc5
  2775  aws_instance.foo.6:
  2776    ID = i-abc6
  2777  aws_instance.foo.7:
  2778    ID = i-abc7
  2779  aws_instance.foo.8:
  2780    ID = i-abc8
  2781  aws_instance.foo.9:
  2782    ID = i-abc9
  2783  aws_instance.foo.10:
  2784    ID = i-abc10
  2785  aws_instance.foo.11:
  2786    ID = i-abc11
  2787  aws_instance.foo.12:
  2788    ID = i-abc12
  2789  	`)
  2790  	if actual != expected {
  2791  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2792  	}
  2793  }
  2794  
  2795  func TestContext2Plan_provider(t *testing.T) {
  2796  	m := testModule(t, "plan-provider")
  2797  	p := testProvider("aws")
  2798  	p.DiffFn = testDiffFn
  2799  
  2800  	var value interface{}
  2801  	p.ConfigureFn = func(c *ResourceConfig) error {
  2802  		value, _ = c.Get("foo")
  2803  		return nil
  2804  	}
  2805  
  2806  	ctx := testContext2(t, &ContextOpts{
  2807  		Module: m,
  2808  		Providers: map[string]ResourceProviderFactory{
  2809  			"aws": testProviderFuncFixed(p),
  2810  		},
  2811  		Variables: map[string]interface{}{
  2812  			"foo": "bar",
  2813  		},
  2814  	})
  2815  
  2816  	if _, err := ctx.Plan(); err != nil {
  2817  		t.Fatalf("err: %s", err)
  2818  	}
  2819  
  2820  	if value != "bar" {
  2821  		t.Fatalf("bad: %#v", value)
  2822  	}
  2823  }
  2824  
  2825  func TestContext2Plan_varListErr(t *testing.T) {
  2826  	m := testModule(t, "plan-var-list-err")
  2827  	p := testProvider("aws")
  2828  	ctx := testContext2(t, &ContextOpts{
  2829  		Module: m,
  2830  		Providers: map[string]ResourceProviderFactory{
  2831  			"aws": testProviderFuncFixed(p),
  2832  		},
  2833  	})
  2834  
  2835  	_, err := ctx.Plan()
  2836  
  2837  	if err == nil {
  2838  		t.Fatal("should error")
  2839  	}
  2840  }
  2841  
  2842  func TestContext2Plan_ignoreChanges(t *testing.T) {
  2843  	m := testModule(t, "plan-ignore-changes")
  2844  	p := testProvider("aws")
  2845  	p.DiffFn = testDiffFn
  2846  	s := &State{
  2847  		Modules: []*ModuleState{
  2848  			&ModuleState{
  2849  				Path: rootModulePath,
  2850  				Resources: map[string]*ResourceState{
  2851  					"aws_instance.foo": &ResourceState{
  2852  						Primary: &InstanceState{
  2853  							ID:         "bar",
  2854  							Attributes: map[string]string{"ami": "ami-abcd1234"},
  2855  						},
  2856  					},
  2857  				},
  2858  			},
  2859  		},
  2860  	}
  2861  	ctx := testContext2(t, &ContextOpts{
  2862  		Module: m,
  2863  		Providers: map[string]ResourceProviderFactory{
  2864  			"aws": testProviderFuncFixed(p),
  2865  		},
  2866  		Variables: map[string]interface{}{
  2867  			"foo": "ami-1234abcd",
  2868  		},
  2869  		State: s,
  2870  	})
  2871  
  2872  	plan, err := ctx.Plan()
  2873  	if err != nil {
  2874  		t.Fatalf("err: %s", err)
  2875  	}
  2876  
  2877  	if len(plan.Diff.RootModule().Resources) < 1 {
  2878  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2879  	}
  2880  
  2881  	actual := strings.TrimSpace(plan.String())
  2882  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr)
  2883  	if actual != expected {
  2884  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2885  	}
  2886  }
  2887  
  2888  func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
  2889  	m := testModule(t, "plan-ignore-changes-wildcard")
  2890  	p := testProvider("aws")
  2891  	p.DiffFn = testDiffFn
  2892  	s := &State{
  2893  		Modules: []*ModuleState{
  2894  			&ModuleState{
  2895  				Path: rootModulePath,
  2896  				Resources: map[string]*ResourceState{
  2897  					"aws_instance.foo": &ResourceState{
  2898  						Primary: &InstanceState{
  2899  							ID: "bar",
  2900  							Attributes: map[string]string{
  2901  								"ami":           "ami-abcd1234",
  2902  								"instance_type": "t2.micro",
  2903  							},
  2904  						},
  2905  					},
  2906  				},
  2907  			},
  2908  		},
  2909  	}
  2910  	ctx := testContext2(t, &ContextOpts{
  2911  		Module: m,
  2912  		Providers: map[string]ResourceProviderFactory{
  2913  			"aws": testProviderFuncFixed(p),
  2914  		},
  2915  		Variables: map[string]interface{}{
  2916  			"foo": "ami-1234abcd",
  2917  			"bar": "t2.small",
  2918  		},
  2919  		State: s,
  2920  	})
  2921  
  2922  	plan, err := ctx.Plan()
  2923  	if err != nil {
  2924  		t.Fatalf("err: %s", err)
  2925  	}
  2926  
  2927  	if len(plan.Diff.RootModule().Resources) > 0 {
  2928  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2929  	}
  2930  
  2931  	actual := strings.TrimSpace(plan.String())
  2932  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr)
  2933  	if actual != expected {
  2934  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2935  	}
  2936  }
  2937  
  2938  func TestContext2Plan_moduleMapLiteral(t *testing.T) {
  2939  	m := testModule(t, "plan-module-map-literal")
  2940  	p := testProvider("aws")
  2941  	p.ApplyFn = testApplyFn
  2942  	p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  2943  		// Here we verify that both the populated and empty map literals made it
  2944  		// through to the resource attributes
  2945  		val, _ := c.Get("tags")
  2946  		m, ok := val.(map[string]interface{})
  2947  		if !ok {
  2948  			t.Fatalf("Tags attr not map: %#v", val)
  2949  		}
  2950  		if m["foo"] != "bar" {
  2951  			t.Fatalf("Bad value in tags attr: %#v", m)
  2952  		}
  2953  		{
  2954  			val, _ := c.Get("meta")
  2955  			m, ok := val.(map[string]interface{})
  2956  			if !ok {
  2957  				t.Fatalf("Meta attr not map: %#v", val)
  2958  			}
  2959  			if len(m) != 0 {
  2960  				t.Fatalf("Meta attr not empty: %#v", val)
  2961  			}
  2962  		}
  2963  		return nil, nil
  2964  	}
  2965  	ctx := testContext2(t, &ContextOpts{
  2966  		Module: m,
  2967  		Providers: map[string]ResourceProviderFactory{
  2968  			"aws": testProviderFuncFixed(p),
  2969  		},
  2970  	})
  2971  
  2972  	if _, err := ctx.Plan(); err != nil {
  2973  		t.Fatalf("err: %s", err)
  2974  	}
  2975  }
  2976  
  2977  func TestContext2Plan_computedValueInMap(t *testing.T) {
  2978  	m := testModule(t, "plan-computed-value-in-map")
  2979  	p := testProvider("aws")
  2980  	p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
  2981  		switch info.Type {
  2982  		case "aws_computed_source":
  2983  			return &InstanceDiff{
  2984  				Attributes: map[string]*ResourceAttrDiff{
  2985  					"computed_read_only": &ResourceAttrDiff{
  2986  						NewComputed: true,
  2987  					},
  2988  				},
  2989  			}, nil
  2990  		}
  2991  
  2992  		return testDiffFn(info, state, c)
  2993  	}
  2994  	ctx := testContext2(t, &ContextOpts{
  2995  		Module: m,
  2996  		Providers: map[string]ResourceProviderFactory{
  2997  			"aws": testProviderFuncFixed(p),
  2998  		},
  2999  	})
  3000  
  3001  	if _, err := ctx.Plan(); err != nil {
  3002  		t.Fatalf("err: %s", err)
  3003  	}
  3004  
  3005  	plan, err := ctx.Plan()
  3006  	if err != nil {
  3007  		t.Fatalf("err: %s", err)
  3008  	}
  3009  
  3010  	actual := strings.TrimSpace(plan.String())
  3011  	expected := strings.TrimSpace(testTerraformPlanComputedValueInMap)
  3012  	if actual != expected {
  3013  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3014  	}
  3015  }
  3016  
  3017  func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
  3018  	m := testModule(t, "plan-module-variable-from-splat")
  3019  	p := testProvider("aws")
  3020  	p.DiffFn = testDiffFn
  3021  	ctx := testContext2(t, &ContextOpts{
  3022  		Module: m,
  3023  		Providers: map[string]ResourceProviderFactory{
  3024  			"aws": testProviderFuncFixed(p),
  3025  		},
  3026  	})
  3027  
  3028  	if _, err := ctx.Plan(); err != nil {
  3029  		t.Fatalf("err: %s", err)
  3030  	}
  3031  
  3032  	plan, err := ctx.Plan()
  3033  	if err != nil {
  3034  		t.Fatalf("err: %s", err)
  3035  	}
  3036  
  3037  	actual := strings.TrimSpace(plan.String())
  3038  	expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat)
  3039  	if actual != expected {
  3040  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3041  	}
  3042  }
  3043  
  3044  func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
  3045  	m := testModule(t, "plan-cdb-depends-datasource")
  3046  	p := testProvider("aws")
  3047  	p.DiffFn = testDiffFn
  3048  	ctx := testContext2(t, &ContextOpts{
  3049  		Module: m,
  3050  		Providers: map[string]ResourceProviderFactory{
  3051  			"aws": testProviderFuncFixed(p),
  3052  		},
  3053  	})
  3054  
  3055  	plan, err := ctx.Plan()
  3056  	if err != nil {
  3057  		t.Fatalf("err: %s", err)
  3058  	}
  3059  
  3060  	if got := len(plan.Diff.Modules); got != 1 {
  3061  		t.Fatalf("got %d modules; want 1", got)
  3062  	}
  3063  
  3064  	moduleDiff := plan.Diff.Modules[0]
  3065  
  3066  	if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok {
  3067  		t.Fatalf("missing diff for aws_instance.foo.0")
  3068  	}
  3069  	if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok {
  3070  		t.Fatalf("missing diff for aws_instance.foo.1")
  3071  	}
  3072  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok {
  3073  		t.Fatalf("missing diff for data.aws_vpc.bar.0")
  3074  	}
  3075  	if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok {
  3076  		t.Fatalf("missing diff for data.aws_vpc.bar.1")
  3077  	}
  3078  }
  3079  
  3080  // interpolated lists need to be stored in the original order.
  3081  func TestContext2Plan_listOrder(t *testing.T) {
  3082  	m := testModule(t, "plan-list-order")
  3083  	p := testProvider("aws")
  3084  	p.ApplyFn = testApplyFn
  3085  	p.DiffFn = testDiffFn
  3086  	ctx := testContext2(t, &ContextOpts{
  3087  		Module: m,
  3088  		Providers: map[string]ResourceProviderFactory{
  3089  			"aws": testProviderFuncFixed(p),
  3090  		},
  3091  	})
  3092  
  3093  	plan, err := ctx.Plan()
  3094  	if err != nil {
  3095  		t.Fatalf("err: %s", err)
  3096  	}
  3097  
  3098  	rDiffs := plan.Diff.Modules[0].Resources
  3099  	rDiffA := rDiffs["aws_instance.a"]
  3100  	rDiffB := rDiffs["aws_instance.b"]
  3101  
  3102  	if !rDiffA.Equal(rDiffB) {
  3103  		t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan)
  3104  	}
  3105  }
  3106  
  3107  // Make sure ignore-changes doesn't interfere with set/list/map diffs.
  3108  // If a resource was being replaced by a RequiresNew attribute that gets
  3109  // ignored, we need to filter the diff properly to properly update rather than
  3110  // replace.
  3111  func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
  3112  	m := testModule(t, "plan-ignore-changes-with-flatmaps")
  3113  	p := testProvider("aws")
  3114  	p.DiffFn = testDiffFn
  3115  	s := &State{
  3116  		Modules: []*ModuleState{
  3117  			&ModuleState{
  3118  				Path: rootModulePath,
  3119  				Resources: map[string]*ResourceState{
  3120  					"aws_instance.foo": &ResourceState{
  3121  						Type: "aws_instance",
  3122  						Primary: &InstanceState{
  3123  							ID: "bar",
  3124  							Attributes: map[string]string{
  3125  								"user_data":   "x",
  3126  								"require_new": "",
  3127  								"set.#":       "1",
  3128  								"set.0.a":     "1",
  3129  								"lst.#":       "1",
  3130  								"lst.0":       "j",
  3131  							},
  3132  						},
  3133  					},
  3134  				},
  3135  			},
  3136  		},
  3137  	}
  3138  	ctx := testContext2(t, &ContextOpts{
  3139  		Module: m,
  3140  		Providers: map[string]ResourceProviderFactory{
  3141  			"aws": testProviderFuncFixed(p),
  3142  		},
  3143  		State: s,
  3144  	})
  3145  
  3146  	plan, err := ctx.Plan()
  3147  	if err != nil {
  3148  		t.Fatalf("err: %s", err)
  3149  	}
  3150  
  3151  	actual := strings.TrimSpace(plan.Diff.String())
  3152  	expected := strings.TrimSpace(testTFPlanDiffIgnoreChangesWithFlatmaps)
  3153  	if actual != expected {
  3154  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3155  	}
  3156  }
  3157  
  3158  // TestContext2Plan_resourceNestedCount ensures resource sets that depend on
  3159  // the count of another resource set (ie: count of a data source that depends
  3160  // on another data source's instance count - data.x.foo.*.id) get properly
  3161  // normalized to the indexes they should be. This case comes up when there is
  3162  // an existing state (after an initial apply).
  3163  func TestContext2Plan_resourceNestedCount(t *testing.T) {
  3164  	m := testModule(t, "nested-resource-count-plan")
  3165  	p := testProvider("aws")
  3166  	p.DiffFn = testDiffFn
  3167  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
  3168  		return is, nil
  3169  	}
  3170  	s := &State{
  3171  		Modules: []*ModuleState{
  3172  			&ModuleState{
  3173  				Path: rootModulePath,
  3174  				Resources: map[string]*ResourceState{
  3175  					"aws_instance.foo.0": &ResourceState{
  3176  						Type: "aws_instance",
  3177  						Primary: &InstanceState{
  3178  							ID: "foo0",
  3179  							Attributes: map[string]string{
  3180  								"id": "foo0",
  3181  							},
  3182  						},
  3183  					},
  3184  					"aws_instance.foo.1": &ResourceState{
  3185  						Type: "aws_instance",
  3186  						Primary: &InstanceState{
  3187  							ID: "foo1",
  3188  							Attributes: map[string]string{
  3189  								"id": "foo1",
  3190  							},
  3191  						},
  3192  					},
  3193  					"aws_instance.bar.0": &ResourceState{
  3194  						Type:         "aws_instance",
  3195  						Dependencies: []string{"aws_instance.foo.*"},
  3196  						Primary: &InstanceState{
  3197  							ID: "bar0",
  3198  							Attributes: map[string]string{
  3199  								"id": "bar0",
  3200  							},
  3201  						},
  3202  					},
  3203  					"aws_instance.bar.1": &ResourceState{
  3204  						Type:         "aws_instance",
  3205  						Dependencies: []string{"aws_instance.foo.*"},
  3206  						Primary: &InstanceState{
  3207  							ID: "bar1",
  3208  							Attributes: map[string]string{
  3209  								"id": "bar1",
  3210  							},
  3211  						},
  3212  					},
  3213  					"aws_instance.baz.0": &ResourceState{
  3214  						Type:         "aws_instance",
  3215  						Dependencies: []string{"aws_instance.bar.*"},
  3216  						Primary: &InstanceState{
  3217  							ID: "baz0",
  3218  							Attributes: map[string]string{
  3219  								"id": "baz0",
  3220  							},
  3221  						},
  3222  					},
  3223  					"aws_instance.baz.1": &ResourceState{
  3224  						Type:         "aws_instance",
  3225  						Dependencies: []string{"aws_instance.bar.*"},
  3226  						Primary: &InstanceState{
  3227  							ID: "baz1",
  3228  							Attributes: map[string]string{
  3229  								"id": "baz1",
  3230  							},
  3231  						},
  3232  					},
  3233  				},
  3234  			},
  3235  		},
  3236  	}
  3237  	ctx := testContext2(t, &ContextOpts{
  3238  		Module: m,
  3239  		Providers: map[string]ResourceProviderFactory{
  3240  			"aws": testProviderFuncFixed(p),
  3241  		},
  3242  		State: s,
  3243  	})
  3244  
  3245  	w, e := ctx.Validate()
  3246  	if len(w) > 0 {
  3247  		t.Fatalf("warnings generated on validate: %#v", w)
  3248  	}
  3249  	if len(e) > 0 {
  3250  		t.Fatalf("errors generated on validate: %#v", e)
  3251  	}
  3252  
  3253  	_, err := ctx.Refresh()
  3254  	if err != nil {
  3255  		t.Fatalf("refresh err: %s", err)
  3256  	}
  3257  
  3258  	plan, err := ctx.Plan()
  3259  	if err != nil {
  3260  		t.Fatalf("plan err: %s", err)
  3261  	}
  3262  
  3263  	actual := strings.TrimSpace(plan.String())
  3264  	expected := strings.TrimSpace(`
  3265  DIFF:
  3266  
  3267  
  3268  
  3269  STATE:
  3270  
  3271  aws_instance.bar.0:
  3272    ID = bar0
  3273  
  3274    Dependencies:
  3275      aws_instance.foo.*
  3276  aws_instance.bar.1:
  3277    ID = bar1
  3278  
  3279    Dependencies:
  3280      aws_instance.foo.*
  3281  aws_instance.baz.0:
  3282    ID = baz0
  3283  
  3284    Dependencies:
  3285      aws_instance.bar.*
  3286  aws_instance.baz.1:
  3287    ID = baz1
  3288  
  3289    Dependencies:
  3290      aws_instance.bar.*
  3291  aws_instance.foo.0:
  3292    ID = foo0
  3293  aws_instance.foo.1:
  3294    ID = foo1
  3295  `)
  3296  	if actual != expected {
  3297  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  3298  	}
  3299  }