| // Copyright (c) The OpenTofu Authors | |
| // SPDX-License-Identifier: MPL-2.0 | |
| // Copyright (c) 2023 HashiCorp, Inc. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| package command | |
| import ( | |
| "flag" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| "testing" | |
| "github.com/opentofu/opentofu/internal/command/arguments" | |
| "github.com/opentofu/opentofu/internal/command/workdir" | |
| "github.com/opentofu/opentofu/internal/backend" | |
| "github.com/opentofu/opentofu/internal/backend/local" | |
| "github.com/opentofu/opentofu/internal/tofu" | |
| ) | |
| func TestMetaInputMode(t *testing.T) { | |
| test = false | |
| defer func() { test = true }() | |
| m := &Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| stateArgs: arguments.State{Lock: true}, | |
| } | |
| // TODO meta-refactor: these assignments are needed because the extendedFlagSet was used here before, | |
| // which had these with defaults as "true". In a future iteration, once these are not needed, we need to remove them. | |
| m.input = true | |
| args := []string{} | |
| fs := flag.NewFlagSet("foo", flag.ContinueOnError) | |
| if err := fs.Parse(args); err != nil { | |
| t.Fatalf("err: %s", err) | |
| } | |
| if m.InputMode() != tofu.InputModeStd { | |
| t.Fatalf("bad: %#v", m.InputMode()) | |
| } | |
| } | |
| func TestMetaInputMode_envVar(t *testing.T) { | |
| test = false | |
| defer func() { test = true }() | |
| m := &Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| stateArgs: arguments.State{Lock: true}, | |
| } | |
| // TODO meta-refactor: these assignments are needed because the extendedFlagSet was used here before, | |
| // which had these with defaults as "true". In a future iteration, once these are not needed, we need to remove them. | |
| m.input = true | |
| args := []string{} | |
| fs := flag.NewFlagSet("foo", flag.ContinueOnError) | |
| if err := fs.Parse(args); err != nil { | |
| t.Fatalf("err: %s", err) | |
| } | |
| off := tofu.InputMode(0) | |
| on := tofu.InputModeStd | |
| cases := []struct { | |
| EnvVar string | |
| Expected tofu.InputMode | |
| }{ | |
| {"false", off}, | |
| {"0", off}, | |
| {"true", on}, | |
| {"1", on}, | |
| } | |
| for _, tc := range cases { | |
| t.Setenv(InputModeEnvVar, tc.EnvVar) | |
| if m.InputMode() != tc.Expected { | |
| t.Fatalf("expected InputMode: %#v, got: %#v", tc.Expected, m.InputMode()) | |
| } | |
| } | |
| } | |
| func TestMetaInputMode_disable(t *testing.T) { | |
| test = false | |
| defer func() { test = true }() | |
| m := &Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| stateArgs: arguments.State{Lock: true}, | |
| input: false, | |
| } | |
| if m.InputMode() > 0 { | |
| t.Fatalf("bad: %#v", m.InputMode()) | |
| } | |
| } | |
| func TestMeta_Env(t *testing.T) { | |
| td := t.TempDir() | |
| t.Chdir(td) | |
| m := &Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| } | |
| env, err := m.Workspace(t.Context()) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| if env != backend.DefaultStateName { | |
| t.Fatalf("expected env %q, got env %q", backend.DefaultStateName, env) | |
| } | |
| testEnv := "test_env" | |
| if err := m.SetWorkspace(testEnv); err != nil { | |
| t.Fatal("error setting env:", err) | |
| } | |
| env, _ = m.Workspace(t.Context()) | |
| if env != testEnv { | |
| t.Fatalf("expected env %q, got env %q", testEnv, env) | |
| } | |
| if err := m.SetWorkspace(backend.DefaultStateName); err != nil { | |
| t.Fatal("error setting env:", err) | |
| } | |
| env, _ = m.Workspace(t.Context()) | |
| if env != backend.DefaultStateName { | |
| t.Fatalf("expected env %q, got env %q", backend.DefaultStateName, env) | |
| } | |
| } | |
| func TestMeta_Workspace_override(t *testing.T) { | |
| m := &Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| } | |
| testCases := map[string]struct { | |
| workspace string | |
| err error | |
| }{ | |
| "": { | |
| "default", | |
| nil, | |
| }, | |
| "development": { | |
| "development", | |
| nil, | |
| }, | |
| "invalid name": { | |
| "", | |
| errInvalidWorkspaceNameEnvVar, | |
| }, | |
| } | |
| for name, tc := range testCases { | |
| t.Run(name, func(t *testing.T) { | |
| t.Setenv(WorkspaceNameEnvVar, name) | |
| workspace, err := m.Workspace(t.Context()) | |
| if workspace != tc.workspace { | |
| t.Errorf("Unexpected workspace\n got: %s\nwant: %s\n", workspace, tc.workspace) | |
| } | |
| if err != tc.err { | |
| t.Errorf("Unexpected error\n got: %s\nwant: %s\n", err, tc.err) | |
| } | |
| }) | |
| } | |
| } | |
| func TestMeta_Workspace_invalidSelected(t *testing.T) { | |
| td := t.TempDir() | |
| t.Chdir(td) | |
| // this is an invalid workspace name | |
| workspace := "test workspace" | |
| // create the workspace directories | |
| if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, workspace), 0755); err != nil { | |
| t.Fatal(err) | |
| } | |
| // create the workspace file to select it | |
| if err := os.MkdirAll(workdir.DefaultDataDir, 0755); err != nil { | |
| t.Fatal(err) | |
| } | |
| if err := os.WriteFile(filepath.Join(workdir.DefaultDataDir, local.DefaultWorkspaceFile), []byte(workspace), 0644); err != nil { | |
| t.Fatal(err) | |
| } | |
| m := &Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| } | |
| ws, err := m.Workspace(t.Context()) | |
| if ws != workspace { | |
| t.Errorf("Unexpected workspace\n got: %s\nwant: %s\n", ws, workspace) | |
| } | |
| if err != nil { | |
| t.Errorf("Unexpected error: %s", err) | |
| } | |
| } | |
| func TestCommand_checkRequiredVersion(t *testing.T) { | |
| // Create a temporary working directory that is empty | |
| td := t.TempDir() | |
| testCopyDir(t, testFixturePath("command-check-required-version"), td) | |
| t.Chdir(td) | |
| view, done := testView(t) | |
| meta := Meta{ | |
| WorkingDir: workdir.NewDir("."), | |
| View: view, | |
| } | |
| diags := meta.checkRequiredVersion(t.Context()) | |
| if diags == nil { | |
| t.Fatalf("diagnostics should contain unmet version constraint, but is nil") | |
| } | |
| view.Diagnostics(diags) | |
| // Required version diags are correct | |
| output := done(t) | |
| errStr := output.Stderr() | |
| if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) { | |
| t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr) | |
| } | |
| if strings.Contains(errStr, `required_version = ">= 0.13.0"`) { | |
| t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr) | |
| } | |
| } |