// SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s package model1_test import ( "testing" "time" "github.com/derailed/k9s/internal/model1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRowEventCustomize(t *testing.T) { uu := map[string]struct { re1, e model1.RowEvent cols []int }{ "empty": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{}}, }, }, "full": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, cols: []int{0, 1, 2}, }, "deltas": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, Deltas: model1.DeltaRow{"a", "b", "c"}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, Deltas: model1.DeltaRow{"a", "b", "c"}, }, cols: []int{0, 1, 2}, }, "deltas-skip": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, Deltas: model1.DeltaRow{"a", "b", "c"}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"3", "1"}}, Deltas: model1.DeltaRow{"c", "a"}, }, cols: []int{2, 0}, }, "reverse": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"3", "2", "1"}}, }, cols: []int{2, 1, 0}, }, "skip": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"3", "1"}}, }, cols: []int{2, 0}, }, "miss": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, e: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"3", "", "1"}}, }, cols: []int{2, 10, 0}, }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { assert.Equal(t, u.e, u.re1.Customize(u.cols)) }) } } func TestRowEventDiff(t *testing.T) { uu := map[string]struct { re1, re2 model1.RowEvent e bool }{ "same": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, re2: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, }, "diff-kind": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, re2: model1.RowEvent{ Kind: model1.EventDelete, Row: model1.Row{ID: "B", Fields: model1.Fields{"1", "2", "3"}}, }, e: true, }, "diff-delta": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, Deltas: model1.DeltaRow{"1", "2", "3"}, }, re2: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, Deltas: model1.DeltaRow{"10", "2", "3"}, }, e: true, }, "diff-id": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, re2: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "B", Fields: model1.Fields{"1", "2", "3"}}, }, e: true, }, "diff-field": { re1: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}, }, re2: model1.RowEvent{ Kind: model1.EventAdd, Row: model1.Row{ID: "A", Fields: model1.Fields{"10", "2", "3"}}, }, e: true, }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { assert.Equal(t, u.e, u.re1.Diff(u.re2, -1)) }) } } func TestRowEventsDiff(t *testing.T) { uu := map[string]struct { re1, re2 *model1.RowEvents ageCol int e bool }{ "same": { re1: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), re2: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), ageCol: -1, }, "diff-len": { re1: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), re2: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), ageCol: -1, e: true, }, "diff-id": { re1: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), re2: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "D", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), ageCol: -1, e: true, }, "diff-order": { re1: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), re2: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), ageCol: -1, e: true, }, "diff-withAge": { re1: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), re2: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "13"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), ageCol: 1, e: true, }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { assert.Equal(t, u.e, u.re1.Diff(u.re2, u.ageCol)) }) } } func TestRowEventsUpsert(t *testing.T) { uu := map[string]struct { ee, e *model1.RowEvents re model1.RowEvent }{ "add": { ee: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), re: model1.RowEvent{ Row: model1.Row{ID: "D", Fields: model1.Fields{"f1", "f2", "f3"}}, }, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "D", Fields: model1.Fields{"f1", "f2", "f3"}}}, ), }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { u.ee.Upsert(u.re) assert.Equal(t, u.e, u.ee) }) } } func TestRowEventsCustomize(t *testing.T) { uu := map[string]struct { re, e *model1.RowEvents cols []int }{ "same": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), cols: []int{0, 1, 2}, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), }, "reverse": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), cols: []int{2, 1, 0}, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"3", "2", "1"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"3", "2", "0"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"3", "2", "10"}}}, ), }, "skip": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), cols: []int{1, 0}, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"2", "1"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"2", "0"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"2", "10"}}}, ), }, "missing": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), cols: []int{1, 0, 4}, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"2", "1", ""}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"2", "0", ""}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"2", "10", ""}}}, ), }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { assert.Equal(t, u.e, u.re.Customize(u.cols)) }) } } func TestRowEventsDelete(t *testing.T) { uu := map[string]struct { re, e *model1.RowEvents id string }{ "first": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), id: "A", e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), }, "middle": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), id: "B", e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), }, "last": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), id: "C", e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, ), }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { require.NoError(t, u.re.Delete(u.id)) assert.Equal(t, u.e, u.re) }) } } func TestRowEventsSort(t *testing.T) { uu := map[string]struct { re, e *model1.RowEvents col int duration, num, asc bool capacity bool }{ "age_time": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", testTime().Add(20 * time.Second).String()}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", testTime().Add(10 * time.Second).String()}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", testTime().String()}}}, ), col: 2, asc: true, duration: true, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", testTime().String()}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", testTime().Add(10 * time.Second).String()}}}, model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", testTime().Add(20 * time.Second).String()}}}, ), }, "col0": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), col: 0, asc: true, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "B", Fields: model1.Fields{"0", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "A", Fields: model1.Fields{"1", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "C", Fields: model1.Fields{"10", "2", "3"}}}, ), }, "id_preserve": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "ns1/B", Fields: model1.Fields{"B", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/A", Fields: model1.Fields{"A", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/C", Fields: model1.Fields{"C", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/B", Fields: model1.Fields{"B", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/A", Fields: model1.Fields{"A", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/C", Fields: model1.Fields{"C", "2", "3"}}}, ), col: 1, asc: true, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "ns1/A", Fields: model1.Fields{"A", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/B", Fields: model1.Fields{"B", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/C", Fields: model1.Fields{"C", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/A", Fields: model1.Fields{"A", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/B", Fields: model1.Fields{"B", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/C", Fields: model1.Fields{"C", "2", "3"}}}, ), }, "capacity": { re: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "ns1/B", Fields: model1.Fields{"B", "2", "3", "1Gi"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/A", Fields: model1.Fields{"A", "2", "3", "1.1G"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/C", Fields: model1.Fields{"C", "2", "3", "0.5Ti"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/B", Fields: model1.Fields{"B", "2", "3", "12e6"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/A", Fields: model1.Fields{"A", "2", "3", "1234"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/C", Fields: model1.Fields{"C", "2", "3", "0.1Ei"}}}, ), col: 3, asc: true, capacity: true, e: model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "ns2/A", Fields: model1.Fields{"A", "2", "3", "1234"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/B", Fields: model1.Fields{"B", "2", "3", "12e6"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/B", Fields: model1.Fields{"B", "2", "3", "1Gi"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/A", Fields: model1.Fields{"A", "2", "3", "1.1G"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/C", Fields: model1.Fields{"C", "2", "3", "0.5Ti"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/C", Fields: model1.Fields{"C", "2", "3", "0.1Ei"}}}, ), }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { u.re.Sort("", u.col, u.duration, u.num, u.capacity, u.asc) assert.Equal(t, u.e, u.re) }) } } func TestRowEventsClone(t *testing.T) { uu := map[string]struct { r *model1.RowEvents }{ "empty": { r: model1.NewRowEventsWithEvts(), }, "full": { r: makeRowEvents(), }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { c := u.r.Clone() assert.Equal(t, u.r.Len(), c.Len()) if !u.r.Empty() { r, ok := u.r.At(0) assert.True(t, ok) r.Row.Fields[0] = "blee" cr, ok := c.At(0) assert.True(t, ok) assert.Equal(t, "A", cr.Row.Fields[0]) } }) } } // Helpers... func makeRowEvents() *model1.RowEvents { return model1.NewRowEventsWithEvts( model1.RowEvent{Row: model1.Row{ID: "ns1/A", Fields: model1.Fields{"A", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/B", Fields: model1.Fields{"B", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns1/C", Fields: model1.Fields{"C", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/A", Fields: model1.Fields{"A", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/B", Fields: model1.Fields{"B", "2", "3"}}}, model1.RowEvent{Row: model1.Row{ID: "ns2/C", Fields: model1.Fields{"C", "2", "3"}}}, ) }