github.com/jpedro/terraform@v0.11.12-beta1/state/state_test.go (about) 1 package state 2 3 import ( 4 "context" 5 "encoding/json" 6 "flag" 7 "io/ioutil" 8 "log" 9 "os" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/terraform/helper/logging" 14 ) 15 16 func TestMain(m *testing.M) { 17 flag.Parse() 18 if testing.Verbose() { 19 // if we're verbose, use the logging requested by TF_LOG 20 logging.SetOutput() 21 } else { 22 // otherwise silence all logs 23 log.SetOutput(ioutil.Discard) 24 } 25 os.Exit(m.Run()) 26 } 27 28 func TestNewLockInfo(t *testing.T) { 29 info1 := NewLockInfo() 30 info2 := NewLockInfo() 31 32 if info1.ID == "" { 33 t.Fatal("LockInfo missing ID") 34 } 35 36 if info1.Version == "" { 37 t.Fatal("LockInfo missing version") 38 } 39 40 if info1.Created.IsZero() { 41 t.Fatal("LockInfo missing Created") 42 } 43 44 if info1.ID == info2.ID { 45 t.Fatal("multiple LockInfo with identical IDs") 46 } 47 48 // test the JSON output is valid 49 newInfo := &LockInfo{} 50 err := json.Unmarshal(info1.Marshal(), newInfo) 51 if err != nil { 52 t.Fatal(err) 53 } 54 } 55 56 func TestLockWithContext(t *testing.T) { 57 inmem := &InmemState{state: TestStateInitial()} 58 // test that it correctly wraps the inmem state 59 s := &inmemLocker{InmemState: inmem} 60 61 id, err := s.Lock(NewLockInfo()) 62 if err != nil { 63 t.Fatal(err) 64 } 65 66 // use a cancelled context for an immediate timeout 67 ctx, cancel := context.WithCancel(context.Background()) 68 cancel() 69 70 info := NewLockInfo() 71 info.Info = "lock with context" 72 _, err = LockWithContext(ctx, s, info) 73 if err == nil { 74 t.Fatal("lock should have failed immediately") 75 } 76 77 // block until LockwithContext has made a first attempt 78 attempted := make(chan struct{}) 79 postLockHook = func() { 80 close(attempted) 81 postLockHook = nil 82 } 83 84 // unlock the state during LockWithContext 85 unlocked := make(chan struct{}) 86 go func() { 87 defer close(unlocked) 88 <-attempted 89 if err := s.Unlock(id); err != nil { 90 t.Fatal(err) 91 } 92 }() 93 94 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second) 95 defer cancel() 96 97 id, err = LockWithContext(ctx, s, info) 98 if err != nil { 99 t.Fatal("lock should have completed within 2s:", err) 100 } 101 102 // ensure the goruotine completes 103 <-unlocked 104 105 // Lock should have been called a total of 4 times. 106 // 1 initial lock, 1 failure, 1 failure + 1 retry 107 if s.lockCounter != 4 { 108 t.Fatalf("lock only called %d times", s.lockCounter) 109 } 110 }