github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/terraform/context_refresh_test.go (about)

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