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