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