talos/internal/pkg/kmsg/reader_test.go
Andrey Smirnov 1fbf40796f feat: implement streaming mode of dmesg, parse messages
Fixes #1563

This implements dmesg reading via `/dev/kmsg`, with message parsing and
formatting. Kernel log facility and severity are parsed, timestamp is
calculated relative to boot time (it's accurate unless time jumps a
lot during node lifetime).

New flags to follow dmesg was added, tail flag allows to stream only new
message (ignoring old messages). We could try to implement tailing last
N messages, just a bit more work, open to suggestions (for symmetry with
regular logs).

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
2019-12-16 17:40:15 +03:00

100 lines
1.8 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package kmsg_test
import (
"context"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/talos-systems/talos/internal/pkg/kmsg"
)
func skipIfNoKmsg(t *testing.T) {
f, err := os.OpenFile("/dev/kmsg", os.O_RDONLY, 0)
if err != nil {
t.Skip("/dev/kmsg is not available", err.Error())
}
f.Close() //nolint: errcheck
}
func TestReaderNoFollow(t *testing.T) {
skipIfNoKmsg(t)
r, err := kmsg.NewReader()
assert.NoError(t, err)
defer r.Close() //nolint: errcheck
messageCount := 0
for packet := range r.Scan(context.Background()) {
assert.NoError(t, packet.Err)
messageCount++
}
assert.Greater(t, messageCount, 0)
assert.NoError(t, r.Close())
}
func TestReaderFollow(t *testing.T) {
testReaderFollow(t, true)
}
func TestReaderFollowTail(t *testing.T) {
testReaderFollow(t, false, kmsg.FromTail())
}
func testReaderFollow(t *testing.T, expectMessages bool, options ...kmsg.Option) {
skipIfNoKmsg(t)
r, err := kmsg.NewReader(append([]kmsg.Option{kmsg.Follow()}, options...)...)
assert.NoError(t, err)
defer r.Close() //nolint: errcheck
messageCount := 0
ctx, ctxCancel := context.WithCancel(context.Background())
defer ctxCancel()
ch := r.Scan(ctx)
var closed bool
LOOP:
for {
select {
case packet, ok := <-ch:
if !ok {
if !closed {
assert.Fail(t, "channel closed before cancel")
}
break LOOP
}
assert.NoError(t, packet.Err)
messageCount++
case <-time.After(100 * time.Millisecond):
// abort
closed = true
ctxCancel()
assert.NoError(t, r.Close())
}
}
if expectMessages {
assert.Greater(t, messageCount, 0)
}
}