github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/command/import_test.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/mitchellh/cli"
    12  	"github.com/zclconf/go-cty/cty"
    13  
    14  	"github.com/iaas-resource-provision/iaas-rpc/internal/configs/configschema"
    15  	"github.com/iaas-resource-provision/iaas-rpc/internal/copy"
    16  	"github.com/iaas-resource-provision/iaas-rpc/internal/providers"
    17  	"github.com/iaas-resource-provision/iaas-rpc/internal/tfdiags"
    18  )
    19  
    20  func TestImport(t *testing.T) {
    21  	defer testChdir(t, testFixturePath("import-provider-implicit"))()
    22  
    23  	statePath := testTempFile(t)
    24  
    25  	p := testProvider()
    26  	ui := new(cli.MockUi)
    27  	view, _ := testView(t)
    28  	c := &ImportCommand{
    29  		Meta: Meta{
    30  			testingOverrides: metaOverridesForProvider(p),
    31  			Ui:               ui,
    32  			View:             view,
    33  		},
    34  	}
    35  
    36  	p.ImportResourceStateFn = nil
    37  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
    38  		ImportedResources: []providers.ImportedResource{
    39  			{
    40  				TypeName: "test_instance",
    41  				State: cty.ObjectVal(map[string]cty.Value{
    42  					"id": cty.StringVal("yay"),
    43  				}),
    44  			},
    45  		},
    46  	}
    47  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
    48  		ResourceTypes: map[string]providers.Schema{
    49  			"test_instance": {
    50  				Block: &configschema.Block{
    51  					Attributes: map[string]*configschema.Attribute{
    52  						"id": {Type: cty.String, Optional: true, Computed: true},
    53  					},
    54  				},
    55  			},
    56  		},
    57  	}
    58  
    59  	args := []string{
    60  		"-state", statePath,
    61  		"test_instance.foo",
    62  		"bar",
    63  	}
    64  	if code := c.Run(args); code != 0 {
    65  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    66  	}
    67  
    68  	if !p.ImportResourceStateCalled {
    69  		t.Fatal("ImportResourceState should be called")
    70  	}
    71  
    72  	testStateOutput(t, statePath, testImportStr)
    73  }
    74  
    75  func TestImport_providerConfig(t *testing.T) {
    76  	defer testChdir(t, testFixturePath("import-provider"))()
    77  
    78  	statePath := testTempFile(t)
    79  
    80  	p := testProvider()
    81  	ui := new(cli.MockUi)
    82  	view, _ := testView(t)
    83  	c := &ImportCommand{
    84  		Meta: Meta{
    85  			testingOverrides: metaOverridesForProvider(p),
    86  			Ui:               ui,
    87  			View:             view,
    88  		},
    89  	}
    90  
    91  	p.ImportResourceStateFn = nil
    92  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
    93  		ImportedResources: []providers.ImportedResource{
    94  			{
    95  				TypeName: "test_instance",
    96  				State: cty.ObjectVal(map[string]cty.Value{
    97  					"id": cty.StringVal("yay"),
    98  				}),
    99  			},
   100  		},
   101  	}
   102  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   103  		Provider: providers.Schema{
   104  			Block: &configschema.Block{
   105  				Attributes: map[string]*configschema.Attribute{
   106  					"foo": {Type: cty.String, Optional: true},
   107  				},
   108  			},
   109  		},
   110  		ResourceTypes: map[string]providers.Schema{
   111  			"test_instance": {
   112  				Block: &configschema.Block{
   113  					Attributes: map[string]*configschema.Attribute{
   114  						"id": {Type: cty.String, Optional: true, Computed: true},
   115  					},
   116  				},
   117  			},
   118  		},
   119  	}
   120  
   121  	configured := false
   122  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
   123  		configured = true
   124  
   125  		cfg := req.Config
   126  		if !cfg.Type().HasAttribute("foo") {
   127  			return providers.ConfigureProviderResponse{
   128  				Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("configuration has no foo argument")),
   129  			}
   130  		}
   131  		if got, want := cfg.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
   132  			return providers.ConfigureProviderResponse{
   133  				Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("foo argument is %#v, but want %#v", got, want)),
   134  			}
   135  		}
   136  
   137  		return providers.ConfigureProviderResponse{}
   138  	}
   139  
   140  	args := []string{
   141  		"-state", statePath,
   142  		"test_instance.foo",
   143  		"bar",
   144  	}
   145  	if code := c.Run(args); code != 0 {
   146  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   147  	}
   148  
   149  	// Verify that we were called
   150  	if !configured {
   151  		t.Fatal("Configure should be called")
   152  	}
   153  
   154  	if !p.ImportResourceStateCalled {
   155  		t.Fatal("ImportResourceState should be called")
   156  	}
   157  
   158  	testStateOutput(t, statePath, testImportStr)
   159  }
   160  
   161  // "remote" state provided by the "local" backend
   162  func TestImport_remoteState(t *testing.T) {
   163  	td := tempDir(t)
   164  	testCopyDir(t, testFixturePath("import-provider-remote-state"), td)
   165  	defer os.RemoveAll(td)
   166  	defer testChdir(t, td)()
   167  
   168  	statePath := "imported.tfstate"
   169  
   170  	providerSource, close := newMockProviderSource(t, map[string][]string{
   171  		"test": []string{"1.2.3"},
   172  	})
   173  	defer close()
   174  
   175  	// init our backend
   176  	ui := cli.NewMockUi()
   177  	view, _ := testView(t)
   178  	m := Meta{
   179  		testingOverrides: metaOverridesForProvider(testProvider()),
   180  		Ui:               ui,
   181  		View:             view,
   182  		ProviderSource:   providerSource,
   183  	}
   184  
   185  	ic := &InitCommand{
   186  		Meta: m,
   187  	}
   188  
   189  	// (Using log here rather than t.Log so that these messages interleave with other trace logs)
   190  	log.Print("[TRACE] TestImport_remoteState running: terraform init")
   191  	if code := ic.Run([]string{}); code != 0 {
   192  		t.Fatalf("init failed\n%s", ui.ErrorWriter)
   193  	}
   194  
   195  	p := testProvider()
   196  	ui = new(cli.MockUi)
   197  	c := &ImportCommand{
   198  		Meta: Meta{
   199  			testingOverrides: metaOverridesForProvider(p),
   200  			Ui:               ui,
   201  			View:             view,
   202  		},
   203  	}
   204  
   205  	p.ImportResourceStateFn = nil
   206  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
   207  		ImportedResources: []providers.ImportedResource{
   208  			{
   209  				TypeName: "test_instance",
   210  				State: cty.ObjectVal(map[string]cty.Value{
   211  					"id": cty.StringVal("yay"),
   212  				}),
   213  			},
   214  		},
   215  	}
   216  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   217  		Provider: providers.Schema{
   218  			Block: &configschema.Block{
   219  				Attributes: map[string]*configschema.Attribute{
   220  					"foo": {Type: cty.String, Optional: true},
   221  				},
   222  			},
   223  		},
   224  		ResourceTypes: map[string]providers.Schema{
   225  			"test_instance": {
   226  				Block: &configschema.Block{
   227  					Attributes: map[string]*configschema.Attribute{
   228  						"id": {Type: cty.String, Optional: true, Computed: true},
   229  					},
   230  				},
   231  			},
   232  		},
   233  	}
   234  
   235  	configured := false
   236  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
   237  		var diags tfdiags.Diagnostics
   238  		configured = true
   239  		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
   240  			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
   241  		}
   242  		return providers.ConfigureProviderResponse{
   243  			Diagnostics: diags,
   244  		}
   245  	}
   246  
   247  	args := []string{
   248  		"test_instance.foo",
   249  		"bar",
   250  	}
   251  	log.Printf("[TRACE] TestImport_remoteState running: terraform import %s %s", args[0], args[1])
   252  	if code := c.Run(args); code != 0 {
   253  		fmt.Println(ui.OutputWriter)
   254  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   255  	}
   256  
   257  	// verify that the local state was unlocked after import
   258  	if _, err := os.Stat(filepath.Join(td, fmt.Sprintf(".%s.lock.info", statePath))); !os.IsNotExist(err) {
   259  		t.Fatal("state left locked after import")
   260  	}
   261  
   262  	// Verify that we were called
   263  	if !configured {
   264  		t.Fatal("Configure should be called")
   265  	}
   266  
   267  	if !p.ImportResourceStateCalled {
   268  		t.Fatal("ImportResourceState should be called")
   269  	}
   270  
   271  	testStateOutput(t, statePath, testImportStr)
   272  }
   273  
   274  // early failure on import should not leave stale lock
   275  func TestImport_initializationErrorShouldUnlock(t *testing.T) {
   276  	td := tempDir(t)
   277  	testCopyDir(t, testFixturePath("import-provider-remote-state"), td)
   278  	defer os.RemoveAll(td)
   279  	defer testChdir(t, td)()
   280  
   281  	statePath := "imported.tfstate"
   282  
   283  	providerSource, close := newMockProviderSource(t, map[string][]string{
   284  		"test": []string{"1.2.3"},
   285  	})
   286  	defer close()
   287  
   288  	// init our backend
   289  	ui := cli.NewMockUi()
   290  	view, _ := testView(t)
   291  	m := Meta{
   292  		testingOverrides: metaOverridesForProvider(testProvider()),
   293  		Ui:               ui,
   294  		View:             view,
   295  		ProviderSource:   providerSource,
   296  	}
   297  
   298  	ic := &InitCommand{
   299  		Meta: m,
   300  	}
   301  
   302  	// (Using log here rather than t.Log so that these messages interleave with other trace logs)
   303  	log.Print("[TRACE] TestImport_initializationErrorShouldUnlock running: terraform init")
   304  	if code := ic.Run([]string{}); code != 0 {
   305  		t.Fatalf("init failed\n%s", ui.ErrorWriter)
   306  	}
   307  
   308  	// overwrite the config with one including a resource from an invalid provider
   309  	copy.CopyFile(filepath.Join(testFixturePath("import-provider-invalid"), "main.tf"), filepath.Join(td, "main.tf"))
   310  
   311  	p := testProvider()
   312  	ui = new(cli.MockUi)
   313  	c := &ImportCommand{
   314  		Meta: Meta{
   315  			testingOverrides: metaOverridesForProvider(p),
   316  			Ui:               ui,
   317  			View:             view,
   318  		},
   319  	}
   320  
   321  	args := []string{
   322  		"unknown_instance.baz",
   323  		"bar",
   324  	}
   325  	log.Printf("[TRACE] TestImport_initializationErrorShouldUnlock running: terraform import %s %s", args[0], args[1])
   326  
   327  	// this should fail
   328  	if code := c.Run(args); code != 1 {
   329  		fmt.Println(ui.OutputWriter)
   330  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   331  	}
   332  
   333  	// specifically, it should fail due to a missing provider
   334  	msg := ui.ErrorWriter.String()
   335  	if want := `unknown provider "registry.terraform.io/hashicorp/unknown"`; !strings.Contains(msg, want) {
   336  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   337  	}
   338  
   339  	// verify that the local state was unlocked after initialization error
   340  	if _, err := os.Stat(filepath.Join(td, fmt.Sprintf(".%s.lock.info", statePath))); !os.IsNotExist(err) {
   341  		t.Fatal("state left locked after import")
   342  	}
   343  }
   344  
   345  func TestImport_providerConfigWithVar(t *testing.T) {
   346  	defer testChdir(t, testFixturePath("import-provider-var"))()
   347  
   348  	statePath := testTempFile(t)
   349  
   350  	p := testProvider()
   351  	ui := new(cli.MockUi)
   352  	view, _ := testView(t)
   353  	c := &ImportCommand{
   354  		Meta: Meta{
   355  			testingOverrides: metaOverridesForProvider(p),
   356  			Ui:               ui,
   357  			View:             view,
   358  		},
   359  	}
   360  
   361  	p.ImportResourceStateFn = nil
   362  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
   363  		ImportedResources: []providers.ImportedResource{
   364  			{
   365  				TypeName: "test_instance",
   366  				State: cty.ObjectVal(map[string]cty.Value{
   367  					"id": cty.StringVal("yay"),
   368  				}),
   369  			},
   370  		},
   371  	}
   372  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   373  		Provider: providers.Schema{
   374  			Block: &configschema.Block{
   375  				Attributes: map[string]*configschema.Attribute{
   376  					"foo": {Type: cty.String, Optional: true},
   377  				},
   378  			},
   379  		},
   380  		ResourceTypes: map[string]providers.Schema{
   381  			"test_instance": {
   382  				Block: &configschema.Block{
   383  					Attributes: map[string]*configschema.Attribute{
   384  						"id": {Type: cty.String, Optional: true, Computed: true},
   385  					},
   386  				},
   387  			},
   388  		},
   389  	}
   390  
   391  	configured := false
   392  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
   393  		var diags tfdiags.Diagnostics
   394  		configured = true
   395  		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
   396  			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
   397  		}
   398  		return providers.ConfigureProviderResponse{
   399  			Diagnostics: diags,
   400  		}
   401  	}
   402  
   403  	args := []string{
   404  		"-state", statePath,
   405  		"-var", "foo=bar",
   406  		"test_instance.foo",
   407  		"bar",
   408  	}
   409  	if code := c.Run(args); code != 0 {
   410  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   411  	}
   412  
   413  	// Verify that we were called
   414  	if !configured {
   415  		t.Fatal("Configure should be called")
   416  	}
   417  
   418  	if !p.ImportResourceStateCalled {
   419  		t.Fatal("ImportResourceState should be called")
   420  	}
   421  
   422  	testStateOutput(t, statePath, testImportStr)
   423  }
   424  
   425  func TestImport_providerConfigWithDataSource(t *testing.T) {
   426  	defer testChdir(t, testFixturePath("import-provider-datasource"))()
   427  
   428  	statePath := testTempFile(t)
   429  
   430  	p := testProvider()
   431  	ui := new(cli.MockUi)
   432  	view, _ := testView(t)
   433  	c := &ImportCommand{
   434  		Meta: Meta{
   435  			testingOverrides: metaOverridesForProvider(p),
   436  			Ui:               ui,
   437  			View:             view,
   438  		},
   439  	}
   440  
   441  	p.ImportResourceStateFn = nil
   442  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
   443  		ImportedResources: []providers.ImportedResource{
   444  			{
   445  				TypeName: "test_instance",
   446  				State: cty.ObjectVal(map[string]cty.Value{
   447  					"id": cty.StringVal("yay"),
   448  				}),
   449  			},
   450  		},
   451  	}
   452  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   453  		Provider: providers.Schema{
   454  			Block: &configschema.Block{
   455  				Attributes: map[string]*configschema.Attribute{
   456  					"foo": {Type: cty.String, Optional: true},
   457  				},
   458  			},
   459  		},
   460  		ResourceTypes: map[string]providers.Schema{
   461  			"test_instance": {
   462  				Block: &configschema.Block{
   463  					Attributes: map[string]*configschema.Attribute{
   464  						"id": {Type: cty.String, Optional: true, Computed: true},
   465  					},
   466  				},
   467  			},
   468  		},
   469  		DataSources: map[string]providers.Schema{
   470  			"test_data": {
   471  				Block: &configschema.Block{
   472  					Attributes: map[string]*configschema.Attribute{
   473  						"foo": {Type: cty.String, Optional: true},
   474  					},
   475  				},
   476  			},
   477  		},
   478  	}
   479  
   480  	args := []string{
   481  		"-state", statePath,
   482  		"test_instance.foo",
   483  		"bar",
   484  	}
   485  	if code := c.Run(args); code != 1 {
   486  		t.Fatalf("bad, wanted error: %d\n\n%s", code, ui.ErrorWriter.String())
   487  	}
   488  }
   489  
   490  func TestImport_providerConfigWithVarDefault(t *testing.T) {
   491  	defer testChdir(t, testFixturePath("import-provider-var-default"))()
   492  
   493  	statePath := testTempFile(t)
   494  
   495  	p := testProvider()
   496  	ui := new(cli.MockUi)
   497  	view, _ := testView(t)
   498  	c := &ImportCommand{
   499  		Meta: Meta{
   500  			testingOverrides: metaOverridesForProvider(p),
   501  			Ui:               ui,
   502  			View:             view,
   503  		},
   504  	}
   505  
   506  	p.ImportResourceStateFn = nil
   507  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
   508  		ImportedResources: []providers.ImportedResource{
   509  			{
   510  				TypeName: "test_instance",
   511  				State: cty.ObjectVal(map[string]cty.Value{
   512  					"id": cty.StringVal("yay"),
   513  				}),
   514  			},
   515  		},
   516  	}
   517  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   518  		Provider: providers.Schema{
   519  			Block: &configschema.Block{
   520  				Attributes: map[string]*configschema.Attribute{
   521  					"foo": {Type: cty.String, Optional: true},
   522  				},
   523  			},
   524  		},
   525  		ResourceTypes: map[string]providers.Schema{
   526  			"test_instance": {
   527  				Block: &configschema.Block{
   528  					Attributes: map[string]*configschema.Attribute{
   529  						"id": {Type: cty.String, Optional: true, Computed: true},
   530  					},
   531  				},
   532  			},
   533  		},
   534  	}
   535  
   536  	configured := false
   537  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
   538  		var diags tfdiags.Diagnostics
   539  		configured = true
   540  		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
   541  			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
   542  		}
   543  		return providers.ConfigureProviderResponse{
   544  			Diagnostics: diags,
   545  		}
   546  	}
   547  
   548  	args := []string{
   549  		"-state", statePath,
   550  		"test_instance.foo",
   551  		"bar",
   552  	}
   553  	if code := c.Run(args); code != 0 {
   554  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   555  	}
   556  
   557  	// Verify that we were called
   558  	if !configured {
   559  		t.Fatal("Configure should be called")
   560  	}
   561  
   562  	if !p.ImportResourceStateCalled {
   563  		t.Fatal("ImportResourceState should be called")
   564  	}
   565  
   566  	testStateOutput(t, statePath, testImportStr)
   567  }
   568  
   569  func TestImport_providerConfigWithVarFile(t *testing.T) {
   570  	defer testChdir(t, testFixturePath("import-provider-var-file"))()
   571  
   572  	statePath := testTempFile(t)
   573  
   574  	p := testProvider()
   575  	ui := new(cli.MockUi)
   576  	view, _ := testView(t)
   577  	c := &ImportCommand{
   578  		Meta: Meta{
   579  			testingOverrides: metaOverridesForProvider(p),
   580  			Ui:               ui,
   581  			View:             view,
   582  		},
   583  	}
   584  
   585  	p.ImportResourceStateFn = nil
   586  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
   587  		ImportedResources: []providers.ImportedResource{
   588  			{
   589  				TypeName: "test_instance",
   590  				State: cty.ObjectVal(map[string]cty.Value{
   591  					"id": cty.StringVal("yay"),
   592  				}),
   593  			},
   594  		},
   595  	}
   596  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   597  		Provider: providers.Schema{
   598  			Block: &configschema.Block{
   599  				Attributes: map[string]*configschema.Attribute{
   600  					"foo": {Type: cty.String, Optional: true},
   601  				},
   602  			},
   603  		},
   604  		ResourceTypes: map[string]providers.Schema{
   605  			"test_instance": {
   606  				Block: &configschema.Block{
   607  					Attributes: map[string]*configschema.Attribute{
   608  						"id": {Type: cty.String, Optional: true, Computed: true},
   609  					},
   610  				},
   611  			},
   612  		},
   613  	}
   614  
   615  	configured := false
   616  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
   617  		var diags tfdiags.Diagnostics
   618  		configured = true
   619  		if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) {
   620  			diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want))
   621  		}
   622  		return providers.ConfigureProviderResponse{
   623  			Diagnostics: diags,
   624  		}
   625  	}
   626  
   627  	args := []string{
   628  		"-state", statePath,
   629  		"-var-file", "blah.tfvars",
   630  		"test_instance.foo",
   631  		"bar",
   632  	}
   633  	if code := c.Run(args); code != 0 {
   634  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   635  	}
   636  
   637  	// Verify that we were called
   638  	if !configured {
   639  		t.Fatal("Configure should be called")
   640  	}
   641  
   642  	if !p.ImportResourceStateCalled {
   643  		t.Fatal("ImportResourceState should be called")
   644  	}
   645  
   646  	testStateOutput(t, statePath, testImportStr)
   647  }
   648  
   649  func TestImport_allowMissingResourceConfig(t *testing.T) {
   650  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   651  
   652  	statePath := testTempFile(t)
   653  
   654  	p := testProvider()
   655  	ui := new(cli.MockUi)
   656  	view, _ := testView(t)
   657  	c := &ImportCommand{
   658  		Meta: Meta{
   659  			testingOverrides: metaOverridesForProvider(p),
   660  			Ui:               ui,
   661  			View:             view,
   662  		},
   663  	}
   664  
   665  	p.ImportResourceStateFn = nil
   666  	p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
   667  		ImportedResources: []providers.ImportedResource{
   668  			{
   669  				TypeName: "test_instance",
   670  				State: cty.ObjectVal(map[string]cty.Value{
   671  					"id": cty.StringVal("yay"),
   672  				}),
   673  			},
   674  		},
   675  	}
   676  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   677  		ResourceTypes: map[string]providers.Schema{
   678  			"test_instance": {
   679  				Block: &configschema.Block{
   680  					Attributes: map[string]*configschema.Attribute{
   681  						"id": {Type: cty.String, Optional: true, Computed: true},
   682  					},
   683  				},
   684  			},
   685  		},
   686  	}
   687  
   688  	args := []string{
   689  		"-state", statePath,
   690  		"-allow-missing-config",
   691  		"test_instance.foo",
   692  		"bar",
   693  	}
   694  
   695  	if code := c.Run(args); code != 0 {
   696  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   697  	}
   698  
   699  	if !p.ImportResourceStateCalled {
   700  		t.Fatal("ImportResourceState should be called")
   701  	}
   702  
   703  	testStateOutput(t, statePath, testImportStr)
   704  }
   705  
   706  func TestImport_emptyConfig(t *testing.T) {
   707  	defer testChdir(t, testFixturePath("empty"))()
   708  
   709  	statePath := testTempFile(t)
   710  
   711  	p := testProvider()
   712  	ui := new(cli.MockUi)
   713  	view, _ := testView(t)
   714  	c := &ImportCommand{
   715  		Meta: Meta{
   716  			testingOverrides: metaOverridesForProvider(p),
   717  			Ui:               ui,
   718  			View:             view,
   719  		},
   720  	}
   721  
   722  	args := []string{
   723  		"-state", statePath,
   724  		"test_instance.foo",
   725  		"bar",
   726  	}
   727  	code := c.Run(args)
   728  	if code != 1 {
   729  		t.Fatalf("import succeeded; expected failure")
   730  	}
   731  
   732  	msg := ui.ErrorWriter.String()
   733  	if want := `No Terraform configuration files`; !strings.Contains(msg, want) {
   734  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   735  	}
   736  }
   737  
   738  func TestImport_missingResourceConfig(t *testing.T) {
   739  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   740  
   741  	statePath := testTempFile(t)
   742  
   743  	p := testProvider()
   744  	ui := new(cli.MockUi)
   745  	view, _ := testView(t)
   746  	c := &ImportCommand{
   747  		Meta: Meta{
   748  			testingOverrides: metaOverridesForProvider(p),
   749  			Ui:               ui,
   750  			View:             view,
   751  		},
   752  	}
   753  
   754  	args := []string{
   755  		"-state", statePath,
   756  		"test_instance.foo",
   757  		"bar",
   758  	}
   759  	code := c.Run(args)
   760  	if code != 1 {
   761  		t.Fatalf("import succeeded; expected failure")
   762  	}
   763  
   764  	msg := ui.ErrorWriter.String()
   765  	if want := `resource address "test_instance.foo" does not exist`; !strings.Contains(msg, want) {
   766  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   767  	}
   768  }
   769  
   770  func TestImport_missingModuleConfig(t *testing.T) {
   771  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   772  
   773  	statePath := testTempFile(t)
   774  
   775  	p := testProvider()
   776  	ui := new(cli.MockUi)
   777  	view, _ := testView(t)
   778  	c := &ImportCommand{
   779  		Meta: Meta{
   780  			testingOverrides: metaOverridesForProvider(p),
   781  			Ui:               ui,
   782  			View:             view,
   783  		},
   784  	}
   785  
   786  	args := []string{
   787  		"-state", statePath,
   788  		"module.baz.test_instance.foo",
   789  		"bar",
   790  	}
   791  	code := c.Run(args)
   792  	if code != 1 {
   793  		t.Fatalf("import succeeded; expected failure")
   794  	}
   795  
   796  	msg := ui.ErrorWriter.String()
   797  	if want := `module.baz is not defined in the configuration`; !strings.Contains(msg, want) {
   798  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   799  	}
   800  }
   801  
   802  func TestImportModuleVarFile(t *testing.T) {
   803  	td := tempDir(t)
   804  	testCopyDir(t, testFixturePath("import-module-var-file"), td)
   805  	defer os.RemoveAll(td)
   806  	defer testChdir(t, td)()
   807  
   808  	statePath := testTempFile(t)
   809  
   810  	p := testProvider()
   811  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   812  		ResourceTypes: map[string]providers.Schema{
   813  			"test_instance": {
   814  				Block: &configschema.Block{
   815  					Attributes: map[string]*configschema.Attribute{
   816  						"foo": {Type: cty.String, Optional: true},
   817  					},
   818  				},
   819  			},
   820  		},
   821  	}
   822  
   823  	providerSource, close := newMockProviderSource(t, map[string][]string{
   824  		"test": []string{"1.2.3"},
   825  	})
   826  	defer close()
   827  
   828  	// init to install the module
   829  	ui := new(cli.MockUi)
   830  	view, _ := testView(t)
   831  	m := Meta{
   832  		testingOverrides: metaOverridesForProvider(testProvider()),
   833  		Ui:               ui,
   834  		View:             view,
   835  		ProviderSource:   providerSource,
   836  	}
   837  
   838  	ic := &InitCommand{
   839  		Meta: m,
   840  	}
   841  	if code := ic.Run([]string{}); code != 0 {
   842  		t.Fatalf("init failed\n%s", ui.ErrorWriter)
   843  	}
   844  
   845  	// import
   846  	ui = new(cli.MockUi)
   847  	c := &ImportCommand{
   848  		Meta: Meta{
   849  			testingOverrides: metaOverridesForProvider(p),
   850  			Ui:               ui,
   851  			View:             view,
   852  		},
   853  	}
   854  	args := []string{
   855  		"-state", statePath,
   856  		"module.child.test_instance.foo",
   857  		"bar",
   858  	}
   859  	code := c.Run(args)
   860  	if code != 0 {
   861  		t.Fatalf("import failed; expected success")
   862  	}
   863  }
   864  
   865  // This test covers an edge case where a module with a complex input variable
   866  // of nested objects has an invalid default which is overridden by the calling
   867  // context, and is used in locals. If we don't evaluate module call variables
   868  // for the import walk, this results in an error.
   869  //
   870  // The specific example has a variable "foo" which is a nested object:
   871  //
   872  //   foo = { bar = { baz = true } }
   873  //
   874  // This is used as foo = var.foo in the call to the child module, which then
   875  // uses the traversal foo.bar.baz in a local. A default value in the child
   876  // module of {} causes this local evaluation to error, breaking import.
   877  func TestImportModuleInputVariableEvaluation(t *testing.T) {
   878  	td := tempDir(t)
   879  	testCopyDir(t, testFixturePath("import-module-input-variable"), td)
   880  	defer os.RemoveAll(td)
   881  	defer testChdir(t, td)()
   882  
   883  	statePath := testTempFile(t)
   884  
   885  	p := testProvider()
   886  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   887  		ResourceTypes: map[string]providers.Schema{
   888  			"test_instance": {
   889  				Block: &configschema.Block{
   890  					Attributes: map[string]*configschema.Attribute{
   891  						"foo": {Type: cty.String, Optional: true},
   892  					},
   893  				},
   894  			},
   895  		},
   896  	}
   897  
   898  	providerSource, close := newMockProviderSource(t, map[string][]string{
   899  		"test": {"1.2.3"},
   900  	})
   901  	defer close()
   902  
   903  	// init to install the module
   904  	ui := new(cli.MockUi)
   905  	view, _ := testView(t)
   906  	m := Meta{
   907  		testingOverrides: metaOverridesForProvider(testProvider()),
   908  		Ui:               ui,
   909  		View:             view,
   910  		ProviderSource:   providerSource,
   911  	}
   912  
   913  	ic := &InitCommand{
   914  		Meta: m,
   915  	}
   916  	if code := ic.Run([]string{}); code != 0 {
   917  		t.Fatalf("init failed\n%s", ui.ErrorWriter)
   918  	}
   919  
   920  	// import
   921  	ui = new(cli.MockUi)
   922  	c := &ImportCommand{
   923  		Meta: Meta{
   924  			testingOverrides: metaOverridesForProvider(p),
   925  			Ui:               ui,
   926  			View:             view,
   927  		},
   928  	}
   929  	args := []string{
   930  		"-state", statePath,
   931  		"module.child.test_instance.foo",
   932  		"bar",
   933  	}
   934  	code := c.Run(args)
   935  	if code != 0 {
   936  		t.Fatalf("import failed; expected success")
   937  	}
   938  }
   939  
   940  func TestImport_dataResource(t *testing.T) {
   941  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   942  
   943  	statePath := testTempFile(t)
   944  
   945  	p := testProvider()
   946  	ui := new(cli.MockUi)
   947  	view, _ := testView(t)
   948  	c := &ImportCommand{
   949  		Meta: Meta{
   950  			testingOverrides: metaOverridesForProvider(p),
   951  			Ui:               ui,
   952  			View:             view,
   953  		},
   954  	}
   955  
   956  	args := []string{
   957  		"-state", statePath,
   958  		"data.test_data_source.foo",
   959  		"bar",
   960  	}
   961  	code := c.Run(args)
   962  	if code != 1 {
   963  		t.Fatalf("import succeeded; expected failure")
   964  	}
   965  
   966  	msg := ui.ErrorWriter.String()
   967  	if want := `A managed resource address is required`; !strings.Contains(msg, want) {
   968  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   969  	}
   970  }
   971  
   972  func TestImport_invalidResourceAddr(t *testing.T) {
   973  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   974  
   975  	statePath := testTempFile(t)
   976  
   977  	p := testProvider()
   978  	ui := new(cli.MockUi)
   979  	view, _ := testView(t)
   980  	c := &ImportCommand{
   981  		Meta: Meta{
   982  			testingOverrides: metaOverridesForProvider(p),
   983  			Ui:               ui,
   984  			View:             view,
   985  		},
   986  	}
   987  
   988  	args := []string{
   989  		"-state", statePath,
   990  		"bananas",
   991  		"bar",
   992  	}
   993  	code := c.Run(args)
   994  	if code != 1 {
   995  		t.Fatalf("import succeeded; expected failure")
   996  	}
   997  
   998  	msg := ui.ErrorWriter.String()
   999  	if want := `Error: Invalid address`; !strings.Contains(msg, want) {
  1000  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
  1001  	}
  1002  }
  1003  
  1004  func TestImport_targetIsModule(t *testing.T) {
  1005  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
  1006  
  1007  	statePath := testTempFile(t)
  1008  
  1009  	p := testProvider()
  1010  	ui := new(cli.MockUi)
  1011  	view, _ := testView(t)
  1012  	c := &ImportCommand{
  1013  		Meta: Meta{
  1014  			testingOverrides: metaOverridesForProvider(p),
  1015  			Ui:               ui,
  1016  			View:             view,
  1017  		},
  1018  	}
  1019  
  1020  	args := []string{
  1021  		"-state", statePath,
  1022  		"module.foo",
  1023  		"bar",
  1024  	}
  1025  	code := c.Run(args)
  1026  	if code != 1 {
  1027  		t.Fatalf("import succeeded; expected failure")
  1028  	}
  1029  
  1030  	msg := ui.ErrorWriter.String()
  1031  	if want := `Error: Invalid address`; !strings.Contains(msg, want) {
  1032  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
  1033  	}
  1034  }
  1035  
  1036  const testImportStr = `
  1037  test_instance.foo:
  1038    ID = yay
  1039    provider = provider["registry.terraform.io/hashicorp/test"]
  1040  `