314 lines
7.1 KiB
Go
314 lines
7.1 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright Authors of K9s
|
|
|
|
package model_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/derailed/k9s/internal/client"
|
|
"github.com/derailed/k9s/internal/dao"
|
|
"github.com/derailed/k9s/internal/model"
|
|
"github.com/derailed/k9s/internal/watch"
|
|
"github.com/stretchr/testify/assert"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/client-go/informers"
|
|
)
|
|
|
|
func init() {
|
|
slog.SetDefault(slog.New(slog.DiscardHandler))
|
|
}
|
|
|
|
func TestLogFullBuffer(t *testing.T) {
|
|
size := 4
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(size), 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
|
|
data := dao.NewLogItems()
|
|
for i := range 2 * size {
|
|
data.Add(dao.NewLogItemFromString("line" + strconv.Itoa(i)))
|
|
m.Append(data.Items()[i])
|
|
}
|
|
m.Notify()
|
|
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
assert.Equal(t, 0, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
}
|
|
|
|
func TestLogFilter(t *testing.T) {
|
|
uu := map[string]struct {
|
|
q string
|
|
e int
|
|
}{
|
|
"plain": {
|
|
q: "line-1",
|
|
e: 2,
|
|
},
|
|
"regexp": {
|
|
q: `pod-line-[1-3]{1}`,
|
|
e: 4,
|
|
},
|
|
"invert": {
|
|
q: `!pod-line-1`,
|
|
e: 8,
|
|
},
|
|
"fuzzy": {
|
|
q: `-f po-l1`,
|
|
e: 2,
|
|
},
|
|
}
|
|
|
|
size := 10
|
|
for k := range uu {
|
|
u := uu[k]
|
|
t.Run(k, func(t *testing.T) {
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(size), 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
|
|
m.Filter(u.q)
|
|
data := dao.NewLogItems()
|
|
for i := range size {
|
|
data.Add(dao.NewLogItemFromString(fmt.Sprintf("pod-line-%d", i+1)))
|
|
m.Append(data.Items()[i])
|
|
}
|
|
|
|
m.Notify()
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
assert.Equal(t, 1, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
assert.Len(t, v.data, u.e)
|
|
|
|
m.ClearFilter()
|
|
assert.Equal(t, 2, v.dataCalled)
|
|
assert.Equal(t, 2, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
assert.Len(t, v.data, size)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLogStartStop(t *testing.T) {
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
m.Start(ctx)
|
|
data := dao.NewLogItems()
|
|
data.Add(dao.NewLogItemFromString("line1"), dao.NewLogItemFromString("line2"))
|
|
for _, d := range data.Items() {
|
|
m.Append(d)
|
|
}
|
|
m.Notify()
|
|
m.Stop()
|
|
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
assert.Equal(t, 0, v.clearCalled)
|
|
assert.Equal(t, 1, v.errCalled)
|
|
assert.Len(t, v.data, 2)
|
|
}
|
|
|
|
func TestLogClear(t *testing.T) {
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
assert.Equal(t, "fred", m.GetPath())
|
|
assert.Equal(t, "blee", m.GetContainer())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
|
|
data := dao.NewLogItems()
|
|
data.Add(dao.NewLogItemFromString("line1"), dao.NewLogItemFromString("line2"))
|
|
for _, d := range data.Items() {
|
|
m.Append(d)
|
|
}
|
|
m.Notify()
|
|
m.Clear()
|
|
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
assert.Equal(t, 1, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
assert.Empty(t, v.data)
|
|
}
|
|
|
|
func TestLogBasic(t *testing.T) {
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(2), 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
|
|
data := dao.NewLogItems()
|
|
data.Add(dao.NewLogItemFromString("line1"), dao.NewLogItemFromString("line2"))
|
|
m.Set(data)
|
|
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
assert.Equal(t, 1, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
ll := make([][]byte, data.Len())
|
|
data.Lines(0, false, ll)
|
|
assert.Equal(t, ll, v.data)
|
|
}
|
|
|
|
func TestLogAppend(t *testing.T) {
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 5*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
items := dao.NewLogItems()
|
|
items.Add(dao.NewLogItemFromString("blah blah"))
|
|
m.Set(items)
|
|
ll := make([][]byte, items.Len())
|
|
items.Lines(0, false, ll)
|
|
assert.Equal(t, ll, v.data)
|
|
|
|
data := dao.NewLogItems()
|
|
data.Add(
|
|
dao.NewLogItemFromString("line1"),
|
|
dao.NewLogItemFromString("line2"),
|
|
)
|
|
for _, d := range data.Items() {
|
|
m.Append(d)
|
|
}
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
ll = make([][]byte, items.Len())
|
|
items.Lines(0, false, ll)
|
|
assert.Equal(t, ll, v.data)
|
|
|
|
m.Notify()
|
|
assert.Equal(t, 2, v.dataCalled)
|
|
assert.Equal(t, 1, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
}
|
|
|
|
func TestLogTimedout(t *testing.T) {
|
|
m := model.NewLog(client.NewGVR("fred"), makeLogOpts(4), 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
|
|
v := newTestView()
|
|
m.AddListener(v)
|
|
|
|
m.Filter("line1")
|
|
data := dao.NewLogItems()
|
|
data.Add(
|
|
dao.NewLogItemFromString("line1"),
|
|
dao.NewLogItemFromString("line2"),
|
|
dao.NewLogItemFromString("line3"),
|
|
dao.NewLogItemFromString("line4"),
|
|
)
|
|
for _, d := range data.Items() {
|
|
m.Append(d)
|
|
}
|
|
m.Notify()
|
|
assert.Equal(t, 1, v.dataCalled)
|
|
assert.Equal(t, 1, v.clearCalled)
|
|
assert.Equal(t, 0, v.errCalled)
|
|
const e = "\x1b[38;5;209ml\x1b[0m\x1b[38;5;209mi\x1b[0m\x1b[38;5;209mn\x1b[0m\x1b[38;5;209me\x1b[0m\x1b[38;5;209m1\x1b[0m"
|
|
assert.Equal(t, e, string(v.data[0]))
|
|
}
|
|
|
|
func TestToggleAllContainers(t *testing.T) {
|
|
opts := makeLogOpts(1)
|
|
opts.DefaultContainer = "duh"
|
|
m := model.NewLog(client.NewGVR(""), opts, 10*time.Millisecond)
|
|
m.Init(makeFactory())
|
|
assert.Equal(t, "blee", m.GetContainer())
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
m.ToggleAllContainers(ctx)
|
|
assert.Empty(t, m.GetContainer())
|
|
m.ToggleAllContainers(ctx)
|
|
assert.Equal(t, "blee", m.GetContainer())
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Helpers...
|
|
|
|
func makeLogOpts(count int) *dao.LogOptions {
|
|
return &dao.LogOptions{
|
|
Path: "fred",
|
|
Container: "blee",
|
|
Lines: int64(count),
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
type testView struct {
|
|
data [][]byte
|
|
dataCalled int
|
|
clearCalled int
|
|
errCalled int
|
|
}
|
|
|
|
func newTestView() *testView {
|
|
return &testView{}
|
|
}
|
|
|
|
func (*testView) LogCanceled() {}
|
|
func (*testView) LogStop() {}
|
|
func (*testView) LogResume() {}
|
|
|
|
func (t *testView) LogChanged(ll [][]byte) {
|
|
t.data = ll
|
|
t.dataCalled++
|
|
}
|
|
|
|
func (t *testView) LogCleared() {
|
|
t.clearCalled++
|
|
t.data = nil
|
|
}
|
|
|
|
func (t *testView) LogFailed(error) {
|
|
t.errCalled++
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
type testFactory struct{}
|
|
|
|
var _ dao.Factory = testFactory{}
|
|
|
|
func (testFactory) Client() client.Connection {
|
|
return nil
|
|
}
|
|
func (testFactory) Get(*client.GVR, string, bool, labels.Selector) (runtime.Object, error) {
|
|
return nil, nil
|
|
}
|
|
func (testFactory) List(*client.GVR, string, bool, labels.Selector) ([]runtime.Object, error) {
|
|
return nil, nil
|
|
}
|
|
func (testFactory) ForResource(string, *client.GVR) (informers.GenericInformer, error) {
|
|
return nil, nil
|
|
}
|
|
func (testFactory) CanForResource(string, *client.GVR, []string) (informers.GenericInformer, error) {
|
|
return nil, nil
|
|
}
|
|
func (testFactory) WaitForCacheSync() {}
|
|
func (testFactory) Forwarders() watch.Forwarders {
|
|
return nil
|
|
}
|
|
func (testFactory) DeleteForwarder(string) {}
|
|
|
|
func makeFactory() dao.Factory {
|
|
return testFactory{}
|
|
}
|