1
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
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
113 testingDir, err := os.MkdirTemp("", "memorymanager_state_test")
114 if err != nil {
115 t.Fatal(err)
116 }
117 defer os.RemoveAll(testingDir)
118
119
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
126 assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint")
127
128
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
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
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
191 cs1.SetMachineState(expectedState.machineState)
192 cs1.SetMemoryAssignments(expectedState.assignments)
193
194
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
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
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
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 }
384
View as plain text