k8s.io/kubernetes@v1.29.3/pkg/kubelet/oom/oom_watcher_linux_test.go (about) 1 /* 2 Copyright 2015 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 oom 18 19 import ( 20 "fmt" 21 "testing" 22 "time" 23 24 v1 "k8s.io/api/core/v1" 25 "k8s.io/client-go/tools/record" 26 27 "github.com/google/cadvisor/utils/oomparser" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 type fakeStreamer struct { 32 oomInstancesToStream []*oomparser.OomInstance 33 } 34 35 func (fs *fakeStreamer) StreamOoms(outStream chan<- *oomparser.OomInstance) { 36 for _, oomInstance := range fs.oomInstancesToStream { 37 outStream <- oomInstance 38 } 39 } 40 41 // TestWatcherRecordsEventsForOomEvents ensures that our OomInstances coming 42 // from `StreamOoms` are translated into events in our recorder. 43 func TestWatcherRecordsEventsForOomEvents(t *testing.T) { 44 oomInstancesToStream := []*oomparser.OomInstance{ 45 { 46 Pid: 1000, 47 ProcessName: "fakeProcess", 48 TimeOfDeath: time.Now(), 49 ContainerName: recordEventContainerName + "some-container", 50 VictimContainerName: recordEventContainerName, 51 }, 52 } 53 numExpectedOomEvents := len(oomInstancesToStream) 54 55 fakeStreamer := &fakeStreamer{ 56 oomInstancesToStream: oomInstancesToStream, 57 } 58 59 fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents) 60 node := &v1.ObjectReference{} 61 62 oomWatcher := &realWatcher{ 63 recorder: fakeRecorder, 64 oomStreamer: fakeStreamer, 65 } 66 assert.NoError(t, oomWatcher.Start(node)) 67 68 eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents) 69 assert.Equal(t, numExpectedOomEvents, len(eventsRecorded)) 70 } 71 72 func getRecordedEvents(fakeRecorder *record.FakeRecorder, numExpectedOomEvents int) []string { 73 eventsRecorded := []string{} 74 75 select { 76 case event := <-fakeRecorder.Events: 77 eventsRecorded = append(eventsRecorded, event) 78 79 if len(eventsRecorded) == numExpectedOomEvents { 80 break 81 } 82 case <-time.After(10 * time.Second): 83 break 84 } 85 86 return eventsRecorded 87 } 88 89 // TestWatcherRecordsEventsForOomEventsCorrectContainerName verifies that we 90 // only record OOM events when the container name is the one for which we want 91 // to record events (i.e. /). 92 func TestWatcherRecordsEventsForOomEventsCorrectContainerName(t *testing.T) { 93 // By "incorrect" container name, we mean a container name for which we 94 // don't want to record an oom event. 95 numOomEventsWithIncorrectContainerName := 1 96 oomInstancesToStream := []*oomparser.OomInstance{ 97 { 98 Pid: 1000, 99 ProcessName: "fakeProcess", 100 TimeOfDeath: time.Now(), 101 ContainerName: recordEventContainerName + "some-container", 102 VictimContainerName: recordEventContainerName, 103 }, 104 { 105 Pid: 1000, 106 ProcessName: "fakeProcess", 107 TimeOfDeath: time.Now(), 108 ContainerName: recordEventContainerName + "kubepods/some-container", 109 VictimContainerName: recordEventContainerName + "kubepods", 110 }, 111 } 112 numExpectedOomEvents := len(oomInstancesToStream) - numOomEventsWithIncorrectContainerName 113 114 fakeStreamer := &fakeStreamer{ 115 oomInstancesToStream: oomInstancesToStream, 116 } 117 118 fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents) 119 node := &v1.ObjectReference{} 120 121 oomWatcher := &realWatcher{ 122 recorder: fakeRecorder, 123 oomStreamer: fakeStreamer, 124 } 125 assert.NoError(t, oomWatcher.Start(node)) 126 127 eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents) 128 assert.Equal(t, numExpectedOomEvents, len(eventsRecorded)) 129 } 130 131 // TestWatcherRecordsEventsForOomEventsWithAdditionalInfo verifies that our the 132 // emitted event has the proper pid/process data when appropriate. 133 func TestWatcherRecordsEventsForOomEventsWithAdditionalInfo(t *testing.T) { 134 // The process and event info should appear in the event message. 135 eventPid := 1000 136 processName := "fakeProcess" 137 138 oomInstancesToStream := []*oomparser.OomInstance{ 139 { 140 Pid: eventPid, 141 ProcessName: processName, 142 TimeOfDeath: time.Now(), 143 ContainerName: recordEventContainerName + "some-container", 144 VictimContainerName: recordEventContainerName, 145 }, 146 } 147 numExpectedOomEvents := len(oomInstancesToStream) 148 149 fakeStreamer := &fakeStreamer{ 150 oomInstancesToStream: oomInstancesToStream, 151 } 152 153 fakeRecorder := record.NewFakeRecorder(numExpectedOomEvents) 154 node := &v1.ObjectReference{} 155 156 oomWatcher := &realWatcher{ 157 recorder: fakeRecorder, 158 oomStreamer: fakeStreamer, 159 } 160 assert.NoError(t, oomWatcher.Start(node)) 161 162 eventsRecorded := getRecordedEvents(fakeRecorder, numExpectedOomEvents) 163 164 assert.Equal(t, numExpectedOomEvents, len(eventsRecorded)) 165 assert.Contains(t, eventsRecorded[0], systemOOMEvent) 166 assert.Contains(t, eventsRecorded[0], fmt.Sprintf("pid: %d", eventPid)) 167 assert.Contains(t, eventsRecorded[0], fmt.Sprintf("victim process: %s", processName)) 168 }