| package statemgr |
| |
| import ( |
| "errors" |
| "sync" |
| |
| "github.com/hashicorp/terraform/internal/states" |
| ) |
| |
| // NewFullFake returns a full state manager that really only supports transient |
| // snapshots. This is primarily intended for testing and is not suitable for |
| // general use. |
| // |
| // The persistent part of the interface is stubbed out as an in-memory store, |
| // and so its snapshots are effectively also transient. |
| // |
| // The given Transient implementation is used to implement the transient |
| // portion of the interface. If nil is given, NewTransientInMemory is |
| // automatically called to create an in-memory transient manager with no |
| // initial transient snapshot. |
| // |
| // If the given initial state is non-nil then a copy of it will be used as |
| // the initial persistent snapshot. |
| // |
| // The Locker portion of the returned manager uses a local mutex to simulate |
| // mutually-exclusive access to the fake persistent portion of the object. |
| func NewFullFake(t Transient, initial *states.State) Full { |
| if t == nil { |
| t = NewTransientInMemory(nil) |
| } |
| |
| // The "persistent" part of our manager is actually just another in-memory |
| // transient used to fake a secondary storage layer. |
| fakeP := NewTransientInMemory(initial.DeepCopy()) |
| |
| return &fakeFull{ |
| t: t, |
| fakeP: fakeP, |
| } |
| } |
| |
| type fakeFull struct { |
| t Transient |
| fakeP Transient |
| |
| lockLock sync.Mutex |
| locked bool |
| } |
| |
| var _ Full = (*fakeFull)(nil) |
| |
| func (m *fakeFull) State() *states.State { |
| return m.t.State() |
| } |
| |
| func (m *fakeFull) WriteState(s *states.State) error { |
| return m.t.WriteState(s) |
| } |
| |
| func (m *fakeFull) RefreshState() error { |
| return m.t.WriteState(m.fakeP.State()) |
| } |
| |
| func (m *fakeFull) PersistState() error { |
| return m.fakeP.WriteState(m.t.State()) |
| } |
| |
| func (m *fakeFull) Lock(info *LockInfo) (string, error) { |
| m.lockLock.Lock() |
| defer m.lockLock.Unlock() |
| |
| if m.locked { |
| return "", &LockError{ |
| Err: errors.New("fake state manager is locked"), |
| Info: info, |
| } |
| } |
| |
| m.locked = true |
| return "placeholder", nil |
| } |
| |
| func (m *fakeFull) Unlock(id string) error { |
| m.lockLock.Lock() |
| defer m.lockLock.Unlock() |
| |
| if !m.locked { |
| return errors.New("fake state manager is not locked") |
| } |
| if id != "placeholder" { |
| return errors.New("wrong lock id for fake state manager") |
| } |
| |
| m.locked = false |
| return nil |
| } |
| |
| // NewUnlockErrorFull returns a state manager that is useful for testing errors |
| // (mostly Unlock errors) when used with the clistate.Locker interface. Lock() |
| // does not return an error because clistate.Locker Lock()s the state at the |
| // start of Unlock(), so Lock() must succeeded for Unlock() to get called. |
| func NewUnlockErrorFull(t Transient, initial *states.State) Full { |
| return &fakeErrorFull{} |
| } |
| |
| type fakeErrorFull struct{} |
| |
| var _ Full = (*fakeErrorFull)(nil) |
| |
| func (m *fakeErrorFull) State() *states.State { |
| return nil |
| } |
| |
| func (m *fakeErrorFull) WriteState(s *states.State) error { |
| return errors.New("fake state manager error") |
| } |
| |
| func (m *fakeErrorFull) RefreshState() error { |
| return errors.New("fake state manager error") |
| } |
| |
| func (m *fakeErrorFull) PersistState() error { |
| return errors.New("fake state manager error") |
| } |
| |
| func (m *fakeErrorFull) Lock(info *LockInfo) (string, error) { |
| return "placeholder", nil |
| } |
| |
| func (m *fakeErrorFull) Unlock(id string) error { |
| return errors.New("fake state manager error") |
| } |