| package command | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"io/ioutil" | 
 | 	"os" | 
 | 	"path/filepath" | 
 | 	"strings" | 
 | 	"testing" | 
 |  | 
 | 	"github.com/google/go-cmp/cmp" | 
 | 	"github.com/hashicorp/terraform/internal/addrs" | 
 | 	"github.com/hashicorp/terraform/internal/configs/configschema" | 
 | 	"github.com/hashicorp/terraform/internal/plans" | 
 | 	"github.com/hashicorp/terraform/internal/providers" | 
 | 	"github.com/hashicorp/terraform/internal/states" | 
 | 	"github.com/hashicorp/terraform/internal/states/statemgr" | 
 | 	"github.com/hashicorp/terraform/internal/terraform" | 
 | 	"github.com/hashicorp/terraform/version" | 
 | 	"github.com/mitchellh/cli" | 
 | 	"github.com/zclconf/go-cty/cty" | 
 | ) | 
 |  | 
 | func TestShow_badArgs(t *testing.T) { | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"bad", | 
 | 		"bad", | 
 | 		"-no-color", | 
 | 	} | 
 |  | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 1 { | 
 | 		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout()) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_noArgsNoState(t *testing.T) { | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	code := c.Run([]string{}) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `No state.` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_noArgsWithState(t *testing.T) { | 
 | 	// Get a temp cwd | 
 | 	testCwd(t) | 
 | 	// Create the default state | 
 | 	testStateFileDefault(t, testState()) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	code := c.Run([]string{}) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `# test_instance.foo:` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_argsWithState(t *testing.T) { | 
 | 	// Create the default state | 
 | 	statePath := testStateFile(t, testState()) | 
 | 	stateDir := filepath.Dir(statePath) | 
 | 	defer os.RemoveAll(stateDir) | 
 | 	defer testChdir(t, stateDir)() | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	path := filepath.Base(statePath) | 
 | 	args := []string{ | 
 | 		path, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 | } | 
 |  | 
 | // https://github.com/hashicorp/terraform/issues/21462 | 
 | func TestShow_argsWithStateAliasedProvider(t *testing.T) { | 
 | 	// Create the default state with aliased resource | 
 | 	testState := states.BuildState(func(s *states.SyncState) { | 
 | 		s.SetResourceInstanceCurrent( | 
 | 			addrs.Resource{ | 
 | 				Mode: addrs.ManagedResourceMode, | 
 | 				Type: "test_instance", | 
 | 				Name: "foo", | 
 | 			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), | 
 | 			&states.ResourceInstanceObjectSrc{ | 
 | 				// The weird whitespace here is reflective of how this would | 
 | 				// get written out in a real state file, due to the indentation | 
 | 				// of all of the containing wrapping objects and arrays. | 
 | 				AttrsJSON:    []byte("{\n            \"id\": \"bar\"\n          }"), | 
 | 				Status:       states.ObjectReady, | 
 | 				Dependencies: []addrs.ConfigResource{}, | 
 | 			}, | 
 | 			addrs.RootModuleInstance.ProviderConfigAliased(addrs.NewDefaultProvider("test"), "alias"), | 
 | 		) | 
 | 	}) | 
 |  | 
 | 	statePath := testStateFile(t, testState) | 
 | 	stateDir := filepath.Dir(statePath) | 
 | 	defer os.RemoveAll(stateDir) | 
 | 	defer testChdir(t, stateDir)() | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	path := filepath.Base(statePath) | 
 | 	args := []string{ | 
 | 		path, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `# missing schema for provider \"test.alias\"` | 
 | 	if strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s", got) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_argsPlanFileDoesNotExist(t *testing.T) { | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"doesNotExist.tfplan", | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 1 { | 
 | 		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout()) | 
 | 	} | 
 |  | 
 | 	got := output.Stderr() | 
 | 	want := `Plan read error: open doesNotExist.tfplan:` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_argsStatefileDoesNotExist(t *testing.T) { | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"doesNotExist.tfstate", | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 1 { | 
 | 		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout()) | 
 | 	} | 
 |  | 
 | 	got := output.Stderr() | 
 | 	want := `State read error: Error loading statefile:` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_json_argsPlanFileDoesNotExist(t *testing.T) { | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"-json", | 
 | 		"doesNotExist.tfplan", | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 1 { | 
 | 		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout()) | 
 | 	} | 
 |  | 
 | 	got := output.Stderr() | 
 | 	want := `Plan read error: open doesNotExist.tfplan:` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_json_argsStatefileDoesNotExist(t *testing.T) { | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"-json", | 
 | 		"doesNotExist.tfstate", | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 1 { | 
 | 		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout()) | 
 | 	} | 
 |  | 
 | 	got := output.Stderr() | 
 | 	want := `State read error: Error loading statefile:` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_planNoop(t *testing.T) { | 
 | 	planPath := testPlanFileNoop(t) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		planPath, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `No changes. Your infrastructure matches the configuration.` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_planWithChanges(t *testing.T) { | 
 | 	planPathWithChanges := showFixturePlanFile(t, plans.DeleteThenCreate) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(showFixtureProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		planPathWithChanges, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `test_instance.foo must be replaced` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_planWithForceReplaceChange(t *testing.T) { | 
 | 	// The main goal of this test is to see that the "replace by request" | 
 | 	// resource instance action reason can round-trip through a plan file and | 
 | 	// be reflected correctly in the "terraform show" output, the same way | 
 | 	// as it would appear in "terraform plan" output. | 
 |  | 
 | 	_, snap := testModuleWithSnapshot(t, "show") | 
 | 	plannedVal := cty.ObjectVal(map[string]cty.Value{ | 
 | 		"id":  cty.UnknownVal(cty.String), | 
 | 		"ami": cty.StringVal("bar"), | 
 | 	}) | 
 | 	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	plan := testPlan(t) | 
 | 	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ | 
 | 		Addr: addrs.Resource{ | 
 | 			Mode: addrs.ManagedResourceMode, | 
 | 			Type: "test_instance", | 
 | 			Name: "foo", | 
 | 		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), | 
 | 		ProviderAddr: addrs.AbsProviderConfig{ | 
 | 			Provider: addrs.NewDefaultProvider("test"), | 
 | 			Module:   addrs.RootModule, | 
 | 		}, | 
 | 		ChangeSrc: plans.ChangeSrc{ | 
 | 			Action: plans.CreateThenDelete, | 
 | 			Before: priorValRaw, | 
 | 			After:  plannedValRaw, | 
 | 		}, | 
 | 		ActionReason: plans.ResourceInstanceReplaceByRequest, | 
 | 	}) | 
 | 	planFilePath := testPlanFile( | 
 | 		t, | 
 | 		snap, | 
 | 		states.NewState(), | 
 | 		plan, | 
 | 	) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(showFixtureProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		planFilePath, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `test_instance.foo will be replaced, as requested` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want) | 
 | 	} | 
 |  | 
 | 	want = `Plan: 1 to add, 0 to change, 1 to destroy.` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want) | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | func TestShow_plan_json(t *testing.T) { | 
 | 	planPath := showFixturePlanFile(t, plans.Create) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(showFixtureProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"-json", | 
 | 		planPath, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_state(t *testing.T) { | 
 | 	originalState := testState() | 
 | 	statePath := testStateFile(t, originalState) | 
 | 	defer os.RemoveAll(filepath.Dir(statePath)) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		statePath, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_json_output(t *testing.T) { | 
 | 	fixtureDir := "testdata/show-json" | 
 | 	testDirs, err := ioutil.ReadDir(fixtureDir) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	for _, entry := range testDirs { | 
 | 		if !entry.IsDir() { | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		t.Run(entry.Name(), func(t *testing.T) { | 
 | 			td := t.TempDir() | 
 | 			inputDir := filepath.Join(fixtureDir, entry.Name()) | 
 | 			testCopyDir(t, inputDir, td) | 
 | 			defer testChdir(t, td)() | 
 |  | 
 | 			expectError := strings.Contains(entry.Name(), "error") | 
 |  | 
 | 			providerSource, close := newMockProviderSource(t, map[string][]string{ | 
 | 				"test":            {"1.2.3"}, | 
 | 				"hashicorp2/test": {"1.2.3"}, | 
 | 			}) | 
 | 			defer close() | 
 |  | 
 | 			p := showFixtureProvider() | 
 |  | 
 | 			// init | 
 | 			ui := new(cli.MockUi) | 
 | 			ic := &InitCommand{ | 
 | 				Meta: Meta{ | 
 | 					testingOverrides: metaOverridesForProvider(p), | 
 | 					Ui:               ui, | 
 | 					ProviderSource:   providerSource, | 
 | 				}, | 
 | 			} | 
 | 			if code := ic.Run([]string{}); code != 0 { | 
 | 				if expectError { | 
 | 					// this should error, but not panic. | 
 | 					return | 
 | 				} | 
 | 				t.Fatalf("init failed\n%s", ui.ErrorWriter) | 
 | 			} | 
 |  | 
 | 			// plan | 
 | 			planView, planDone := testView(t) | 
 | 			pc := &PlanCommand{ | 
 | 				Meta: Meta{ | 
 | 					testingOverrides: metaOverridesForProvider(p), | 
 | 					View:             planView, | 
 | 					ProviderSource:   providerSource, | 
 | 				}, | 
 | 			} | 
 |  | 
 | 			args := []string{ | 
 | 				"-out=terraform.plan", | 
 | 			} | 
 |  | 
 | 			code := pc.Run(args) | 
 | 			planOutput := planDone(t) | 
 |  | 
 | 			if code != 0 { | 
 | 				t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr()) | 
 | 			} | 
 |  | 
 | 			// show | 
 | 			showView, showDone := testView(t) | 
 | 			sc := &ShowCommand{ | 
 | 				Meta: Meta{ | 
 | 					testingOverrides: metaOverridesForProvider(p), | 
 | 					View:             showView, | 
 | 					ProviderSource:   providerSource, | 
 | 				}, | 
 | 			} | 
 |  | 
 | 			args = []string{ | 
 | 				"-json", | 
 | 				"terraform.plan", | 
 | 			} | 
 | 			defer os.Remove("terraform.plan") | 
 | 			code = sc.Run(args) | 
 | 			showOutput := showDone(t) | 
 |  | 
 | 			if code != 0 { | 
 | 				t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr()) | 
 | 			} | 
 |  | 
 | 			// compare view output to wanted output | 
 | 			var got, want plan | 
 |  | 
 | 			gotString := showOutput.Stdout() | 
 | 			json.Unmarshal([]byte(gotString), &got) | 
 |  | 
 | 			wantFile, err := os.Open("output.json") | 
 | 			if err != nil { | 
 | 				t.Fatalf("unexpected err: %s", err) | 
 | 			} | 
 | 			defer wantFile.Close() | 
 | 			byteValue, err := ioutil.ReadAll(wantFile) | 
 | 			if err != nil { | 
 | 				t.Fatalf("unexpected err: %s", err) | 
 | 			} | 
 | 			json.Unmarshal([]byte(byteValue), &want) | 
 |  | 
 | 			// Disregard format version to reduce needless test fixture churn | 
 | 			want.FormatVersion = got.FormatVersion | 
 |  | 
 | 			if !cmp.Equal(got, want) { | 
 | 				t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want)) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_json_output_sensitive(t *testing.T) { | 
 | 	td := t.TempDir() | 
 | 	inputDir := "testdata/show-json-sensitive" | 
 | 	testCopyDir(t, inputDir, td) | 
 | 	defer testChdir(t, td)() | 
 |  | 
 | 	providerSource, close := newMockProviderSource(t, map[string][]string{"test": {"1.2.3"}}) | 
 | 	defer close() | 
 |  | 
 | 	p := showFixtureSensitiveProvider() | 
 |  | 
 | 	// init | 
 | 	ui := new(cli.MockUi) | 
 | 	ic := &InitCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(p), | 
 | 			Ui:               ui, | 
 | 			ProviderSource:   providerSource, | 
 | 		}, | 
 | 	} | 
 | 	if code := ic.Run([]string{}); code != 0 { | 
 | 		t.Fatalf("init failed\n%s", ui.ErrorWriter) | 
 | 	} | 
 |  | 
 | 	// plan | 
 | 	planView, planDone := testView(t) | 
 | 	pc := &PlanCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(p), | 
 | 			View:             planView, | 
 | 			ProviderSource:   providerSource, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"-out=terraform.plan", | 
 | 	} | 
 | 	code := pc.Run(args) | 
 | 	planOutput := planDone(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr()) | 
 | 	} | 
 |  | 
 | 	// show | 
 | 	showView, showDone := testView(t) | 
 | 	sc := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(p), | 
 | 			View:             showView, | 
 | 			ProviderSource:   providerSource, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args = []string{ | 
 | 		"-json", | 
 | 		"terraform.plan", | 
 | 	} | 
 | 	defer os.Remove("terraform.plan") | 
 | 	code = sc.Run(args) | 
 | 	showOutput := showDone(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr()) | 
 | 	} | 
 |  | 
 | 	// compare ui output to wanted output | 
 | 	var got, want plan | 
 |  | 
 | 	gotString := showOutput.Stdout() | 
 | 	json.Unmarshal([]byte(gotString), &got) | 
 |  | 
 | 	wantFile, err := os.Open("output.json") | 
 | 	if err != nil { | 
 | 		t.Fatalf("unexpected err: %s", err) | 
 | 	} | 
 | 	defer wantFile.Close() | 
 | 	byteValue, err := ioutil.ReadAll(wantFile) | 
 | 	if err != nil { | 
 | 		t.Fatalf("unexpected err: %s", err) | 
 | 	} | 
 | 	json.Unmarshal([]byte(byteValue), &want) | 
 |  | 
 | 	// Disregard format version to reduce needless test fixture churn | 
 | 	want.FormatVersion = got.FormatVersion | 
 |  | 
 | 	if !cmp.Equal(got, want) { | 
 | 		t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want)) | 
 | 	} | 
 | } | 
 |  | 
 | // Failing conditions are only present in JSON output for refresh-only plans, | 
 | // so we test that separately here. | 
 | func TestShow_json_output_conditions_refresh_only(t *testing.T) { | 
 | 	td := t.TempDir() | 
 | 	inputDir := "testdata/show-json/conditions" | 
 | 	testCopyDir(t, inputDir, td) | 
 | 	defer testChdir(t, td)() | 
 |  | 
 | 	providerSource, close := newMockProviderSource(t, map[string][]string{"test": {"1.2.3"}}) | 
 | 	defer close() | 
 |  | 
 | 	p := showFixtureSensitiveProvider() | 
 |  | 
 | 	// init | 
 | 	ui := new(cli.MockUi) | 
 | 	ic := &InitCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(p), | 
 | 			Ui:               ui, | 
 | 			ProviderSource:   providerSource, | 
 | 		}, | 
 | 	} | 
 | 	if code := ic.Run([]string{}); code != 0 { | 
 | 		t.Fatalf("init failed\n%s", ui.ErrorWriter) | 
 | 	} | 
 |  | 
 | 	// plan | 
 | 	planView, planDone := testView(t) | 
 | 	pc := &PlanCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(p), | 
 | 			View:             planView, | 
 | 			ProviderSource:   providerSource, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		"-refresh-only", | 
 | 		"-out=terraform.plan", | 
 | 		"-var=ami=bad-ami", | 
 | 		"-state=for-refresh.tfstate", | 
 | 	} | 
 | 	code := pc.Run(args) | 
 | 	planOutput := planDone(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr()) | 
 | 	} | 
 |  | 
 | 	// show | 
 | 	showView, showDone := testView(t) | 
 | 	sc := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(p), | 
 | 			View:             showView, | 
 | 			ProviderSource:   providerSource, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args = []string{ | 
 | 		"-json", | 
 | 		"terraform.plan", | 
 | 	} | 
 | 	defer os.Remove("terraform.plan") | 
 | 	code = sc.Run(args) | 
 | 	showOutput := showDone(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr()) | 
 | 	} | 
 |  | 
 | 	// compare JSON output to wanted output | 
 | 	var got, want plan | 
 |  | 
 | 	gotString := showOutput.Stdout() | 
 | 	json.Unmarshal([]byte(gotString), &got) | 
 |  | 
 | 	wantFile, err := os.Open("output-refresh-only.json") | 
 | 	if err != nil { | 
 | 		t.Fatalf("unexpected err: %s", err) | 
 | 	} | 
 | 	defer wantFile.Close() | 
 | 	byteValue, err := ioutil.ReadAll(wantFile) | 
 | 	if err != nil { | 
 | 		t.Fatalf("unexpected err: %s", err) | 
 | 	} | 
 | 	json.Unmarshal([]byte(byteValue), &want) | 
 |  | 
 | 	// Disregard format version to reduce needless test fixture churn | 
 | 	want.FormatVersion = got.FormatVersion | 
 |  | 
 | 	if !cmp.Equal(got, want) { | 
 | 		t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want)) | 
 | 	} | 
 | } | 
 |  | 
 | // similar test as above, without the plan | 
 | func TestShow_json_output_state(t *testing.T) { | 
 | 	fixtureDir := "testdata/show-json-state" | 
 | 	testDirs, err := ioutil.ReadDir(fixtureDir) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	for _, entry := range testDirs { | 
 | 		if !entry.IsDir() { | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		t.Run(entry.Name(), func(t *testing.T) { | 
 | 			td := t.TempDir() | 
 | 			inputDir := filepath.Join(fixtureDir, entry.Name()) | 
 | 			testCopyDir(t, inputDir, td) | 
 | 			defer testChdir(t, td)() | 
 |  | 
 | 			providerSource, close := newMockProviderSource(t, map[string][]string{ | 
 | 				"test": {"1.2.3"}, | 
 | 			}) | 
 | 			defer close() | 
 |  | 
 | 			p := showFixtureProvider() | 
 |  | 
 | 			// init | 
 | 			ui := new(cli.MockUi) | 
 | 			ic := &InitCommand{ | 
 | 				Meta: Meta{ | 
 | 					testingOverrides: metaOverridesForProvider(p), | 
 | 					Ui:               ui, | 
 | 					ProviderSource:   providerSource, | 
 | 				}, | 
 | 			} | 
 | 			if code := ic.Run([]string{}); code != 0 { | 
 | 				t.Fatalf("init failed\n%s", ui.ErrorWriter) | 
 | 			} | 
 |  | 
 | 			// show | 
 | 			showView, showDone := testView(t) | 
 | 			sc := &ShowCommand{ | 
 | 				Meta: Meta{ | 
 | 					testingOverrides: metaOverridesForProvider(p), | 
 | 					View:             showView, | 
 | 					ProviderSource:   providerSource, | 
 | 				}, | 
 | 			} | 
 |  | 
 | 			code := sc.Run([]string{"-json"}) | 
 | 			showOutput := showDone(t) | 
 |  | 
 | 			if code != 0 { | 
 | 				t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, showOutput.Stderr()) | 
 | 			} | 
 |  | 
 | 			// compare ui output to wanted output | 
 | 			type state struct { | 
 | 				FormatVersion    string                 `json:"format_version,omitempty"` | 
 | 				TerraformVersion string                 `json:"terraform_version"` | 
 | 				Values           map[string]interface{} `json:"values,omitempty"` | 
 | 				SensitiveValues  map[string]bool        `json:"sensitive_values,omitempty"` | 
 | 			} | 
 | 			var got, want state | 
 |  | 
 | 			gotString := showOutput.Stdout() | 
 | 			json.Unmarshal([]byte(gotString), &got) | 
 |  | 
 | 			wantFile, err := os.Open("output.json") | 
 | 			if err != nil { | 
 | 				t.Fatalf("unexpected error: %s", err) | 
 | 			} | 
 | 			defer wantFile.Close() | 
 | 			byteValue, err := ioutil.ReadAll(wantFile) | 
 | 			if err != nil { | 
 | 				t.Fatalf("unexpected err: %s", err) | 
 | 			} | 
 | 			json.Unmarshal([]byte(byteValue), &want) | 
 |  | 
 | 			if !cmp.Equal(got, want) { | 
 | 				t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want)) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_planWithNonDefaultStateLineage(t *testing.T) { | 
 | 	// Create a temporary working directory that is empty | 
 | 	td := t.TempDir() | 
 | 	testCopyDir(t, testFixturePath("show"), td) | 
 | 	defer testChdir(t, td)() | 
 |  | 
 | 	// Write default state file with a testing lineage ("fake-for-testing") | 
 | 	testStateFileDefault(t, testState()) | 
 |  | 
 | 	// Create a plan with a different lineage, which we should still be able | 
 | 	// to show | 
 | 	_, snap := testModuleWithSnapshot(t, "show") | 
 | 	state := testState() | 
 | 	plan := testPlan(t) | 
 | 	stateMeta := statemgr.SnapshotMeta{ | 
 | 		Lineage:          "fake-for-plan", | 
 | 		Serial:           1, | 
 | 		TerraformVersion: version.SemVer, | 
 | 	} | 
 | 	planPath := testPlanFileMatchState(t, snap, state, plan, stateMeta) | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	args := []string{ | 
 | 		planPath, | 
 | 		"-no-color", | 
 | 	} | 
 | 	code := c.Run(args) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 0 { | 
 | 		t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr()) | 
 | 	} | 
 |  | 
 | 	got := output.Stdout() | 
 | 	want := `No changes. Your infrastructure matches the configuration.` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestShow_corruptStatefile(t *testing.T) { | 
 | 	td := t.TempDir() | 
 | 	inputDir := "testdata/show-corrupt-statefile" | 
 | 	testCopyDir(t, inputDir, td) | 
 | 	defer testChdir(t, td)() | 
 |  | 
 | 	view, done := testView(t) | 
 | 	c := &ShowCommand{ | 
 | 		Meta: Meta{ | 
 | 			testingOverrides: metaOverridesForProvider(testProvider()), | 
 | 			View:             view, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	code := c.Run([]string{}) | 
 | 	output := done(t) | 
 |  | 
 | 	if code != 1 { | 
 | 		t.Fatalf("unexpected exit status %d; want 1\ngot: %s", code, output.Stdout()) | 
 | 	} | 
 |  | 
 | 	got := output.Stderr() | 
 | 	want := `Unsupported state file format` | 
 | 	if !strings.Contains(got, want) { | 
 | 		t.Errorf("unexpected output\ngot: %s\nwant:\n%s", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | // showFixtureSchema returns a schema suitable for processing the configuration | 
 | // in testdata/show. This schema should be assigned to a mock provider | 
 | // named "test". | 
 | func showFixtureSchema() *providers.GetProviderSchemaResponse { | 
 | 	return &providers.GetProviderSchemaResponse{ | 
 | 		Provider: providers.Schema{ | 
 | 			Block: &configschema.Block{ | 
 | 				Attributes: map[string]*configschema.Attribute{ | 
 | 					"region": {Type: cty.String, Optional: true}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		ResourceTypes: map[string]providers.Schema{ | 
 | 			"test_instance": { | 
 | 				Block: &configschema.Block{ | 
 | 					Attributes: map[string]*configschema.Attribute{ | 
 | 						"id":  {Type: cty.String, Optional: true, Computed: true}, | 
 | 						"ami": {Type: cty.String, Optional: true}, | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 	} | 
 | } | 
 |  | 
 | // showFixtureSensitiveSchema returns a schema suitable for processing the configuration | 
 | // in testdata/show. This schema should be assigned to a mock provider | 
 | // named "test". It includes a sensitive attribute. | 
 | func showFixtureSensitiveSchema() *providers.GetProviderSchemaResponse { | 
 | 	return &providers.GetProviderSchemaResponse{ | 
 | 		Provider: providers.Schema{ | 
 | 			Block: &configschema.Block{ | 
 | 				Attributes: map[string]*configschema.Attribute{ | 
 | 					"region": {Type: cty.String, Optional: true}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		ResourceTypes: map[string]providers.Schema{ | 
 | 			"test_instance": { | 
 | 				Block: &configschema.Block{ | 
 | 					Attributes: map[string]*configschema.Attribute{ | 
 | 						"id":       {Type: cty.String, Optional: true, Computed: true}, | 
 | 						"ami":      {Type: cty.String, Optional: true}, | 
 | 						"password": {Type: cty.String, Optional: true, Sensitive: true}, | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 	} | 
 | } | 
 |  | 
 | // showFixtureProvider returns a mock provider that is configured for basic | 
 | // operation with the configuration in testdata/show. This mock has | 
 | // GetSchemaResponse, PlanResourceChangeFn, and ApplyResourceChangeFn populated, | 
 | // with the plan/apply steps just passing through the data determined by | 
 | // Terraform Core. | 
 | func showFixtureProvider() *terraform.MockProvider { | 
 | 	p := testProvider() | 
 | 	p.GetProviderSchemaResponse = showFixtureSchema() | 
 | 	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { | 
 | 		idVal := req.PriorState.GetAttr("id") | 
 | 		amiVal := req.PriorState.GetAttr("ami") | 
 | 		if amiVal.RawEquals(cty.StringVal("refresh-me")) { | 
 | 			amiVal = cty.StringVal("refreshed") | 
 | 		} | 
 | 		return providers.ReadResourceResponse{ | 
 | 			NewState: cty.ObjectVal(map[string]cty.Value{ | 
 | 				"id":  idVal, | 
 | 				"ami": amiVal, | 
 | 			}), | 
 | 			Private: req.Private, | 
 | 		} | 
 | 	} | 
 | 	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { | 
 | 		// this is a destroy plan, | 
 | 		if req.ProposedNewState.IsNull() { | 
 | 			resp.PlannedState = req.ProposedNewState | 
 | 			resp.PlannedPrivate = req.PriorPrivate | 
 | 			return resp | 
 | 		} | 
 |  | 
 | 		idVal := req.ProposedNewState.GetAttr("id") | 
 | 		amiVal := req.ProposedNewState.GetAttr("ami") | 
 | 		if idVal.IsNull() { | 
 | 			idVal = cty.UnknownVal(cty.String) | 
 | 		} | 
 | 		var reqRep []cty.Path | 
 | 		if amiVal.RawEquals(cty.StringVal("force-replace")) { | 
 | 			reqRep = append(reqRep, cty.GetAttrPath("ami")) | 
 | 		} | 
 | 		return providers.PlanResourceChangeResponse{ | 
 | 			PlannedState: cty.ObjectVal(map[string]cty.Value{ | 
 | 				"id":  idVal, | 
 | 				"ami": amiVal, | 
 | 			}), | 
 | 			RequiresReplace: reqRep, | 
 | 		} | 
 | 	} | 
 | 	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { | 
 | 		idVal := req.PlannedState.GetAttr("id") | 
 | 		amiVal := req.PlannedState.GetAttr("ami") | 
 | 		if !idVal.IsKnown() { | 
 | 			idVal = cty.StringVal("placeholder") | 
 | 		} | 
 | 		return providers.ApplyResourceChangeResponse{ | 
 | 			NewState: cty.ObjectVal(map[string]cty.Value{ | 
 | 				"id":  idVal, | 
 | 				"ami": amiVal, | 
 | 			}), | 
 | 		} | 
 | 	} | 
 | 	return p | 
 | } | 
 |  | 
 | // showFixtureSensitiveProvider returns a mock provider that is configured for basic | 
 | // operation with the configuration in testdata/show. This mock has | 
 | // GetSchemaResponse, PlanResourceChangeFn, and ApplyResourceChangeFn populated, | 
 | // with the plan/apply steps just passing through the data determined by | 
 | // Terraform Core. It also has a sensitive attribute in the provider schema. | 
 | func showFixtureSensitiveProvider() *terraform.MockProvider { | 
 | 	p := testProvider() | 
 | 	p.GetProviderSchemaResponse = showFixtureSensitiveSchema() | 
 | 	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { | 
 | 		idVal := req.ProposedNewState.GetAttr("id") | 
 | 		if idVal.IsNull() { | 
 | 			idVal = cty.UnknownVal(cty.String) | 
 | 		} | 
 | 		return providers.PlanResourceChangeResponse{ | 
 | 			PlannedState: cty.ObjectVal(map[string]cty.Value{ | 
 | 				"id":       idVal, | 
 | 				"ami":      req.ProposedNewState.GetAttr("ami"), | 
 | 				"password": req.ProposedNewState.GetAttr("password"), | 
 | 			}), | 
 | 		} | 
 | 	} | 
 | 	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { | 
 | 		idVal := req.PlannedState.GetAttr("id") | 
 | 		if !idVal.IsKnown() { | 
 | 			idVal = cty.StringVal("placeholder") | 
 | 		} | 
 | 		return providers.ApplyResourceChangeResponse{ | 
 | 			NewState: cty.ObjectVal(map[string]cty.Value{ | 
 | 				"id":       idVal, | 
 | 				"ami":      req.PlannedState.GetAttr("ami"), | 
 | 				"password": req.PlannedState.GetAttr("password"), | 
 | 			}), | 
 | 		} | 
 | 	} | 
 | 	return p | 
 | } | 
 |  | 
 | // showFixturePlanFile creates a plan file at a temporary location containing a | 
 | // single change to create or update the test_instance.foo that is included in the "show" | 
 | // test fixture, returning the location of that plan file. | 
 | // `action` is the planned change you would like to elicit | 
 | func showFixturePlanFile(t *testing.T, action plans.Action) string { | 
 | 	_, snap := testModuleWithSnapshot(t, "show") | 
 | 	plannedVal := cty.ObjectVal(map[string]cty.Value{ | 
 | 		"id":  cty.UnknownVal(cty.String), | 
 | 		"ami": cty.StringVal("bar"), | 
 | 	}) | 
 | 	priorValRaw, err := plans.NewDynamicValue(cty.NullVal(plannedVal.Type()), plannedVal.Type()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	plannedValRaw, err := plans.NewDynamicValue(plannedVal, plannedVal.Type()) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	plan := testPlan(t) | 
 | 	plan.Changes.SyncWrapper().AppendResourceInstanceChange(&plans.ResourceInstanceChangeSrc{ | 
 | 		Addr: addrs.Resource{ | 
 | 			Mode: addrs.ManagedResourceMode, | 
 | 			Type: "test_instance", | 
 | 			Name: "foo", | 
 | 		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), | 
 | 		ProviderAddr: addrs.AbsProviderConfig{ | 
 | 			Provider: addrs.NewDefaultProvider("test"), | 
 | 			Module:   addrs.RootModule, | 
 | 		}, | 
 | 		ChangeSrc: plans.ChangeSrc{ | 
 | 			Action: action, | 
 | 			Before: priorValRaw, | 
 | 			After:  plannedValRaw, | 
 | 		}, | 
 | 	}) | 
 | 	return testPlanFile( | 
 | 		t, | 
 | 		snap, | 
 | 		states.NewState(), | 
 | 		plan, | 
 | 	) | 
 | } | 
 |  | 
 | // this simplified plan struct allows us to preserve field order when marshaling | 
 | // the command output. NOTE: we are leaving "terraform_version" out of this test | 
 | // to avoid needing to constantly update the expected output; as a potential | 
 | // TODO we could write a jsonplan compare function. | 
 | type plan struct { | 
 | 	FormatVersion   string                 `json:"format_version,omitempty"` | 
 | 	Variables       map[string]interface{} `json:"variables,omitempty"` | 
 | 	PlannedValues   map[string]interface{} `json:"planned_values,omitempty"` | 
 | 	ResourceDrift   []interface{}          `json:"resource_drift,omitempty"` | 
 | 	ResourceChanges []interface{}          `json:"resource_changes,omitempty"` | 
 | 	OutputChanges   map[string]interface{} `json:"output_changes,omitempty"` | 
 | 	PriorState      priorState             `json:"prior_state,omitempty"` | 
 | 	Config          map[string]interface{} `json:"configuration,omitempty"` | 
 | } | 
 |  | 
 | type priorState struct { | 
 | 	FormatVersion   string                 `json:"format_version,omitempty"` | 
 | 	Values          map[string]interface{} `json:"values,omitempty"` | 
 | 	SensitiveValues map[string]bool        `json:"sensitive_values,omitempty"` | 
 | } |