Skip to content

Commit

Permalink
add tests for ForceUnlock (#330)
Browse files Browse the repository at this point in the history
* add tests for ForceUnlock

* add compatibility code for dir arg

* generate lock id error for all backend types
  • Loading branch information
kmoe authored Aug 31, 2022
1 parent 24e3216 commit f6775dd
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 3 deletions.
13 changes: 13 additions & 0 deletions tfexec/exit_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var (
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 {
Expand Down Expand Up @@ -160,6 +161,8 @@ func (tf *Terraform) wrapExitError(ctx context.Context, err error, stderr string
}
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)
Expand Down Expand Up @@ -256,6 +259,16 @@ 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
Expand Down
14 changes: 11 additions & 3 deletions tfexec/force_unlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tfexec

import (
"context"
"fmt"
"os/exec"
)

Expand All @@ -21,7 +22,10 @@ func (opt *DirOption) configureForceUnlock(conf *forceUnlockConfig) {

// ForceUnlock represents the `terraform force-unlock` command
func (tf *Terraform) ForceUnlock(ctx context.Context, lockID string, opts ...ForceUnlockOption) error {
unlockCmd := tf.forceUnlockCmd(ctx, lockID, opts...)
unlockCmd, err := tf.forceUnlockCmd(ctx, lockID, opts...)
if err != nil {
return err
}

if err := tf.runTerraformCmd(ctx, unlockCmd); err != nil {
return err
Expand All @@ -30,7 +34,7 @@ func (tf *Terraform) ForceUnlock(ctx context.Context, lockID string, opts ...For
return nil
}

func (tf *Terraform) forceUnlockCmd(ctx context.Context, lockID string, opts ...ForceUnlockOption) *exec.Cmd {
func (tf *Terraform) forceUnlockCmd(ctx context.Context, lockID string, opts ...ForceUnlockOption) (*exec.Cmd, error) {
c := defaultForceUnlockOptions

for _, o := range opts {
Expand All @@ -43,8 +47,12 @@ func (tf *Terraform) forceUnlockCmd(ctx context.Context, lockID string, opts ...

// optional positional arguments
if c.dir != "" {
err := tf.compatible(ctx, nil, tf0_15_0)
if err != nil {
return nil, fmt.Errorf("[DIR] option was removed in Terraform v0.15.0")
}
args = append(args, c.dir)
}

return tf.buildTerraformCmd(ctx, nil, args...)
return tf.buildTerraformCmd(ctx, nil, args...), nil
}
63 changes: 63 additions & 0 deletions tfexec/force_unlock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package tfexec

import (
"context"
"testing"

"github.com/hashicorp/terraform-exec/tfexec/internal/testutil"
)

func TestForceUnlockCmd(t *testing.T) {
td := t.TempDir()

tf, err := NewTerraform(td, tfVersion(t, testutil.Latest_v1_1))
if err != nil {
t.Fatal(err)
}

// empty env, to avoid environ mismatch in testing
tf.SetEnv(map[string]string{})

t.Run("defaults", func(t *testing.T) {
forceUnlockCmd, err := tf.forceUnlockCmd(context.Background(), "12345")
if err != nil {
t.Fatal(err)
}

assertCmd(t, []string{
"force-unlock",
"-no-color",
"-force",
"12345",
}, nil, forceUnlockCmd)
})
}

// The optional final positional [DIR] argument is available
// until v0.15.0.
func TestForceUnlockCmd_pre015(t *testing.T) {
td := t.TempDir()

tf, err := NewTerraform(td, tfVersion(t, testutil.Latest014))
if err != nil {
t.Fatal(err)
}

// empty env, to avoid environ mismatch in testing
tf.SetEnv(map[string]string{})

t.Run("override all defaults", func(t *testing.T) {
forceUnlockCmd, err := tf.forceUnlockCmd(context.Background(), "12345", Dir("mydir"))
if err != nil {
t.Fatal(err)
}

assertCmd(t, []string{
"force-unlock",
"-no-color",
"-force",
"12345",
"mydir",
}, nil, forceUnlockCmd)
})
}
16 changes: 16 additions & 0 deletions tfexec/internal/e2etest/force_unlock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package e2etest

import (
"context"
"errors"
"testing"

"github.com/hashicorp/go-version"
Expand Down Expand Up @@ -40,4 +41,19 @@ func TestForceUnlock(t *testing.T) {
t.Fatalf("error running ForceUnlock: %v", err)
}
})
runTest(t, "inmem_backend_locked", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) {
err := tf.Init(context.Background())
if err != nil {
t.Fatalf("error running Init: %v", err)
}

err = tf.ForceUnlock(context.Background(), "badlockid")
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)
}
})
}

0 comments on commit f6775dd

Please sign in to comment.