Skip to content

Commit f6775dd

Browse files
authored
add tests for ForceUnlock (#330)
* add tests for ForceUnlock * add compatibility code for dir arg * generate lock id error for all backend types
1 parent 24e3216 commit f6775dd

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

tfexec/exit_errors.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ var (
4646
statePlanReadErrRegexp = regexp.MustCompile(
4747
`Terraform couldn't read the given file as a state or plan file.|` +
4848
`Error: Failed to read the given file as a state or plan file`)
49+
lockIdInvalidErrRegexp = regexp.MustCompile(`Failed to unlock state: `)
4950
)
5051

5152
func (tf *Terraform) wrapExitError(ctx context.Context, err error, stderr string) error {
@@ -160,6 +161,8 @@ func (tf *Terraform) wrapExitError(ctx context.Context, err error, stderr string
160161
}
161162
case statePlanReadErrRegexp.MatchString(stderr):
162163
return &ErrStatePlanRead{stderr: stderr}
164+
case lockIdInvalidErrRegexp.MatchString(stderr):
165+
return &ErrLockIdInvalid{stderr: stderr}
163166
}
164167

165168
return fmt.Errorf("%w\n%s", &unwrapper{exitErr, ctxErr}, stderr)
@@ -256,6 +259,16 @@ func (e *ErrNoConfig) Error() string {
256259
return e.stderr
257260
}
258261

262+
type ErrLockIdInvalid struct {
263+
unwrapper
264+
265+
stderr string
266+
}
267+
268+
func (e *ErrLockIdInvalid) Error() string {
269+
return e.stderr
270+
}
271+
259272
// ErrCLIUsage is returned when the combination of flags or arguments is incorrect.
260273
//
261274
// CLI indicates usage errors in three different ways: either

tfexec/force_unlock.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package tfexec
22

33
import (
44
"context"
5+
"fmt"
56
"os/exec"
67
)
78

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

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

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

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

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

4448
// optional positional arguments
4549
if c.dir != "" {
50+
err := tf.compatible(ctx, nil, tf0_15_0)
51+
if err != nil {
52+
return nil, fmt.Errorf("[DIR] option was removed in Terraform v0.15.0")
53+
}
4654
args = append(args, c.dir)
4755
}
4856

49-
return tf.buildTerraformCmd(ctx, nil, args...)
57+
return tf.buildTerraformCmd(ctx, nil, args...), nil
5058
}

tfexec/force_unlock_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package tfexec
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-exec/tfexec/internal/testutil"
8+
)
9+
10+
func TestForceUnlockCmd(t *testing.T) {
11+
td := t.TempDir()
12+
13+
tf, err := NewTerraform(td, tfVersion(t, testutil.Latest_v1_1))
14+
if err != nil {
15+
t.Fatal(err)
16+
}
17+
18+
// empty env, to avoid environ mismatch in testing
19+
tf.SetEnv(map[string]string{})
20+
21+
t.Run("defaults", func(t *testing.T) {
22+
forceUnlockCmd, err := tf.forceUnlockCmd(context.Background(), "12345")
23+
if err != nil {
24+
t.Fatal(err)
25+
}
26+
27+
assertCmd(t, []string{
28+
"force-unlock",
29+
"-no-color",
30+
"-force",
31+
"12345",
32+
}, nil, forceUnlockCmd)
33+
})
34+
}
35+
36+
// The optional final positional [DIR] argument is available
37+
// until v0.15.0.
38+
func TestForceUnlockCmd_pre015(t *testing.T) {
39+
td := t.TempDir()
40+
41+
tf, err := NewTerraform(td, tfVersion(t, testutil.Latest014))
42+
if err != nil {
43+
t.Fatal(err)
44+
}
45+
46+
// empty env, to avoid environ mismatch in testing
47+
tf.SetEnv(map[string]string{})
48+
49+
t.Run("override all defaults", func(t *testing.T) {
50+
forceUnlockCmd, err := tf.forceUnlockCmd(context.Background(), "12345", Dir("mydir"))
51+
if err != nil {
52+
t.Fatal(err)
53+
}
54+
55+
assertCmd(t, []string{
56+
"force-unlock",
57+
"-no-color",
58+
"-force",
59+
"12345",
60+
"mydir",
61+
}, nil, forceUnlockCmd)
62+
})
63+
}

tfexec/internal/e2etest/force_unlock_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package e2etest
22

33
import (
44
"context"
5+
"errors"
56
"testing"
67

78
"github.com/hashicorp/go-version"
@@ -40,4 +41,19 @@ func TestForceUnlock(t *testing.T) {
4041
t.Fatalf("error running ForceUnlock: %v", err)
4142
}
4243
})
44+
runTest(t, "inmem_backend_locked", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) {
45+
err := tf.Init(context.Background())
46+
if err != nil {
47+
t.Fatalf("error running Init: %v", err)
48+
}
49+
50+
err = tf.ForceUnlock(context.Background(), "badlockid")
51+
if err == nil {
52+
t.Fatalf("expected error when running ForceUnlock with invalid lock id")
53+
}
54+
var foErr *tfexec.ErrLockIdInvalid
55+
if !errors.As(err, &foErr) {
56+
t.Fatalf("expected ErrLockIdInvalid, %T returned: %s", err, err)
57+
}
58+
})
4359
}

0 commit comments

Comments
 (0)