github.com/opentofu/opentofu@v1.7.1/internal/command/state_list_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/mitchellh/cli" 13 ) 14 15 func TestStateList(t *testing.T) { 16 state := testState() 17 statePath := testStateFile(t, state) 18 19 p := testProvider() 20 ui := cli.NewMockUi() 21 c := &StateListCommand{ 22 Meta: Meta{ 23 testingOverrides: metaOverridesForProvider(p), 24 Ui: ui, 25 }, 26 } 27 28 args := []string{ 29 "-state", statePath, 30 } 31 if code := c.Run(args); code != 0 { 32 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 33 } 34 35 // Test that outputs were displayed 36 expected := strings.TrimSpace(testStateListOutput) + "\n" 37 actual := ui.OutputWriter.String() 38 if actual != expected { 39 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 40 } 41 } 42 43 func TestStateListWithID(t *testing.T) { 44 state := testState() 45 statePath := testStateFile(t, state) 46 47 p := testProvider() 48 ui := cli.NewMockUi() 49 c := &StateListCommand{ 50 Meta: Meta{ 51 testingOverrides: metaOverridesForProvider(p), 52 Ui: ui, 53 }, 54 } 55 56 args := []string{ 57 "-state", statePath, 58 "-id", "bar", 59 } 60 if code := c.Run(args); code != 0 { 61 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 62 } 63 64 // Test that outputs were displayed 65 expected := strings.TrimSpace(testStateListOutput) + "\n" 66 actual := ui.OutputWriter.String() 67 if actual != expected { 68 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 69 } 70 } 71 72 func TestStateListWithNonExistentID(t *testing.T) { 73 state := testState() 74 statePath := testStateFile(t, state) 75 76 p := testProvider() 77 ui := cli.NewMockUi() 78 c := &StateListCommand{ 79 Meta: Meta{ 80 testingOverrides: metaOverridesForProvider(p), 81 Ui: ui, 82 }, 83 } 84 85 args := []string{ 86 "-state", statePath, 87 "-id", "baz", 88 } 89 if code := c.Run(args); code != 0 { 90 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 91 } 92 93 // Test that output is empty 94 if ui.OutputWriter != nil { 95 actual := ui.OutputWriter.String() 96 if actual != "" { 97 t.Fatalf("Expected an empty output but got: %q", actual) 98 } 99 } 100 } 101 102 func TestStateList_backendDefaultState(t *testing.T) { 103 // Create a temporary working directory that is empty 104 td := t.TempDir() 105 testCopyDir(t, testFixturePath("state-list-backend-default"), td) 106 defer testChdir(t, td)() 107 108 p := testProvider() 109 ui := cli.NewMockUi() 110 c := &StateListCommand{ 111 Meta: Meta{ 112 testingOverrides: metaOverridesForProvider(p), 113 Ui: ui, 114 }, 115 } 116 117 args := []string{} 118 if code := c.Run(args); code != 0 { 119 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 120 } 121 122 // Test that outputs were displayed 123 expected := "null_resource.a\n" 124 actual := ui.OutputWriter.String() 125 if actual != expected { 126 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 127 } 128 } 129 130 func TestStateList_backendCustomState(t *testing.T) { 131 // Create a temporary working directory that is empty 132 td := t.TempDir() 133 testCopyDir(t, testFixturePath("state-list-backend-custom"), td) 134 defer testChdir(t, td)() 135 136 p := testProvider() 137 ui := cli.NewMockUi() 138 c := &StateListCommand{ 139 Meta: Meta{ 140 testingOverrides: metaOverridesForProvider(p), 141 Ui: ui, 142 }, 143 } 144 145 args := []string{} 146 if code := c.Run(args); code != 0 { 147 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 148 } 149 150 // Test that outputs were displayed 151 expected := "null_resource.a\n" 152 actual := ui.OutputWriter.String() 153 if actual != expected { 154 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 155 } 156 } 157 158 func TestStateList_backendOverrideState(t *testing.T) { 159 // Create a temporary working directory that is empty 160 td := t.TempDir() 161 testCopyDir(t, testFixturePath("state-list-backend-custom"), td) 162 defer testChdir(t, td)() 163 164 p := testProvider() 165 ui := cli.NewMockUi() 166 c := &StateListCommand{ 167 Meta: Meta{ 168 testingOverrides: metaOverridesForProvider(p), 169 Ui: ui, 170 }, 171 } 172 173 // This test is configured to use a local backend that has 174 // a custom path defined. So we test if we can still pass 175 // is a user defined state file that will then override the 176 // one configured in the backend. As this file does not exist 177 // it should exit with a no state found error. 178 args := []string{"-state=" + DefaultStateFilename} 179 if code := c.Run(args); code != 1 { 180 t.Fatalf("bad: %d", code) 181 } 182 if !strings.Contains(ui.ErrorWriter.String(), "No state file was found!") { 183 t.Fatalf("expected a no state file error, got: %s", ui.ErrorWriter.String()) 184 } 185 } 186 187 func TestStateList_noState(t *testing.T) { 188 testCwd(t) 189 190 p := testProvider() 191 ui := cli.NewMockUi() 192 c := &StateListCommand{ 193 Meta: Meta{ 194 testingOverrides: metaOverridesForProvider(p), 195 Ui: ui, 196 }, 197 } 198 199 args := []string{} 200 if code := c.Run(args); code != 1 { 201 t.Fatalf("bad: %d", code) 202 } 203 } 204 205 func TestStateList_modules(t *testing.T) { 206 // Create a temporary working directory that is empty 207 td := t.TempDir() 208 testCopyDir(t, testFixturePath("state-list-nested-modules"), td) 209 defer testChdir(t, td)() 210 211 p := testProvider() 212 ui := cli.NewMockUi() 213 c := &StateListCommand{ 214 Meta: Meta{ 215 testingOverrides: metaOverridesForProvider(p), 216 Ui: ui, 217 }, 218 } 219 220 t.Run("list resources in module and submodules", func(t *testing.T) { 221 args := []string{"module.nest"} 222 if code := c.Run(args); code != 0 { 223 t.Fatalf("bad: %d", code) 224 } 225 226 // resources in the module and any submodules should be included in the outputs 227 expected := "module.nest.test_instance.nest\nmodule.nest.module.subnest.test_instance.subnest\n" 228 actual := ui.OutputWriter.String() 229 if actual != expected { 230 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 231 } 232 }) 233 234 t.Run("submodule has resources only", func(t *testing.T) { 235 // now get the state for a module that has no resources, only another nested module 236 ui.OutputWriter.Reset() 237 args := []string{"module.nonexist"} 238 if code := c.Run(args); code != 0 { 239 t.Fatalf("bad: %d", code) 240 } 241 expected := "module.nonexist.module.child.test_instance.child\n" 242 actual := ui.OutputWriter.String() 243 if actual != expected { 244 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 245 } 246 }) 247 248 t.Run("expanded module", func(t *testing.T) { 249 // finally get the state for a module with an index 250 ui.OutputWriter.Reset() 251 args := []string{"module.count"} 252 if code := c.Run(args); code != 0 { 253 t.Fatalf("bad: %d", code) 254 } 255 expected := "module.count[0].test_instance.count\nmodule.count[1].test_instance.count\n" 256 actual := ui.OutputWriter.String() 257 if actual != expected { 258 t.Fatalf("Expected:\n%q\n\nTo equal: %q", actual, expected) 259 } 260 }) 261 262 t.Run("completely nonexistent module", func(t *testing.T) { 263 // finally get the state for a module with an index 264 ui.OutputWriter.Reset() 265 args := []string{"module.notevenalittlebit"} 266 if code := c.Run(args); code != 1 { 267 t.Fatalf("bad: %d", code) 268 } 269 }) 270 271 } 272 273 const testStateListOutput = ` 274 test_instance.foo 275 `