blob: 36423f3ac64ad94e2f306aea2e2a4f9b787ca7f7 [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Lorenz Brunf8da2e72022-06-14 12:39:32 +02004package pstore
5
6import (
7 "fmt"
8 "testing"
9 "testing/fstest"
10 "time"
11)
12
13func TestParseHeader(t *testing.T) {
14 var cases = []struct {
15 input string
16 expectedOut *pstoreDmesgHeader
17 }{
18 {"Panic#2 Part30", &pstoreDmesgHeader{"Panic", 2, 30}},
19 {"Oops#1 Part5", &pstoreDmesgHeader{"Oops", 1, 5}},
20 // Random kernel output that is similar, but definitely not a dump header
21 {"<4>[2501503.489317] Oops: 0010 [#1] SMP NOPTI", nil},
22 }
23 for i, c := range cases {
24 t.Run(fmt.Sprintf("Test#%d", i+1), func(t *testing.T) {
25 out, err := parseDmesgHeader(c.input)
26 switch {
27 case err != nil && c.expectedOut != nil:
28 t.Errorf("Failed parsing %q: %v", c.input, err)
29 case err == nil && c.expectedOut == nil:
30 t.Errorf("Successfully parsed %q, expected error", c.input)
31 case err != nil && c.expectedOut == nil:
32 case err == nil && c.expectedOut != nil:
33 if out.Part != c.expectedOut.Part {
34 t.Errorf("Expected part to be %d, got %d", c.expectedOut.Part, out.Part)
35 }
36 if out.Counter != c.expectedOut.Counter {
37 t.Errorf("Expected counter to be %d, got %d", c.expectedOut.Counter, out.Counter)
38 }
39 if out.Reason != c.expectedOut.Reason {
40 t.Errorf("Expected reason to be %q, got %q", c.expectedOut.Reason, out.Reason)
41 }
42 }
43 })
44 }
45}
46
47func TestGetKmsgDumps(t *testing.T) {
48 testTime1 := time.Date(2022, 06, 13, 1, 2, 3, 4, time.UTC)
49 testTime2 := time.Date(2020, 06, 13, 1, 2, 3, 4, time.UTC)
50 testTime3 := time.Date(2010, 06, 13, 1, 2, 3, 4, time.UTC)
51 cases := []struct {
52 name string
53 inputFS fstest.MapFS
54 expectErr bool
55 expectedDumps []KmsgDump
56 }{
57 {"EmptyPstore", map[string]*fstest.MapFile{}, false, []KmsgDump{}},
58 {"SingleDumpSingleFile", map[string]*fstest.MapFile{
59 "dmesg-efi-165467917816002": {ModTime: testTime1, Data: []byte("Panic#2 Part1\ntest1\ntest2")},
60 "yolo-efi-165467917816002": {ModTime: testTime1, Data: []byte("something totally unrelated")},
61 }, false, []KmsgDump{{
62 Reason: "Panic",
63 OccurredAt: testTime1,
64 Counter: 2,
65 Lines: []string{
66 "test1",
67 "test2",
68 },
69 }}},
70 {"SingleDumpMultipleFiles", map[string]*fstest.MapFile{
71 "dmesg-efi-165467917816002": {ModTime: testTime1, Data: []byte("Panic#2 Part1\ntest2\ntest3")},
72 "dmesg-efi-165467917817002": {ModTime: testTime2, Data: []byte("Panic#2 Part2\ntest1")},
73 }, false, []KmsgDump{{
74 Reason: "Panic",
75 OccurredAt: testTime1,
76 Counter: 2,
77 Lines: []string{
78 "test1",
79 "test2",
80 "test3",
81 },
82 }}},
83 {"MultipleDumpsMultipleFiles", map[string]*fstest.MapFile{
84 "dmesg-efi-165467917816002": {ModTime: testTime1, Data: []byte("Panic#2 Part1\ntest2\ntest3")},
85 "dmesg-efi-165467917817002": {ModTime: testTime2, Data: []byte("Panic#2 Part2\ntest1")},
86 "dmesg-efi-265467917816002": {ModTime: testTime3, Data: []byte("Oops#1 Part1\noops3")},
87 "dmesg-efi-265467917817002": {ModTime: testTime2, Data: []byte("Oops#1 Part2\noops1\noops2")},
88 }, false, []KmsgDump{{
89 Reason: "Panic",
90 OccurredAt: testTime1,
91 Counter: 2,
92 Lines: []string{
93 "test1",
94 "test2",
95 "test3",
96 },
97 }, {
98 Reason: "Oops",
99 OccurredAt: testTime3,
100 Counter: 1,
101 Lines: []string{
102 "oops1",
103 "oops2",
104 "oops3",
105 },
106 }}},
107 }
108 for _, c := range cases {
109 t.Run(c.name, func(t *testing.T) {
110 dumps, err := getKmsgDumpsFromFS(c.inputFS)
111 switch {
112 case err == nil && c.expectErr:
Tim Windelschmidtd0d5d9d2025-03-26 22:07:11 +0100113 t.Fatal("Expected error, but got none")
Lorenz Brunf8da2e72022-06-14 12:39:32 +0200114 return
115 case err != nil && !c.expectErr:
Tim Windelschmidtd0d5d9d2025-03-26 22:07:11 +0100116 t.Fatalf("Got unexpected error: %v", err)
Lorenz Brunf8da2e72022-06-14 12:39:32 +0200117 return
118 case err != nil && c.expectErr:
119 // Got expected error
120 return
121 case err == nil && !c.expectErr:
122 if len(dumps) != len(c.expectedDumps) {
123 t.Fatalf("Expected %d dumps, got %d", len(c.expectedDumps), len(dumps))
124 }
125 for i, dump := range dumps {
126 if dump.OccurredAt != c.expectedDumps[i].OccurredAt {
127 t.Errorf("Dump %d expected to have occurred at %v, got %v", i, c.expectedDumps[i].OccurredAt, dump.OccurredAt)
128 }
129 if dump.Reason != c.expectedDumps[i].Reason {
130 t.Errorf("Expected reason in dump %d to be %v, got %v", i, c.expectedDumps[i].Reason, dump.Reason)
131 }
132 if dump.Counter != c.expectedDumps[i].Counter {
133 t.Errorf("Expected counter in dump %d to be %d, got %d", i, c.expectedDumps[i].Counter, dump.Counter)
134 }
135 if len(dump.Lines) != len(c.expectedDumps[i].Lines) {
136 t.Errorf("Expected number of lines in dump %d to be %d, got %d", i, len(c.expectedDumps[i].Lines), len(dump.Lines))
137 }
138 for j := range dump.Lines {
139 if dump.Lines[j] != c.expectedDumps[i].Lines[j] {
140 t.Errorf("Expected line %d in dump %d to be %q, got %q", i, j, c.expectedDumps[i].Lines[j], dump.Lines[j])
141 }
142 }
143 }
144 }
145 })
146 }
147}