mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-02-02 05:41:10 -08:00
This extends the kubectl segment to optionally not rely on the kubectl command and instead to directly parse kubeconfig files like kubectl does. This is meant as a performance optimization similar to how the git segment can determine the current branch itself without calling to git. Especially on Windows and in the presence other factors slowing process creation like like AntiVirus this can make shells using the segment considerably more responsive. The functionality is enabled using the new parse_kubeconfig prop. It defaults to false to prevent breaking existing users in case there are any unanticipated behavioral changes. Additionally the new template properties Cluster and User were added as they are easily available and helpful in kubectl setups with more elaborate configuration.
164 lines
5.9 KiB
Go
164 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type kubectlArgs struct {
|
|
kubectlExists bool
|
|
kubectlErr bool
|
|
kubeconfig string
|
|
parseKubeConfig bool
|
|
template string
|
|
displayError bool
|
|
kubectlOutContext string
|
|
kubectlOutNamespace string
|
|
kubectlOutUser string
|
|
kubectlOutCluster string
|
|
files map[string]string
|
|
}
|
|
|
|
const testKubectlAllInfoTemplate = "{{.Context}} :: {{.Namespace}} :: {{.User}} :: {{.Cluster}}"
|
|
|
|
func bootStrapKubectlTest(args *kubectlArgs) *kubectl {
|
|
env := new(MockedEnvironment)
|
|
env.On("hasCommand", "kubectl").Return(args.kubectlExists)
|
|
kubectlOut := args.kubectlOutContext + "," + args.kubectlOutNamespace + "," + args.kubectlOutUser + "," + args.kubectlOutCluster
|
|
var kubectlErr error
|
|
if args.kubectlErr {
|
|
kubectlErr = &commandError{
|
|
err: "oops",
|
|
exitCode: 1,
|
|
}
|
|
}
|
|
env.On("runCommand", "kubectl",
|
|
[]string{"config", "view", "--minify", "--output", "jsonpath={..current-context},{..namespace},{..context.user},{..context.cluster}"}).Return(kubectlOut, kubectlErr)
|
|
|
|
env.On("getenv", "KUBECONFIG").Return(args.kubeconfig)
|
|
for path, content := range args.files {
|
|
env.On("getFileContent", path).Return(content)
|
|
}
|
|
env.On("homeDir", nil).Return("testhome")
|
|
|
|
k := &kubectl{
|
|
env: env,
|
|
props: map[Property]interface{}{
|
|
SegmentTemplate: args.template,
|
|
DisplayError: args.displayError,
|
|
ParseKubeConfig: args.parseKubeConfig,
|
|
},
|
|
}
|
|
return k
|
|
}
|
|
|
|
func TestKubectlSegment(t *testing.T) {
|
|
standardTemplate := "{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}"
|
|
lsep := string(filepath.ListSeparator)
|
|
|
|
cases := []struct {
|
|
Case string
|
|
Template string
|
|
DisplayError bool
|
|
KubectlExists bool
|
|
Kubeconfig string
|
|
ParseKubeConfig bool
|
|
Context string
|
|
Namespace string
|
|
User string
|
|
Cluster string
|
|
KubectlErr bool
|
|
ExpectedEnabled bool
|
|
ExpectedString string
|
|
Files map[string]string
|
|
}{
|
|
{Case: "disabled", Template: standardTemplate, KubectlExists: false, Context: "aaa", Namespace: "bbb", ExpectedString: "", ExpectedEnabled: false},
|
|
{Case: "normal", Template: standardTemplate, KubectlExists: true, Context: "aaa", Namespace: "bbb", ExpectedString: "aaa :: bbb", ExpectedEnabled: true},
|
|
{Case: "all information", Template: testKubectlAllInfoTemplate, KubectlExists: true, Context: "aaa", Namespace: "bbb", User: "ccc", Cluster: "ddd",
|
|
ExpectedString: "aaa :: bbb :: ccc :: ddd", ExpectedEnabled: true},
|
|
{Case: "no namespace", Template: standardTemplate, KubectlExists: true, Context: "aaa", Namespace: "", ExpectedString: "aaa", ExpectedEnabled: true},
|
|
{Case: "kubectl error", Template: standardTemplate, DisplayError: true, KubectlExists: true, Context: "aaa", Namespace: "bbb", KubectlErr: true,
|
|
ExpectedString: "KUBECTL ERR :: KUBECTL ERR", ExpectedEnabled: true},
|
|
{Case: "kubectl error hidden", Template: standardTemplate, DisplayError: false, KubectlExists: true, Context: "aaa", Namespace: "bbb", KubectlErr: true, ExpectedEnabled: false},
|
|
{Case: "kubeconfig home", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true, Files: testKubeConfigFiles, ExpectedString: "aaa :: bbb :: ccc :: ddd",
|
|
ExpectedEnabled: true},
|
|
{Case: "kubeconfig multiple current marker first", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true,
|
|
Kubeconfig: "" + lsep + "currentcontextmarker" + lsep + "contextdefinition" + lsep + "contextredefinition",
|
|
Files: testKubeConfigFiles, ExpectedString: "ctx :: ns :: usr :: cl", ExpectedEnabled: true},
|
|
{Case: "kubeconfig multiple context first", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true,
|
|
Kubeconfig: "contextdefinition" + lsep + "contextredefinition" + lsep + "currentcontextmarker" + lsep,
|
|
Files: testKubeConfigFiles, ExpectedString: "ctx :: ns :: usr :: cl", ExpectedEnabled: true},
|
|
{Case: "kubeconfig error hidden", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true, Kubeconfig: "invalid", Files: testKubeConfigFiles, ExpectedEnabled: false},
|
|
{Case: "kubeconfig error", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true,
|
|
Kubeconfig: "invalid", Files: testKubeConfigFiles, DisplayError: true,
|
|
ExpectedString: "KUBECONFIG ERR :: KUBECONFIG ERR :: KUBECONFIG ERR :: KUBECONFIG ERR", ExpectedEnabled: true},
|
|
{Case: "kubeconfig incomplete", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true,
|
|
Kubeconfig: "currentcontextmarker" + lsep + "contextdefinitionincomplete",
|
|
Files: testKubeConfigFiles, ExpectedString: "ctx :: :: :: ", ExpectedEnabled: true},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
args := &kubectlArgs{
|
|
kubectlExists: tc.KubectlExists,
|
|
template: tc.Template,
|
|
displayError: tc.DisplayError,
|
|
kubectlOutContext: tc.Context,
|
|
kubectlOutNamespace: tc.Namespace,
|
|
kubectlOutUser: tc.User,
|
|
kubectlOutCluster: tc.Cluster,
|
|
kubectlErr: tc.KubectlErr,
|
|
parseKubeConfig: tc.ParseKubeConfig,
|
|
files: tc.Files,
|
|
kubeconfig: tc.Kubeconfig,
|
|
}
|
|
kubectl := bootStrapKubectlTest(args)
|
|
assert.Equal(t, tc.ExpectedEnabled, kubectl.enabled(), tc.Case)
|
|
if tc.ExpectedEnabled {
|
|
assert.Equal(t, tc.ExpectedString, kubectl.string(), tc.Case)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testKubeConfigFiles = map[string]string{
|
|
filepath.Join("testhome", ".kube/config"): `
|
|
apiVersion: v1
|
|
contexts:
|
|
- context:
|
|
cluster: ddd
|
|
user: ccc
|
|
namespace: bbb
|
|
name: aaa
|
|
current-context: aaa
|
|
`,
|
|
"contextdefinition": `
|
|
apiVersion: v1
|
|
contexts:
|
|
- context:
|
|
cluster: cl
|
|
user: usr
|
|
namespace: ns
|
|
name: ctx
|
|
`,
|
|
"currentcontextmarker": `
|
|
apiVersion: v1
|
|
current-context: ctx
|
|
`,
|
|
"invalid": "this is not yaml",
|
|
"contextdefinitionincomplete": `
|
|
apiVersion: v1
|
|
contexts:
|
|
- name: ctx
|
|
`,
|
|
"contextredefinition": `
|
|
apiVersion: v1
|
|
contexts:
|
|
- context:
|
|
cluster: wrongcl
|
|
user: wrongu
|
|
namespace: wrongns
|
|
name: ctx
|
|
`,
|
|
}
|