github.com/opentofu/opentofu@v1.7.1/internal/command/state_show_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package command
     7  
     8  import (
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/opentofu/opentofu/internal/addrs"
    13  	"github.com/opentofu/opentofu/internal/configs/configschema"
    14  	"github.com/opentofu/opentofu/internal/providers"
    15  	"github.com/opentofu/opentofu/internal/states"
    16  	"github.com/opentofu/opentofu/internal/terminal"
    17  	"github.com/zclconf/go-cty/cty"
    18  )
    19  
    20  func TestStateShow(t *testing.T) {
    21  	state := states.BuildState(func(s *states.SyncState) {
    22  		s.SetResourceInstanceCurrent(
    23  			addrs.Resource{
    24  				Mode: addrs.ManagedResourceMode,
    25  				Type: "test_instance",
    26  				Name: "foo",
    27  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    28  			&states.ResourceInstanceObjectSrc{
    29  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
    30  				Status:    states.ObjectReady,
    31  			},
    32  			addrs.AbsProviderConfig{
    33  				Provider: addrs.NewDefaultProvider("test"),
    34  				Module:   addrs.RootModule,
    35  			},
    36  		)
    37  	})
    38  	statePath := testStateFile(t, state)
    39  
    40  	p := testProvider()
    41  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
    42  		ResourceTypes: map[string]providers.Schema{
    43  			"test_instance": {
    44  				Block: &configschema.Block{
    45  					Attributes: map[string]*configschema.Attribute{
    46  						"id":  {Type: cty.String, Optional: true, Computed: true},
    47  						"foo": {Type: cty.String, Optional: true},
    48  						"bar": {Type: cty.String, Optional: true},
    49  					},
    50  				},
    51  			},
    52  		},
    53  	}
    54  
    55  	streams, done := terminal.StreamsForTesting(t)
    56  	c := &StateShowCommand{
    57  		Meta: Meta{
    58  			testingOverrides: metaOverridesForProvider(p),
    59  			Streams:          streams,
    60  		},
    61  	}
    62  
    63  	args := []string{
    64  		"-state", statePath,
    65  		"test_instance.foo",
    66  	}
    67  	code := c.Run(args)
    68  	output := done(t)
    69  	if code != 0 {
    70  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
    71  	}
    72  
    73  	// Test that outputs were displayed
    74  	expected := strings.TrimSpace(testStateShowOutput) + "\n"
    75  	actual := output.Stdout()
    76  	if actual != expected {
    77  		t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected)
    78  	}
    79  }
    80  
    81  func TestStateShow_multi(t *testing.T) {
    82  	submod, _ := addrs.ParseModuleInstanceStr("module.sub")
    83  	state := states.BuildState(func(s *states.SyncState) {
    84  		s.SetResourceInstanceCurrent(
    85  			addrs.Resource{
    86  				Mode: addrs.ManagedResourceMode,
    87  				Type: "test_instance",
    88  				Name: "foo",
    89  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    90  			&states.ResourceInstanceObjectSrc{
    91  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
    92  				Status:    states.ObjectReady,
    93  			},
    94  			addrs.AbsProviderConfig{
    95  				Provider: addrs.NewDefaultProvider("test"),
    96  				Module:   addrs.RootModule,
    97  			},
    98  		)
    99  		s.SetResourceInstanceCurrent(
   100  			addrs.Resource{
   101  				Mode: addrs.ManagedResourceMode,
   102  				Type: "test_instance",
   103  				Name: "foo",
   104  			}.Instance(addrs.NoKey).Absolute(submod),
   105  			&states.ResourceInstanceObjectSrc{
   106  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   107  				Status:    states.ObjectReady,
   108  			},
   109  			addrs.AbsProviderConfig{
   110  				Provider: addrs.NewDefaultProvider("test"),
   111  				Module:   submod.Module(),
   112  			},
   113  		)
   114  	})
   115  	statePath := testStateFile(t, state)
   116  
   117  	p := testProvider()
   118  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   119  		ResourceTypes: map[string]providers.Schema{
   120  			"test_instance": {
   121  				Block: &configschema.Block{
   122  					Attributes: map[string]*configschema.Attribute{
   123  						"id":  {Type: cty.String, Optional: true, Computed: true},
   124  						"foo": {Type: cty.String, Optional: true},
   125  						"bar": {Type: cty.String, Optional: true},
   126  					},
   127  				},
   128  			},
   129  		},
   130  	}
   131  
   132  	streams, done := terminal.StreamsForTesting(t)
   133  	c := &StateShowCommand{
   134  		Meta: Meta{
   135  			testingOverrides: metaOverridesForProvider(p),
   136  			Streams:          streams,
   137  		},
   138  	}
   139  
   140  	args := []string{
   141  		"-state", statePath,
   142  		"test_instance.foo",
   143  	}
   144  	code := c.Run(args)
   145  	output := done(t)
   146  	if code != 0 {
   147  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   148  	}
   149  
   150  	// Test that outputs were displayed
   151  	expected := strings.TrimSpace(testStateShowOutput) + "\n"
   152  	actual := output.Stdout()
   153  	if actual != expected {
   154  		t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected)
   155  	}
   156  }
   157  
   158  func TestStateShow_noState(t *testing.T) {
   159  	testCwd(t)
   160  
   161  	p := testProvider()
   162  	streams, done := terminal.StreamsForTesting(t)
   163  	c := &StateShowCommand{
   164  		Meta: Meta{
   165  			testingOverrides: metaOverridesForProvider(p),
   166  			Streams:          streams,
   167  		},
   168  	}
   169  
   170  	args := []string{
   171  		"test_instance.foo",
   172  	}
   173  	if code := c.Run(args); code != 1 {
   174  		t.Fatalf("bad: %d", code)
   175  	}
   176  	output := done(t)
   177  	if !strings.Contains(output.Stderr(), "No state file was found!") {
   178  		t.Fatalf("expected a no state file error, got: %s", output.Stderr())
   179  	}
   180  }
   181  
   182  func TestStateShow_emptyState(t *testing.T) {
   183  	state := states.NewState()
   184  	statePath := testStateFile(t, state)
   185  
   186  	p := testProvider()
   187  	streams, done := terminal.StreamsForTesting(t)
   188  	c := &StateShowCommand{
   189  		Meta: Meta{
   190  			testingOverrides: metaOverridesForProvider(p),
   191  			Streams:          streams,
   192  		},
   193  	}
   194  
   195  	args := []string{
   196  		"-state", statePath,
   197  		"test_instance.foo",
   198  	}
   199  	if code := c.Run(args); code != 1 {
   200  		t.Fatalf("bad: %d", code)
   201  	}
   202  	output := done(t)
   203  	if !strings.Contains(output.Stderr(), "No instance found for the given address!") {
   204  		t.Fatalf("expected a no instance found error, got: %s", output.Stderr())
   205  	}
   206  }
   207  
   208  func TestStateShow_configured_provider(t *testing.T) {
   209  	state := states.BuildState(func(s *states.SyncState) {
   210  		s.SetResourceInstanceCurrent(
   211  			addrs.Resource{
   212  				Mode: addrs.ManagedResourceMode,
   213  				Type: "test_instance",
   214  				Name: "foo",
   215  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   216  			&states.ResourceInstanceObjectSrc{
   217  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   218  				Status:    states.ObjectReady,
   219  			},
   220  			addrs.AbsProviderConfig{
   221  				Provider: addrs.NewDefaultProvider("test-beta"),
   222  				Module:   addrs.RootModule,
   223  			},
   224  		)
   225  	})
   226  	statePath := testStateFile(t, state)
   227  
   228  	p := testProvider()
   229  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   230  		ResourceTypes: map[string]providers.Schema{
   231  			"test_instance": {
   232  				Block: &configschema.Block{
   233  					Attributes: map[string]*configschema.Attribute{
   234  						"id":  {Type: cty.String, Optional: true, Computed: true},
   235  						"foo": {Type: cty.String, Optional: true},
   236  						"bar": {Type: cty.String, Optional: true},
   237  					},
   238  				},
   239  			},
   240  		},
   241  	}
   242  
   243  	streams, done := terminal.StreamsForTesting(t)
   244  	c := &StateShowCommand{
   245  		Meta: Meta{
   246  			testingOverrides: &testingOverrides{
   247  				Providers: map[addrs.Provider]providers.Factory{
   248  					addrs.NewDefaultProvider("test-beta"): providers.FactoryFixed(p),
   249  				},
   250  			},
   251  			Streams: streams,
   252  		},
   253  	}
   254  
   255  	args := []string{
   256  		"-state", statePath,
   257  		"test_instance.foo",
   258  	}
   259  	code := c.Run(args)
   260  	output := done(t)
   261  	if code != 0 {
   262  		t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
   263  	}
   264  
   265  	// Test that outputs were displayed
   266  	expected := strings.TrimSpace(testStateShowOutput) + "\n"
   267  	actual := output.Stdout()
   268  	if actual != expected {
   269  		t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected)
   270  	}
   271  }
   272  
   273  const testStateShowOutput = `
   274  # test_instance.foo:
   275  resource "test_instance" "foo" {
   276      bar = "value"
   277      foo = "value"
   278      id  = "bar"
   279  }
   280  `