Add test for apply/refresh on locked state files
Verify that these operations fail when a state file is locked.
This commit is contained in:
parent
fb60b6f6f2
commit
bd65ddbcaa
|
@ -8,12 +8,10 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -65,13 +63,11 @@ func TestApply(t *testing.T) {
|
|||
func TestApply_lockedState(t *testing.T) {
|
||||
statePath := testTempFile(t)
|
||||
|
||||
locker := exec.Command("go", "run", "testadata/statelocker.go", statePath)
|
||||
locker.Stderr = os.Stderr
|
||||
if err := locker.Start(); err != nil {
|
||||
unlock, err := testLockState(statePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer locker.Process.Signal(syscall.SIGTERM)
|
||||
defer unlock()
|
||||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
|
@ -86,8 +82,13 @@ func TestApply_lockedState(t *testing.T) {
|
|||
"-state", statePath,
|
||||
testFixturePath("apply"),
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
if code := c.Run(args); code == 0 {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
output := ui.ErrorWriter.String()
|
||||
if !strings.Contains(output, "locked") {
|
||||
t.Fatal("command output does not look like a lock error:", output)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,17 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-getter"
|
||||
|
@ -529,3 +532,37 @@ func testRemoteState(t *testing.T, s *terraform.State, c int) (*terraform.Remote
|
|||
|
||||
return remote, srv
|
||||
}
|
||||
|
||||
// testlockState calls a separate process to the lock the state file at path.
|
||||
// deferFunc should be called in the caller to properly unlock the file.
|
||||
func testLockState(path string) (func(), error) {
|
||||
locker := exec.Command("go", "run", "testdata/statelocker.go", path)
|
||||
pr, pw, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer pr.Close()
|
||||
defer pw.Close()
|
||||
locker.Stderr = pw
|
||||
locker.Stdout = pw
|
||||
|
||||
if err := locker.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deferFunc := func() {
|
||||
locker.Process.Signal(syscall.SIGTERM)
|
||||
locker.Wait()
|
||||
}
|
||||
|
||||
// wait for the process to lock
|
||||
buf := make([]byte, 1024)
|
||||
n, err := pr.Read(buf)
|
||||
if err != nil {
|
||||
return deferFunc, fmt.Errorf("read from statelocker returned: %s", err)
|
||||
}
|
||||
|
||||
if string(buf[:n]) != "LOCKED" {
|
||||
return deferFunc, fmt.Errorf("statelocker wrote", string(buf[:n]))
|
||||
}
|
||||
return deferFunc, nil
|
||||
}
|
||||
|
|
|
@ -59,6 +59,43 @@ func TestRefresh(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRefresh_lockedState(t *testing.T) {
|
||||
state := testState()
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
unlock, err := testLockState(statePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
c := &RefreshCommand{
|
||||
Meta: Meta{
|
||||
ContextOpts: testCtxConfig(p),
|
||||
Ui: ui,
|
||||
},
|
||||
}
|
||||
|
||||
p.RefreshFn = nil
|
||||
p.RefreshReturn = &terraform.InstanceState{ID: "yes"}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
testFixturePath("refresh"),
|
||||
}
|
||||
|
||||
if code := c.Run(args); code == 0 {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
output := ui.ErrorWriter.String()
|
||||
if !strings.Contains(output, "locked") {
|
||||
t.Fatal("command output does not look like a lock error:", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefresh_badState(t *testing.T) {
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
|
|
Loading…
Reference in New Issue