mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-06-06 23:13:39 +00:00
7df161aee0
* Fix enter misbehaving. * Cleanup after previous tui implementation. * Fix race condition and improve logging * Add filtering of the namespaces by text input in the wizard UI
351 lines
7.9 KiB
Go
351 lines
7.9 KiB
Go
package ui
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/nvm/kportal/internal/k8s"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestFilterStrings(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
items []string
|
|
filter string
|
|
expected []string
|
|
}{
|
|
{
|
|
name: "empty filter returns all items",
|
|
items: []string{"namespace-1", "namespace-2", "namespace-3"},
|
|
filter: "",
|
|
expected: []string{"namespace-1", "namespace-2", "namespace-3"},
|
|
},
|
|
{
|
|
name: "filter matches multiple items",
|
|
items: []string{"prod-api", "prod-db", "staging-api", "dev-api"},
|
|
filter: "prod",
|
|
expected: []string{"prod-api", "prod-db"},
|
|
},
|
|
{
|
|
name: "filter matches single item",
|
|
items: []string{"namespace-1", "namespace-2", "namespace-3"},
|
|
filter: "2",
|
|
expected: []string{"namespace-2"},
|
|
},
|
|
{
|
|
name: "filter matches no items",
|
|
items: []string{"namespace-1", "namespace-2", "namespace-3"},
|
|
filter: "xyz",
|
|
expected: []string{},
|
|
},
|
|
{
|
|
name: "case insensitive matching",
|
|
items: []string{"Production", "Staging", "Development"},
|
|
filter: "prod",
|
|
expected: []string{"Production"},
|
|
},
|
|
{
|
|
name: "partial string matching",
|
|
items: []string{"my-app-frontend", "my-app-backend", "other-service"},
|
|
filter: "app",
|
|
expected: []string{"my-app-frontend", "my-app-backend"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := filterStrings(tt.items, tt.filter)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMatchesFilter(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
item string
|
|
filter string
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "empty filter matches everything",
|
|
item: "namespace-1",
|
|
filter: "",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "exact match",
|
|
item: "namespace-1",
|
|
filter: "namespace-1",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "partial match",
|
|
item: "production-api",
|
|
filter: "prod",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "no match",
|
|
item: "namespace-1",
|
|
filter: "xyz",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "case insensitive match",
|
|
item: "Production",
|
|
filter: "prod",
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := matchesFilter(tt.item, tt.filter)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetFilteredContexts(t *testing.T) {
|
|
wizard := &AddWizardState{
|
|
contexts: []string{"prod-cluster", "staging-cluster", "dev-cluster", "test-cluster"},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
filter string
|
|
expected []string
|
|
}{
|
|
{
|
|
name: "no filter returns all",
|
|
filter: "",
|
|
expected: []string{"prod-cluster", "staging-cluster", "dev-cluster", "test-cluster"},
|
|
},
|
|
{
|
|
name: "filter by 'prod'",
|
|
filter: "prod",
|
|
expected: []string{"prod-cluster"},
|
|
},
|
|
{
|
|
name: "filter by 'cluster'",
|
|
filter: "cluster",
|
|
expected: []string{"prod-cluster", "staging-cluster", "dev-cluster", "test-cluster"},
|
|
},
|
|
{
|
|
name: "filter by 'staging'",
|
|
filter: "staging",
|
|
expected: []string{"staging-cluster"},
|
|
},
|
|
{
|
|
name: "filter with no matches",
|
|
filter: "xyz",
|
|
expected: []string{},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
wizard.searchFilter = tt.filter
|
|
result := wizard.getFilteredContexts()
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetFilteredNamespaces(t *testing.T) {
|
|
wizard := &AddWizardState{
|
|
namespaces: []string{
|
|
"kube-system", "kube-public", "default",
|
|
"prod-api", "prod-db", "staging-api", "staging-db",
|
|
"monitoring", "logging",
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
filter string
|
|
expected []string
|
|
}{
|
|
{
|
|
name: "no filter returns all",
|
|
filter: "",
|
|
expected: []string{
|
|
"kube-system", "kube-public", "default",
|
|
"prod-api", "prod-db", "staging-api", "staging-db",
|
|
"monitoring", "logging",
|
|
},
|
|
},
|
|
{
|
|
name: "filter by 'prod'",
|
|
filter: "prod",
|
|
expected: []string{"prod-api", "prod-db"},
|
|
},
|
|
{
|
|
name: "filter by 'kube'",
|
|
filter: "kube",
|
|
expected: []string{"kube-system", "kube-public"},
|
|
},
|
|
{
|
|
name: "filter by 'api'",
|
|
filter: "api",
|
|
expected: []string{"prod-api", "staging-api"},
|
|
},
|
|
{
|
|
name: "filter by 'ing' (partial match)",
|
|
filter: "ing",
|
|
expected: []string{"staging-api", "staging-db", "monitoring", "logging"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
wizard.searchFilter = tt.filter
|
|
result := wizard.getFilteredNamespaces()
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetFilteredServices(t *testing.T) {
|
|
wizard := &AddWizardState{
|
|
services: []k8s.ServiceInfo{
|
|
{Name: "api-gateway"},
|
|
{Name: "api-backend"},
|
|
{Name: "database"},
|
|
{Name: "redis-cache"},
|
|
{Name: "postgres-db"},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
filter string
|
|
expected []string
|
|
}{
|
|
{
|
|
name: "no filter returns all",
|
|
filter: "",
|
|
expected: []string{"api-gateway", "api-backend", "database", "redis-cache", "postgres-db"},
|
|
},
|
|
{
|
|
name: "filter by 'api'",
|
|
filter: "api",
|
|
expected: []string{"api-gateway", "api-backend"},
|
|
},
|
|
{
|
|
name: "filter by 'db'",
|
|
filter: "db",
|
|
expected: []string{"postgres-db"},
|
|
},
|
|
{
|
|
name: "filter by 'base'",
|
|
filter: "base",
|
|
expected: []string{"database"},
|
|
},
|
|
{
|
|
name: "filter by 'redis'",
|
|
filter: "redis",
|
|
expected: []string{"redis-cache"},
|
|
},
|
|
{
|
|
name: "filter with no matches",
|
|
filter: "xyz",
|
|
expected: []string{},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
wizard.searchFilter = tt.filter
|
|
result := wizard.getFilteredServices()
|
|
resultNames := make([]string, len(result))
|
|
for i, svc := range result {
|
|
resultNames[i] = svc.Name
|
|
}
|
|
assert.Equal(t, tt.expected, resultNames)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestClearSearchFilter(t *testing.T) {
|
|
wizard := &AddWizardState{
|
|
searchFilter: "test",
|
|
cursor: 5,
|
|
scrollOffset: 10,
|
|
}
|
|
|
|
wizard.clearSearchFilter()
|
|
|
|
assert.Equal(t, "", wizard.searchFilter, "searchFilter should be cleared")
|
|
assert.Equal(t, 0, wizard.cursor, "cursor should be reset to 0")
|
|
assert.Equal(t, 0, wizard.scrollOffset, "scrollOffset should be reset to 0")
|
|
}
|
|
|
|
func TestMoveCursorWithFilteredLists(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
step AddWizardStep
|
|
contexts []string
|
|
namespaces []string
|
|
searchFilter string
|
|
initialCursor int
|
|
delta int
|
|
expectedCursor int
|
|
}{
|
|
{
|
|
name: "move down in filtered contexts",
|
|
step: StepSelectContext,
|
|
contexts: []string{"prod-1", "prod-2", "staging-1", "dev-1"},
|
|
searchFilter: "prod",
|
|
initialCursor: 0,
|
|
delta: 1,
|
|
expectedCursor: 1,
|
|
},
|
|
{
|
|
name: "cannot move beyond filtered list",
|
|
step: StepSelectContext,
|
|
contexts: []string{"prod-1", "prod-2", "staging-1", "dev-1"},
|
|
searchFilter: "prod",
|
|
initialCursor: 1,
|
|
delta: 1,
|
|
expectedCursor: 1, // Should stay at 1 (last item in filtered list)
|
|
},
|
|
{
|
|
name: "move up in filtered list",
|
|
step: StepSelectNamespace,
|
|
namespaces: []string{"ns-1", "ns-2", "ns-3", "other"},
|
|
searchFilter: "ns",
|
|
initialCursor: 2,
|
|
delta: -1,
|
|
expectedCursor: 1,
|
|
},
|
|
{
|
|
name: "cannot move above 0",
|
|
step: StepSelectNamespace,
|
|
namespaces: []string{"ns-1", "ns-2", "ns-3"},
|
|
searchFilter: "ns",
|
|
initialCursor: 0,
|
|
delta: -1,
|
|
expectedCursor: 0,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
wizard := &AddWizardState{
|
|
step: tt.step,
|
|
inputMode: InputModeList,
|
|
cursor: tt.initialCursor,
|
|
contexts: tt.contexts,
|
|
namespaces: tt.namespaces,
|
|
searchFilter: tt.searchFilter,
|
|
}
|
|
|
|
wizard.moveCursor(tt.delta)
|
|
|
|
assert.Equal(t, tt.expectedCursor, wizard.cursor)
|
|
})
|
|
}
|
|
}
|