Remove exit error types (#352)
* remove exit error types
* reinstate error wrapping for context errs
diff --git a/tfexec/cmd_default.go b/tfexec/cmd_default.go
index 6d7b768..7323d55 100644
--- a/tfexec/cmd_default.go
+++ b/tfexec/cmd_default.go
@@ -40,11 +40,14 @@
}
err = cmd.Start()
- if err == nil && ctx.Err() != nil {
- err = ctx.Err()
+ if ctx.Err() != nil {
+ return cmdErr{
+ err: err,
+ ctxErr: ctx.Err(),
+ }
}
if err != nil {
- return tf.wrapExitError(ctx, err, "")
+ return err
}
var errStdout, errStderr error
@@ -66,19 +69,22 @@
wg.Wait()
err = cmd.Wait()
- if err == nil && ctx.Err() != nil {
- err = ctx.Err()
+ if ctx.Err() != nil {
+ return cmdErr{
+ err: err,
+ ctxErr: ctx.Err(),
+ }
}
if err != nil {
- return tf.wrapExitError(ctx, err, errBuf.String())
+ return err
}
// Return error if there was an issue reading the std out/err
if errStdout != nil && ctx.Err() != nil {
- return tf.wrapExitError(ctx, errStdout, errBuf.String())
+ return errStdout
}
if errStderr != nil && ctx.Err() != nil {
- return tf.wrapExitError(ctx, errStderr, errBuf.String())
+ return errStderr
}
return nil
diff --git a/tfexec/cmd_linux.go b/tfexec/cmd_linux.go
index 6fa40e0..9975791 100644
--- a/tfexec/cmd_linux.go
+++ b/tfexec/cmd_linux.go
@@ -45,11 +45,14 @@
}
err = cmd.Start()
- if err == nil && ctx.Err() != nil {
- err = ctx.Err()
+ if ctx.Err() != nil {
+ return cmdErr{
+ err: err,
+ ctxErr: ctx.Err(),
+ }
}
if err != nil {
- return tf.wrapExitError(ctx, err, "")
+ return err
}
var errStdout, errStderr error
@@ -71,19 +74,22 @@
wg.Wait()
err = cmd.Wait()
- if err == nil && ctx.Err() != nil {
- err = ctx.Err()
+ if ctx.Err() != nil {
+ return cmdErr{
+ err: err,
+ ctxErr: ctx.Err(),
+ }
}
if err != nil {
- return tf.wrapExitError(ctx, err, errBuf.String())
+ return err
}
// Return error if there was an issue reading the std out/err
if errStdout != nil && ctx.Err() != nil {
- return tf.wrapExitError(ctx, errStdout, errBuf.String())
+ return errStdout
}
if errStderr != nil && ctx.Err() != nil {
- return tf.wrapExitError(ctx, errStderr, errBuf.String())
+ return errStderr
}
return nil
diff --git a/tfexec/errors.go b/tfexec/errors.go
index 7a32ef2..3bbb431 100644
--- a/tfexec/errors.go
+++ b/tfexec/errors.go
@@ -1,6 +1,9 @@
package tfexec
-import "fmt"
+import (
+ "context"
+ "fmt"
+)
// this file contains non-parsed exported errors
@@ -37,3 +40,25 @@
func (err *ErrManualEnvVar) Error() string {
return fmt.Sprintf("manual setting of env var %q detected", err.Name)
}
+
+// cmdErr is a custom error type to be returned when a cmd exits with a context
+// error such as context.Canceled or context.DeadlineExceeded.
+// The type is specifically designed to respond true to errors.Is for these two
+// errors.
+// See https://github.com/golang/go/issues/21880 for why this is necessary.
+type cmdErr struct {
+ err error
+ ctxErr error
+}
+
+func (e cmdErr) Is(target error) bool {
+ switch target {
+ case context.DeadlineExceeded, context.Canceled:
+ return e.ctxErr == context.DeadlineExceeded || e.ctxErr == context.Canceled
+ }
+ return false
+}
+
+func (e cmdErr) Error() string {
+ return e.err.Error()
+}
diff --git a/tfexec/exit_errors.go b/tfexec/exit_errors.go
deleted file mode 100644
index cd84bf5..0000000
--- a/tfexec/exit_errors.go
+++ /dev/null
@@ -1,348 +0,0 @@
-package tfexec
-
-import (
- "context"
- "fmt"
- "os/exec"
- "regexp"
- "strings"
- "text/template"
-)
-
-// this file contains errors parsed from stderr
-
-var (
- // The "Required variable not set:" case is for 0.11
- missingVarErrRegexp = regexp.MustCompile(`Error: No value for required variable|Error: Required variable not set:`)
- missingVarNameRegexp = regexp.MustCompile(`The root module input variable\s"(.+)"\sis\snot\sset,\sand\shas\sno\sdefault|Error: Required variable not set: (.+)`)
-
- usageRegexp = regexp.MustCompile(`Too many command line arguments|^Usage: .*Options:.*|Error: Invalid -\d+ option`)
-
- noInitErrRegexp = regexp.MustCompile(
- // UNINITIALISED PROVIDERS/MODULES
- `Error: Could not satisfy plugin requirements|` +
- `Error: Could not load plugin|` + // v0.13
- `Please run \"terraform init\"|` + // v1.1.0 early alpha versions (ref 89b05050)
- `run:\s+terraform init|` + // v1.1.0 (ref df578afd)
- `Run\s+\"terraform init\"|` + // v1.2.0
-
- // UNINITIALISED BACKENDS
- `Error: Initialization required.|` + // v0.13
- `Error: Backend initialization required, please run \"terraform init\"`, // v0.15
- )
-
- noConfigErrRegexp = regexp.MustCompile(`Error: No configuration files`)
-
- workspaceDoesNotExistRegexp = regexp.MustCompile(`Workspace "(.+)" doesn't exist.`)
-
- workspaceAlreadyExistsRegexp = regexp.MustCompile(`Workspace "(.+)" already exists`)
-
- tfVersionMismatchErrRegexp = regexp.MustCompile(`Error: The currently running version of Terraform doesn't meet the|Error: Unsupported Terraform Core version`)
- tfVersionMismatchConstraintRegexp = regexp.MustCompile(`required_version = "(.+)"|Required version: (.+)\b`)
- configInvalidErrRegexp = regexp.MustCompile(
- `There are some problems with the configuration, described below.|` +
- `Error: Unsupported block type|Error: Unsupported argument`, // v1.4+
- )
-
- stateLockErrRegexp = regexp.MustCompile(`Error acquiring the state lock`)
- stateLockInfoRegexp = regexp.MustCompile(`Lock Info:\n\s*ID:\s*([^\n]+)\n\s*Path:\s*([^\n]+)\n\s*Operation:\s*([^\n]+)\n\s*Who:\s*([^\n]+)\n\s*Version:\s*([^\n]+)\n\s*Created:\s*([^\n]+)\n`)
- statePlanReadErrRegexp = regexp.MustCompile(
- `Terraform couldn't read the given file as a state or plan file.|` +
- `Error: Failed to read the given file as a state or plan file`)
- lockIdInvalidErrRegexp = regexp.MustCompile(`Failed to unlock state: `)
-)
-
-func (tf *Terraform) wrapExitError(ctx context.Context, err error, stderr string) error {
- exitErr, ok := err.(*exec.ExitError)
- if !ok {
- // not an exit error, short circuit, nothing to wrap
- return err
- }
-
- ctxErr := ctx.Err()
-
- // nothing to parse, return early
- errString := strings.TrimSpace(stderr)
- if errString == "" {
- return &unwrapper{exitErr, ctxErr}
- }
-
- switch {
- case tfVersionMismatchErrRegexp.MatchString(stderr):
- constraint := ""
- constraints := tfVersionMismatchConstraintRegexp.FindStringSubmatch(stderr)
- for i := 1; i < len(constraints); i++ {
- constraint = strings.TrimSpace(constraints[i])
- if constraint != "" {
- break
- }
- }
-
- if constraint == "" {
- // hardcode a value here for weird cases (incl. 0.12)
- constraint = "unknown"
- }
-
- // only set this if it happened to be cached already
- ver := ""
- if tf != nil && tf.execVersion != nil {
- ver = tf.execVersion.String()
- }
-
- return &ErrTFVersionMismatch{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- Constraint: constraint,
- TFVersion: ver,
- }
- case missingVarErrRegexp.MatchString(stderr):
- name := ""
- names := missingVarNameRegexp.FindStringSubmatch(stderr)
- for i := 1; i < len(names); i++ {
- name = strings.TrimSpace(names[i])
- if name != "" {
- break
- }
- }
-
- return &ErrMissingVar{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- VariableName: name,
- }
- case usageRegexp.MatchString(stderr):
- return &ErrCLIUsage{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- stderr: stderr,
- }
- case noInitErrRegexp.MatchString(stderr):
- return &ErrNoInit{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- stderr: stderr,
- }
- case noConfigErrRegexp.MatchString(stderr):
- return &ErrNoConfig{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- stderr: stderr,
- }
- case workspaceDoesNotExistRegexp.MatchString(stderr):
- submatches := workspaceDoesNotExistRegexp.FindStringSubmatch(stderr)
- if len(submatches) == 2 {
- return &ErrNoWorkspace{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- Name: submatches[1],
- }
- }
- case workspaceAlreadyExistsRegexp.MatchString(stderr):
- submatches := workspaceAlreadyExistsRegexp.FindStringSubmatch(stderr)
- if len(submatches) == 2 {
- return &ErrWorkspaceExists{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- Name: submatches[1],
- }
- }
- case configInvalidErrRegexp.MatchString(stderr):
- return &ErrConfigInvalid{stderr: stderr}
- case stateLockErrRegexp.MatchString(stderr):
- submatches := stateLockInfoRegexp.FindStringSubmatch(stderr)
- if len(submatches) == 7 {
- return &ErrStateLocked{
- unwrapper: unwrapper{exitErr, ctxErr},
-
- ID: submatches[1],
- Path: submatches[2],
- Operation: submatches[3],
- Who: submatches[4],
- Version: submatches[5],
- Created: submatches[6],
- }
- }
- case statePlanReadErrRegexp.MatchString(stderr):
- return &ErrStatePlanRead{stderr: stderr}
- case lockIdInvalidErrRegexp.MatchString(stderr):
- return &ErrLockIdInvalid{stderr: stderr}
- }
-
- return fmt.Errorf("%w\n%s", &unwrapper{exitErr, ctxErr}, stderr)
-}
-
-type unwrapper struct {
- err error
- ctxErr error
-}
-
-func (u *unwrapper) Unwrap() error {
- return u.err
-}
-
-func (u *unwrapper) Is(target error) bool {
- switch target {
- case context.DeadlineExceeded, context.Canceled:
- return u.ctxErr == context.DeadlineExceeded ||
- u.ctxErr == context.Canceled
- }
- return false
-}
-
-func (u *unwrapper) Error() string {
- return u.err.Error()
-}
-
-type ErrConfigInvalid struct {
- stderr string
-}
-
-func (e *ErrConfigInvalid) Error() string {
- return "configuration is invalid"
-}
-
-type ErrMissingVar struct {
- unwrapper
-
- VariableName string
-}
-
-func (err *ErrMissingVar) Error() string {
- return fmt.Sprintf("variable %q was required but not supplied", err.VariableName)
-}
-
-type ErrNoWorkspace struct {
- unwrapper
-
- Name string
-}
-
-func (err *ErrNoWorkspace) Error() string {
- return fmt.Sprintf("workspace %q does not exist", err.Name)
-}
-
-// ErrWorkspaceExists is returned when creating a workspace that already exists
-type ErrWorkspaceExists struct {
- unwrapper
-
- Name string
-}
-
-func (err *ErrWorkspaceExists) Error() string {
- return fmt.Sprintf("workspace %q already exists", err.Name)
-}
-
-type ErrNoInit struct {
- unwrapper
-
- stderr string
-}
-
-func (e *ErrNoInit) Error() string {
- return e.stderr
-}
-
-type ErrStatePlanRead struct {
- unwrapper
-
- stderr string
-}
-
-func (e *ErrStatePlanRead) Error() string {
- return e.stderr
-}
-
-type ErrNoConfig struct {
- unwrapper
-
- stderr string
-}
-
-func (e *ErrNoConfig) Error() string {
- return e.stderr
-}
-
-type ErrLockIdInvalid struct {
- unwrapper
-
- stderr string
-}
-
-func (e *ErrLockIdInvalid) Error() string {
- return e.stderr
-}
-
-// ErrCLIUsage is returned when the combination of flags or arguments is incorrect.
-//
-// CLI indicates usage errors in three different ways: either
-//
-// 1. Exit 1, with a custom error message on stderr.
-// 2. Exit 1, with command usage logged to stderr.
-// 3. Exit 127, with command usage logged to stdout.
-// Currently cases 1 and 2 are handled.
-// TODO KEM: Handle exit 127 case. How does this work on non-Unix platforms?
-type ErrCLIUsage struct {
- unwrapper
-
- stderr string
-}
-
-func (e *ErrCLIUsage) Error() string {
- return e.stderr
-}
-
-// ErrTFVersionMismatch is returned when the running Terraform version is not compatible with the
-// value specified for required_version in the terraform block.
-type ErrTFVersionMismatch struct {
- unwrapper
-
- TFVersion string
-
- // Constraint is not returned in the error messaging on 0.12
- Constraint string
-}
-
-func (e *ErrTFVersionMismatch) Error() string {
- version := "version"
- if e.TFVersion != "" {
- version = e.TFVersion
- }
-
- requirement := ""
- if e.Constraint != "" {
- requirement = fmt.Sprintf(" (%s required)", e.Constraint)
- }
-
- return fmt.Sprintf("terraform %s not supported by configuration%s",
- version, requirement)
-}
-
-// ErrStateLocked is returned when the state lock is already held by another process.
-type ErrStateLocked struct {
- unwrapper
-
- ID string
- Path string
- Operation string
- Who string
- Version string
- Created string
-}
-
-func (e *ErrStateLocked) Error() string {
- tmpl := `Lock Info:
- ID: {{.ID}}
- Path: {{.Path}}
- Operation: {{.Operation}}
- Who: {{.Who}}
- Version: {{.Version}}
- Created: {{.Created}}
-`
-
- t := template.Must(template.New("LockInfo").Parse(tmpl))
- var out strings.Builder
- if err := t.Execute(&out, e); err != nil {
- return "error acquiring the state lock"
- }
- return fmt.Sprintf("error acquiring the state lock: %v", out.String())
-}
diff --git a/tfexec/internal/e2etest/errors_test.go b/tfexec/internal/e2etest/errors_test.go
index 9577555..d75986d 100644
--- a/tfexec/internal/e2etest/errors_test.go
+++ b/tfexec/internal/e2etest/errors_test.go
@@ -54,32 +54,15 @@
shortVarName := "no_default"
longVarName := "no_default_really_long_variable_name_that_will_line_wrap_tf_output"
- // Test for ErrMissingVar and properly formatted error message on shorter variable names
_, err = tf.Plan(context.Background(), tfexec.Var(longVarName+"=foo"))
if err == nil {
t.Fatalf("expected error running Plan, none returned")
}
- var e *tfexec.ErrMissingVar
- if !errors.As(err, &e) {
- t.Fatalf("expected ErrMissingVar, got %T, %s", err, err)
- }
- if e.VariableName != shortVarName {
- t.Fatalf("expected missing %s, got %q", shortVarName, e.VariableName)
- }
-
- // Test for ErrMissingVar and properly formatted error message on long variable names
_, err = tf.Plan(context.Background(), tfexec.Var(shortVarName+"=foo"))
if err == nil {
t.Fatalf("expected error running Plan, none returned")
}
- if !errors.As(err, &e) {
- t.Fatalf("expected ErrMissingVar, got %T, %s", err, err)
- }
-
- if e.VariableName != longVarName {
- t.Fatalf("expected missing %s, got %q", longVarName, e.VariableName)
- }
var ee *exec.ExitError
if !errors.As(err, &ee) {
@@ -107,20 +90,6 @@
t.Fatal("expected error, but didn't find one")
}
- var e *tfexec.ErrTFVersionMismatch
- if !errors.As(err, &e) {
- t.Fatalf("expected ErrTFVersionMismatch, got %T, %s", err, err)
- }
-
- // in 0.12, we just return "unknown" as the specifics are not included in the error messaging
- if e.Constraint != "unknown" && e.Constraint != ">99.0.0" {
- t.Fatalf("unexpected constraint %q", e.Constraint)
- }
-
- if e.TFVersion != tfv.String() {
- t.Fatalf("expected %q, got %q", tfv.String(), e.TFVersion)
- }
-
var ee *exec.ExitError
if !errors.As(err, &ee) {
t.Fatalf("expected exec.ExitError, got %T, %s", err, err)
@@ -139,11 +108,6 @@
if err == nil {
t.Fatal("expected error, but didn't find one")
}
-
- var stateLockedErr *tfexec.ErrStateLocked
- if !errors.As(err, &stateLockedErr) {
- t.Fatalf("expected ErrTFVersionMismatch, got %T, %s", err, err)
- }
})
}
diff --git a/tfexec/internal/e2etest/force_unlock_test.go b/tfexec/internal/e2etest/force_unlock_test.go
index c5d626a..1280aa3 100644
--- a/tfexec/internal/e2etest/force_unlock_test.go
+++ b/tfexec/internal/e2etest/force_unlock_test.go
@@ -2,7 +2,6 @@
import (
"context"
- "errors"
"testing"
"github.com/hashicorp/go-version"
@@ -51,9 +50,5 @@
if err == nil {
t.Fatalf("expected error when running ForceUnlock with invalid lock id")
}
- var foErr *tfexec.ErrLockIdInvalid
- if !errors.As(err, &foErr) {
- t.Fatalf("expected ErrLockIdInvalid, %T returned: %s", err, err)
- }
})
}
diff --git a/tfexec/internal/e2etest/show_test.go b/tfexec/internal/e2etest/show_test.go
index e1cb92b..72e0ae9 100644
--- a/tfexec/internal/e2etest/show_test.go
+++ b/tfexec/internal/e2etest/show_test.go
@@ -111,16 +111,15 @@
}
func TestShow_noInitBasic(t *testing.T) {
- // Prior to v1.2.0, running show before init always results in ErrNoInit.
+ // Prior to v1.2.0, running show before init always results in an error.
// In the basic case, in which the local backend is implicit and there are
// no providers to download, this is unintended behaviour, as
// init is not actually necessary. This is considered a known issue in
// pre-1.2.0 versions.
runTestWithVersions(t, []string{testutil.Latest012, testutil.Latest013, testutil.Latest014, testutil.Latest015, testutil.Latest_v1, testutil.Latest_v1_1}, "basic", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) {
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
@@ -149,16 +148,15 @@
}
func TestShow_noInitModule(t *testing.T) {
- // Prior to v1.2.0, running show before init always results in ErrNoInit.
+ // Prior to v1.2.0, running show before init always results in an error.
// In the basic case, in which the local backend is implicit and there are
// no providers to download, this is unintended behaviour, as
// init is not actually necessary. This is considered a known issue in
// pre-1.2.0 versions.
runTestWithVersions(t, []string{testutil.Latest012, testutil.Latest013, testutil.Latest014, testutil.Latest015, testutil.Latest_v1, testutil.Latest_v1_1}, "registry_module", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) {
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
@@ -191,10 +189,9 @@
t.Skip("terraform show was added in Terraform 0.12, so test is not valid")
}
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
@@ -205,10 +202,9 @@
t.Skip("terraform show was added in Terraform 0.12, so test is not valid")
}
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
@@ -219,10 +215,9 @@
t.Skip("cloud backend was added in Terraform 1.1, so test is not valid")
}
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
@@ -237,10 +232,9 @@
t.Skip("etcd backend was removed in Terraform 1.3, so test is not valid")
}
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
@@ -251,10 +245,9 @@
t.Skip("terraform show was added in Terraform 0.12, so test is not valid")
}
- var noInit *tfexec.ErrNoInit
_, err := tf.Show(context.Background())
- if !errors.As(err, &noInit) {
- t.Fatalf("expected error ErrNoInit, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
@@ -270,10 +263,9 @@
t.Fatalf("error running Init in test directory: %s", err)
}
- var statePlanReadErr *tfexec.ErrStatePlanRead
_, err = tf.ShowStateFile(context.Background(), "statefilefoo")
- if !errors.As(err, &statePlanReadErr) {
- t.Fatalf("expected error ErrStatePlanRead, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
diff --git a/tfexec/internal/e2etest/validate_test.go b/tfexec/internal/e2etest/validate_test.go
index d57ebe2..e2f247c 100644
--- a/tfexec/internal/e2etest/validate_test.go
+++ b/tfexec/internal/e2etest/validate_test.go
@@ -2,7 +2,6 @@
import (
"context"
- "errors"
"testing"
"github.com/google/go-cmp/cmp"
@@ -46,12 +45,10 @@
if err != nil {
t.Logf("error initializing: %s", err)
- // allow for invalid config errors only here
- // 0.13 will return this, 0.12 will not
+ // 0.13 will error, 0.12 will not
// unsure why 0.12 terraform init does not have a non-zero exit code for syntax problems
- var confErr *tfexec.ErrConfigInvalid
- if !errors.As(err, &confErr) {
- t.Fatalf("expected err ErrConfigInvalid, got %T: %s", err, err)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
}
diff --git a/tfexec/internal/e2etest/workspace_test.go b/tfexec/internal/e2etest/workspace_test.go
index 35964ec..6848965 100644
--- a/tfexec/internal/e2etest/workspace_test.go
+++ b/tfexec/internal/e2etest/workspace_test.go
@@ -2,7 +2,6 @@
import (
"context"
- "errors"
"reflect"
"testing"
@@ -45,12 +44,8 @@
runTest(t, "basic", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) {
const doesNotExistWorkspace = "does-not-exist"
err := tf.WorkspaceSelect(context.Background(), doesNotExistWorkspace)
- var wsErr *tfexec.ErrNoWorkspace
- if !errors.As(err, &wsErr) {
- t.Fatalf("expected ErrNoWorkspace, %T returned: %s", err, err)
- }
- if wsErr.Name != doesNotExistWorkspace {
- t.Fatalf("expected %q, got %q", doesNotExistWorkspace, wsErr.Name)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
}
@@ -71,12 +66,8 @@
t.Run("create existing workspace", func(t *testing.T) {
err := tf.WorkspaceNew(context.Background(), newWorkspace)
- var wsErr *tfexec.ErrWorkspaceExists
- if !errors.As(err, &wsErr) {
- t.Fatalf("expected ErrWorkspaceExists, %T returned: %s", err, err)
- }
- if wsErr.Name != newWorkspace {
- t.Fatalf("expected %q, got %q", newWorkspace, wsErr.Name)
+ if err == nil {
+ t.Fatalf("expected error, but did not get one")
}
})
})