github.com/opentofu/opentofu@v1.7.1/internal/states/statemgr/statemgr_fake.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package statemgr 7 8 import ( 9 "errors" 10 "sync" 11 12 "github.com/opentofu/opentofu/internal/states" 13 "github.com/opentofu/opentofu/internal/tofu" 14 ) 15 16 // NewFullFake returns a full state manager that really only supports transient 17 // snapshots. This is primarily intended for testing and is not suitable for 18 // general use. 19 // 20 // The persistent part of the interface is stubbed out as an in-memory store, 21 // and so its snapshots are effectively also transient. 22 // 23 // The given Transient implementation is used to implement the transient 24 // portion of the interface. If nil is given, NewTransientInMemory is 25 // automatically called to create an in-memory transient manager with no 26 // initial transient snapshot. 27 // 28 // If the given initial state is non-nil then a copy of it will be used as 29 // the initial persistent snapshot. 30 // 31 // The Locker portion of the returned manager uses a local mutex to simulate 32 // mutually-exclusive access to the fake persistent portion of the object. 33 func NewFullFake(t Transient, initial *states.State) Full { 34 if t == nil { 35 t = NewTransientInMemory(nil) 36 } 37 38 // The "persistent" part of our manager is actually just another in-memory 39 // transient used to fake a secondary storage layer. 40 fakeP := NewTransientInMemory(initial.DeepCopy()) 41 42 return &fakeFull{ 43 t: t, 44 fakeP: fakeP, 45 } 46 } 47 48 type fakeFull struct { 49 t Transient 50 fakeP Transient 51 52 lockLock sync.Mutex 53 locked bool 54 } 55 56 var _ Full = (*fakeFull)(nil) 57 58 func (m *fakeFull) State() *states.State { 59 return m.t.State() 60 } 61 62 func (m *fakeFull) WriteState(s *states.State) error { 63 return m.t.WriteState(s) 64 } 65 66 func (m *fakeFull) RefreshState() error { 67 return m.t.WriteState(m.fakeP.State()) 68 } 69 70 func (m *fakeFull) PersistState(schemas *tofu.Schemas) error { 71 return m.fakeP.WriteState(m.t.State()) 72 } 73 74 func (m *fakeFull) GetRootOutputValues() (map[string]*states.OutputValue, error) { 75 return m.State().RootModule().OutputValues, nil 76 } 77 78 func (m *fakeFull) Lock(info *LockInfo) (string, error) { 79 m.lockLock.Lock() 80 defer m.lockLock.Unlock() 81 82 if m.locked { 83 return "", &LockError{ 84 Err: errors.New("fake state manager is locked"), 85 Info: info, 86 } 87 } 88 89 m.locked = true 90 return "placeholder", nil 91 } 92 93 func (m *fakeFull) Unlock(id string) error { 94 m.lockLock.Lock() 95 defer m.lockLock.Unlock() 96 97 if !m.locked { 98 return errors.New("fake state manager is not locked") 99 } 100 if id != "placeholder" { 101 return errors.New("wrong lock id for fake state manager") 102 } 103 104 m.locked = false 105 return nil 106 } 107 108 // NewUnlockErrorFull returns a state manager that is useful for testing errors 109 // (mostly Unlock errors) when used with the clistate.Locker interface. Lock() 110 // does not return an error because clistate.Locker Lock()s the state at the 111 // start of Unlock(), so Lock() must succeeded for Unlock() to get called. 112 func NewUnlockErrorFull(t Transient, initial *states.State) Full { 113 return &fakeErrorFull{} 114 } 115 116 type fakeErrorFull struct{} 117 118 var _ Full = (*fakeErrorFull)(nil) 119 120 func (m *fakeErrorFull) State() *states.State { 121 return nil 122 } 123 124 func (m *fakeErrorFull) GetRootOutputValues() (map[string]*states.OutputValue, error) { 125 return nil, errors.New("fake state manager error") 126 } 127 128 func (m *fakeErrorFull) WriteState(s *states.State) error { 129 return errors.New("fake state manager error") 130 } 131 132 func (m *fakeErrorFull) RefreshState() error { 133 return errors.New("fake state manager error") 134 } 135 136 func (m *fakeErrorFull) PersistState(schemas *tofu.Schemas) error { 137 return errors.New("fake state manager error") 138 } 139 140 func (m *fakeErrorFull) Lock(info *LockInfo) (string, error) { 141 return "placeholder", nil 142 } 143 144 func (m *fakeErrorFull) Unlock(id string) error { 145 return errors.New("fake state manager error") 146 }