204 lines
6.9 KiB
Go
204 lines
6.9 KiB
Go
// Copyright 2015 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package oomparser
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
const startLine = "Jan 21 22:01:49 localhost kernel: [62278.816267] ruby invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0"
|
|
const endLine = "Jan 21 22:01:49 localhost kernel: [62279.421192] Killed process 19667 (evilprogram2) total-vm:1460016kB, anon-rss:1414008kB, file-rss:4kB"
|
|
const containerLine = "Jan 26 14:10:07 kateknister0.mtv.corp.google.com kernel: [1814368.465205] Task in /mem2 killed as a result of limit of /mem2"
|
|
const containerLogFile = "containerOomExampleLog.txt"
|
|
const systemLogFile = "systemOomExampleLog.txt"
|
|
|
|
func createExpectedContainerOomInstance(t *testing.T) *OomInstance {
|
|
const longForm = "Jan _2 15:04:05 2006"
|
|
deathTime, err := time.Parse(longForm, "Jan 5 15:19:27 2015")
|
|
if err != nil {
|
|
t.Fatalf("could not parse expected time when creating expected container oom instance. Had error %v", err)
|
|
return nil
|
|
}
|
|
return &OomInstance{
|
|
Pid: 13536,
|
|
ProcessName: "memorymonster",
|
|
TimeOfDeath: deathTime,
|
|
ContainerName: "/mem2",
|
|
}
|
|
}
|
|
|
|
func createExpectedSystemOomInstance(t *testing.T) *OomInstance {
|
|
const longForm = "Jan _2 15:04:05 2006"
|
|
deathTime, err := time.Parse(longForm, "Jan 28 19:58:45 2015")
|
|
if err != nil {
|
|
t.Fatalf("could not parse expected time when creating expected system oom instance. Had error %v", err)
|
|
return nil
|
|
}
|
|
return &OomInstance{
|
|
Pid: 1532,
|
|
ProcessName: "badsysprogram",
|
|
TimeOfDeath: deathTime,
|
|
ContainerName: "/",
|
|
}
|
|
}
|
|
|
|
func TestGetContainerName(t *testing.T) {
|
|
currentOomInstance := new(OomInstance)
|
|
err := getContainerName(startLine, currentOomInstance)
|
|
if err != nil {
|
|
t.Errorf("bad line fed to getContainerName should yield no error, but had error %v", err)
|
|
}
|
|
if currentOomInstance.ContainerName != "" {
|
|
t.Errorf("bad line fed to getContainerName yielded no container name but set it to %s", currentOomInstance.ContainerName)
|
|
}
|
|
err = getContainerName(containerLine, currentOomInstance)
|
|
if err != nil {
|
|
t.Errorf("container line fed to getContainerName should yield no error, but had error %v", err)
|
|
}
|
|
if currentOomInstance.ContainerName != "/mem2" {
|
|
t.Errorf("getContainerName should have set containerName to /mem2, not %s", currentOomInstance.ContainerName)
|
|
}
|
|
}
|
|
|
|
func TestGetProcessNamePid(t *testing.T) {
|
|
currentOomInstance := new(OomInstance)
|
|
couldParseLine, err := getProcessNamePid(startLine, currentOomInstance)
|
|
if err != nil {
|
|
t.Errorf("bad line fed to getProcessNamePid should yield no error, but had error %v", err)
|
|
}
|
|
if couldParseLine {
|
|
t.Errorf("bad line fed to getProcessNamePid should return false but returned %v", couldParseLine)
|
|
}
|
|
|
|
const longForm = "Jan _2 15:04:05 2006"
|
|
correctTime, err := time.Parse(longForm, "Jan 21 22:01:49 2015")
|
|
couldParseLine, err = getProcessNamePid(endLine, currentOomInstance)
|
|
if err != nil {
|
|
t.Errorf("good line fed to getProcessNamePid should yield no error, but had error %v", err)
|
|
}
|
|
if !couldParseLine {
|
|
t.Errorf("good line fed to getProcessNamePid should return true but returned %v", couldParseLine)
|
|
}
|
|
if currentOomInstance.ProcessName != "evilprogram2" {
|
|
t.Errorf("getProcessNamePid should have set processName to evilprogram2, not %s", currentOomInstance.ProcessName)
|
|
}
|
|
if currentOomInstance.Pid != 19667 {
|
|
t.Errorf("getProcessNamePid should have set PID to 19667, not %d", currentOomInstance.Pid)
|
|
}
|
|
if !correctTime.Equal(currentOomInstance.TimeOfDeath) {
|
|
t.Errorf("getProcessNamePid should have set date to %v, not %v", correctTime, currentOomInstance.TimeOfDeath)
|
|
}
|
|
}
|
|
|
|
func TestCheckIfStartOfMessages(t *testing.T) {
|
|
couldParseLine, err := checkIfStartOfOomMessages(endLine)
|
|
if err != nil {
|
|
t.Errorf("bad line fed to checkIfStartOfMessages should yield no error, but had error %v", err)
|
|
}
|
|
if couldParseLine {
|
|
t.Errorf("bad line fed to checkIfStartOfMessages should return false but returned %v", couldParseLine)
|
|
}
|
|
|
|
couldParseLine, err = checkIfStartOfOomMessages(startLine)
|
|
if err != nil {
|
|
t.Errorf("start line fed to checkIfStartOfMessages should yield no error, but had error %v", err)
|
|
}
|
|
if !couldParseLine {
|
|
t.Errorf("start line fed to checkIfStartOfMessages should return true but returned %v", couldParseLine)
|
|
}
|
|
}
|
|
|
|
func TestAnalyzeLinesContainerOom(t *testing.T) {
|
|
expectedContainerOomInstance := createExpectedContainerOomInstance(t)
|
|
helpTestAnalyzeLines(expectedContainerOomInstance, containerLogFile, t)
|
|
}
|
|
|
|
func TestAnalyzeLinesSystemOom(t *testing.T) {
|
|
expectedSystemOomInstance := createExpectedSystemOomInstance(t)
|
|
helpTestAnalyzeLines(expectedSystemOomInstance, systemLogFile, t)
|
|
}
|
|
|
|
func helpTestAnalyzeLines(oomCheckInstance *OomInstance, sysFile string, t *testing.T) {
|
|
outStream := make(chan *OomInstance)
|
|
oomLog := new(OomParser)
|
|
oomLog.systemFile = sysFile
|
|
file, err := os.Open(oomLog.systemFile)
|
|
if err != nil {
|
|
t.Errorf("couldn't open test log: %v", err)
|
|
}
|
|
timeout := make(chan bool, 1)
|
|
go func() {
|
|
time.Sleep(1 * time.Second)
|
|
timeout <- true
|
|
}()
|
|
go oomLog.analyzeLines(file, outStream)
|
|
select {
|
|
case oomInstance := <-outStream:
|
|
if *oomCheckInstance != *oomInstance {
|
|
t.Errorf("wrong instance returned. Expected %v and got %v",
|
|
oomCheckInstance, oomInstance)
|
|
}
|
|
case <-timeout:
|
|
t.Error(
|
|
"timeout happened before oomInstance was found in test file")
|
|
}
|
|
}
|
|
|
|
func TestStreamOomsContainer(t *testing.T) {
|
|
expectedContainerOomInstance := createExpectedContainerOomInstance(t)
|
|
helpTestStreamOoms(expectedContainerOomInstance, containerLogFile, t)
|
|
}
|
|
|
|
func TestStreamOomsSystem(t *testing.T) {
|
|
expectedSystemOomInstance := createExpectedSystemOomInstance(t)
|
|
helpTestStreamOoms(expectedSystemOomInstance, systemLogFile, t)
|
|
}
|
|
|
|
func helpTestStreamOoms(oomCheckInstance *OomInstance, sysFile string, t *testing.T) {
|
|
outStream := make(chan *OomInstance)
|
|
oomLog := new(OomParser)
|
|
oomLog.systemFile = sysFile
|
|
timeout := make(chan bool, 1)
|
|
go func() {
|
|
time.Sleep(1 * time.Second)
|
|
timeout <- true
|
|
}()
|
|
|
|
err := oomLog.StreamOoms(outStream)
|
|
if err != nil {
|
|
t.Errorf("had an error opening file: %v", err)
|
|
}
|
|
|
|
select {
|
|
case oomInstance := <-outStream:
|
|
if *oomCheckInstance != *oomInstance {
|
|
t.Errorf("wrong instance returned. Expected %v and got %v",
|
|
oomCheckInstance, oomInstance)
|
|
}
|
|
case <-timeout:
|
|
t.Error(
|
|
"timeout happened before oomInstance was found in test file")
|
|
}
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
_, err := New()
|
|
if err != nil {
|
|
t.Errorf("function New() had error %v", err)
|
|
}
|
|
}
|