github.com/jrasell/terraform@v0.6.17-0.20160523115548-2652f5232949/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(t *testing.T) {
    15  	m := testModule(t, "plan-good")
    16  	p := testProvider("aws")
    17  	p.DiffFn = testDiffFn
    18  	ctx := testContext2(t, &ContextOpts{
    19  		Module: m,
    20  		Providers: map[string]ResourceProviderFactory{
    21  			"aws": testProviderFuncFixed(p),
    22  		},
    23  	})
    24  
    25  	plan, err := ctx.Plan()
    26  	if err != nil {
    27  		t.Fatalf("err: %s", err)
    28  	}
    29  
    30  	if len(plan.Diff.RootModule().Resources) < 2 {
    31  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
    32  	}
    33  
    34  	actual := strings.TrimSpace(plan.String())
    35  	expected := strings.TrimSpace(testTerraformPlanStr)
    36  	if actual != expected {
    37  		t.Fatalf("bad:\n%s", actual)
    38  	}
    39  }
    40  
    41  func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
    42  	m := testModule(t, "plan-cbd-maintain-root")
    43  	p := testProvider("aws")
    44  	p.DiffFn = testDiffFn
    45  	ctx := testContext2(t, &ContextOpts{
    46  		Module: m,
    47  		Providers: map[string]ResourceProviderFactory{
    48  			"aws": testProviderFuncFixed(p),
    49  		},
    50  		Variables: map[string]string{
    51  			"in": "a,b,c",
    52  		},
    53  	})
    54  
    55  	plan, err := ctx.Plan()
    56  	if err != nil {
    57  		t.Fatalf("err: %s", err)
    58  	}
    59  
    60  	actual := strings.TrimSpace(plan.String())
    61  	expected := strings.TrimSpace(`
    62  DIFF:
    63  
    64  CREATE: aws_instance.bar.0
    65  CREATE: aws_instance.bar.1
    66  CREATE: aws_instance.foo.0
    67  CREATE: aws_instance.foo.1
    68  
    69  STATE:
    70  
    71  <no state>
    72  		`)
    73  	if actual != expected {
    74  		t.Fatalf("expected:\n%s, got:\n%s", expected, actual)
    75  	}
    76  }
    77  
    78  func TestContext2Plan_emptyDiff(t *testing.T) {
    79  	m := testModule(t, "plan-empty")
    80  	p := testProvider("aws")
    81  	p.DiffFn = func(
    82  		info *InstanceInfo,
    83  		s *InstanceState,
    84  		c *ResourceConfig) (*InstanceDiff, error) {
    85  		return nil, nil
    86  	}
    87  
    88  	ctx := testContext2(t, &ContextOpts{
    89  		Module: m,
    90  		Providers: map[string]ResourceProviderFactory{
    91  			"aws": testProviderFuncFixed(p),
    92  		},
    93  	})
    94  
    95  	plan, err := ctx.Plan()
    96  	if err != nil {
    97  		t.Fatalf("err: %s", err)
    98  	}
    99  
   100  	actual := strings.TrimSpace(plan.String())
   101  	expected := strings.TrimSpace(testTerraformPlanEmptyStr)
   102  	if actual != expected {
   103  		t.Fatalf("bad:\n%s", actual)
   104  	}
   105  }
   106  
   107  func TestContext2Plan_escapedVar(t *testing.T) {
   108  	m := testModule(t, "plan-escaped-var")
   109  	p := testProvider("aws")
   110  	p.DiffFn = testDiffFn
   111  	ctx := testContext2(t, &ContextOpts{
   112  		Module: m,
   113  		Providers: map[string]ResourceProviderFactory{
   114  			"aws": testProviderFuncFixed(p),
   115  		},
   116  	})
   117  
   118  	plan, err := ctx.Plan()
   119  	if err != nil {
   120  		t.Fatalf("err: %s", err)
   121  	}
   122  
   123  	actual := strings.TrimSpace(plan.String())
   124  	expected := strings.TrimSpace(testTerraformPlanEscapedVarStr)
   125  	if actual != expected {
   126  		t.Fatalf("bad:\n%s", actual)
   127  	}
   128  }
   129  
   130  func TestContext2Plan_minimal(t *testing.T) {
   131  	m := testModule(t, "plan-empty")
   132  	p := testProvider("aws")
   133  	p.DiffFn = testDiffFn
   134  	ctx := testContext2(t, &ContextOpts{
   135  		Module: m,
   136  		Providers: map[string]ResourceProviderFactory{
   137  			"aws": testProviderFuncFixed(p),
   138  		},
   139  	})
   140  
   141  	plan, err := ctx.Plan()
   142  	if err != nil {
   143  		t.Fatalf("err: %s", err)
   144  	}
   145  
   146  	actual := strings.TrimSpace(plan.String())
   147  	expected := strings.TrimSpace(testTerraformPlanEmptyStr)
   148  	if actual != expected {
   149  		t.Fatalf("bad:\n%s", actual)
   150  	}
   151  }
   152  
   153  func TestContext2Plan_modules(t *testing.T) {
   154  	m := testModule(t, "plan-modules")
   155  	p := testProvider("aws")
   156  	p.DiffFn = testDiffFn
   157  	ctx := testContext2(t, &ContextOpts{
   158  		Module: m,
   159  		Providers: map[string]ResourceProviderFactory{
   160  			"aws": testProviderFuncFixed(p),
   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(testTerraformPlanModulesStr)
   171  	if actual != expected {
   172  		t.Fatalf("bad:\n%s", actual)
   173  	}
   174  }
   175  
   176  // GH-1475
   177  func TestContext2Plan_moduleCycle(t *testing.T) {
   178  	m := testModule(t, "plan-module-cycle")
   179  	p := testProvider("aws")
   180  	p.DiffFn = testDiffFn
   181  	ctx := testContext2(t, &ContextOpts{
   182  		Module: m,
   183  		Providers: map[string]ResourceProviderFactory{
   184  			"aws": testProviderFuncFixed(p),
   185  		},
   186  	})
   187  
   188  	plan, err := ctx.Plan()
   189  	if err != nil {
   190  		t.Fatalf("err: %s", err)
   191  	}
   192  
   193  	actual := strings.TrimSpace(plan.String())
   194  	expected := strings.TrimSpace(testTerraformPlanModuleCycleStr)
   195  	if actual != expected {
   196  		t.Fatalf("bad:\n%s", actual)
   197  	}
   198  }
   199  
   200  func TestContext2Plan_moduleDeadlock(t *testing.T) {
   201  	testCheckDeadlock(t, func() {
   202  		m := testModule(t, "plan-module-deadlock")
   203  		p := testProvider("aws")
   204  		p.DiffFn = testDiffFn
   205  
   206  		ctx := testContext2(t, &ContextOpts{
   207  			Module: m,
   208  			Providers: map[string]ResourceProviderFactory{
   209  				"aws": testProviderFuncFixed(p),
   210  			},
   211  		})
   212  
   213  		plan, err := ctx.Plan()
   214  		if err != nil {
   215  			t.Fatalf("err: %s", err)
   216  		}
   217  
   218  		actual := strings.TrimSpace(plan.String())
   219  		expected := strings.TrimSpace(`
   220  DIFF:
   221  
   222  module.child:
   223    CREATE: aws_instance.foo.0
   224    CREATE: aws_instance.foo.1
   225    CREATE: aws_instance.foo.2
   226  
   227  STATE:
   228  
   229  <no state>
   230  		`)
   231  		if actual != expected {
   232  			t.Fatalf("expected:\n%sgot:\n%s", expected, actual)
   233  		}
   234  	})
   235  }
   236  
   237  func TestContext2Plan_moduleInput(t *testing.T) {
   238  	m := testModule(t, "plan-module-input")
   239  	p := testProvider("aws")
   240  	p.DiffFn = testDiffFn
   241  	ctx := testContext2(t, &ContextOpts{
   242  		Module: m,
   243  		Providers: map[string]ResourceProviderFactory{
   244  			"aws": testProviderFuncFixed(p),
   245  		},
   246  	})
   247  
   248  	plan, err := ctx.Plan()
   249  	if err != nil {
   250  		t.Fatalf("err: %s", err)
   251  	}
   252  
   253  	actual := strings.TrimSpace(plan.String())
   254  	expected := strings.TrimSpace(testTerraformPlanModuleInputStr)
   255  	if actual != expected {
   256  		t.Fatalf("bad:\n%s", actual)
   257  	}
   258  }
   259  
   260  func TestContext2Plan_moduleInputComputed(t *testing.T) {
   261  	m := testModule(t, "plan-module-input-computed")
   262  	p := testProvider("aws")
   263  	p.DiffFn = testDiffFn
   264  	ctx := testContext2(t, &ContextOpts{
   265  		Module: m,
   266  		Providers: map[string]ResourceProviderFactory{
   267  			"aws": testProviderFuncFixed(p),
   268  		},
   269  	})
   270  
   271  	plan, err := ctx.Plan()
   272  	if err != nil {
   273  		t.Fatalf("err: %s", err)
   274  	}
   275  
   276  	actual := strings.TrimSpace(plan.String())
   277  	expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr)
   278  	if actual != expected {
   279  		t.Fatalf("bad:\n%s", actual)
   280  	}
   281  }
   282  
   283  func TestContext2Plan_moduleInputFromVar(t *testing.T) {
   284  	m := testModule(t, "plan-module-input-var")
   285  	p := testProvider("aws")
   286  	p.DiffFn = testDiffFn
   287  	ctx := testContext2(t, &ContextOpts{
   288  		Module: m,
   289  		Providers: map[string]ResourceProviderFactory{
   290  			"aws": testProviderFuncFixed(p),
   291  		},
   292  		Variables: map[string]string{
   293  			"foo": "52",
   294  		},
   295  	})
   296  
   297  	plan, err := ctx.Plan()
   298  	if err != nil {
   299  		t.Fatalf("err: %s", err)
   300  	}
   301  
   302  	actual := strings.TrimSpace(plan.String())
   303  	expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr)
   304  	if actual != expected {
   305  		t.Fatalf("bad:\n%s", actual)
   306  	}
   307  }
   308  
   309  func TestContext2Plan_moduleMultiVar(t *testing.T) {
   310  	m := testModule(t, "plan-module-multi-var")
   311  	p := testProvider("aws")
   312  	p.DiffFn = testDiffFn
   313  	ctx := testContext2(t, &ContextOpts{
   314  		Module: m,
   315  		Providers: map[string]ResourceProviderFactory{
   316  			"aws": testProviderFuncFixed(p),
   317  		},
   318  	})
   319  
   320  	plan, err := ctx.Plan()
   321  	if err != nil {
   322  		t.Fatalf("err: %s", err)
   323  	}
   324  
   325  	actual := strings.TrimSpace(plan.String())
   326  	expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr)
   327  	if actual != expected {
   328  		t.Fatalf("bad:\n%s", actual)
   329  	}
   330  }
   331  
   332  func TestContext2Plan_moduleOrphans(t *testing.T) {
   333  	m := testModule(t, "plan-modules-remove")
   334  	p := testProvider("aws")
   335  	p.DiffFn = testDiffFn
   336  	s := &State{
   337  		Modules: []*ModuleState{
   338  			&ModuleState{
   339  				Path: []string{"root", "child"},
   340  				Resources: map[string]*ResourceState{
   341  					"aws_instance.foo": &ResourceState{
   342  						Type: "aws_instance",
   343  						Primary: &InstanceState{
   344  							ID: "baz",
   345  						},
   346  					},
   347  				},
   348  			},
   349  		},
   350  	}
   351  	ctx := testContext2(t, &ContextOpts{
   352  		Module: m,
   353  		Providers: map[string]ResourceProviderFactory{
   354  			"aws": testProviderFuncFixed(p),
   355  		},
   356  		State: s,
   357  	})
   358  
   359  	plan, err := ctx.Plan()
   360  	if err != nil {
   361  		t.Fatalf("err: %s", err)
   362  	}
   363  
   364  	actual := strings.TrimSpace(plan.String())
   365  	expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr)
   366  	if actual != expected {
   367  		t.Fatalf("bad:\n%s", actual)
   368  	}
   369  }
   370  
   371  // https://github.com/hashicorp/terraform/issues/3114
   372  func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
   373  	m := testModule(t, "plan-modules-remove-provisioners")
   374  	p := testProvider("aws")
   375  	pr := testProvisioner()
   376  	p.DiffFn = testDiffFn
   377  	s := &State{
   378  		Modules: []*ModuleState{
   379  			&ModuleState{
   380  				Path: []string{"root"},
   381  				Resources: map[string]*ResourceState{
   382  					"aws_instance.top": &ResourceState{
   383  						Type: "aws_instance",
   384  						Primary: &InstanceState{
   385  							ID: "top",
   386  						},
   387  					},
   388  				},
   389  			},
   390  			&ModuleState{
   391  				Path: []string{"root", "parent", "childone"},
   392  				Resources: map[string]*ResourceState{
   393  					"aws_instance.foo": &ResourceState{
   394  						Type: "aws_instance",
   395  						Primary: &InstanceState{
   396  							ID: "baz",
   397  						},
   398  					},
   399  				},
   400  			},
   401  			&ModuleState{
   402  				Path: []string{"root", "parent", "childtwo"},
   403  				Resources: map[string]*ResourceState{
   404  					"aws_instance.foo": &ResourceState{
   405  						Type: "aws_instance",
   406  						Primary: &InstanceState{
   407  							ID: "baz",
   408  						},
   409  					},
   410  				},
   411  			},
   412  		},
   413  	}
   414  	ctx := testContext2(t, &ContextOpts{
   415  		Module: m,
   416  		Providers: map[string]ResourceProviderFactory{
   417  			"aws": testProviderFuncFixed(p),
   418  		},
   419  		Provisioners: map[string]ResourceProvisionerFactory{
   420  			"shell": testProvisionerFuncFixed(pr),
   421  		},
   422  		State: s,
   423  	})
   424  
   425  	plan, err := ctx.Plan()
   426  	if err != nil {
   427  		t.Fatalf("err: %s", err)
   428  	}
   429  
   430  	actual := strings.TrimSpace(plan.String())
   431  	expected := strings.TrimSpace(`
   432  DIFF:
   433  
   434  module.parent.childone:
   435    DESTROY: aws_instance.foo
   436  module.parent.childtwo:
   437    DESTROY: aws_instance.foo
   438  
   439  STATE:
   440  
   441  aws_instance.top:
   442    ID = top
   443  
   444  module.parent.childone:
   445    aws_instance.foo:
   446      ID = baz
   447  module.parent.childtwo:
   448    aws_instance.foo:
   449      ID = baz
   450  	`)
   451  	if actual != expected {
   452  		t.Fatalf("bad:\n%s", actual)
   453  	}
   454  }
   455  
   456  func TestContext2Plan_moduleProviderInherit(t *testing.T) {
   457  	var l sync.Mutex
   458  	var calls []string
   459  
   460  	m := testModule(t, "plan-module-provider-inherit")
   461  	ctx := testContext2(t, &ContextOpts{
   462  		Module: m,
   463  		Providers: map[string]ResourceProviderFactory{
   464  			"aws": func() (ResourceProvider, error) {
   465  				l.Lock()
   466  				defer l.Unlock()
   467  
   468  				p := testProvider("aws")
   469  				p.ConfigureFn = func(c *ResourceConfig) error {
   470  					if v, ok := c.Get("from"); !ok || v.(string) != "root" {
   471  						return fmt.Errorf("bad")
   472  					}
   473  
   474  					return nil
   475  				}
   476  				p.DiffFn = func(
   477  					info *InstanceInfo,
   478  					state *InstanceState,
   479  					c *ResourceConfig) (*InstanceDiff, error) {
   480  					v, _ := c.Get("from")
   481  					calls = append(calls, v.(string))
   482  					return testDiffFn(info, state, c)
   483  				}
   484  				return p, nil
   485  			},
   486  		},
   487  	})
   488  
   489  	_, err := ctx.Plan()
   490  	if err != nil {
   491  		t.Fatalf("err: %s", err)
   492  	}
   493  
   494  	actual := calls
   495  	sort.Strings(actual)
   496  	expected := []string{"child", "root"}
   497  	if !reflect.DeepEqual(actual, expected) {
   498  		t.Fatalf("bad: %#v", actual)
   499  	}
   500  }
   501  
   502  func TestContext2Plan_moduleProviderDefaults(t *testing.T) {
   503  	var l sync.Mutex
   504  	var calls []string
   505  	toCount := 0
   506  
   507  	m := testModule(t, "plan-module-provider-defaults")
   508  	ctx := testContext2(t, &ContextOpts{
   509  		Module: m,
   510  		Providers: map[string]ResourceProviderFactory{
   511  			"aws": func() (ResourceProvider, error) {
   512  				l.Lock()
   513  				defer l.Unlock()
   514  
   515  				p := testProvider("aws")
   516  				p.ConfigureFn = func(c *ResourceConfig) error {
   517  					if v, ok := c.Get("from"); !ok || v.(string) != "root" {
   518  						return fmt.Errorf("bad")
   519  					}
   520  					if v, ok := c.Get("to"); ok && v.(string) == "child" {
   521  						toCount++
   522  					}
   523  
   524  					return nil
   525  				}
   526  				p.DiffFn = func(
   527  					info *InstanceInfo,
   528  					state *InstanceState,
   529  					c *ResourceConfig) (*InstanceDiff, error) {
   530  					v, _ := c.Get("from")
   531  					calls = append(calls, v.(string))
   532  					return testDiffFn(info, state, c)
   533  				}
   534  				return p, nil
   535  			},
   536  		},
   537  	})
   538  
   539  	_, err := ctx.Plan()
   540  	if err != nil {
   541  		t.Fatalf("err: %s", err)
   542  	}
   543  
   544  	if toCount != 1 {
   545  		t.Fatalf(
   546  			"provider in child didn't set proper config\n\n"+
   547  				"toCount: %d", toCount)
   548  	}
   549  
   550  	actual := calls
   551  	sort.Strings(actual)
   552  	expected := []string{"child", "root"}
   553  	if !reflect.DeepEqual(actual, expected) {
   554  		t.Fatalf("bad: %#v", actual)
   555  	}
   556  }
   557  
   558  func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
   559  	var l sync.Mutex
   560  	var calls []string
   561  
   562  	m := testModule(t, "plan-module-provider-defaults-var")
   563  	ctx := testContext2(t, &ContextOpts{
   564  		Module: m,
   565  		Providers: map[string]ResourceProviderFactory{
   566  			"aws": func() (ResourceProvider, error) {
   567  				l.Lock()
   568  				defer l.Unlock()
   569  
   570  				p := testProvider("aws")
   571  				p.ConfigureFn = func(c *ResourceConfig) error {
   572  					var buf bytes.Buffer
   573  					if v, ok := c.Get("from"); ok {
   574  						buf.WriteString(v.(string) + "\n")
   575  					}
   576  					if v, ok := c.Get("to"); ok {
   577  						buf.WriteString(v.(string) + "\n")
   578  					}
   579  
   580  					calls = append(calls, buf.String())
   581  					return nil
   582  				}
   583  				p.DiffFn = testDiffFn
   584  				return p, nil
   585  			},
   586  		},
   587  		Variables: map[string]string{
   588  			"foo": "root",
   589  		},
   590  	})
   591  
   592  	_, err := ctx.Plan()
   593  	if err != nil {
   594  		t.Fatalf("err: %s", err)
   595  	}
   596  
   597  	expected := []string{
   598  		"root\n",
   599  		"root\nchild\n",
   600  	}
   601  	if !reflect.DeepEqual(calls, expected) {
   602  		t.Fatalf("BAD: %#v", calls)
   603  	}
   604  }
   605  
   606  func TestContext2Plan_moduleVar(t *testing.T) {
   607  	m := testModule(t, "plan-module-var")
   608  	p := testProvider("aws")
   609  	p.DiffFn = testDiffFn
   610  	ctx := testContext2(t, &ContextOpts{
   611  		Module: m,
   612  		Providers: map[string]ResourceProviderFactory{
   613  			"aws": testProviderFuncFixed(p),
   614  		},
   615  	})
   616  
   617  	plan, err := ctx.Plan()
   618  	if err != nil {
   619  		t.Fatalf("err: %s", err)
   620  	}
   621  
   622  	actual := strings.TrimSpace(plan.String())
   623  	expected := strings.TrimSpace(testTerraformPlanModuleVarStr)
   624  	if actual != expected {
   625  		t.Fatalf("bad:\n%s", actual)
   626  	}
   627  }
   628  
   629  func TestContext2Plan_moduleVarWrongType(t *testing.T) {
   630  	m := testModule(t, "plan-module-wrong-var-type")
   631  	p := testProvider("aws")
   632  	p.DiffFn = testDiffFn
   633  	ctx := testContext2(t, &ContextOpts{
   634  		Module: m,
   635  		Providers: map[string]ResourceProviderFactory{
   636  			"aws": testProviderFuncFixed(p),
   637  		},
   638  	})
   639  
   640  	_, err := ctx.Plan()
   641  	if err == nil {
   642  		t.Fatalf("should error")
   643  	}
   644  }
   645  
   646  func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) {
   647  	m := testModule(t, "plan-module-wrong-var-type-nested")
   648  	p := testProvider("aws")
   649  	p.DiffFn = testDiffFn
   650  	ctx := testContext2(t, &ContextOpts{
   651  		Module: m,
   652  		Providers: map[string]ResourceProviderFactory{
   653  			"aws": testProviderFuncFixed(p),
   654  		},
   655  	})
   656  
   657  	_, err := ctx.Plan()
   658  	if err == nil {
   659  		t.Fatalf("should error")
   660  	}
   661  }
   662  
   663  func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) {
   664  	m := testModule(t, "plan-module-var-with-default-value")
   665  	p := testProvider("null")
   666  	p.DiffFn = testDiffFn
   667  	ctx := testContext2(t, &ContextOpts{
   668  		Module: m,
   669  		Providers: map[string]ResourceProviderFactory{
   670  			"null": testProviderFuncFixed(p),
   671  		},
   672  	})
   673  
   674  	_, err := ctx.Plan()
   675  	if err != nil {
   676  		t.Fatalf("bad: %s", err)
   677  	}
   678  }
   679  
   680  func TestContext2Plan_moduleVarComputed(t *testing.T) {
   681  	m := testModule(t, "plan-module-var-computed")
   682  	p := testProvider("aws")
   683  	p.DiffFn = testDiffFn
   684  	ctx := testContext2(t, &ContextOpts{
   685  		Module: m,
   686  		Providers: map[string]ResourceProviderFactory{
   687  			"aws": testProviderFuncFixed(p),
   688  		},
   689  	})
   690  
   691  	plan, err := ctx.Plan()
   692  	if err != nil {
   693  		t.Fatalf("err: %s", err)
   694  	}
   695  
   696  	actual := strings.TrimSpace(plan.String())
   697  	expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr)
   698  	if actual != expected {
   699  		t.Fatalf("bad:\n%s", actual)
   700  	}
   701  }
   702  
   703  func TestContext2Plan_nil(t *testing.T) {
   704  	m := testModule(t, "plan-nil")
   705  	p := testProvider("aws")
   706  	p.DiffFn = testDiffFn
   707  	ctx := testContext2(t, &ContextOpts{
   708  		Module: m,
   709  		Providers: map[string]ResourceProviderFactory{
   710  			"aws": testProviderFuncFixed(p),
   711  		},
   712  		State: &State{
   713  			Modules: []*ModuleState{
   714  				&ModuleState{
   715  					Path: rootModulePath,
   716  					Resources: map[string]*ResourceState{
   717  						"aws_instance.foo": &ResourceState{
   718  							Type: "aws_instance",
   719  							Primary: &InstanceState{
   720  								ID: "bar",
   721  							},
   722  						},
   723  					},
   724  				},
   725  			},
   726  		},
   727  	})
   728  
   729  	plan, err := ctx.Plan()
   730  	if err != nil {
   731  		t.Fatalf("err: %s", err)
   732  	}
   733  	if len(plan.Diff.RootModule().Resources) != 0 {
   734  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
   735  	}
   736  }
   737  
   738  func TestContext2Plan_preventDestroy_bad(t *testing.T) {
   739  	m := testModule(t, "plan-prevent-destroy-bad")
   740  	p := testProvider("aws")
   741  	p.DiffFn = testDiffFn
   742  	ctx := testContext2(t, &ContextOpts{
   743  		Module: m,
   744  		Providers: map[string]ResourceProviderFactory{
   745  			"aws": testProviderFuncFixed(p),
   746  		},
   747  		State: &State{
   748  			Modules: []*ModuleState{
   749  				&ModuleState{
   750  					Path: rootModulePath,
   751  					Resources: map[string]*ResourceState{
   752  						"aws_instance.foo": &ResourceState{
   753  							Type: "aws_instance",
   754  							Primary: &InstanceState{
   755  								ID: "i-abc123",
   756  							},
   757  						},
   758  					},
   759  				},
   760  			},
   761  		},
   762  	})
   763  
   764  	plan, err := ctx.Plan()
   765  
   766  	expectedErr := "aws_instance.foo: the plan would destroy"
   767  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
   768  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
   769  			expectedErr, err, plan)
   770  	}
   771  }
   772  
   773  func TestContext2Plan_preventDestroy_good(t *testing.T) {
   774  	m := testModule(t, "plan-prevent-destroy-good")
   775  	p := testProvider("aws")
   776  	p.DiffFn = testDiffFn
   777  	ctx := testContext2(t, &ContextOpts{
   778  		Module: m,
   779  		Providers: map[string]ResourceProviderFactory{
   780  			"aws": testProviderFuncFixed(p),
   781  		},
   782  		State: &State{
   783  			Modules: []*ModuleState{
   784  				&ModuleState{
   785  					Path: rootModulePath,
   786  					Resources: map[string]*ResourceState{
   787  						"aws_instance.foo": &ResourceState{
   788  							Type: "aws_instance",
   789  							Primary: &InstanceState{
   790  								ID: "i-abc123",
   791  							},
   792  						},
   793  					},
   794  				},
   795  			},
   796  		},
   797  	})
   798  
   799  	plan, err := ctx.Plan()
   800  	if err != nil {
   801  		t.Fatalf("err: %s", err)
   802  	}
   803  	if !plan.Diff.Empty() {
   804  		t.Fatalf("Expected empty plan, got %s", plan.String())
   805  	}
   806  }
   807  
   808  func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
   809  	m := testModule(t, "plan-prevent-destroy-good")
   810  	p := testProvider("aws")
   811  	p.DiffFn = testDiffFn
   812  	ctx := testContext2(t, &ContextOpts{
   813  		Module: m,
   814  		Providers: map[string]ResourceProviderFactory{
   815  			"aws": testProviderFuncFixed(p),
   816  		},
   817  		State: &State{
   818  			Modules: []*ModuleState{
   819  				&ModuleState{
   820  					Path: rootModulePath,
   821  					Resources: map[string]*ResourceState{
   822  						"aws_instance.foo": &ResourceState{
   823  							Type: "aws_instance",
   824  							Primary: &InstanceState{
   825  								ID: "i-abc123",
   826  							},
   827  						},
   828  					},
   829  				},
   830  			},
   831  		},
   832  		Destroy: true,
   833  	})
   834  
   835  	plan, err := ctx.Plan()
   836  
   837  	expectedErr := "aws_instance.foo: the plan would destroy"
   838  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
   839  		t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
   840  			expectedErr, err, plan)
   841  	}
   842  }
   843  
   844  func TestContext2Plan_computed(t *testing.T) {
   845  	m := testModule(t, "plan-computed")
   846  	p := testProvider("aws")
   847  	p.DiffFn = testDiffFn
   848  	ctx := testContext2(t, &ContextOpts{
   849  		Module: m,
   850  		Providers: map[string]ResourceProviderFactory{
   851  			"aws": testProviderFuncFixed(p),
   852  		},
   853  	})
   854  
   855  	plan, err := ctx.Plan()
   856  	if err != nil {
   857  		t.Fatalf("err: %s", err)
   858  	}
   859  
   860  	actual := strings.TrimSpace(plan.String())
   861  	expected := strings.TrimSpace(testTerraformPlanComputedStr)
   862  	if actual != expected {
   863  		t.Fatalf("bad:\n%s", actual)
   864  	}
   865  }
   866  
   867  func TestContext2Plan_computedList(t *testing.T) {
   868  	m := testModule(t, "plan-computed-list")
   869  	p := testProvider("aws")
   870  	p.DiffFn = testDiffFn
   871  	ctx := testContext2(t, &ContextOpts{
   872  		Module: m,
   873  		Providers: map[string]ResourceProviderFactory{
   874  			"aws": testProviderFuncFixed(p),
   875  		},
   876  	})
   877  
   878  	plan, err := ctx.Plan()
   879  	if err != nil {
   880  		t.Fatalf("err: %s", err)
   881  	}
   882  
   883  	actual := strings.TrimSpace(plan.String())
   884  	expected := strings.TrimSpace(testTerraformPlanComputedListStr)
   885  	if actual != expected {
   886  		t.Fatalf("bad:\n%s", actual)
   887  	}
   888  }
   889  
   890  func TestContext2Plan_count(t *testing.T) {
   891  	m := testModule(t, "plan-count")
   892  	p := testProvider("aws")
   893  	p.DiffFn = testDiffFn
   894  	ctx := testContext2(t, &ContextOpts{
   895  		Module: m,
   896  		Providers: map[string]ResourceProviderFactory{
   897  			"aws": testProviderFuncFixed(p),
   898  		},
   899  	})
   900  
   901  	plan, err := ctx.Plan()
   902  	if err != nil {
   903  		t.Fatalf("err: %s", err)
   904  	}
   905  
   906  	if len(plan.Diff.RootModule().Resources) < 6 {
   907  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
   908  	}
   909  
   910  	actual := strings.TrimSpace(plan.String())
   911  	expected := strings.TrimSpace(testTerraformPlanCountStr)
   912  	if actual != expected {
   913  		t.Fatalf("bad:\n%s", actual)
   914  	}
   915  }
   916  
   917  func TestContext2Plan_countComputed(t *testing.T) {
   918  	m := testModule(t, "plan-count-computed")
   919  	p := testProvider("aws")
   920  	p.DiffFn = testDiffFn
   921  	ctx := testContext2(t, &ContextOpts{
   922  		Module: m,
   923  		Providers: map[string]ResourceProviderFactory{
   924  			"aws": testProviderFuncFixed(p),
   925  		},
   926  	})
   927  
   928  	_, err := ctx.Plan()
   929  	if err == nil {
   930  		t.Fatal("should error")
   931  	}
   932  }
   933  
   934  func TestContext2Plan_countIndex(t *testing.T) {
   935  	m := testModule(t, "plan-count-index")
   936  	p := testProvider("aws")
   937  	p.DiffFn = testDiffFn
   938  	ctx := testContext2(t, &ContextOpts{
   939  		Module: m,
   940  		Providers: map[string]ResourceProviderFactory{
   941  			"aws": testProviderFuncFixed(p),
   942  		},
   943  	})
   944  
   945  	plan, err := ctx.Plan()
   946  	if err != nil {
   947  		t.Fatalf("err: %s", err)
   948  	}
   949  
   950  	actual := strings.TrimSpace(plan.String())
   951  	expected := strings.TrimSpace(testTerraformPlanCountIndexStr)
   952  	if actual != expected {
   953  		t.Fatalf("bad:\n%s", actual)
   954  	}
   955  }
   956  
   957  func TestContext2Plan_countIndexZero(t *testing.T) {
   958  	m := testModule(t, "plan-count-index-zero")
   959  	p := testProvider("aws")
   960  	p.DiffFn = testDiffFn
   961  	ctx := testContext2(t, &ContextOpts{
   962  		Module: m,
   963  		Providers: map[string]ResourceProviderFactory{
   964  			"aws": testProviderFuncFixed(p),
   965  		},
   966  	})
   967  
   968  	plan, err := ctx.Plan()
   969  	if err != nil {
   970  		t.Fatalf("err: %s", err)
   971  	}
   972  
   973  	actual := strings.TrimSpace(plan.String())
   974  	expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr)
   975  	if actual != expected {
   976  		t.Fatalf("bad:\n%s", actual)
   977  	}
   978  }
   979  
   980  func TestContext2Plan_countVar(t *testing.T) {
   981  	m := testModule(t, "plan-count-var")
   982  	p := testProvider("aws")
   983  	p.DiffFn = testDiffFn
   984  	ctx := testContext2(t, &ContextOpts{
   985  		Module: m,
   986  		Providers: map[string]ResourceProviderFactory{
   987  			"aws": testProviderFuncFixed(p),
   988  		},
   989  		Variables: map[string]string{
   990  			"count": "3",
   991  		},
   992  	})
   993  
   994  	plan, err := ctx.Plan()
   995  	if err != nil {
   996  		t.Fatalf("err: %s", err)
   997  	}
   998  
   999  	actual := strings.TrimSpace(plan.String())
  1000  	expected := strings.TrimSpace(testTerraformPlanCountVarStr)
  1001  	if actual != expected {
  1002  		t.Fatalf("bad:\n%s", actual)
  1003  	}
  1004  }
  1005  
  1006  func TestContext2Plan_countZero(t *testing.T) {
  1007  	m := testModule(t, "plan-count-zero")
  1008  	p := testProvider("aws")
  1009  	p.DiffFn = testDiffFn
  1010  	ctx := testContext2(t, &ContextOpts{
  1011  		Module: m,
  1012  		Providers: map[string]ResourceProviderFactory{
  1013  			"aws": testProviderFuncFixed(p),
  1014  		},
  1015  	})
  1016  
  1017  	plan, err := ctx.Plan()
  1018  	if err != nil {
  1019  		t.Fatalf("err: %s", err)
  1020  	}
  1021  
  1022  	actual := strings.TrimSpace(plan.String())
  1023  	expected := strings.TrimSpace(testTerraformPlanCountZeroStr)
  1024  	if actual != expected {
  1025  		t.Fatalf("bad:\n%s", actual)
  1026  	}
  1027  }
  1028  
  1029  func TestContext2Plan_countOneIndex(t *testing.T) {
  1030  	m := testModule(t, "plan-count-one-index")
  1031  	p := testProvider("aws")
  1032  	p.DiffFn = testDiffFn
  1033  	ctx := testContext2(t, &ContextOpts{
  1034  		Module: m,
  1035  		Providers: map[string]ResourceProviderFactory{
  1036  			"aws": testProviderFuncFixed(p),
  1037  		},
  1038  	})
  1039  
  1040  	plan, err := ctx.Plan()
  1041  	if err != nil {
  1042  		t.Fatalf("err: %s", err)
  1043  	}
  1044  
  1045  	actual := strings.TrimSpace(plan.String())
  1046  	expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr)
  1047  	if actual != expected {
  1048  		t.Fatalf("bad:\n%s", actual)
  1049  	}
  1050  }
  1051  
  1052  func TestContext2Plan_countDecreaseToOne(t *testing.T) {
  1053  	m := testModule(t, "plan-count-dec")
  1054  	p := testProvider("aws")
  1055  	p.DiffFn = testDiffFn
  1056  	s := &State{
  1057  		Modules: []*ModuleState{
  1058  			&ModuleState{
  1059  				Path: rootModulePath,
  1060  				Resources: map[string]*ResourceState{
  1061  					"aws_instance.foo.0": &ResourceState{
  1062  						Type: "aws_instance",
  1063  						Primary: &InstanceState{
  1064  							ID: "bar",
  1065  							Attributes: map[string]string{
  1066  								"foo":  "foo",
  1067  								"type": "aws_instance",
  1068  							},
  1069  						},
  1070  					},
  1071  					"aws_instance.foo.1": &ResourceState{
  1072  						Type: "aws_instance",
  1073  						Primary: &InstanceState{
  1074  							ID: "bar",
  1075  						},
  1076  					},
  1077  					"aws_instance.foo.2": &ResourceState{
  1078  						Type: "aws_instance",
  1079  						Primary: &InstanceState{
  1080  							ID: "bar",
  1081  						},
  1082  					},
  1083  				},
  1084  			},
  1085  		},
  1086  	}
  1087  	ctx := testContext2(t, &ContextOpts{
  1088  		Module: m,
  1089  		Providers: map[string]ResourceProviderFactory{
  1090  			"aws": testProviderFuncFixed(p),
  1091  		},
  1092  		State: s,
  1093  	})
  1094  
  1095  	plan, err := ctx.Plan()
  1096  	if err != nil {
  1097  		t.Fatalf("err: %s", err)
  1098  	}
  1099  
  1100  	actual := strings.TrimSpace(plan.String())
  1101  	expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr)
  1102  	if actual != expected {
  1103  		t.Fatalf("bad:\n%s", actual)
  1104  	}
  1105  }
  1106  
  1107  func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
  1108  	m := testModule(t, "plan-count-inc")
  1109  	p := testProvider("aws")
  1110  	p.DiffFn = testDiffFn
  1111  	s := &State{
  1112  		Modules: []*ModuleState{
  1113  			&ModuleState{
  1114  				Path: rootModulePath,
  1115  				Resources: map[string]*ResourceState{
  1116  					"aws_instance.foo": &ResourceState{
  1117  						Type: "aws_instance",
  1118  						Primary: &InstanceState{
  1119  							ID: "bar",
  1120  							Attributes: map[string]string{
  1121  								"foo":  "foo",
  1122  								"type": "aws_instance",
  1123  							},
  1124  						},
  1125  					},
  1126  				},
  1127  			},
  1128  		},
  1129  	}
  1130  	ctx := testContext2(t, &ContextOpts{
  1131  		Module: m,
  1132  		Providers: map[string]ResourceProviderFactory{
  1133  			"aws": testProviderFuncFixed(p),
  1134  		},
  1135  		State: s,
  1136  	})
  1137  
  1138  	plan, err := ctx.Plan()
  1139  	if err != nil {
  1140  		t.Fatalf("err: %s", err)
  1141  	}
  1142  
  1143  	actual := strings.TrimSpace(plan.String())
  1144  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr)
  1145  	if actual != expected {
  1146  		t.Fatalf("bad:\n%s", actual)
  1147  	}
  1148  }
  1149  
  1150  func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
  1151  	m := testModule(t, "plan-count-inc")
  1152  	p := testProvider("aws")
  1153  	p.DiffFn = testDiffFn
  1154  	s := &State{
  1155  		Modules: []*ModuleState{
  1156  			&ModuleState{
  1157  				Path: rootModulePath,
  1158  				Resources: map[string]*ResourceState{
  1159  					"aws_instance.foo.0": &ResourceState{
  1160  						Type: "aws_instance",
  1161  						Primary: &InstanceState{
  1162  							ID: "bar",
  1163  							Attributes: map[string]string{
  1164  								"foo":  "foo",
  1165  								"type": "aws_instance",
  1166  							},
  1167  						},
  1168  					},
  1169  				},
  1170  			},
  1171  		},
  1172  	}
  1173  	ctx := testContext2(t, &ContextOpts{
  1174  		Module: m,
  1175  		Providers: map[string]ResourceProviderFactory{
  1176  			"aws": testProviderFuncFixed(p),
  1177  		},
  1178  		State: s,
  1179  	})
  1180  
  1181  	plan, err := ctx.Plan()
  1182  	if err != nil {
  1183  		t.Fatalf("err: %s", err)
  1184  	}
  1185  
  1186  	actual := strings.TrimSpace(plan.String())
  1187  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr)
  1188  	if actual != expected {
  1189  		t.Fatalf("bad:\n%s", actual)
  1190  	}
  1191  }
  1192  
  1193  // https://github.com/PeoplePerHour/terraform/pull/11
  1194  //
  1195  // This tests a case where both a "resource" and "resource.0" are in
  1196  // the state file, which apparently is a reasonable backwards compatibility
  1197  // concern found in the above 3rd party repo.
  1198  func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
  1199  	m := testModule(t, "plan-count-inc")
  1200  	p := testProvider("aws")
  1201  	p.DiffFn = testDiffFn
  1202  	s := &State{
  1203  		Modules: []*ModuleState{
  1204  			&ModuleState{
  1205  				Path: rootModulePath,
  1206  				Resources: map[string]*ResourceState{
  1207  					"aws_instance.foo": &ResourceState{
  1208  						Type: "aws_instance",
  1209  						Primary: &InstanceState{
  1210  							ID: "bar",
  1211  							Attributes: map[string]string{
  1212  								"foo":  "foo",
  1213  								"type": "aws_instance",
  1214  							},
  1215  						},
  1216  					},
  1217  					"aws_instance.foo.0": &ResourceState{
  1218  						Type: "aws_instance",
  1219  						Primary: &InstanceState{
  1220  							ID: "bar",
  1221  							Attributes: map[string]string{
  1222  								"foo":  "foo",
  1223  								"type": "aws_instance",
  1224  							},
  1225  						},
  1226  					},
  1227  				},
  1228  			},
  1229  		},
  1230  	}
  1231  	ctx := testContext2(t, &ContextOpts{
  1232  		Module: m,
  1233  		Providers: map[string]ResourceProviderFactory{
  1234  			"aws": testProviderFuncFixed(p),
  1235  		},
  1236  		State: s,
  1237  	})
  1238  
  1239  	plan, err := ctx.Plan()
  1240  	if err != nil {
  1241  		t.Fatalf("err: %s", err)
  1242  	}
  1243  
  1244  	actual := strings.TrimSpace(plan.String())
  1245  	expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr)
  1246  	if actual != expected {
  1247  		t.Fatalf("bad:\n%s", actual)
  1248  	}
  1249  }
  1250  
  1251  func TestContext2Plan_destroy(t *testing.T) {
  1252  	m := testModule(t, "plan-destroy")
  1253  	p := testProvider("aws")
  1254  	p.DiffFn = testDiffFn
  1255  	s := &State{
  1256  		Modules: []*ModuleState{
  1257  			&ModuleState{
  1258  				Path: rootModulePath,
  1259  				Resources: map[string]*ResourceState{
  1260  					"aws_instance.one": &ResourceState{
  1261  						Type: "aws_instance",
  1262  						Primary: &InstanceState{
  1263  							ID: "bar",
  1264  						},
  1265  					},
  1266  					"aws_instance.two": &ResourceState{
  1267  						Type: "aws_instance",
  1268  						Primary: &InstanceState{
  1269  							ID: "baz",
  1270  						},
  1271  					},
  1272  				},
  1273  			},
  1274  		},
  1275  	}
  1276  	ctx := testContext2(t, &ContextOpts{
  1277  		Module: m,
  1278  		Providers: map[string]ResourceProviderFactory{
  1279  			"aws": testProviderFuncFixed(p),
  1280  		},
  1281  		State:   s,
  1282  		Destroy: true,
  1283  	})
  1284  
  1285  	plan, err := ctx.Plan()
  1286  	if err != nil {
  1287  		t.Fatalf("err: %s", err)
  1288  	}
  1289  
  1290  	if len(plan.Diff.RootModule().Resources) != 2 {
  1291  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1292  	}
  1293  
  1294  	actual := strings.TrimSpace(plan.String())
  1295  	expected := strings.TrimSpace(testTerraformPlanDestroyStr)
  1296  	if actual != expected {
  1297  		t.Fatalf("bad:\n%s", actual)
  1298  	}
  1299  }
  1300  
  1301  func TestContext2Plan_moduleDestroy(t *testing.T) {
  1302  	m := testModule(t, "plan-module-destroy")
  1303  	p := testProvider("aws")
  1304  	p.DiffFn = testDiffFn
  1305  	s := &State{
  1306  		Modules: []*ModuleState{
  1307  			&ModuleState{
  1308  				Path: rootModulePath,
  1309  				Resources: map[string]*ResourceState{
  1310  					"aws_instance.foo": &ResourceState{
  1311  						Type: "aws_instance",
  1312  						Primary: &InstanceState{
  1313  							ID: "bar",
  1314  						},
  1315  					},
  1316  				},
  1317  			},
  1318  			&ModuleState{
  1319  				Path: []string{"root", "child"},
  1320  				Resources: map[string]*ResourceState{
  1321  					"aws_instance.foo": &ResourceState{
  1322  						Type: "aws_instance",
  1323  						Primary: &InstanceState{
  1324  							ID: "bar",
  1325  						},
  1326  					},
  1327  				},
  1328  			},
  1329  		},
  1330  	}
  1331  	ctx := testContext2(t, &ContextOpts{
  1332  		Module: m,
  1333  		Providers: map[string]ResourceProviderFactory{
  1334  			"aws": testProviderFuncFixed(p),
  1335  		},
  1336  		State:   s,
  1337  		Destroy: true,
  1338  	})
  1339  
  1340  	plan, err := ctx.Plan()
  1341  	if err != nil {
  1342  		t.Fatalf("err: %s", err)
  1343  	}
  1344  
  1345  	actual := strings.TrimSpace(plan.String())
  1346  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr)
  1347  	if actual != expected {
  1348  		t.Fatalf("bad:\n%s", actual)
  1349  	}
  1350  }
  1351  
  1352  // GH-1835
  1353  func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
  1354  	m := testModule(t, "plan-module-destroy-gh-1835")
  1355  	p := testProvider("aws")
  1356  	p.DiffFn = testDiffFn
  1357  	s := &State{
  1358  		Modules: []*ModuleState{
  1359  			&ModuleState{
  1360  				Path: []string{"root", "a_module"},
  1361  				Resources: map[string]*ResourceState{
  1362  					"aws_instance.a": &ResourceState{
  1363  						Type: "aws_instance",
  1364  						Primary: &InstanceState{
  1365  							ID: "a",
  1366  						},
  1367  					},
  1368  				},
  1369  			},
  1370  			&ModuleState{
  1371  				Path: []string{"root", "b_module"},
  1372  				Resources: map[string]*ResourceState{
  1373  					"aws_instance.b": &ResourceState{
  1374  						Type: "aws_instance",
  1375  						Primary: &InstanceState{
  1376  							ID: "b",
  1377  						},
  1378  					},
  1379  				},
  1380  			},
  1381  		},
  1382  	}
  1383  	ctx := testContext2(t, &ContextOpts{
  1384  		Module: m,
  1385  		Providers: map[string]ResourceProviderFactory{
  1386  			"aws": testProviderFuncFixed(p),
  1387  		},
  1388  		State:   s,
  1389  		Destroy: true,
  1390  	})
  1391  
  1392  	plan, err := ctx.Plan()
  1393  	if err != nil {
  1394  		t.Fatalf("err: %s", err)
  1395  	}
  1396  
  1397  	actual := strings.TrimSpace(plan.String())
  1398  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr)
  1399  	if actual != expected {
  1400  		t.Fatalf("bad:\n%s", actual)
  1401  	}
  1402  }
  1403  
  1404  func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
  1405  	m := testModule(t, "plan-module-destroy-multivar")
  1406  	p := testProvider("aws")
  1407  	p.DiffFn = testDiffFn
  1408  	s := &State{
  1409  		Modules: []*ModuleState{
  1410  			&ModuleState{
  1411  				Path:      rootModulePath,
  1412  				Resources: map[string]*ResourceState{},
  1413  			},
  1414  			&ModuleState{
  1415  				Path: []string{"root", "child"},
  1416  				Resources: map[string]*ResourceState{
  1417  					"aws_instance.foo.0": &ResourceState{
  1418  						Type: "aws_instance",
  1419  						Primary: &InstanceState{
  1420  							ID: "bar0",
  1421  						},
  1422  					},
  1423  					"aws_instance.foo.1": &ResourceState{
  1424  						Type: "aws_instance",
  1425  						Primary: &InstanceState{
  1426  							ID: "bar1",
  1427  						},
  1428  					},
  1429  				},
  1430  			},
  1431  		},
  1432  	}
  1433  	ctx := testContext2(t, &ContextOpts{
  1434  		Module: m,
  1435  		Providers: map[string]ResourceProviderFactory{
  1436  			"aws": testProviderFuncFixed(p),
  1437  		},
  1438  		State:   s,
  1439  		Destroy: true,
  1440  	})
  1441  
  1442  	plan, err := ctx.Plan()
  1443  	if err != nil {
  1444  		t.Fatalf("err: %s", err)
  1445  	}
  1446  
  1447  	actual := strings.TrimSpace(plan.String())
  1448  	expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr)
  1449  	if actual != expected {
  1450  		t.Fatalf("bad:\n%s", actual)
  1451  	}
  1452  }
  1453  
  1454  func TestContext2Plan_pathVar(t *testing.T) {
  1455  	cwd, err := os.Getwd()
  1456  	if err != nil {
  1457  		t.Fatalf("err: %s", err)
  1458  	}
  1459  
  1460  	m := testModule(t, "plan-path-var")
  1461  	p := testProvider("aws")
  1462  	p.DiffFn = testDiffFn
  1463  	ctx := testContext2(t, &ContextOpts{
  1464  		Module: m,
  1465  		Providers: map[string]ResourceProviderFactory{
  1466  			"aws": testProviderFuncFixed(p),
  1467  		},
  1468  	})
  1469  
  1470  	plan, err := ctx.Plan()
  1471  	if err != nil {
  1472  		t.Fatalf("err: %s", err)
  1473  	}
  1474  
  1475  	actual := strings.TrimSpace(plan.String())
  1476  	expected := strings.TrimSpace(testTerraformPlanPathVarStr)
  1477  
  1478  	// Warning: this ordering REALLY matters for this test. The
  1479  	// order is: cwd, module, root.
  1480  	expected = fmt.Sprintf(
  1481  		expected,
  1482  		cwd,
  1483  		m.Config().Dir,
  1484  		m.Config().Dir)
  1485  
  1486  	if actual != expected {
  1487  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1488  	}
  1489  }
  1490  
  1491  func TestContext2Plan_diffVar(t *testing.T) {
  1492  	m := testModule(t, "plan-diffvar")
  1493  	p := testProvider("aws")
  1494  	s := &State{
  1495  		Modules: []*ModuleState{
  1496  			&ModuleState{
  1497  				Path: rootModulePath,
  1498  				Resources: map[string]*ResourceState{
  1499  					"aws_instance.foo": &ResourceState{
  1500  						Primary: &InstanceState{
  1501  							ID: "bar",
  1502  							Attributes: map[string]string{
  1503  								"num": "2",
  1504  							},
  1505  						},
  1506  					},
  1507  				},
  1508  			},
  1509  		},
  1510  	}
  1511  	ctx := testContext2(t, &ContextOpts{
  1512  		Module: m,
  1513  		Providers: map[string]ResourceProviderFactory{
  1514  			"aws": testProviderFuncFixed(p),
  1515  		},
  1516  		State: s,
  1517  	})
  1518  
  1519  	p.DiffFn = func(
  1520  		info *InstanceInfo,
  1521  		s *InstanceState,
  1522  		c *ResourceConfig) (*InstanceDiff, error) {
  1523  		if s.ID != "bar" {
  1524  			return testDiffFn(info, s, c)
  1525  		}
  1526  
  1527  		return &InstanceDiff{
  1528  			Attributes: map[string]*ResourceAttrDiff{
  1529  				"num": &ResourceAttrDiff{
  1530  					Old: "2",
  1531  					New: "3",
  1532  				},
  1533  			},
  1534  		}, nil
  1535  	}
  1536  
  1537  	plan, err := ctx.Plan()
  1538  	if err != nil {
  1539  		t.Fatalf("err: %s", err)
  1540  	}
  1541  
  1542  	actual := strings.TrimSpace(plan.String())
  1543  	expected := strings.TrimSpace(testTerraformPlanDiffVarStr)
  1544  	if actual != expected {
  1545  		t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected)
  1546  	}
  1547  }
  1548  
  1549  func TestContext2Plan_hook(t *testing.T) {
  1550  	m := testModule(t, "plan-good")
  1551  	h := new(MockHook)
  1552  	p := testProvider("aws")
  1553  	p.DiffFn = testDiffFn
  1554  	ctx := testContext2(t, &ContextOpts{
  1555  		Module: m,
  1556  		Hooks:  []Hook{h},
  1557  		Providers: map[string]ResourceProviderFactory{
  1558  			"aws": testProviderFuncFixed(p),
  1559  		},
  1560  	})
  1561  
  1562  	_, err := ctx.Plan()
  1563  	if err != nil {
  1564  		t.Fatalf("err: %s", err)
  1565  	}
  1566  
  1567  	if !h.PreDiffCalled {
  1568  		t.Fatal("should be called")
  1569  	}
  1570  	if !h.PostDiffCalled {
  1571  		t.Fatal("should be called")
  1572  	}
  1573  }
  1574  
  1575  func TestContext2Plan_orphan(t *testing.T) {
  1576  	m := testModule(t, "plan-orphan")
  1577  	p := testProvider("aws")
  1578  	p.DiffFn = testDiffFn
  1579  	s := &State{
  1580  		Modules: []*ModuleState{
  1581  			&ModuleState{
  1582  				Path: rootModulePath,
  1583  				Resources: map[string]*ResourceState{
  1584  					"aws_instance.baz": &ResourceState{
  1585  						Type: "aws_instance",
  1586  						Primary: &InstanceState{
  1587  							ID: "bar",
  1588  						},
  1589  					},
  1590  				},
  1591  			},
  1592  		},
  1593  	}
  1594  	ctx := testContext2(t, &ContextOpts{
  1595  		Module: m,
  1596  		Providers: map[string]ResourceProviderFactory{
  1597  			"aws": testProviderFuncFixed(p),
  1598  		},
  1599  		State: s,
  1600  	})
  1601  
  1602  	plan, err := ctx.Plan()
  1603  	if err != nil {
  1604  		t.Fatalf("err: %s", err)
  1605  	}
  1606  
  1607  	actual := strings.TrimSpace(plan.String())
  1608  	expected := strings.TrimSpace(testTerraformPlanOrphanStr)
  1609  	if actual != expected {
  1610  		t.Fatalf("bad:\n%s", actual)
  1611  	}
  1612  }
  1613  
  1614  func TestContext2Plan_state(t *testing.T) {
  1615  	m := testModule(t, "plan-good")
  1616  	p := testProvider("aws")
  1617  	p.DiffFn = testDiffFn
  1618  	s := &State{
  1619  		Modules: []*ModuleState{
  1620  			&ModuleState{
  1621  				Path: rootModulePath,
  1622  				Resources: map[string]*ResourceState{
  1623  					"aws_instance.foo": &ResourceState{
  1624  						Primary: &InstanceState{
  1625  							ID: "bar",
  1626  						},
  1627  					},
  1628  				},
  1629  			},
  1630  		},
  1631  	}
  1632  	ctx := testContext2(t, &ContextOpts{
  1633  		Module: m,
  1634  		Providers: map[string]ResourceProviderFactory{
  1635  			"aws": testProviderFuncFixed(p),
  1636  		},
  1637  		State: s,
  1638  	})
  1639  
  1640  	plan, err := ctx.Plan()
  1641  	if err != nil {
  1642  		t.Fatalf("err: %s", err)
  1643  	}
  1644  
  1645  	if len(plan.Diff.RootModule().Resources) < 2 {
  1646  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  1647  	}
  1648  
  1649  	actual := strings.TrimSpace(plan.String())
  1650  	expected := strings.TrimSpace(testTerraformPlanStateStr)
  1651  	if actual != expected {
  1652  		t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
  1653  	}
  1654  }
  1655  
  1656  func TestContext2Plan_taint(t *testing.T) {
  1657  	m := testModule(t, "plan-taint")
  1658  	p := testProvider("aws")
  1659  	p.DiffFn = testDiffFn
  1660  	s := &State{
  1661  		Modules: []*ModuleState{
  1662  			&ModuleState{
  1663  				Path: rootModulePath,
  1664  				Resources: map[string]*ResourceState{
  1665  					"aws_instance.foo": &ResourceState{
  1666  						Type: "aws_instance",
  1667  						Primary: &InstanceState{
  1668  							ID:         "bar",
  1669  							Attributes: map[string]string{"num": "2"},
  1670  						},
  1671  					},
  1672  					"aws_instance.bar": &ResourceState{
  1673  						Type: "aws_instance",
  1674  						Tainted: []*InstanceState{
  1675  							&InstanceState{
  1676  								ID: "baz",
  1677  							},
  1678  						},
  1679  					},
  1680  				},
  1681  			},
  1682  		},
  1683  	}
  1684  	ctx := testContext2(t, &ContextOpts{
  1685  		Module: m,
  1686  		Providers: map[string]ResourceProviderFactory{
  1687  			"aws": testProviderFuncFixed(p),
  1688  		},
  1689  		State: s,
  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(testTerraformPlanTaintStr)
  1699  	if actual != expected {
  1700  		t.Fatalf("bad:\n%s", actual)
  1701  	}
  1702  }
  1703  
  1704  func TestContext2Plan_multiple_taint(t *testing.T) {
  1705  	m := testModule(t, "plan-taint")
  1706  	p := testProvider("aws")
  1707  	p.DiffFn = testDiffFn
  1708  	s := &State{
  1709  		Modules: []*ModuleState{
  1710  			&ModuleState{
  1711  				Path: rootModulePath,
  1712  				Resources: map[string]*ResourceState{
  1713  					"aws_instance.foo": &ResourceState{
  1714  						Type: "aws_instance",
  1715  						Primary: &InstanceState{
  1716  							ID:         "bar",
  1717  							Attributes: map[string]string{"num": "2"},
  1718  						},
  1719  					},
  1720  					"aws_instance.bar": &ResourceState{
  1721  						Type: "aws_instance",
  1722  						Tainted: []*InstanceState{
  1723  							&InstanceState{
  1724  								ID: "baz",
  1725  							},
  1726  							&InstanceState{
  1727  								ID: "zip",
  1728  							},
  1729  						},
  1730  					},
  1731  				},
  1732  			},
  1733  		},
  1734  	}
  1735  	ctx := testContext2(t, &ContextOpts{
  1736  		Module: m,
  1737  		Providers: map[string]ResourceProviderFactory{
  1738  			"aws": testProviderFuncFixed(p),
  1739  		},
  1740  		State: s,
  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(testTerraformPlanMultipleTaintStr)
  1750  	if actual != expected {
  1751  		t.Fatalf("bad:\n%s", actual)
  1752  	}
  1753  }
  1754  
  1755  // Fails about 50% of the time before the fix for GH-4982, covers the fix.
  1756  func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
  1757  	m := testModule(t, "plan-taint-interpolated-count")
  1758  	p := testProvider("aws")
  1759  	p.DiffFn = testDiffFn
  1760  	s := &State{
  1761  		Modules: []*ModuleState{
  1762  			&ModuleState{
  1763  				Path: rootModulePath,
  1764  				Resources: map[string]*ResourceState{
  1765  					"aws_instance.foo.0": &ResourceState{
  1766  						Type: "aws_instance",
  1767  						Tainted: []*InstanceState{
  1768  							&InstanceState{ID: "bar"},
  1769  						},
  1770  					},
  1771  					"aws_instance.foo.1": &ResourceState{
  1772  						Type:    "aws_instance",
  1773  						Primary: &InstanceState{ID: "bar"},
  1774  					},
  1775  					"aws_instance.foo.2": &ResourceState{
  1776  						Type:    "aws_instance",
  1777  						Primary: &InstanceState{ID: "bar"},
  1778  					},
  1779  				},
  1780  			},
  1781  		},
  1782  	}
  1783  	ctx := testContext2(t, &ContextOpts{
  1784  		Module: m,
  1785  		Providers: map[string]ResourceProviderFactory{
  1786  			"aws": testProviderFuncFixed(p),
  1787  		},
  1788  		State: s,
  1789  	})
  1790  
  1791  	for i := 0; i < 100; i++ {
  1792  		plan, err := ctx.Plan()
  1793  		if err != nil {
  1794  			t.Fatalf("err: %s", err)
  1795  		}
  1796  
  1797  		actual := strings.TrimSpace(plan.String())
  1798  		expected := strings.TrimSpace(`
  1799  DIFF:
  1800  
  1801  DESTROY/CREATE: aws_instance.foo.0
  1802  
  1803  STATE:
  1804  
  1805  aws_instance.foo.0: (1 tainted)
  1806    ID = <not created>
  1807    Tainted ID 1 = bar
  1808  aws_instance.foo.1:
  1809    ID = bar
  1810  aws_instance.foo.2:
  1811    ID = bar
  1812  		`)
  1813  		if actual != expected {
  1814  			t.Fatalf("bad:\n%s", actual)
  1815  		}
  1816  	}
  1817  }
  1818  
  1819  func TestContext2Plan_targeted(t *testing.T) {
  1820  	m := testModule(t, "plan-targeted")
  1821  	p := testProvider("aws")
  1822  	p.DiffFn = testDiffFn
  1823  	ctx := testContext2(t, &ContextOpts{
  1824  		Module: m,
  1825  		Providers: map[string]ResourceProviderFactory{
  1826  			"aws": testProviderFuncFixed(p),
  1827  		},
  1828  		Targets: []string{"aws_instance.foo"},
  1829  	})
  1830  
  1831  	plan, err := ctx.Plan()
  1832  	if err != nil {
  1833  		t.Fatalf("err: %s", err)
  1834  	}
  1835  
  1836  	actual := strings.TrimSpace(plan.String())
  1837  	expected := strings.TrimSpace(`
  1838  DIFF:
  1839  
  1840  CREATE: aws_instance.foo
  1841    num:  "" => "2"
  1842    type: "" => "aws_instance"
  1843  
  1844  STATE:
  1845  
  1846  <no state>
  1847  	`)
  1848  	if actual != expected {
  1849  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  1850  	}
  1851  }
  1852  
  1853  func TestContext2Plan_targetedOrphan(t *testing.T) {
  1854  	m := testModule(t, "plan-targeted-orphan")
  1855  	p := testProvider("aws")
  1856  	p.DiffFn = testDiffFn
  1857  	ctx := testContext2(t, &ContextOpts{
  1858  		Module: m,
  1859  		Providers: map[string]ResourceProviderFactory{
  1860  			"aws": testProviderFuncFixed(p),
  1861  		},
  1862  		State: &State{
  1863  			Modules: []*ModuleState{
  1864  				&ModuleState{
  1865  					Path: rootModulePath,
  1866  					Resources: map[string]*ResourceState{
  1867  						"aws_instance.orphan": &ResourceState{
  1868  							Type: "aws_instance",
  1869  							Primary: &InstanceState{
  1870  								ID: "i-789xyz",
  1871  							},
  1872  						},
  1873  						"aws_instance.nottargeted": &ResourceState{
  1874  							Type: "aws_instance",
  1875  							Primary: &InstanceState{
  1876  								ID: "i-abc123",
  1877  							},
  1878  						},
  1879  					},
  1880  				},
  1881  			},
  1882  		},
  1883  		Destroy: true,
  1884  		Targets: []string{"aws_instance.orphan"},
  1885  	})
  1886  
  1887  	plan, err := ctx.Plan()
  1888  	if err != nil {
  1889  		t.Fatalf("err: %s", err)
  1890  	}
  1891  
  1892  	actual := strings.TrimSpace(plan.String())
  1893  	expected := strings.TrimSpace(`DIFF:
  1894  
  1895  DESTROY: aws_instance.orphan
  1896  
  1897  STATE:
  1898  
  1899  aws_instance.nottargeted:
  1900    ID = i-abc123
  1901  aws_instance.orphan:
  1902    ID = i-789xyz
  1903  `)
  1904  	if actual != expected {
  1905  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  1906  	}
  1907  }
  1908  
  1909  // https://github.com/hashicorp/terraform/issues/2538
  1910  func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
  1911  	m := testModule(t, "plan-targeted-module-orphan")
  1912  	p := testProvider("aws")
  1913  	p.DiffFn = testDiffFn
  1914  	ctx := testContext2(t, &ContextOpts{
  1915  		Module: m,
  1916  		Providers: map[string]ResourceProviderFactory{
  1917  			"aws": testProviderFuncFixed(p),
  1918  		},
  1919  		State: &State{
  1920  			Modules: []*ModuleState{
  1921  				&ModuleState{
  1922  					Path: []string{"root", "child"},
  1923  					Resources: map[string]*ResourceState{
  1924  						"aws_instance.orphan": &ResourceState{
  1925  							Type: "aws_instance",
  1926  							Primary: &InstanceState{
  1927  								ID: "i-789xyz",
  1928  							},
  1929  						},
  1930  						"aws_instance.nottargeted": &ResourceState{
  1931  							Type: "aws_instance",
  1932  							Primary: &InstanceState{
  1933  								ID: "i-abc123",
  1934  							},
  1935  						},
  1936  					},
  1937  				},
  1938  			},
  1939  		},
  1940  		Destroy: true,
  1941  		Targets: []string{"module.child.aws_instance.orphan"},
  1942  	})
  1943  
  1944  	plan, err := ctx.Plan()
  1945  	if err != nil {
  1946  		t.Fatalf("err: %s", err)
  1947  	}
  1948  
  1949  	actual := strings.TrimSpace(plan.String())
  1950  	expected := strings.TrimSpace(`DIFF:
  1951  
  1952  module.child:
  1953    DESTROY: aws_instance.orphan
  1954  
  1955  STATE:
  1956  
  1957  module.child:
  1958    aws_instance.nottargeted:
  1959      ID = i-abc123
  1960    aws_instance.orphan:
  1961      ID = i-789xyz
  1962  `)
  1963  	if actual != expected {
  1964  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  1965  	}
  1966  }
  1967  
  1968  // https://github.com/hashicorp/terraform/issues/4515
  1969  func TestContext2Plan_targetedOverTen(t *testing.T) {
  1970  	m := testModule(t, "plan-targeted-over-ten")
  1971  	p := testProvider("aws")
  1972  	p.DiffFn = testDiffFn
  1973  
  1974  	resources := make(map[string]*ResourceState)
  1975  	var expectedState []string
  1976  	for i := 0; i < 13; i++ {
  1977  		key := fmt.Sprintf("aws_instance.foo.%d", i)
  1978  		id := fmt.Sprintf("i-abc%d", i)
  1979  		resources[key] = &ResourceState{
  1980  			Type:    "aws_instance",
  1981  			Primary: &InstanceState{ID: id},
  1982  		}
  1983  		expectedState = append(expectedState,
  1984  			fmt.Sprintf("%s:\n  ID = %s\n", key, id))
  1985  	}
  1986  	ctx := testContext2(t, &ContextOpts{
  1987  		Module: m,
  1988  		Providers: map[string]ResourceProviderFactory{
  1989  			"aws": testProviderFuncFixed(p),
  1990  		},
  1991  		State: &State{
  1992  			Modules: []*ModuleState{
  1993  				&ModuleState{
  1994  					Path:      rootModulePath,
  1995  					Resources: resources,
  1996  				},
  1997  			},
  1998  		},
  1999  		Targets: []string{"aws_instance.foo[1]"},
  2000  	})
  2001  
  2002  	plan, err := ctx.Plan()
  2003  	if err != nil {
  2004  		t.Fatalf("err: %s", err)
  2005  	}
  2006  
  2007  	actual := strings.TrimSpace(plan.String())
  2008  	sort.Strings(expectedState)
  2009  	expected := strings.TrimSpace(`
  2010  DIFF:
  2011  
  2012  
  2013  
  2014  STATE:
  2015  
  2016  aws_instance.foo.0:
  2017    ID = i-abc0
  2018  aws_instance.foo.1:
  2019    ID = i-abc1
  2020  aws_instance.foo.10:
  2021    ID = i-abc10
  2022  aws_instance.foo.11:
  2023    ID = i-abc11
  2024  aws_instance.foo.12:
  2025    ID = i-abc12
  2026  aws_instance.foo.2:
  2027    ID = i-abc2
  2028  aws_instance.foo.3:
  2029    ID = i-abc3
  2030  aws_instance.foo.4:
  2031    ID = i-abc4
  2032  aws_instance.foo.5:
  2033    ID = i-abc5
  2034  aws_instance.foo.6:
  2035    ID = i-abc6
  2036  aws_instance.foo.7:
  2037    ID = i-abc7
  2038  aws_instance.foo.8:
  2039    ID = i-abc8
  2040  aws_instance.foo.9:
  2041    ID = i-abc9
  2042  	`)
  2043  	if actual != expected {
  2044  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  2045  	}
  2046  }
  2047  
  2048  func TestContext2Plan_provider(t *testing.T) {
  2049  	m := testModule(t, "plan-provider")
  2050  	p := testProvider("aws")
  2051  	p.DiffFn = testDiffFn
  2052  
  2053  	var value interface{}
  2054  	p.ConfigureFn = func(c *ResourceConfig) error {
  2055  		value, _ = c.Get("foo")
  2056  		return nil
  2057  	}
  2058  
  2059  	ctx := testContext2(t, &ContextOpts{
  2060  		Module: m,
  2061  		Providers: map[string]ResourceProviderFactory{
  2062  			"aws": testProviderFuncFixed(p),
  2063  		},
  2064  		Variables: map[string]string{
  2065  			"foo": "bar",
  2066  		},
  2067  	})
  2068  
  2069  	if _, err := ctx.Plan(); err != nil {
  2070  		t.Fatalf("err: %s", err)
  2071  	}
  2072  
  2073  	if value != "bar" {
  2074  		t.Fatalf("bad: %#v", value)
  2075  	}
  2076  }
  2077  
  2078  func TestContext2Plan_varListErr(t *testing.T) {
  2079  	m := testModule(t, "plan-var-list-err")
  2080  	p := testProvider("aws")
  2081  	ctx := testContext2(t, &ContextOpts{
  2082  		Module: m,
  2083  		Providers: map[string]ResourceProviderFactory{
  2084  			"aws": testProviderFuncFixed(p),
  2085  		},
  2086  	})
  2087  
  2088  	_, err := ctx.Plan()
  2089  
  2090  	if err == nil {
  2091  		t.Fatal("should error")
  2092  	}
  2093  }
  2094  
  2095  func TestContext2Plan_ignoreChanges(t *testing.T) {
  2096  	m := testModule(t, "plan-ignore-changes")
  2097  	p := testProvider("aws")
  2098  	p.DiffFn = testDiffFn
  2099  	s := &State{
  2100  		Modules: []*ModuleState{
  2101  			&ModuleState{
  2102  				Path: rootModulePath,
  2103  				Resources: map[string]*ResourceState{
  2104  					"aws_instance.foo": &ResourceState{
  2105  						Primary: &InstanceState{
  2106  							ID:         "bar",
  2107  							Attributes: map[string]string{"ami": "ami-abcd1234"},
  2108  						},
  2109  					},
  2110  				},
  2111  			},
  2112  		},
  2113  	}
  2114  	ctx := testContext2(t, &ContextOpts{
  2115  		Module: m,
  2116  		Providers: map[string]ResourceProviderFactory{
  2117  			"aws": testProviderFuncFixed(p),
  2118  		},
  2119  		Variables: map[string]string{
  2120  			"foo": "ami-1234abcd",
  2121  		},
  2122  		State: s,
  2123  	})
  2124  
  2125  	plan, err := ctx.Plan()
  2126  	if err != nil {
  2127  		t.Fatalf("err: %s", err)
  2128  	}
  2129  
  2130  	if len(plan.Diff.RootModule().Resources) < 1 {
  2131  		t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
  2132  	}
  2133  
  2134  	actual := strings.TrimSpace(plan.String())
  2135  	expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr)
  2136  	if actual != expected {
  2137  		t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
  2138  	}
  2139  }