opentofu/states/statemgr/statemgr_test.go
Martin Atkins 53cafc542b statemgr: New package for state managers
This idea of a "state manager" was previously modelled via the
confusingly-named state.State interface, which we've been calling a "state
manager" only in some local variable names in situations where there were
also *terraform.State variables.

As part of reworking our state models to make room for the new type
system, we also need to change what was previously the state.StateReader
interface. Since we've found the previous organization confusing anyway,
here we just copy all of those interfaces over into statemgr where we can
make the relationship to states.State hopefully a little clearer.

This is not yet a complete move of the functionality from "state", since
we're not yet ready to break existing callers. In a future commit we'll
turn the interfaces in the old "state" package into aliases of the
interfaces in this package, and update all the implementers of what will
by then be statemgr.Reader to use *states.State instead of
*terraform.State.

This also includes an adaptation of what was previously state.LocalState
into statemgr.FileSystem, using the new state serialization functionality
from package statefile instead of the old terraform.ReadState and
terraform.WriteState.
2018-10-16 18:49:20 -07:00

103 lines
1.9 KiB
Go

package statemgr
import (
"context"
"encoding/json"
"flag"
"io/ioutil"
"log"
"os"
"testing"
"time"
"github.com/hashicorp/terraform/helper/logging"
)
func TestNewLockInfo(t *testing.T) {
info1 := NewLockInfo()
info2 := NewLockInfo()
if info1.ID == "" {
t.Fatal("LockInfo missing ID")
}
if info1.Version == "" {
t.Fatal("LockInfo missing version")
}
if info1.Created.IsZero() {
t.Fatal("LockInfo missing Created")
}
if info1.ID == info2.ID {
t.Fatal("multiple LockInfo with identical IDs")
}
// test the JSON output is valid
newInfo := &LockInfo{}
err := json.Unmarshal(info1.Marshal(), newInfo)
if err != nil {
t.Fatal(err)
}
}
func TestLockWithContext(t *testing.T) {
s := NewFullFake(nil, TestFullInitialState())
id, err := s.Lock(NewLockInfo())
if err != nil {
t.Fatal(err)
}
// use a cancelled context for an immediate timeout
ctx, cancel := context.WithCancel(context.Background())
cancel()
info := NewLockInfo()
info.Info = "lock with context"
_, err = LockWithContext(ctx, s, info)
if err == nil {
t.Fatal("lock should have failed immediately")
}
// block until LockwithContext has made a first attempt
attempted := make(chan struct{})
postLockHook = func() {
close(attempted)
postLockHook = nil
}
// unlock the state during LockWithContext
unlocked := make(chan struct{})
go func() {
defer close(unlocked)
<-attempted
if err := s.Unlock(id); err != nil {
t.Fatal(err)
}
}()
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
id, err = LockWithContext(ctx, s, info)
if err != nil {
t.Fatal("lock should have completed within 2s:", err)
}
// ensure the goruotine completes
<-unlocked
}
func TestMain(m *testing.M) {
flag.Parse()
if testing.Verbose() {
// if we're verbose, use the logging requested by TF_LOG
logging.SetOutput()
} else {
// otherwise silence all logs
log.SetOutput(ioutil.Discard)
}
os.Exit(m.Run())
}