github.com/google/cadvisor@v0.49.1/utils/oomparser/oomparser_test.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package oomparser
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/euank/go-kmsg-parser/kmsgparser"
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  const (
    27  	startLine           = "ruby invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0"
    28  	endLine             = "Killed process 19667 (evil-program2) total-vm:1460016kB, anon-rss:1414008kB, file-rss:4kB"
    29  	legacyContainerLine = "Task in /mem2 killed as a result of limit of /mem3"
    30  	containerLine       = "oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8,mems_allowed=0,oom_memcg=/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012,task_memcg=/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012/ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8,task=manager,pid=966,uid=0"
    31  )
    32  
    33  func TestGetLegacyContainerName(t *testing.T) {
    34  	currentOomInstance := new(OomInstance)
    35  	finished, err := getContainerName(startLine, currentOomInstance)
    36  	if err != nil {
    37  		t.Errorf("bad line fed to getContainerName should yield no error, but had error %v", err)
    38  	}
    39  	if finished {
    40  		t.Errorf("bad line fed to getContainerName should not result in a finished oom log, but it did")
    41  	}
    42  	if currentOomInstance.ContainerName != "" {
    43  		t.Errorf("bad line fed to getContainerName yielded no container name but set it to %s", currentOomInstance.ContainerName)
    44  	}
    45  	finished, err = getContainerName(legacyContainerLine, currentOomInstance)
    46  	if err != nil {
    47  		t.Errorf("container line fed to getContainerName should yield no error, but had error %v", err)
    48  	}
    49  	if finished {
    50  		t.Errorf("getContainerName with the legacy log line should not result in a finished oom log, but it did")
    51  
    52  	}
    53  	if currentOomInstance.ContainerName != "/mem2" {
    54  		t.Errorf("getContainerName should have set containerName to /mem2, not %s", currentOomInstance.ContainerName)
    55  	}
    56  	if currentOomInstance.VictimContainerName != "/mem3" {
    57  		t.Errorf("getContainerName should have set victimContainerName to /mem3, not %s", currentOomInstance.VictimContainerName)
    58  	}
    59  }
    60  
    61  func TestGetContainerName(t *testing.T) {
    62  	currentOomInstance := new(OomInstance)
    63  	finished, err := getContainerName(startLine, currentOomInstance)
    64  	if err != nil {
    65  		t.Errorf("bad line fed to getContainerName should yield no error, but had error %v", err)
    66  	}
    67  	if finished {
    68  		t.Errorf("bad line fed to getContainerName should not result in a finished oom log, but it did")
    69  	}
    70  	if currentOomInstance.ContainerName != "" {
    71  		t.Errorf("bad line fed to getContainerName yielded no container name but set it to %s", currentOomInstance.ContainerName)
    72  	}
    73  	finished, err = getContainerName(containerLine, currentOomInstance)
    74  	if err != nil {
    75  		t.Errorf("container line fed to getContainerName should yield no error, but had error %v", err)
    76  	}
    77  	if !finished {
    78  		t.Errorf("getContainerName with the complete log line should result in a finished oom log, but it did not")
    79  
    80  	}
    81  	if currentOomInstance.ContainerName != "/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012/ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8" {
    82  		t.Errorf("getContainerName should have set containerName to /kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012/ef807430361e6e82b45db92e2e9b6fbec98f419b12c591e655c1a725565e73a8, not %s", currentOomInstance.ContainerName)
    83  	}
    84  	if currentOomInstance.VictimContainerName != "/kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012" {
    85  		t.Errorf("getContainerName should have set victimContainerName to /kubepods/burstable/podfbdfe8e3-1c87-4ff2-907c-b2ec8e25d012, not %s", currentOomInstance.VictimContainerName)
    86  	}
    87  	if currentOomInstance.Pid != 966 {
    88  		t.Errorf("getContainerName should have set Pid to 966, not %d", currentOomInstance.Pid)
    89  	}
    90  	if currentOomInstance.ProcessName != "manager" {
    91  		t.Errorf("getContainerName should have set ProcessName to manager, not %s", currentOomInstance.ProcessName)
    92  	}
    93  	if currentOomInstance.Constraint != "CONSTRAINT_MEMCG" {
    94  		t.Errorf("getContainerName should have set ProcessName to CONSTRAINT_MEMCG, not %s", currentOomInstance.Constraint)
    95  	}
    96  }
    97  
    98  func TestGetProcessNamePid(t *testing.T) {
    99  	currentOomInstance := new(OomInstance)
   100  	couldParseLine, err := getProcessNamePid(startLine, currentOomInstance)
   101  	if err != nil {
   102  		t.Errorf("bad line fed to getProcessNamePid should yield no error, but had error %v", err)
   103  	}
   104  	if couldParseLine {
   105  		t.Errorf("bad line fed to getProcessNamePid should return false but returned %v", couldParseLine)
   106  	}
   107  
   108  	couldParseLine, err = getProcessNamePid(endLine, currentOomInstance)
   109  	if err != nil {
   110  		t.Errorf("good line fed to getProcessNamePid should yield no error, but had error %v", err)
   111  	}
   112  	if !couldParseLine {
   113  		t.Errorf("good line fed to getProcessNamePid should return true but returned %v", couldParseLine)
   114  	}
   115  	if currentOomInstance.ProcessName != "evil-program2" {
   116  		t.Errorf("getProcessNamePid should have set processName to evil-program2, not %s", currentOomInstance.ProcessName)
   117  	}
   118  	if currentOomInstance.Pid != 19667 {
   119  		t.Errorf("getProcessNamePid should have set PID to 19667, not %d", currentOomInstance.Pid)
   120  	}
   121  }
   122  
   123  func TestCheckIfStartOfMessages(t *testing.T) {
   124  	couldParseLine := checkIfStartOfOomMessages(endLine)
   125  	if couldParseLine {
   126  		t.Errorf("bad line fed to checkIfStartOfMessages should return false but returned %v", couldParseLine)
   127  	}
   128  	couldParseLine = checkIfStartOfOomMessages(startLine)
   129  	if !couldParseLine {
   130  		t.Errorf("start line fed to checkIfStartOfMessages should return true but returned %v", couldParseLine)
   131  	}
   132  }
   133  
   134  func TestLastLineRegex(t *testing.T) {
   135  	processNames := []string{"foo", "python3.4", "foo-bar", "Plex Media Server", "x86_64-pc-linux-gnu-c++-5.4.0", "[", "()", `"with quotes"`}
   136  	for _, name := range processNames {
   137  		line := fmt.Sprintf("Jan 21 22:01:49 localhost kernel: [62279.421192] Killed process 1234 (%s) total-vm:1460016kB, anon-rss:1414008kB, file-rss:4kB", name)
   138  		oomInfo := &OomInstance{}
   139  		isPid, err := getProcessNamePid(line, oomInfo)
   140  		assert.True(t, isPid)
   141  		assert.NoError(t, err)
   142  		assert.Equal(t, 1234, oomInfo.Pid)
   143  		assert.Equal(t, name, oomInfo.ProcessName)
   144  	}
   145  }
   146  
   147  func TestStreamOOMs(t *testing.T) {
   148  	mockMsgs := make(chan kmsgparser.Message)
   149  	p := &OomParser{
   150  		parser: &mockKmsgParser{
   151  			messages: mockMsgs,
   152  		},
   153  	}
   154  
   155  	oomsOut := make(chan *OomInstance)
   156  
   157  	go func() {
   158  		p.StreamOoms(oomsOut)
   159  	}()
   160  
   161  	writeAll := func(m []string, t time.Time) {
   162  		for _, msg := range m {
   163  			mockMsgs <- kmsgparser.Message{
   164  				Message:   msg,
   165  				Timestamp: t,
   166  			}
   167  		}
   168  	}
   169  
   170  	type in struct {
   171  		msgs []string
   172  		time time.Time
   173  	}
   174  
   175  	testTime := time.Unix(0xf331f4ee, 0)
   176  	testTime2 := time.Unix(0xfa51f001, 0)
   177  	testPairs := []struct {
   178  		in  []in
   179  		out []*OomInstance
   180  	}{
   181  		{
   182  			in: []in{{
   183  				time: testTime,
   184  				msgs: []string{
   185  					"memorymonster invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=0",
   186  					"memorymonster cpuset=/ mems_allowed=0",
   187  					"CPU: 5 PID: 13536 Comm: memorymonster Tainted: P           OX 3.13.0-43-generic #72-Ubuntu",
   188  					"Hardware name: Hewlett-Packard HP Z420 Workstation/1589, BIOS J61 v03.65 12/19/2013",
   189  					" ffff88072ae10800 ffff8807a4835c48 ffffffff81720bf6 ffff8807a8e86000",
   190  					" ffff8807a4835cd0 ffffffff8171b4b1 0000000000000246 ffff88072ae10800",
   191  					" ffff8807a4835c90 ffff8807a4835ca0 ffffffff811522a7 0000000000000001",
   192  					"Call Trace:",
   193  					" [<ffffffff81720bf6>] dump_stack+0x45/0x56",
   194  					" [<ffffffff8171b4b1>] dump_header+0x7f/0x1f1",
   195  					" [<ffffffff811522a7>] ? find_lock_task_mm+0x27/0x70",
   196  					" [<ffffffff811526de>] oom_kill_process+0x1ce/0x330",
   197  					" [<ffffffff812d6ce5>] ? security_capable_noaudit+0x15/0x20",
   198  					" [<ffffffff811b491c>] mem_cgroup_oom_synchronize+0x51c/0x560",
   199  					" [<ffffffff811b3e50>] ? mem_cgroup_charge_common+0xa0/0xa0",
   200  					" [<ffffffff81152e64>] pagefault_out_of_memory+0x14/0x80",
   201  					" [<ffffffff81719aa1>] mm_fault_error+0x8e/0x180",
   202  					" [<ffffffff8172cf31>] __do_page_fault+0x4a1/0x560",
   203  					" [<ffffffff810a0255>] ? set_next_entity+0x95/0xb0",
   204  					" [<ffffffff81012609>] ? __switch_to+0x169/0x4c0",
   205  					" [<ffffffff8172d00a>] do_page_fault+0x1a/0x70",
   206  					" [<ffffffff81729468>] page_fault+0x28/0x30",
   207  					"Task in /mem2 killed as a result of limit of /mem2",
   208  					"memory: usage 980kB, limit 980kB, failcnt 4152239",
   209  					"memory+swap: usage 0kB, limit 18014398509481983kB, failcnt 0",
   210  					"kmem: usage 0kB, limit 18014398509481983kB, failcnt 0",
   211  					"Memory cgroup stats for /mem2: cache:0KB rss:980KB rss_huge:0KB mapped_file:0KB writeback:20KB inactive_anon:560KB active_anon:420KB inactive_file:0KB active_file:0KB unevictable:0KB",
   212  					"[ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name",
   213  					"[13536] 275858 13536  8389663      343   16267  8324326             0 memorymonster",
   214  					"Memory cgroup out of memory: Kill process 13536 (memorymonster) score 996 or sacrifice child",
   215  					"Killed process 13536 (memorymonster) total-vm:33558652kB, anon-rss:920kB, file-rss:452kB",
   216  				},
   217  			}},
   218  			out: []*OomInstance{{
   219  				TimeOfDeath:         testTime,
   220  				ContainerName:       "/mem2",
   221  				ProcessName:         "memorymonster",
   222  				Pid:                 13536,
   223  				VictimContainerName: "/mem2",
   224  			}},
   225  		},
   226  		{
   227  			in: []in{{
   228  				time: testTime,
   229  				msgs: []string{
   230  					"badsysprogram invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0",
   231  					"badsysprogram cpuset=/ mems_allowed=0",
   232  					"CPU: 0 PID: 1532 Comm: badsysprogram Not tainted 3.13.0-27-generic #50-Ubuntu",
   233  					"Hardware name: Google Google, BIOS Google 01/01/2011",
   234  					" 0000000000000000 ffff880069715a90 ffffffff817199c4 ffff8800680d8000",
   235  					" ffff880069715b18 ffffffff817142ff 0000000000000000 0000000000000000",
   236  					" 0000000000000000 0000000000000000 0000000000000000 0000000000000000",
   237  					"Call Trace:",
   238  					" [<ffffffff817199c4>] dump_stack+0x45/0x56",
   239  					" [<ffffffff817142ff>] dump_header+0x7f/0x1f1",
   240  					" [<ffffffff8115196e>] oom_kill_process+0x1ce/0x330",
   241  					" [<ffffffff812d3395>] ? security_capable_noaudit+0x15/0x20",
   242  					" [<ffffffff811520a4>] out_of_memory+0x414/0x450",
   243  					" [<ffffffff81158377>] __alloc_pages_nodemask+0xa87/0xb20",
   244  					" [<ffffffff811985da>] alloc_pages_vma+0x9a/0x140",
   245  					" [<ffffffff8117909b>] handle_mm_fault+0xb2b/0xf10",
   246  					" [<ffffffff81725924>] __do_page_fault+0x184/0x560",
   247  					" [<ffffffff8101b7d9>] ? sched_clock+0x9/0x10",
   248  					" [<ffffffff8109d13d>] ? sched_clock_local+0x1d/0x80",
   249  					" [<ffffffff811112ec>] ? acct_account_cputime+0x1c/0x20",
   250  					" [<ffffffff8109d76b>] ? account_user_time+0x8b/0xa0",
   251  					" [<ffffffff8109dd84>] ? vtime_account_user+0x54/0x60",
   252  					" [<ffffffff81725d1a>] do_page_fault+0x1a/0x70",
   253  					" [<ffffffff81722188>] page_fault+0x28/0x30",
   254  					"Mem-Info:",
   255  					"Node 0 DMA per-cpu:",
   256  					"CPU    0: hi:    0, btch:   1 usd:   0",
   257  					"Node 0 DMA32 per-cpu:",
   258  					"CPU    0: hi:  186, btch:  31 usd:  86",
   259  					"active_anon:405991 inactive_anon:57 isolated_anon:0",
   260  					" active_file:35 inactive_file:69 isolated_file:0",
   261  					" unevictable:0 dirty:0 writeback:0 unstable:0",
   262  					" free:12929 slab_reclaimable:1635 slab_unreclaimable:1919",
   263  					" mapped:34 shmem:70 pagetables:1423 bounce:0",
   264  					" free_cma:0",
   265  					"Node 0 DMA free:7124kB min:412kB low:512kB high:616kB active_anon:8508kB inactive_anon:4kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:4kB slab_reclaimable:16kB slab_unreclaimable:16kB kernel_stack:0kB pagetables:12kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes",
   266  					"lowmem_reserve[]: 0 1679 1679 1679",
   267  					"Node 0 DMA32 free:44592kB min:44640kB low:55800kB high:66960kB active_anon:1615456kB inactive_anon:224kB active_file:140kB inactive_file:276kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1765368kB managed:1722912kB mlocked:0kB dirty:0kB writeback:0kB mapped:136kB shmem:276kB slab_reclaimable:6524kB slab_unreclaimable:7660kB kernel_stack:592kB pagetables:5680kB unstable:0kB bounce:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:819 all_unreclaimable? yes",
   268  					"lowmem_reserve[]: 0 0 0 0",
   269  					"Node 0 DMA: 5*4kB (UM) 6*8kB (UEM) 7*16kB (UEM) 1*32kB (M) 2*64kB (UE) 3*128kB (UEM) 1*256kB (E) 2*512kB (EM) 3*1024kB (UEM) 1*2048kB (R) 0*4096kB = 7124kB",
   270  					"Node 0 DMA32: 74*4kB (UEM) 125*8kB (UEM) 78*16kB (UEM) 26*32kB (UE) 12*64kB (UEM) 4*128kB (UE) 4*256kB (UE) 2*512kB (E) 11*1024kB (UE) 7*2048kB (UE) 3*4096kB (UR) = 44592kB",
   271  					"Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB",
   272  					"204 total pagecache pages",
   273  					"0 pages in swap cache",
   274  					"Swap cache stats: add 0, delete 0, find 0/0",
   275  					"Free swap  = 0kB",
   276  					"Total swap = 0kB",
   277  					"445340 pages RAM",
   278  					"0 pages HighMem/MovableOnly",
   279  					"10614 pages reserved",
   280  					"[ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name",
   281  					"[  273]     0   273     4869       50      13        0             0 upstart-udev-br",
   282  					"[  293]     0   293    12802      154      28        0         -1000 systemd-udevd",
   283  					"[  321]     0   321     3819       54      12        0             0 upstart-file-br",
   284  					"[  326]   102   326     9805      109      24        0             0 dbus-daemon",
   285  					"[  334]   101   334    63960       94      26        0             0 rsyslogd",
   286  					"[  343]     0   343    10863      102      26        0             0 systemd-logind",
   287  					"[  546]     0   546     3815       60      13        0             0 upstart-socket-",
   288  					"[  710]     0   710     2556      587       8        0             0 dhclient",
   289  					"[  863]     0   863     3955       48      13        0             0 getty",
   290  					"[  865]     0   865     3955       50      13        0             0 getty",
   291  					"[  867]     0   867     3955       51      13        0             0 getty",
   292  					"[  868]     0   868     3955       51      12        0             0 getty",
   293  					"[  870]     0   870     3955       49      13        0             0 getty",
   294  					"[  915]     0   915     5914       61      16        0             0 cron",
   295  					"[ 1015]     0  1015    10885     1524      25        0             0 manage_addresse",
   296  					"[ 1028]     0  1028     3955       49      13        0             0 getty",
   297  					"[ 1033]     0  1033     3197       48      12        0             0 getty",
   298  					"[ 1264]     0  1264    11031     1635      26        0             0 manage_accounts",
   299  					"[ 1268]     0  1268    15341      180      33        0         -1000 sshd",
   300  					"[ 1313]   104  1313     6804      154      17        0             0 ntpd",
   301  					"[ 1389]     0  1389    25889      255      55        0             0 sshd",
   302  					"[ 1407]  1020  1407    25889      255      52        0             0 sshd",
   303  					"[ 1408]  1020  1408     5711      581      17        0             0 bash",
   304  					"[ 1425]     0  1425    25889      256      53        0             0 sshd",
   305  					"[ 1443]  1020  1443    25889      257      52        0             0 sshd",
   306  					"[ 1444]  1020  1444     5711      581      16        0             0 bash",
   307  					"[ 1476]  1020  1476     1809       25       9        0             0 tail",
   308  					"[ 1532]  1020  1532   410347   398810     788        0             0 badsysprogram",
   309  					"Out of memory: Kill process 1532 (badsysprogram) score 919 or sacrifice child",
   310  					"Killed process 1532 (badsysprogram) total-vm:1641388kB, anon-rss:1595164kB, file-rss:76kB",
   311  				},
   312  			}},
   313  			out: []*OomInstance{{
   314  				Pid:                 1532,
   315  				ProcessName:         "badsysprogram",
   316  				TimeOfDeath:         testTime,
   317  				ContainerName:       "/",
   318  				VictimContainerName: "/",
   319  			}},
   320  		},
   321  		{ // Multiple OOMs
   322  			// These were generated via `docker run -m 20M euank/gunpowder-memhog 2G; docker run -m 300M euank/gunpowder-memhog 800M`
   323  			// followed by nabbing output from `/dev/kmsg` and stripping the syslog-ish prefixes `kmsgparser` will handle anyways.
   324  			in: []in{
   325  				{
   326  					time: testTime,
   327  					msgs: []string{
   328  						"docker0: port 2(veth380a1cd) entered disabled state",
   329  						"device veth380a1cd left promiscuous mode",
   330  						"docker0: port 2(veth380a1cd) entered disabled state",
   331  						"docker0: port 2(vethcd0dbfb) entered blocking state",
   332  						"docker0: port 2(vethcd0dbfb) entered disabled state",
   333  						"device vethcd0dbfb entered promiscuous mode",
   334  						"IPv6: ADDRCONF(NETDEV_UP): vethcd0dbfb: link is not ready",
   335  						"IPv6: ADDRCONF(NETDEV_CHANGE): vethcd0dbfb: link becomes ready",
   336  						"docker0: port 2(vethcd0dbfb) entered blocking state",
   337  						"docker0: port 2(vethcd0dbfb) entered forwarding state",
   338  						"docker0: port 2(vethcd0dbfb) entered disabled state",
   339  						"eth0: renamed from vethbcd01c4",
   340  						"docker0: port 2(vethcd0dbfb) entered blocking state",
   341  						"docker0: port 2(vethcd0dbfb) entered forwarding state",
   342  						"gunpowder-memho invoked oom-killer: gfp_mask=0x24000c0(GFP_KERNEL), order=0, oom_score_adj=0",
   343  						"gunpowder-memho cpuset=2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50 mems_allowed=0",
   344  						"CPU: 0 PID: 1381 Comm: gunpowder-memho Tainted: G           O    4.8.0-gentoo #2",
   345  						"Hardware name: LENOVO 20BSCTO1WW/20BSCTO1WW, BIOS N14ET32W (1.10 ) 08/13/2015",
   346  						" 0000000000000000 ffff8800968e3ca0 ffffffff8137ad47 ffff8800968e3d68",
   347  						" ffff8800b74ee540 ffff8800968e3d00 ffffffff811261dd 0000000000000003",
   348  						" 0000000000000000 0000000000000001 0000000000000246 0000000000000202",
   349  						"Call Trace:",
   350  						" [<ffffffff8137ad47>] dump_stack+0x4d/0x63",
   351  						" [<ffffffff811261dd>] dump_header+0x58/0x1c8",
   352  						" [<ffffffff810e85fe>] oom_kill_process+0x7e/0x362",
   353  						" [<ffffffff811221a8>] ? mem_cgroup_iter+0x109/0x23e",
   354  						" [<ffffffff811239dc>] mem_cgroup_out_of_memory+0x241/0x299",
   355  						" [<ffffffff81124447>] mem_cgroup_oom_synchronize+0x273/0x28c",
   356  						" [<ffffffff81120839>] ? __mem_cgroup_insert_exceeded+0x76/0x76",
   357  						" [<ffffffff810e8b46>] pagefault_out_of_memory+0x1f/0x76",
   358  						" [<ffffffff81038f38>] mm_fault_error+0x56/0x108",
   359  						" [<ffffffff81039355>] __do_page_fault+0x36b/0x3ee",
   360  						" [<ffffffff81039405>] do_page_fault+0xc/0xe",
   361  						" [<ffffffff81560082>] page_fault+0x22/0x30",
   362  						"Task in /docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50 killed as a result of limit of /docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50",
   363  						"memory: usage 20480kB, limit 20480kB, failcnt 1204",
   364  						"memory+swap: usage 40940kB, limit 40960kB, failcnt 6",
   365  						"kmem: usage 220kB, limit 9007199254740988kB, failcnt 0",
   366  						"Memory cgroup stats for /docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50: cache:0KB rss:20260KB rss_huge:0KB mapped_file:0KB dirty:0KB writeback:1016KB swap:20460KB inactive_anon:10232KB active_anon:10028KB inactive_file:0KB active_file:0KB unevictable:0KB",
   367  						"[ pid ]   uid  tgid total_vm      rss nr_ptes nr_pmds swapents oom_score_adj name",
   368  						"[ 1381]     0  1381   530382     5191      34       4     5489             0 gunpowder-memho",
   369  						"Memory cgroup out of memory: Kill process 1381 (gunpowder-memho) score 1046 or sacrifice child",
   370  						"Killed process 1381 (gunpowder-memho) total-vm:2121528kB, anon-rss:18624kB, file-rss:2140kB, shmem-rss:0kB",
   371  						"oom_reaper: reaped process 1381 (gunpowder-memho), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB",
   372  						"docker0: port 2(vethcd0dbfb) entered disabled state",
   373  						"vethbcd01c4: renamed from eth0",
   374  						"docker0: port 2(vethcd0dbfb) entered disabled state",
   375  						"device vethcd0dbfb left promiscuous mode",
   376  						"docker0: port 2(vethcd0dbfb) entered disabled state",
   377  						"docker0: port 2(veth4cb51e1) entered blocking state",
   378  						"docker0: port 2(veth4cb51e1) entered disabled state",
   379  						"device veth4cb51e1 entered promiscuous mode",
   380  					},
   381  				},
   382  				{
   383  					time: testTime2,
   384  					msgs: []string{
   385  						"IPv6: ADDRCONF(NETDEV_UP): veth4cb51e1: link is not ready",
   386  						"docker0: port 2(veth4cb51e1) entered blocking state",
   387  						"docker0: port 2(veth4cb51e1) entered forwarding state",
   388  						"IPv6: ADDRCONF(NETDEV_CHANGE): veth4cb51e1: link becomes ready",
   389  						"docker0: port 2(veth4cb51e1) entered disabled state",
   390  						"eth0: renamed from veth4b89c12",
   391  						"docker0: port 2(veth4cb51e1) entered blocking state",
   392  						"docker0: port 2(veth4cb51e1) entered forwarding state",
   393  						"gunpowder-memho invoked oom-killer: gfp_mask=0x24000c0(GFP_KERNEL), order=0, oom_score_adj=0",
   394  						"gunpowder-memho cpuset=6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70 mems_allowed=0",
   395  						"CPU: 0 PID: 1667 Comm: gunpowder-memho Tainted: G           O    4.8.0-gentoo #2",
   396  						"Hardware name: LENOVO 20BSCTO1WW/20BSCTO1WW, BIOS N14ET32W (1.10 ) 08/13/2015",
   397  						" 0000000000000000 ffff88008137fca0 ffffffff8137ad47 ffff88008137fd68",
   398  						" ffff8801c75b0c40 ffff88008137fd00 ffffffff811261dd 0000000000000003",
   399  						" 0000000000000000 0000000000000001 0000000000000246 0000000000000202",
   400  						"Call Trace:",
   401  						" [<ffffffff8137ad47>] dump_stack+0x4d/0x63",
   402  						" [<ffffffff811261dd>] dump_header+0x58/0x1c8",
   403  						" [<ffffffff810e85fe>] oom_kill_process+0x7e/0x362",
   404  						" [<ffffffff811221a8>] ? mem_cgroup_iter+0x109/0x23e",
   405  						" [<ffffffff811239dc>] mem_cgroup_out_of_memory+0x241/0x299",
   406  						" [<ffffffff81124447>] mem_cgroup_oom_synchronize+0x273/0x28c",
   407  						" [<ffffffff81120839>] ? __mem_cgroup_insert_exceeded+0x76/0x76",
   408  						" [<ffffffff810e8b46>] pagefault_out_of_memory+0x1f/0x76",
   409  						" [<ffffffff81038f38>] mm_fault_error+0x56/0x108",
   410  						" [<ffffffff81039355>] __do_page_fault+0x36b/0x3ee",
   411  						" [<ffffffff81039405>] do_page_fault+0xc/0xe",
   412  						" [<ffffffff81560082>] page_fault+0x22/0x30",
   413  						"Task in /docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70 killed as a result of limit of /docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70",
   414  						"memory: usage 307112kB, limit 307200kB, failcnt 35982",
   415  						"memory+swap: usage 614400kB, limit 614400kB, failcnt 11",
   416  						"kmem: usage 1308kB, limit 9007199254740988kB, failcnt 0",
   417  						"Memory cgroup stats for /docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70: cache:0KB rss:305804KB rss_huge:0KB mapped_file:0KB dirty:0KB writeback:55884KB swap:307288KB inactive_anon:152940KB active_anon:152832KB inactive_file:0KB active_file:0KB unevictable:0KB",
   418  						"[ pid ]   uid  tgid total_vm      rss nr_ptes nr_pmds swapents oom_score_adj name",
   419  						"[ 1667]     0  1667   210894    62557     315       4    91187             0 gunpowder-memho",
   420  						"Memory cgroup out of memory: Kill process 1667 (gunpowder-memho) score 1003 or sacrifice child",
   421  						"Killed process 1667 (gunpowder-memho) total-vm:843576kB, anon-rss:248180kB, file-rss:2048kB, shmem-rss:0kB",
   422  						"oom_reaper: reaped process 1667 (gunpowder-memho), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB",
   423  						"docker0: port 2(veth4cb51e1) entered disabled state",
   424  						"veth4b89c12: renamed from eth0",
   425  						"docker0: port 2(veth4cb51e1) entered blocking state",
   426  						"docker0: port 2(veth4cb51e1) entered forwarding state",
   427  						"docker0: port 2(veth4cb51e1) entered disabled state",
   428  						"device veth4cb51e1 left promiscuous mode",
   429  						"docker0: port 2(veth4cb51e1) entered disabled state",
   430  					},
   431  				},
   432  			},
   433  			out: []*OomInstance{
   434  				{
   435  					Pid:                 1381,
   436  					ProcessName:         "gunpowder-memho",
   437  					TimeOfDeath:         testTime,
   438  					ContainerName:       "/docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50",
   439  					VictimContainerName: "/docker/2e088fe462e25e60be1dafafe2c05c47bda1a97978648d10ad2b7484fc0b8f50",
   440  				},
   441  				{
   442  					Pid:                 1667,
   443  					ProcessName:         "gunpowder-memho",
   444  					TimeOfDeath:         testTime2,
   445  					ContainerName:       "/docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70",
   446  					VictimContainerName: "/docker/6c6fcab8562fd3150854986b78552c732f234fd405b624207b8843528a145e70",
   447  				},
   448  			},
   449  		},
   450  	}
   451  
   452  	for _, pair := range testPairs {
   453  		pair := pair
   454  		go func() {
   455  			for _, x := range pair.in {
   456  				writeAll(x.msgs, x.time)
   457  			}
   458  		}()
   459  		for _, expected := range pair.out {
   460  			oom := <-oomsOut
   461  			assert.Equal(t, expected, oom)
   462  		}
   463  
   464  		select {
   465  		case oom := <-oomsOut:
   466  			t.Errorf("did not expect any remaining OOMs, got %+v", oom)
   467  		default:
   468  		}
   469  
   470  	}
   471  }
   472  
   473  type mockKmsgParser struct {
   474  	messages chan kmsgparser.Message
   475  }
   476  
   477  func (m *mockKmsgParser) SeekEnd() error {
   478  	return nil
   479  }
   480  
   481  func (m *mockKmsgParser) Parse() <-chan kmsgparser.Message {
   482  	return m.messages
   483  }
   484  
   485  func (m *mockKmsgParser) SetLogger(kmsgparser.Logger) {}
   486  func (m *mockKmsgParser) Close() error {
   487  	close(m.messages)
   488  	return nil
   489  }