github.com/ibm-cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/terraform/context_refresh_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  	"strings"
     7  	"sync"
     8  	"testing"
     9  )
    10  
    11  func TestContext2Refresh(t *testing.T) {
    12  	p := testProvider("aws")
    13  	m := testModule(t, "refresh-basic")
    14  	ctx := testContext2(t, &ContextOpts{
    15  		Module: m,
    16  		Providers: map[string]ResourceProviderFactory{
    17  			"aws": testProviderFuncFixed(p),
    18  		},
    19  		State: &State{
    20  			Modules: []*ModuleState{
    21  				&ModuleState{
    22  					Path: rootModulePath,
    23  					Resources: map[string]*ResourceState{
    24  						"aws_instance.web": &ResourceState{
    25  							Type: "aws_instance",
    26  							Primary: &InstanceState{
    27  								ID: "foo",
    28  							},
    29  						},
    30  					},
    31  				},
    32  			},
    33  		},
    34  	})
    35  
    36  	p.RefreshFn = nil
    37  	p.RefreshReturn = &InstanceState{
    38  		ID: "foo",
    39  	}
    40  
    41  	s, err := ctx.Refresh()
    42  	mod := s.RootModule()
    43  	if err != nil {
    44  		t.Fatalf("err: %s", err)
    45  	}
    46  	if !p.RefreshCalled {
    47  		t.Fatal("refresh should be called")
    48  	}
    49  	if p.RefreshState.ID != "foo" {
    50  		t.Fatalf("bad: %#v", p.RefreshState)
    51  	}
    52  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
    53  		t.Fatalf("bad: %#v %#v", mod.Resources["aws_instance.web"], p.RefreshReturn)
    54  	}
    55  
    56  	for _, r := range mod.Resources {
    57  		if r.Type == "" {
    58  			t.Fatalf("no type: %#v", r)
    59  		}
    60  	}
    61  }
    62  
    63  func TestContext2Refresh_dataComputedModuleVar(t *testing.T) {
    64  	p := testProvider("aws")
    65  	m := testModule(t, "refresh-data-module-var")
    66  	ctx := testContext2(t, &ContextOpts{
    67  		Module: m,
    68  		Providers: map[string]ResourceProviderFactory{
    69  			"aws": testProviderFuncFixed(p),
    70  		},
    71  	})
    72  
    73  	p.RefreshFn = nil
    74  	p.RefreshReturn = &InstanceState{
    75  		ID: "foo",
    76  	}
    77  
    78  	s, err := ctx.Refresh()
    79  	if err != nil {
    80  		t.Fatalf("err: %s", err)
    81  	}
    82  
    83  	checkStateString(t, s, `
    84  <no state>
    85  module.child:
    86    <no state>`)
    87  }
    88  
    89  func TestContext2Refresh_targeted(t *testing.T) {
    90  	p := testProvider("aws")
    91  	m := testModule(t, "refresh-targeted")
    92  	ctx := testContext2(t, &ContextOpts{
    93  		Module: m,
    94  		Providers: map[string]ResourceProviderFactory{
    95  			"aws": testProviderFuncFixed(p),
    96  		},
    97  		State: &State{
    98  			Modules: []*ModuleState{
    99  				&ModuleState{
   100  					Path: rootModulePath,
   101  					Resources: map[string]*ResourceState{
   102  						"aws_vpc.metoo":      resourceState("aws_vpc", "vpc-abc123"),
   103  						"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
   104  						"aws_instance.me":    resourceState("aws_instance", "i-abc123"),
   105  						"aws_elb.meneither":  resourceState("aws_elb", "lb-abc123"),
   106  					},
   107  				},
   108  			},
   109  		},
   110  		Targets: []string{"aws_instance.me"},
   111  	})
   112  
   113  	refreshedResources := make([]string, 0, 2)
   114  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
   115  		refreshedResources = append(refreshedResources, i.Id)
   116  		return is, nil
   117  	}
   118  
   119  	_, err := ctx.Refresh()
   120  	if err != nil {
   121  		t.Fatalf("err: %s", err)
   122  	}
   123  
   124  	expected := []string{"aws_vpc.metoo", "aws_instance.me"}
   125  	if !reflect.DeepEqual(refreshedResources, expected) {
   126  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   127  	}
   128  }
   129  
   130  func TestContext2Refresh_targetedCount(t *testing.T) {
   131  	p := testProvider("aws")
   132  	m := testModule(t, "refresh-targeted-count")
   133  	ctx := testContext2(t, &ContextOpts{
   134  		Module: m,
   135  		Providers: map[string]ResourceProviderFactory{
   136  			"aws": testProviderFuncFixed(p),
   137  		},
   138  		State: &State{
   139  			Modules: []*ModuleState{
   140  				&ModuleState{
   141  					Path: rootModulePath,
   142  					Resources: map[string]*ResourceState{
   143  						"aws_vpc.metoo":      resourceState("aws_vpc", "vpc-abc123"),
   144  						"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
   145  						"aws_instance.me.0":  resourceState("aws_instance", "i-abc123"),
   146  						"aws_instance.me.1":  resourceState("aws_instance", "i-cde567"),
   147  						"aws_instance.me.2":  resourceState("aws_instance", "i-cde789"),
   148  						"aws_elb.meneither":  resourceState("aws_elb", "lb-abc123"),
   149  					},
   150  				},
   151  			},
   152  		},
   153  		Targets: []string{"aws_instance.me"},
   154  	})
   155  
   156  	refreshedResources := make([]string, 0, 2)
   157  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
   158  		refreshedResources = append(refreshedResources, i.Id)
   159  		return is, nil
   160  	}
   161  
   162  	_, err := ctx.Refresh()
   163  	if err != nil {
   164  		t.Fatalf("err: %s", err)
   165  	}
   166  
   167  	// Target didn't specify index, so we should get all our instances
   168  	expected := []string{
   169  		"aws_vpc.metoo",
   170  		"aws_instance.me.0",
   171  		"aws_instance.me.1",
   172  		"aws_instance.me.2",
   173  	}
   174  	sort.Strings(expected)
   175  	sort.Strings(refreshedResources)
   176  	if !reflect.DeepEqual(refreshedResources, expected) {
   177  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   178  	}
   179  }
   180  
   181  func TestContext2Refresh_targetedCountIndex(t *testing.T) {
   182  	p := testProvider("aws")
   183  	m := testModule(t, "refresh-targeted-count")
   184  	ctx := testContext2(t, &ContextOpts{
   185  		Module: m,
   186  		Providers: map[string]ResourceProviderFactory{
   187  			"aws": testProviderFuncFixed(p),
   188  		},
   189  		State: &State{
   190  			Modules: []*ModuleState{
   191  				&ModuleState{
   192  					Path: rootModulePath,
   193  					Resources: map[string]*ResourceState{
   194  						"aws_vpc.metoo":      resourceState("aws_vpc", "vpc-abc123"),
   195  						"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
   196  						"aws_instance.me.0":  resourceState("aws_instance", "i-abc123"),
   197  						"aws_instance.me.1":  resourceState("aws_instance", "i-cde567"),
   198  						"aws_instance.me.2":  resourceState("aws_instance", "i-cde789"),
   199  						"aws_elb.meneither":  resourceState("aws_elb", "lb-abc123"),
   200  					},
   201  				},
   202  			},
   203  		},
   204  		Targets: []string{"aws_instance.me[0]"},
   205  	})
   206  
   207  	refreshedResources := make([]string, 0, 2)
   208  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
   209  		refreshedResources = append(refreshedResources, i.Id)
   210  		return is, nil
   211  	}
   212  
   213  	_, err := ctx.Refresh()
   214  	if err != nil {
   215  		t.Fatalf("err: %s", err)
   216  	}
   217  
   218  	expected := []string{"aws_vpc.metoo", "aws_instance.me.0"}
   219  	if !reflect.DeepEqual(refreshedResources, expected) {
   220  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   221  	}
   222  }
   223  
   224  func TestContext2Refresh_moduleComputedVar(t *testing.T) {
   225  	p := testProvider("aws")
   226  	m := testModule(t, "refresh-module-computed-var")
   227  	ctx := testContext2(t, &ContextOpts{
   228  		Module: m,
   229  		Providers: map[string]ResourceProviderFactory{
   230  			"aws": testProviderFuncFixed(p),
   231  		},
   232  	})
   233  
   234  	// This was failing (see GH-2188) at some point, so this test just
   235  	// verifies that the failure goes away.
   236  	if _, err := ctx.Refresh(); err != nil {
   237  		t.Fatalf("err: %s", err)
   238  	}
   239  }
   240  
   241  func TestContext2Refresh_delete(t *testing.T) {
   242  	p := testProvider("aws")
   243  	m := testModule(t, "refresh-basic")
   244  	ctx := testContext2(t, &ContextOpts{
   245  		Module: m,
   246  		Providers: map[string]ResourceProviderFactory{
   247  			"aws": testProviderFuncFixed(p),
   248  		},
   249  		State: &State{
   250  			Modules: []*ModuleState{
   251  				&ModuleState{
   252  					Path: rootModulePath,
   253  					Resources: map[string]*ResourceState{
   254  						"aws_instance.web": &ResourceState{
   255  							Type: "aws_instance",
   256  							Primary: &InstanceState{
   257  								ID: "foo",
   258  							},
   259  						},
   260  					},
   261  				},
   262  			},
   263  		},
   264  	})
   265  
   266  	p.RefreshFn = nil
   267  	p.RefreshReturn = nil
   268  
   269  	s, err := ctx.Refresh()
   270  	if err != nil {
   271  		t.Fatalf("err: %s", err)
   272  	}
   273  
   274  	mod := s.RootModule()
   275  	if len(mod.Resources) > 0 {
   276  		t.Fatal("resources should be empty")
   277  	}
   278  }
   279  
   280  func TestContext2Refresh_ignoreUncreated(t *testing.T) {
   281  	p := testProvider("aws")
   282  	m := testModule(t, "refresh-basic")
   283  	ctx := testContext2(t, &ContextOpts{
   284  		Module: m,
   285  		Providers: map[string]ResourceProviderFactory{
   286  			"aws": testProviderFuncFixed(p),
   287  		},
   288  		State: nil,
   289  	})
   290  
   291  	p.RefreshFn = nil
   292  	p.RefreshReturn = &InstanceState{
   293  		ID: "foo",
   294  	}
   295  
   296  	_, err := ctx.Refresh()
   297  	if err != nil {
   298  		t.Fatalf("err: %s", err)
   299  	}
   300  	if p.RefreshCalled {
   301  		t.Fatal("refresh should not be called")
   302  	}
   303  }
   304  
   305  func TestContext2Refresh_hook(t *testing.T) {
   306  	h := new(MockHook)
   307  	p := testProvider("aws")
   308  	m := testModule(t, "refresh-basic")
   309  	ctx := testContext2(t, &ContextOpts{
   310  		Module: m,
   311  		Hooks:  []Hook{h},
   312  		Providers: map[string]ResourceProviderFactory{
   313  			"aws": testProviderFuncFixed(p),
   314  		},
   315  		State: &State{
   316  			Modules: []*ModuleState{
   317  				&ModuleState{
   318  					Path: rootModulePath,
   319  					Resources: map[string]*ResourceState{
   320  						"aws_instance.web": &ResourceState{
   321  							Type: "aws_instance",
   322  							Primary: &InstanceState{
   323  								ID: "foo",
   324  							},
   325  						},
   326  					},
   327  				},
   328  			},
   329  		},
   330  	})
   331  
   332  	if _, err := ctx.Refresh(); err != nil {
   333  		t.Fatalf("err: %s", err)
   334  	}
   335  	if !h.PreRefreshCalled {
   336  		t.Fatal("should be called")
   337  	}
   338  	if !h.PostRefreshCalled {
   339  		t.Fatal("should be called")
   340  	}
   341  }
   342  
   343  func TestContext2Refresh_modules(t *testing.T) {
   344  	p := testProvider("aws")
   345  	m := testModule(t, "refresh-modules")
   346  	state := &State{
   347  		Modules: []*ModuleState{
   348  			&ModuleState{
   349  				Path: rootModulePath,
   350  				Resources: map[string]*ResourceState{
   351  					"aws_instance.web": &ResourceState{
   352  						Type: "aws_instance",
   353  						Primary: &InstanceState{
   354  							ID:      "bar",
   355  							Tainted: true,
   356  						},
   357  					},
   358  				},
   359  			},
   360  
   361  			&ModuleState{
   362  				Path: []string{"root", "child"},
   363  				Resources: map[string]*ResourceState{
   364  					"aws_instance.web": &ResourceState{
   365  						Type: "aws_instance",
   366  						Primary: &InstanceState{
   367  							ID: "baz",
   368  						},
   369  					},
   370  				},
   371  			},
   372  		},
   373  	}
   374  	ctx := testContext2(t, &ContextOpts{
   375  		Module: m,
   376  		Providers: map[string]ResourceProviderFactory{
   377  			"aws": testProviderFuncFixed(p),
   378  		},
   379  		State: state,
   380  	})
   381  
   382  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   383  		if s.ID != "baz" {
   384  			return s, nil
   385  		}
   386  
   387  		s.ID = "new"
   388  		return s, nil
   389  	}
   390  
   391  	s, err := ctx.Refresh()
   392  	if err != nil {
   393  		t.Fatalf("err: %s", err)
   394  	}
   395  
   396  	actual := strings.TrimSpace(s.String())
   397  	expected := strings.TrimSpace(testContextRefreshModuleStr)
   398  	if actual != expected {
   399  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   400  	}
   401  }
   402  
   403  func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
   404  	m := testModule(t, "refresh-module-input-computed-output")
   405  	p := testProvider("aws")
   406  	p.DiffFn = testDiffFn
   407  	ctx := testContext2(t, &ContextOpts{
   408  		Module: m,
   409  		Providers: map[string]ResourceProviderFactory{
   410  			"aws": testProviderFuncFixed(p),
   411  		},
   412  	})
   413  
   414  	if _, err := ctx.Refresh(); err != nil {
   415  		t.Fatalf("err: %s", err)
   416  	}
   417  }
   418  
   419  func TestContext2Refresh_moduleVarModule(t *testing.T) {
   420  	m := testModule(t, "refresh-module-var-module")
   421  	p := testProvider("aws")
   422  	p.DiffFn = testDiffFn
   423  	ctx := testContext2(t, &ContextOpts{
   424  		Module: m,
   425  		Providers: map[string]ResourceProviderFactory{
   426  			"aws": testProviderFuncFixed(p),
   427  		},
   428  	})
   429  
   430  	if _, err := ctx.Refresh(); err != nil {
   431  		t.Fatalf("err: %s", err)
   432  	}
   433  }
   434  
   435  // GH-70
   436  func TestContext2Refresh_noState(t *testing.T) {
   437  	p := testProvider("aws")
   438  	m := testModule(t, "refresh-no-state")
   439  	ctx := testContext2(t, &ContextOpts{
   440  		Module: m,
   441  		Providers: map[string]ResourceProviderFactory{
   442  			"aws": testProviderFuncFixed(p),
   443  		},
   444  	})
   445  
   446  	p.RefreshFn = nil
   447  	p.RefreshReturn = &InstanceState{
   448  		ID: "foo",
   449  	}
   450  
   451  	if _, err := ctx.Refresh(); err != nil {
   452  		t.Fatalf("err: %s", err)
   453  	}
   454  }
   455  
   456  func TestContext2Refresh_output(t *testing.T) {
   457  	p := testProvider("aws")
   458  	m := testModule(t, "refresh-output")
   459  	ctx := testContext2(t, &ContextOpts{
   460  		Module: m,
   461  		Providers: map[string]ResourceProviderFactory{
   462  			"aws": testProviderFuncFixed(p),
   463  		},
   464  		State: &State{
   465  			Modules: []*ModuleState{
   466  				&ModuleState{
   467  					Path: rootModulePath,
   468  					Resources: map[string]*ResourceState{
   469  						"aws_instance.web": &ResourceState{
   470  							Type: "aws_instance",
   471  							Primary: &InstanceState{
   472  								ID: "foo",
   473  								Attributes: map[string]string{
   474  									"foo": "bar",
   475  								},
   476  							},
   477  						},
   478  					},
   479  
   480  					Outputs: map[string]*OutputState{
   481  						"foo": &OutputState{
   482  							Type:      "string",
   483  							Sensitive: false,
   484  							Value:     "foo",
   485  						},
   486  					},
   487  				},
   488  			},
   489  		},
   490  	})
   491  
   492  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   493  		return s, nil
   494  	}
   495  
   496  	s, err := ctx.Refresh()
   497  	if err != nil {
   498  		t.Fatalf("err: %s", err)
   499  	}
   500  
   501  	actual := strings.TrimSpace(s.String())
   502  	expected := strings.TrimSpace(testContextRefreshOutputStr)
   503  	if actual != expected {
   504  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   505  	}
   506  }
   507  
   508  func TestContext2Refresh_outputPartial(t *testing.T) {
   509  	p := testProvider("aws")
   510  	m := testModule(t, "refresh-output-partial")
   511  	ctx := testContext2(t, &ContextOpts{
   512  		Module: m,
   513  		Providers: map[string]ResourceProviderFactory{
   514  			"aws": testProviderFuncFixed(p),
   515  		},
   516  		State: &State{
   517  			Modules: []*ModuleState{
   518  				&ModuleState{
   519  					Path: rootModulePath,
   520  					Resources: map[string]*ResourceState{
   521  						"aws_instance.foo": &ResourceState{
   522  							Type: "aws_instance",
   523  							Primary: &InstanceState{
   524  								ID: "foo",
   525  							},
   526  						},
   527  					},
   528  					Outputs: map[string]*OutputState{},
   529  				},
   530  			},
   531  		},
   532  	})
   533  
   534  	p.RefreshFn = nil
   535  	p.RefreshReturn = nil
   536  
   537  	s, err := ctx.Refresh()
   538  	if err != nil {
   539  		t.Fatalf("err: %s", err)
   540  	}
   541  
   542  	actual := strings.TrimSpace(s.String())
   543  	expected := strings.TrimSpace(testContextRefreshOutputPartialStr)
   544  	if actual != expected {
   545  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   546  	}
   547  }
   548  
   549  func TestContext2Refresh_stateBasic(t *testing.T) {
   550  	p := testProvider("aws")
   551  	m := testModule(t, "refresh-basic")
   552  	state := &State{
   553  		Modules: []*ModuleState{
   554  			&ModuleState{
   555  				Path: rootModulePath,
   556  				Resources: map[string]*ResourceState{
   557  					"aws_instance.web": &ResourceState{
   558  						Type: "aws_instance",
   559  						Primary: &InstanceState{
   560  							ID: "bar",
   561  						},
   562  					},
   563  				},
   564  			},
   565  		},
   566  	}
   567  	ctx := testContext2(t, &ContextOpts{
   568  		Module: m,
   569  		Providers: map[string]ResourceProviderFactory{
   570  			"aws": testProviderFuncFixed(p),
   571  		},
   572  		State: state,
   573  	})
   574  
   575  	p.RefreshFn = nil
   576  	p.RefreshReturn = &InstanceState{
   577  		ID: "foo",
   578  	}
   579  
   580  	s, err := ctx.Refresh()
   581  	if err != nil {
   582  		t.Fatalf("err: %s", err)
   583  	}
   584  	originalMod := state.RootModule()
   585  	mod := s.RootModule()
   586  	if !p.RefreshCalled {
   587  		t.Fatal("refresh should be called")
   588  	}
   589  	if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) {
   590  		t.Fatalf(
   591  			"bad:\n\n%#v\n\n%#v",
   592  			p.RefreshState,
   593  			originalMod.Resources["aws_instance.web"].Primary)
   594  	}
   595  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
   596  		t.Fatalf("bad: %#v", mod.Resources)
   597  	}
   598  }
   599  
   600  func TestContext2Refresh_dataOrphan(t *testing.T) {
   601  	p := testProvider("null")
   602  	state := &State{
   603  		Modules: []*ModuleState{
   604  			&ModuleState{
   605  				Path: rootModulePath,
   606  				Resources: map[string]*ResourceState{
   607  					"data.null_data_source.bar": &ResourceState{
   608  						Type: "foo",
   609  						Primary: &InstanceState{
   610  							ID: "foo",
   611  						},
   612  					},
   613  				},
   614  			},
   615  		},
   616  	}
   617  	ctx := testContext2(t, &ContextOpts{
   618  		Providers: map[string]ResourceProviderFactory{
   619  			"null": testProviderFuncFixed(p),
   620  		},
   621  		State: state,
   622  	})
   623  
   624  	s, err := ctx.Refresh()
   625  	if err != nil {
   626  		t.Fatalf("err: %s", err)
   627  	}
   628  
   629  	checkStateString(t, s, `<no state>`)
   630  }
   631  
   632  func TestContext2Refresh_dataState(t *testing.T) {
   633  	p := testProvider("null")
   634  	m := testModule(t, "refresh-data-resource-basic")
   635  	state := &State{
   636  		Modules: []*ModuleState{
   637  			&ModuleState{
   638  				Path: rootModulePath,
   639  				// Intentionally no resources since data resources are
   640  				// supposed to refresh themselves even if they didn't
   641  				// already exist.
   642  				Resources: map[string]*ResourceState{},
   643  			},
   644  		},
   645  	}
   646  	ctx := testContext2(t, &ContextOpts{
   647  		Module: m,
   648  		Providers: map[string]ResourceProviderFactory{
   649  			"null": testProviderFuncFixed(p),
   650  		},
   651  		State: state,
   652  	})
   653  
   654  	p.ReadDataDiffFn = nil
   655  	p.ReadDataDiffReturn = &InstanceDiff{
   656  		Attributes: map[string]*ResourceAttrDiff{
   657  			"inputs.#": {
   658  				Old:  "0",
   659  				New:  "1",
   660  				Type: DiffAttrInput,
   661  			},
   662  			"inputs.test": {
   663  				Old:  "",
   664  				New:  "yes",
   665  				Type: DiffAttrInput,
   666  			},
   667  			"outputs.#": {
   668  				Old:         "",
   669  				New:         "",
   670  				NewComputed: true,
   671  				Type:        DiffAttrOutput,
   672  			},
   673  		},
   674  	}
   675  
   676  	p.ReadDataApplyFn = nil
   677  	p.ReadDataApplyReturn = &InstanceState{
   678  		ID: "-",
   679  	}
   680  
   681  	s, err := ctx.Refresh()
   682  	if err != nil {
   683  		t.Fatalf("err: %s", err)
   684  	}
   685  
   686  	if !p.ReadDataDiffCalled {
   687  		t.Fatal("ReadDataDiff should have been called")
   688  	}
   689  	if !p.ReadDataApplyCalled {
   690  		t.Fatal("ReadDataApply should have been called")
   691  	}
   692  
   693  	mod := s.RootModule()
   694  	if got := mod.Resources["data.null_data_source.testing"].Primary.ID; got != "-" {
   695  		t.Fatalf("resource id is %q; want %s", got, "-")
   696  	}
   697  	if !reflect.DeepEqual(mod.Resources["data.null_data_source.testing"].Primary, p.ReadDataApplyReturn) {
   698  		t.Fatalf("bad: %#v", mod.Resources)
   699  	}
   700  }
   701  
   702  func TestContext2Refresh_dataStateRefData(t *testing.T) {
   703  	p := testProvider("null")
   704  	m := testModule(t, "refresh-data-ref-data")
   705  	state := &State{
   706  		Modules: []*ModuleState{
   707  			&ModuleState{
   708  				Path: rootModulePath,
   709  				// Intentionally no resources since data resources are
   710  				// supposed to refresh themselves even if they didn't
   711  				// already exist.
   712  				Resources: map[string]*ResourceState{},
   713  			},
   714  		},
   715  	}
   716  	ctx := testContext2(t, &ContextOpts{
   717  		Module: m,
   718  		Providers: map[string]ResourceProviderFactory{
   719  			"null": testProviderFuncFixed(p),
   720  		},
   721  		State: state,
   722  	})
   723  
   724  	p.ReadDataDiffFn = testDataDiffFn
   725  	p.ReadDataApplyFn = testDataApplyFn
   726  
   727  	s, err := ctx.Refresh()
   728  	if err != nil {
   729  		t.Fatalf("err: %s", err)
   730  	}
   731  
   732  	actual := strings.TrimSpace(s.String())
   733  	expected := strings.TrimSpace(testTerraformRefreshDataRefDataStr)
   734  	if actual != expected {
   735  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   736  	}
   737  }
   738  
   739  func TestContext2Refresh_tainted(t *testing.T) {
   740  	p := testProvider("aws")
   741  	m := testModule(t, "refresh-basic")
   742  	state := &State{
   743  		Modules: []*ModuleState{
   744  			&ModuleState{
   745  				Path: rootModulePath,
   746  				Resources: map[string]*ResourceState{
   747  					"aws_instance.web": &ResourceState{
   748  						Type: "aws_instance",
   749  						Primary: &InstanceState{
   750  							ID:      "bar",
   751  							Tainted: true,
   752  						},
   753  					},
   754  				},
   755  			},
   756  		},
   757  	}
   758  	ctx := testContext2(t, &ContextOpts{
   759  		Module: m,
   760  		Providers: map[string]ResourceProviderFactory{
   761  			"aws": testProviderFuncFixed(p),
   762  		},
   763  		State: state,
   764  	})
   765  
   766  	p.RefreshFn = nil
   767  	p.RefreshReturn = &InstanceState{
   768  		ID:      "foo",
   769  		Tainted: true,
   770  	}
   771  
   772  	s, err := ctx.Refresh()
   773  	if err != nil {
   774  		t.Fatalf("err: %s", err)
   775  	}
   776  	if !p.RefreshCalled {
   777  		t.Fatal("refresh should be called")
   778  	}
   779  
   780  	actual := strings.TrimSpace(s.String())
   781  	expected := strings.TrimSpace(testContextRefreshTaintedStr)
   782  	if actual != expected {
   783  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   784  	}
   785  }
   786  
   787  // Doing a Refresh (or any operation really, but Refresh usually
   788  // happens first) with a config with an unknown provider should result in
   789  // an error. The key bug this found was that this wasn't happening if
   790  // Providers was _empty_.
   791  func TestContext2Refresh_unknownProvider(t *testing.T) {
   792  	m := testModule(t, "refresh-unknown-provider")
   793  	p := testProvider("aws")
   794  	p.ApplyFn = testApplyFn
   795  	p.DiffFn = testDiffFn
   796  	ctx := testContext2(t, &ContextOpts{
   797  		Module:    m,
   798  		Providers: map[string]ResourceProviderFactory{},
   799  		State: &State{
   800  			Modules: []*ModuleState{
   801  				&ModuleState{
   802  					Path: rootModulePath,
   803  					Resources: map[string]*ResourceState{
   804  						"aws_instance.web": &ResourceState{
   805  							Type: "aws_instance",
   806  							Primary: &InstanceState{
   807  								ID: "foo",
   808  							},
   809  						},
   810  					},
   811  				},
   812  			},
   813  		},
   814  	})
   815  
   816  	if _, err := ctx.Refresh(); err == nil {
   817  		t.Fatal("should error")
   818  	}
   819  }
   820  
   821  func TestContext2Refresh_vars(t *testing.T) {
   822  	p := testProvider("aws")
   823  	m := testModule(t, "refresh-vars")
   824  	ctx := testContext2(t, &ContextOpts{
   825  		Module: m,
   826  		Providers: map[string]ResourceProviderFactory{
   827  			"aws": testProviderFuncFixed(p),
   828  		},
   829  		State: &State{
   830  
   831  			Modules: []*ModuleState{
   832  				&ModuleState{
   833  					Path: rootModulePath,
   834  					Resources: map[string]*ResourceState{
   835  						"aws_instance.web": &ResourceState{
   836  							Type: "aws_instance",
   837  							Primary: &InstanceState{
   838  								ID: "foo",
   839  							},
   840  						},
   841  					},
   842  				},
   843  			},
   844  		},
   845  	})
   846  
   847  	p.RefreshFn = nil
   848  	p.RefreshReturn = &InstanceState{
   849  		ID: "foo",
   850  	}
   851  
   852  	s, err := ctx.Refresh()
   853  	if err != nil {
   854  		t.Fatalf("err: %s", err)
   855  	}
   856  	mod := s.RootModule()
   857  	if !p.RefreshCalled {
   858  		t.Fatal("refresh should be called")
   859  	}
   860  	if p.RefreshState.ID != "foo" {
   861  		t.Fatalf("bad: %#v", p.RefreshState)
   862  	}
   863  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
   864  		t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"])
   865  	}
   866  
   867  	for _, r := range mod.Resources {
   868  		if r.Type == "" {
   869  			t.Fatalf("no type: %#v", r)
   870  		}
   871  	}
   872  }
   873  
   874  func TestContext2Refresh_orphanModule(t *testing.T) {
   875  	p := testProvider("aws")
   876  	m := testModule(t, "refresh-module-orphan")
   877  
   878  	// Create a custom refresh function to track the order they were visited
   879  	var order []string
   880  	var orderLock sync.Mutex
   881  	p.RefreshFn = func(
   882  		info *InstanceInfo,
   883  		is *InstanceState) (*InstanceState, error) {
   884  		orderLock.Lock()
   885  		defer orderLock.Unlock()
   886  
   887  		order = append(order, is.ID)
   888  		return is, nil
   889  	}
   890  
   891  	state := &State{
   892  		Modules: []*ModuleState{
   893  			&ModuleState{
   894  				Path: rootModulePath,
   895  				Resources: map[string]*ResourceState{
   896  					"aws_instance.foo": &ResourceState{
   897  						Primary: &InstanceState{
   898  							ID: "i-abc123",
   899  							Attributes: map[string]string{
   900  								"childid":      "i-bcd234",
   901  								"grandchildid": "i-cde345",
   902  							},
   903  						},
   904  						Dependencies: []string{
   905  							"module.child",
   906  							"module.child",
   907  						},
   908  					},
   909  				},
   910  			},
   911  			&ModuleState{
   912  				Path: append(rootModulePath, "child"),
   913  				Resources: map[string]*ResourceState{
   914  					"aws_instance.bar": &ResourceState{
   915  						Primary: &InstanceState{
   916  							ID: "i-bcd234",
   917  							Attributes: map[string]string{
   918  								"grandchildid": "i-cde345",
   919  							},
   920  						},
   921  						Dependencies: []string{
   922  							"module.grandchild",
   923  						},
   924  					},
   925  				},
   926  				Outputs: map[string]*OutputState{
   927  					"id": &OutputState{
   928  						Value: "i-bcd234",
   929  						Type:  "string",
   930  					},
   931  					"grandchild_id": &OutputState{
   932  						Value: "i-cde345",
   933  						Type:  "string",
   934  					},
   935  				},
   936  			},
   937  			&ModuleState{
   938  				Path: append(rootModulePath, "child", "grandchild"),
   939  				Resources: map[string]*ResourceState{
   940  					"aws_instance.baz": &ResourceState{
   941  						Primary: &InstanceState{
   942  							ID: "i-cde345",
   943  						},
   944  					},
   945  				},
   946  				Outputs: map[string]*OutputState{
   947  					"id": &OutputState{
   948  						Value: "i-cde345",
   949  						Type:  "string",
   950  					},
   951  				},
   952  			},
   953  		},
   954  	}
   955  	ctx := testContext2(t, &ContextOpts{
   956  		Module: m,
   957  		Providers: map[string]ResourceProviderFactory{
   958  			"aws": testProviderFuncFixed(p),
   959  		},
   960  		State: state,
   961  	})
   962  
   963  	testCheckDeadlock(t, func() {
   964  		_, err := ctx.Refresh()
   965  		if err != nil {
   966  			t.Fatalf("err: %s", err)
   967  		}
   968  
   969  		// TODO: handle order properly for orphaned modules / resources
   970  		// expected := []string{"i-abc123", "i-bcd234", "i-cde345"}
   971  		// if !reflect.DeepEqual(order, expected) {
   972  		// 	t.Fatalf("expected: %#v, got: %#v", expected, order)
   973  		// }
   974  	})
   975  }
   976  
   977  func TestContext2Validate(t *testing.T) {
   978  	p := testProvider("aws")
   979  	m := testModule(t, "validate-good")
   980  	c := testContext2(t, &ContextOpts{
   981  		Module: m,
   982  		Providers: map[string]ResourceProviderFactory{
   983  			"aws": testProviderFuncFixed(p),
   984  		},
   985  	})
   986  
   987  	w, e := c.Validate()
   988  	if len(w) > 0 {
   989  		t.Fatalf("bad: %#v", w)
   990  	}
   991  	if len(e) > 0 {
   992  		t.Fatalf("bad: %s", e)
   993  	}
   994  }