mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-06-11 00:09:31 +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
316 lines
8.0 KiB
Go
316 lines
8.0 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestLoadConfig_ValidYAML(t *testing.T) {
|
|
// Create a temporary config file
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, ".kportal.yaml")
|
|
|
|
validYAML := `contexts:
|
|
- name: dev-cluster
|
|
namespaces:
|
|
- name: default
|
|
forwards:
|
|
- resource: pod/my-app
|
|
protocol: tcp
|
|
port: 8080
|
|
localPort: 8080
|
|
- name: staging
|
|
forwards:
|
|
- resource: service/postgres
|
|
protocol: tcp
|
|
port: 5432
|
|
localPort: 5433
|
|
- name: prod-cluster
|
|
namespaces:
|
|
- name: production
|
|
forwards:
|
|
- resource: pod
|
|
selector: app=nginx,env=prod
|
|
protocol: tcp
|
|
port: 80
|
|
localPort: 8081
|
|
`
|
|
|
|
err := os.WriteFile(configPath, []byte(validYAML), 0644)
|
|
assert.NoError(t, err, "should write temp config file")
|
|
|
|
// Load the config
|
|
cfg, err := LoadConfig(configPath)
|
|
assert.NoError(t, err, "LoadConfig should succeed")
|
|
assert.NotNil(t, cfg, "config should not be nil")
|
|
|
|
// Verify structure
|
|
assert.Len(t, cfg.Contexts, 2, "should have 2 contexts")
|
|
|
|
// Verify first context
|
|
assert.Equal(t, "dev-cluster", cfg.Contexts[0].Name)
|
|
assert.Len(t, cfg.Contexts[0].Namespaces, 2, "dev-cluster should have 2 namespaces")
|
|
|
|
// Verify first namespace in first context
|
|
assert.Equal(t, "default", cfg.Contexts[0].Namespaces[0].Name)
|
|
assert.Len(t, cfg.Contexts[0].Namespaces[0].Forwards, 1)
|
|
|
|
// Verify forward details
|
|
fwd := cfg.Contexts[0].Namespaces[0].Forwards[0]
|
|
assert.Equal(t, "pod/my-app", fwd.Resource)
|
|
assert.Equal(t, "tcp", fwd.Protocol)
|
|
assert.Equal(t, 8080, fwd.Port)
|
|
assert.Equal(t, 8080, fwd.LocalPort)
|
|
assert.Equal(t, "", fwd.Selector)
|
|
|
|
// Verify runtime fields are populated
|
|
assert.Equal(t, "dev-cluster", fwd.GetContext())
|
|
assert.Equal(t, "default", fwd.GetNamespace())
|
|
}
|
|
|
|
func TestLoadConfig_InvalidYAML(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, ".kportal.yaml")
|
|
|
|
invalidYAML := `contexts:
|
|
- name: dev-cluster
|
|
namespaces:
|
|
- name: default
|
|
forwards: [this is invalid yaml syntax
|
|
`
|
|
|
|
err := os.WriteFile(configPath, []byte(invalidYAML), 0644)
|
|
assert.NoError(t, err, "should write temp config file")
|
|
|
|
// Load the config
|
|
cfg, err := LoadConfig(configPath)
|
|
assert.Error(t, err, "LoadConfig should fail with invalid YAML")
|
|
assert.Nil(t, cfg, "config should be nil on error")
|
|
assert.Contains(t, err.Error(), "failed to parse YAML", "error should mention YAML parsing")
|
|
}
|
|
|
|
func TestLoadConfig_FileNotFound(t *testing.T) {
|
|
// Try to load a non-existent file
|
|
cfg, err := LoadConfig("/non/existent/path/.kportal.yaml")
|
|
assert.Error(t, err, "LoadConfig should fail with non-existent file")
|
|
assert.Nil(t, cfg, "config should be nil on error")
|
|
assert.Contains(t, err.Error(), "failed to stat config file", "error should mention stat failure")
|
|
}
|
|
|
|
func TestForward_ID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
forward Forward
|
|
expectedID string
|
|
}{
|
|
{
|
|
name: "pod with explicit name",
|
|
forward: Forward{
|
|
Resource: "pod/my-app",
|
|
Port: 8080,
|
|
LocalPort: 8080,
|
|
contextName: "dev-cluster",
|
|
namespaceName: "default",
|
|
},
|
|
expectedID: "dev-cluster/default/pod/my-app:8080",
|
|
},
|
|
{
|
|
name: "service resource",
|
|
forward: Forward{
|
|
Resource: "service/postgres",
|
|
Port: 5432,
|
|
LocalPort: 5433,
|
|
contextName: "prod-cluster",
|
|
namespaceName: "database",
|
|
},
|
|
expectedID: "prod-cluster/database/service/postgres:5433",
|
|
},
|
|
{
|
|
name: "pod with selector",
|
|
forward: Forward{
|
|
Resource: "pod",
|
|
Selector: "app=nginx",
|
|
Port: 80,
|
|
LocalPort: 8081,
|
|
contextName: "staging",
|
|
namespaceName: "web",
|
|
},
|
|
expectedID: "staging/web/pod:8081",
|
|
},
|
|
{
|
|
name: "forward with alias",
|
|
forward: Forward{
|
|
Resource: "service/postgres",
|
|
Port: 5432,
|
|
LocalPort: 5432,
|
|
Alias: "shared-postgres",
|
|
contextName: "home",
|
|
namespaceName: "shared-resources",
|
|
},
|
|
expectedID: "shared-postgres:5432",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
id := tt.forward.ID()
|
|
assert.Equal(t, tt.expectedID, id, "ID() should return correct format")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestForward_String(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
forward Forward
|
|
expectedString string
|
|
}{
|
|
{
|
|
name: "pod without selector",
|
|
forward: Forward{
|
|
Resource: "pod/my-app",
|
|
Port: 8080,
|
|
LocalPort: 8080,
|
|
contextName: "dev-cluster",
|
|
namespaceName: "default",
|
|
},
|
|
expectedString: "dev-cluster/default/pod/my-app:8080→8080",
|
|
},
|
|
{
|
|
name: "service resource",
|
|
forward: Forward{
|
|
Resource: "service/postgres",
|
|
Port: 5432,
|
|
LocalPort: 5433,
|
|
contextName: "prod-cluster",
|
|
namespaceName: "database",
|
|
},
|
|
expectedString: "prod-cluster/database/service/postgres:5432→5433",
|
|
},
|
|
{
|
|
name: "pod with selector",
|
|
forward: Forward{
|
|
Resource: "pod",
|
|
Selector: "app=nginx,env=prod",
|
|
Port: 80,
|
|
LocalPort: 8081,
|
|
contextName: "staging",
|
|
namespaceName: "web",
|
|
},
|
|
expectedString: "staging/web/pod[app=nginx,env=prod]:80→8081",
|
|
},
|
|
{
|
|
name: "forward with alias",
|
|
forward: Forward{
|
|
Resource: "service/redis",
|
|
Port: 6379,
|
|
LocalPort: 6379,
|
|
Alias: "redis-at-home",
|
|
contextName: "home",
|
|
namespaceName: "shared-resources",
|
|
},
|
|
expectedString: "redis-at-home:6379→6379",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
str := tt.forward.String()
|
|
assert.Equal(t, tt.expectedString, str, "String() should return correct format")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseConfig_ValidYAML(t *testing.T) {
|
|
yamlData := []byte(`contexts:
|
|
- name: test-cluster
|
|
namespaces:
|
|
- name: default
|
|
forwards:
|
|
- resource: pod/app
|
|
protocol: tcp
|
|
port: 8080
|
|
localPort: 8080
|
|
`)
|
|
|
|
cfg, err := ParseConfig(yamlData)
|
|
assert.NoError(t, err, "ParseConfig should succeed")
|
|
assert.NotNil(t, cfg, "config should not be nil")
|
|
assert.Len(t, cfg.Contexts, 1)
|
|
assert.Equal(t, "test-cluster", cfg.Contexts[0].Name)
|
|
}
|
|
|
|
func TestParseConfig_PopulatesRuntimeFields(t *testing.T) {
|
|
yamlData := []byte(`contexts:
|
|
- name: my-cluster
|
|
namespaces:
|
|
- name: my-namespace
|
|
forwards:
|
|
- resource: pod/my-pod
|
|
port: 8080
|
|
localPort: 8080
|
|
`)
|
|
|
|
cfg, err := ParseConfig(yamlData)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, cfg)
|
|
|
|
// Check that runtime fields are populated
|
|
fwd := cfg.Contexts[0].Namespaces[0].Forwards[0]
|
|
assert.Equal(t, "my-cluster", fwd.GetContext())
|
|
assert.Equal(t, "my-namespace", fwd.GetNamespace())
|
|
assert.Equal(t, "my-cluster/my-namespace/pod/my-pod:8080", fwd.ID())
|
|
}
|
|
|
|
func TestConfig_GetAllForwards(t *testing.T) {
|
|
yamlData := []byte(`contexts:
|
|
- name: cluster1
|
|
namespaces:
|
|
- name: ns1
|
|
forwards:
|
|
- resource: pod/app1
|
|
port: 8080
|
|
localPort: 8080
|
|
- resource: pod/app2
|
|
port: 8081
|
|
localPort: 8081
|
|
- name: ns2
|
|
forwards:
|
|
- resource: service/db
|
|
port: 5432
|
|
localPort: 5432
|
|
- name: cluster2
|
|
namespaces:
|
|
- name: ns3
|
|
forwards:
|
|
- resource: pod/app3
|
|
port: 9090
|
|
localPort: 9090
|
|
`)
|
|
|
|
cfg, err := ParseConfig(yamlData)
|
|
assert.NoError(t, err)
|
|
|
|
forwards := cfg.GetAllForwards()
|
|
assert.Len(t, forwards, 4, "should return all forwards from all contexts and namespaces")
|
|
}
|
|
|
|
func TestForward_SetContext(t *testing.T) {
|
|
fwd := Forward{
|
|
Resource: "pod/my-app",
|
|
Port: 8080,
|
|
LocalPort: 8080,
|
|
}
|
|
|
|
assert.Equal(t, "", fwd.GetContext(), "initial context should be empty")
|
|
assert.Equal(t, "", fwd.GetNamespace(), "initial namespace should be empty")
|
|
|
|
fwd.SetContext("my-cluster", "my-namespace")
|
|
|
|
assert.Equal(t, "my-cluster", fwd.GetContext())
|
|
assert.Equal(t, "my-namespace", fwd.GetNamespace())
|
|
}
|