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  `