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 `