github.com/ddev/ddev@v1.23.2-0.20240519125000-d824ffe36ff3/pkg/config/state/state_manager_test.go (about) 1 package state_test 2 3 import ( 4 "path/filepath" 5 "testing" 6 7 "github.com/ddev/ddev/pkg/config/state/storage/yaml" 8 "github.com/ddev/ddev/pkg/config/state/types" 9 "github.com/stretchr/testify/suite" 10 ) 11 12 func TestStateTestSuite(t *testing.T) { 13 suite.Run(t, new(StateTestSuite)) 14 } 15 16 type TestStateSubEntry struct { 17 BoolField1 bool `yaml:"bool_field1,omitempty"` 18 IntField1 int `yaml:"int_field1,omitempty"` 19 UIntField1 uint `yaml:"uint_field1,omitempty"` 20 FloatField1 float32 `yaml:"float_field1,omitempty"` 21 StringField1 string `yaml:"string_field1,omitempty"` 22 } 23 24 type TestStateEntry struct { 25 BoolField1 bool `yaml:"bool_field1,omitempty"` 26 BoolField2 bool `yaml:"bool_field2,omitempty"` 27 IntField1 int `yaml:"int_field1,omitempty"` 28 IntField2 int16 `yaml:"int_field2,omitempty"` 29 UIntField1 uint `yaml:"uint_field1,omitempty"` 30 UIntField2 uint16 `yaml:"uint_field2,omitempty"` 31 FloatField1 float32 `yaml:"float_field1,omitempty"` 32 FloatField2 float64 `yaml:"float_field2,omitempty"` 33 StringField1 string `yaml:"string_field1,omitempty"` 34 StringField2 string `yaml:"string_field2,omitempty"` 35 Sub TestStateSubEntry `yaml:"sub,omitempty"` 36 } 37 38 type StateTestSuite struct { 39 suite.Suite 40 } 41 42 func (suite *StateTestSuite) TestGetReturnsCorrectState() { 43 var tests = []struct { 44 Key types.StateEntryKey 45 Expected TestStateEntry 46 }{ 47 // key1 to 3 are available in the test data. 48 { 49 Key: "key1", 50 Expected: TestStateEntry{ 51 BoolField1: true, 52 BoolField2: false, 53 IntField1: 11, 54 IntField2: 12, 55 UIntField1: 112, 56 UIntField2: 123, 57 FloatField1: 1.1, 58 FloatField2: 1.2, 59 StringField1: "string11", 60 StringField2: "string12", 61 }, 62 }, 63 { 64 Key: "key2", 65 Expected: TestStateEntry{ 66 BoolField1: false, 67 BoolField2: true, 68 IntField1: 21, 69 IntField2: 22, 70 UIntField1: 212, 71 UIntField2: 223, 72 FloatField1: 2.1, 73 FloatField2: 2.2, 74 StringField1: "string21", 75 StringField2: "string22", 76 }, 77 }, 78 { 79 Key: "key3", 80 Expected: TestStateEntry{ 81 BoolField1: true, 82 BoolField2: true, 83 IntField1: 31, 84 IntField2: 32, 85 UIntField1: 312, 86 UIntField2: 323, 87 FloatField1: 3.1, 88 FloatField2: 3.2, 89 StringField1: "string31", 90 StringField2: "string32", 91 }, 92 }, 93 // Tests if the initialization works properly. 94 { 95 Key: "dummy", 96 Expected: TestStateEntry{}, 97 }, 98 } 99 100 // Use the state file from the test data. 101 state := yaml.NewState(filepath.Join("testdata", "state.yml")) 102 103 // Variable must be initialized before the for loop to make the last test 104 // working which needs values to be set. 105 stateEntry := TestStateEntry{} 106 107 for _, tt := range tests { 108 suite.Run(tt.Key, func() { 109 suite.NoError(state.Get(tt.Key, &stateEntry)) 110 suite.EqualValues(tt.Expected, stateEntry) 111 }) 112 } 113 } 114 115 func (suite *StateTestSuite) TestSetUpdatesState() { 116 // Use a non existing state file from the temp dir. 117 state := yaml.NewState(filepath.Join(suite.T().TempDir(), "state.yml")) 118 119 stateEntryOut := TestStateEntry{ 120 BoolField1: true, 121 BoolField2: false, 122 FloatField1: 12.34, 123 FloatField2: 23.45, 124 IntField1: 12, 125 IntField2: 23, 126 UIntField1: 123, 127 UIntField2: 234, 128 StringField1: "string1", 129 StringField2: "string2", 130 Sub: TestStateSubEntry{ 131 BoolField1: true, 132 IntField1: 1, 133 UIntField1: 2, 134 FloatField1: 3.1, 135 StringField1: "string1", 136 }, 137 } 138 stateEntryIn := TestStateEntry{} 139 140 suite.NoError(state.Set("test_state_entry", stateEntryOut)) 141 suite.NoError(state.Get("test_state_entry", &stateEntryIn)) 142 suite.EqualValues(stateEntryOut, stateEntryIn) 143 } 144 145 func (suite *StateTestSuite) TestSetPreservesExistingStates() { 146 var tests = []struct { 147 Key types.StateEntryKey 148 Entry TestStateEntry 149 }{ 150 { 151 Key: "key1", 152 Entry: TestStateEntry{ 153 BoolField1: true, 154 BoolField2: false, 155 IntField1: 11, 156 IntField2: 12, 157 UIntField1: 112, 158 UIntField2: 123, 159 FloatField1: 1.1, 160 FloatField2: 1.2, 161 StringField1: "string11", 162 StringField2: "string12", 163 }, 164 }, 165 { 166 Key: "key2", 167 Entry: TestStateEntry{ 168 BoolField1: false, 169 BoolField2: true, 170 IntField1: 21, 171 IntField2: 22, 172 UIntField1: 212, 173 UIntField2: 223, 174 FloatField1: 2.1, 175 FloatField2: 2.2, 176 StringField1: "string21", 177 StringField2: "string22", 178 }, 179 }, 180 { 181 Key: "key3", 182 Entry: TestStateEntry{ 183 BoolField1: true, 184 BoolField2: true, 185 IntField1: 31, 186 IntField2: 32, 187 UIntField1: 312, 188 UIntField2: 323, 189 FloatField1: 3.1, 190 FloatField2: 3.2, 191 StringField1: "string31", 192 StringField2: "string32", 193 }, 194 }, 195 } 196 197 // Use a non existing state file from the temp dir. 198 state := yaml.NewState(filepath.Join(suite.T().TempDir(), "state.yml")) 199 200 for _, tt := range tests { 201 suite.NoError(state.Set(tt.Key, tt.Entry)) 202 } 203 204 // Save and reload states. 205 suite.NoError(state.Save()) 206 suite.NoError(state.Load()) 207 208 // Add test state. 209 testState := TestStateEntry{ 210 BoolField1: true, 211 BoolField2: true, 212 } 213 suite.NoError(state.Set("test", testState)) 214 215 // Verify previous states. 216 stateEntry := TestStateEntry{} 217 218 for _, tt := range tests { 219 suite.Run(tt.Key, func() { 220 suite.NoError(state.Get(tt.Key, &stateEntry)) 221 suite.EqualValues(tt.Entry, stateEntry) 222 }) 223 } 224 225 // Verify test state. 226 suite.NoError(state.Get("test", &stateEntry)) 227 suite.EqualValues(testState, stateEntry) 228 } 229 230 func (suite *StateTestSuite) TestGetExpectsPointer() { 231 // Use a non existing state file from the temp dir. 232 state := yaml.NewState(filepath.Join(suite.T().TempDir(), "state.yml")) 233 234 stateEntry := TestStateEntry{} 235 236 suite.ErrorContains(state.Get("test_state_entry", stateEntry), "stateEntry must be a pointer") 237 } 238 239 func (suite *StateTestSuite) TestSetExpectsNonPointer() { 240 // Use a non existing state file from the temp dir. 241 state := yaml.NewState(filepath.Join(suite.T().TempDir(), "state.yml")) 242 243 stateEntry := TestStateEntry{} 244 245 suite.ErrorContains(state.Set("test_state_entry", &stateEntry), "stateEntry must not be a pointer") 246 } 247 248 func (suite *StateTestSuite) TestLoadedIsProperlySet() { 249 var tests = []struct { 250 Name string 251 File string 252 }{ 253 { 254 Name: "StateExists", 255 File: filepath.Join("testdata", "state.yml"), 256 }, 257 { 258 Name: "StateNotExists", 259 File: filepath.Join(suite.T().TempDir(), "state.yml"), 260 }, 261 } 262 263 for _, tt := range tests { 264 suite.Run(tt.Name, func() { 265 state := yaml.NewState(tt.File) 266 267 suite.False(state.Loaded()) 268 suite.NoError(state.Load()) 269 suite.True(state.Loaded()) 270 suite.NoError(state.Save()) 271 suite.True(state.Loaded()) 272 }) 273 } 274 } 275 276 func (suite *StateTestSuite) TestChangedIsProperlySet() { 277 state := yaml.NewState(filepath.Join(suite.T().TempDir(), "state.yml")) 278 279 suite.False(state.Changed()) 280 suite.NoError(state.Load()) 281 suite.False(state.Changed()) 282 suite.NoError(state.Set("test_state_entry", TestStateEntry{})) 283 suite.True(state.Changed()) 284 suite.NoError(state.Save()) 285 suite.False(state.Changed()) 286 }