k8s.io/kubernetes@v1.29.3/pkg/kubelet/cm/memorymanager/state/state_checkpoint_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package state 18 19 import ( 20 "os" 21 "strings" 22 "testing" 23 24 "github.com/stretchr/testify/assert" 25 26 v1 "k8s.io/api/core/v1" 27 "k8s.io/kubernetes/pkg/kubelet/checkpointmanager" 28 testutil "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/testing" 29 ) 30 31 const testingCheckpoint = "memorymanager_checkpoint_test" 32 33 // assertStateEqual marks provided test as failed if provided states differ 34 func assertStateEqual(t *testing.T, restoredState, expectedState State) { 35 expectedMachineState := expectedState.GetMachineState() 36 restoredMachineState := restoredState.GetMachineState() 37 assert.Equal(t, expectedMachineState, restoredMachineState, "expected MachineState does not equal to restored one") 38 39 expectedMemoryAssignments := expectedState.GetMemoryAssignments() 40 restoredMemoryAssignments := restoredState.GetMemoryAssignments() 41 assert.Equal(t, expectedMemoryAssignments, restoredMemoryAssignments, "state memory assignments mismatch") 42 } 43 44 func TestCheckpointStateRestore(t *testing.T) { 45 testCases := []struct { 46 description string 47 checkpointContent string 48 expectedError string 49 expectedState *stateMemory 50 }{ 51 { 52 "Restore non-existing checkpoint", 53 "", 54 "", 55 &stateMemory{}, 56 }, 57 { 58 "Restore valid checkpoint", 59 `{ 60 "policyName":"static", 61 "machineState":{"0":{"numberOfAssignments":0,"memoryMap":{"memory":{"total":2048,"systemReserved":512,"allocatable":1536,"reserved":512,"free":1024}},"cells":[]}}, 62 "entries":{"pod":{"container1":[{"numaAffinity":[0],"type":"memory","size":512}]}}, 63 "checksum": 4215593881 64 }`, 65 "", 66 &stateMemory{ 67 assignments: ContainerMemoryAssignments{ 68 "pod": map[string][]Block{ 69 "container1": { 70 { 71 NUMAAffinity: []int{0}, 72 Type: v1.ResourceMemory, 73 Size: 512, 74 }, 75 }, 76 }, 77 }, 78 machineState: NUMANodeMap{ 79 0: &NUMANodeState{ 80 MemoryMap: map[v1.ResourceName]*MemoryTable{ 81 v1.ResourceMemory: { 82 Allocatable: 1536, 83 Free: 1024, 84 Reserved: 512, 85 SystemReserved: 512, 86 TotalMemSize: 2048, 87 }, 88 }, 89 }, 90 }, 91 }, 92 }, 93 { 94 "Restore checkpoint with invalid checksum", 95 `{ 96 "policyName":"static", 97 "machineState":{"0":{"numberOfAssignments":0,"memoryMap":{"memory":{"total":2048,"systemReserved":512,"allocatable":1536,"reserved":512,"free":1024}},"cells":[]}}, 98 "entries":{"pod":{"container1":[{"affinity":[0],"type":"memory","size":512}]}}, 99 "checksum": 101010 100 }`, 101 "checkpoint is corrupted", 102 &stateMemory{}, 103 }, 104 { 105 "Restore checkpoint with invalid JSON", 106 `{`, 107 "unexpected end of JSON input", 108 &stateMemory{}, 109 }, 110 } 111 112 // create temp dir 113 testingDir, err := os.MkdirTemp("", "memorymanager_state_test") 114 if err != nil { 115 t.Fatal(err) 116 } 117 defer os.RemoveAll(testingDir) 118 119 // create checkpoint manager for testing 120 cpm, err := checkpointmanager.NewCheckpointManager(testingDir) 121 assert.NoError(t, err, "could not create testing checkpoint manager") 122 123 for _, tc := range testCases { 124 t.Run(tc.description, func(t *testing.T) { 125 // ensure there is no previous checkpoint 126 assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint") 127 128 // prepare checkpoint for testing 129 if strings.TrimSpace(tc.checkpointContent) != "" { 130 checkpoint := &testutil.MockCheckpoint{Content: tc.checkpointContent} 131 assert.NoError(t, cpm.CreateCheckpoint(testingCheckpoint, checkpoint), "could not create testing checkpoint") 132 } 133 134 restoredState, err := NewCheckpointState(testingDir, testingCheckpoint, "static") 135 if strings.TrimSpace(tc.expectedError) != "" { 136 assert.Error(t, err) 137 assert.Contains(t, err.Error(), "could not restore state from checkpoint: "+tc.expectedError) 138 } else { 139 assert.NoError(t, err, "unexpected error while creating checkpointState") 140 // compare state after restoration with the one expected 141 assertStateEqual(t, restoredState, tc.expectedState) 142 } 143 }) 144 } 145 } 146 147 func TestCheckpointStateStore(t *testing.T) { 148 expectedState := &stateMemory{ 149 assignments: ContainerMemoryAssignments{ 150 "pod": map[string][]Block{ 151 "container1": { 152 { 153 NUMAAffinity: []int{0}, 154 Type: v1.ResourceMemory, 155 Size: 1024, 156 }, 157 }, 158 }, 159 }, 160 machineState: NUMANodeMap{ 161 0: &NUMANodeState{ 162 MemoryMap: map[v1.ResourceName]*MemoryTable{ 163 v1.ResourceMemory: { 164 Allocatable: 1536, 165 Free: 512, 166 Reserved: 1024, 167 SystemReserved: 512, 168 TotalMemSize: 2048, 169 }, 170 }, 171 }, 172 }, 173 } 174 175 // create temp dir 176 testingDir, err := os.MkdirTemp("", "memorymanager_state_test") 177 if err != nil { 178 t.Fatal(err) 179 } 180 defer os.RemoveAll(testingDir) 181 182 cpm, err := checkpointmanager.NewCheckpointManager(testingDir) 183 assert.NoError(t, err, "could not create testing checkpoint manager") 184 185 assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint") 186 187 cs1, err := NewCheckpointState(testingDir, testingCheckpoint, "static") 188 assert.NoError(t, err, "could not create testing checkpointState instance") 189 190 // set values of cs1 instance so they are stored in checkpoint and can be read by cs2 191 cs1.SetMachineState(expectedState.machineState) 192 cs1.SetMemoryAssignments(expectedState.assignments) 193 194 // restore checkpoint with previously stored values 195 cs2, err := NewCheckpointState(testingDir, testingCheckpoint, "static") 196 assert.NoError(t, err, "could not create testing checkpointState instance") 197 198 assertStateEqual(t, cs2, expectedState) 199 } 200 201 func TestCheckpointStateHelpers(t *testing.T) { 202 testCases := []struct { 203 description string 204 machineState NUMANodeMap 205 assignments ContainerMemoryAssignments 206 }{ 207 { 208 description: "One container", 209 assignments: ContainerMemoryAssignments{ 210 "pod": map[string][]Block{ 211 "container1": { 212 { 213 NUMAAffinity: []int{0}, 214 Type: v1.ResourceMemory, 215 Size: 1024, 216 }, 217 }, 218 }, 219 }, 220 machineState: NUMANodeMap{ 221 0: &NUMANodeState{ 222 MemoryMap: map[v1.ResourceName]*MemoryTable{ 223 v1.ResourceMemory: { 224 Allocatable: 1536, 225 Free: 512, 226 Reserved: 1024, 227 SystemReserved: 512, 228 TotalMemSize: 2048, 229 }, 230 }, 231 Cells: []int{}, 232 }, 233 }, 234 }, 235 { 236 description: "Two containers", 237 assignments: ContainerMemoryAssignments{ 238 "pod": map[string][]Block{ 239 "container1": { 240 { 241 NUMAAffinity: []int{0}, 242 Type: v1.ResourceMemory, 243 Size: 512, 244 }, 245 }, 246 "container2": { 247 { 248 NUMAAffinity: []int{0}, 249 Type: v1.ResourceMemory, 250 Size: 512, 251 }, 252 }, 253 }, 254 }, 255 machineState: NUMANodeMap{ 256 0: &NUMANodeState{ 257 MemoryMap: map[v1.ResourceName]*MemoryTable{ 258 v1.ResourceMemory: { 259 Allocatable: 1536, 260 Free: 512, 261 Reserved: 1024, 262 SystemReserved: 512, 263 TotalMemSize: 2048, 264 }, 265 }, 266 Cells: []int{}, 267 }, 268 }, 269 }, 270 { 271 description: "Container without assigned memory", 272 assignments: ContainerMemoryAssignments{ 273 "pod": map[string][]Block{ 274 "container1": {}, 275 }, 276 }, 277 machineState: NUMANodeMap{ 278 0: &NUMANodeState{ 279 MemoryMap: map[v1.ResourceName]*MemoryTable{ 280 v1.ResourceMemory: { 281 Allocatable: 1536, 282 Free: 1536, 283 Reserved: 0, 284 SystemReserved: 512, 285 TotalMemSize: 2048, 286 }, 287 }, 288 Cells: []int{}, 289 }, 290 }, 291 }, 292 } 293 294 // create temp dir 295 testingDir, err := os.MkdirTemp("", "memorymanager_state_test") 296 if err != nil { 297 t.Fatal(err) 298 } 299 defer os.RemoveAll(testingDir) 300 301 cpm, err := checkpointmanager.NewCheckpointManager(testingDir) 302 assert.NoError(t, err, "could not create testing checkpoint manager") 303 304 for _, tc := range testCases { 305 t.Run(tc.description, func(t *testing.T) { 306 // ensure there is no previous checkpoint 307 assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint") 308 309 state, err := NewCheckpointState(testingDir, testingCheckpoint, "static") 310 assert.NoError(t, err, "could not create testing checkpoint manager") 311 312 state.SetMachineState(tc.machineState) 313 assert.Equal(t, tc.machineState, state.GetMachineState(), "machine state inconsistent") 314 315 for pod := range tc.assignments { 316 for container, blocks := range tc.assignments[pod] { 317 state.SetMemoryBlocks(pod, container, blocks) 318 assert.Equal(t, blocks, state.GetMemoryBlocks(pod, container), "memory block inconsistent") 319 320 state.Delete(pod, container) 321 assert.Nil(t, state.GetMemoryBlocks(pod, container), "deleted container still existing in state") 322 } 323 } 324 }) 325 } 326 } 327 328 func TestCheckpointStateClear(t *testing.T) { 329 testCases := []struct { 330 description string 331 machineState NUMANodeMap 332 assignments ContainerMemoryAssignments 333 }{ 334 { 335 description: "Valid state cleaning", 336 assignments: ContainerMemoryAssignments{ 337 "pod": map[string][]Block{ 338 "container1": { 339 { 340 NUMAAffinity: []int{0}, 341 Type: v1.ResourceMemory, 342 Size: 1024, 343 }, 344 }, 345 }, 346 }, 347 machineState: NUMANodeMap{ 348 0: &NUMANodeState{ 349 MemoryMap: map[v1.ResourceName]*MemoryTable{ 350 v1.ResourceMemory: { 351 Allocatable: 1536, 352 Free: 512, 353 Reserved: 1024, 354 SystemReserved: 512, 355 TotalMemSize: 2048, 356 }, 357 }, 358 }, 359 }, 360 }, 361 } 362 363 // create temp dir 364 testingDir, err := os.MkdirTemp("", "memorymanager_state_test") 365 if err != nil { 366 t.Fatal(err) 367 } 368 defer os.RemoveAll(testingDir) 369 370 for _, tc := range testCases { 371 t.Run(tc.description, func(t *testing.T) { 372 state, err := NewCheckpointState(testingDir, testingCheckpoint, "static") 373 assert.NoError(t, err, "could not create testing checkpoint manager") 374 375 state.SetMachineState(tc.machineState) 376 state.SetMemoryAssignments(tc.assignments) 377 378 state.ClearState() 379 assert.Equal(t, NUMANodeMap{}, state.GetMachineState(), "cleared state with non-empty machine state") 380 assert.Equal(t, ContainerMemoryAssignments{}, state.GetMemoryAssignments(), "cleared state with non-empty memory assignments") 381 }) 382 } 383 }