From b011cffff8675d095f1d7fa600fc6f8cf7d1f2b3 Mon Sep 17 00:00:00 2001 From: Maciej Szulik Date: Thu, 15 May 2025 16:24:43 +0200 Subject: [PATCH] kuberc: pick the first known version when decoding + tests Signed-off-by: Maciej Szulik Kubernetes-commit: 1f355e5b44141be55da269a9183d53bbccd16c95 --- pkg/kuberc/marshal.go | 5 +- pkg/kuberc/marshal_test.go | 103 +++++++++++++++++++++++++++++ testdata/kuberc/allversions.kuberc | 34 ++++++++++ testdata/kuberc/empty.kuberc | 0 testdata/kuberc/multiple1.kuberc | 36 ++++++++++ testdata/kuberc/multiple2.kuberc | 42 ++++++++++++ testdata/kuberc/multiple3.kuberc | 36 ++++++++++ testdata/kuberc/multiple4.kuberc | 45 +++++++++++++ testdata/kuberc/unknown.kuberc | 11 +++ testdata/kuberc/unknown2.kuberc | 24 +++++++ testdata/kuberc/v1alpha1.kuberc | 11 +++ testdata/kuberc/v1beta1.kuberc | 11 +++ 12 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 pkg/kuberc/marshal_test.go create mode 100644 testdata/kuberc/allversions.kuberc create mode 100644 testdata/kuberc/empty.kuberc create mode 100644 testdata/kuberc/multiple1.kuberc create mode 100644 testdata/kuberc/multiple2.kuberc create mode 100644 testdata/kuberc/multiple3.kuberc create mode 100644 testdata/kuberc/multiple4.kuberc create mode 100644 testdata/kuberc/unknown.kuberc create mode 100644 testdata/kuberc/unknown2.kuberc create mode 100644 testdata/kuberc/v1alpha1.kuberc create mode 100644 testdata/kuberc/v1beta1.kuberc diff --git a/pkg/kuberc/marshal.go b/pkg/kuberc/marshal.go index 06f40d534..3c2323e45 100644 --- a/pkg/kuberc/marshal.go +++ b/pkg/kuberc/marshal.go @@ -88,13 +88,14 @@ func decodePreference(kubercFile string) (*config.Preference, error) { } // we have a usable preferences to return - klog.V(5).Infof("kuberc: successfully decoded entry %d in %s", attemptedItems, kubercFile) + klog.V(5).Infof("kuberc: using entry %d (%s) in %s", attemptedItems, gvk.GroupVersion(), kubercFile) return preferences, strictDecodeErr - } + if attemptedItems > 0 { return nil, fmt.Errorf("no valid preferences found in %s, use --v=5 to see details", kubercFile) } + // empty doc klog.V(5).Infof("kuberc: no preferences found in %s", kubercFile) return nil, nil diff --git a/pkg/kuberc/marshal_test.go b/pkg/kuberc/marshal_test.go new file mode 100644 index 000000000..a2259b83e --- /dev/null +++ b/pkg/kuberc/marshal_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kuberc + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDecodePreference(t *testing.T) { + testCases := map[string]struct { + kuberc string + expectedAliases []string + expectedDefaults []string + expectedError string + }{ + "v1alpha1": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "v1alpha1.kuberc"), + expectedDefaults: []string{"v1alpha1-apply", "v1alpha1-delete"}, + }, + "v1beta1": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "v1beta1.kuberc"), + expectedDefaults: []string{"v1beta1-apply", "v1beta1-delete"}, + }, + "first known version (v1beta1) with all versions": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "allversions.kuberc"), + expectedAliases: []string{"getn", "runx"}, + expectedDefaults: []string{"v1beta1-apply", "v1beta1-delete"}, + }, + "first known (v1beta1) with multiple versions (unknown, v1beta1, v1alpha1)": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "multiple1.kuberc"), + expectedDefaults: []string{"v1beta1-apply", "v1beta1-delete"}, + }, + "first known (v1beta1) with multiple versions (unknown, v1beta1, v1beta1, v1alpha1)": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "multiple2.kuberc"), + expectedDefaults: []string{"v1beta1-apply-first", "v1beta1-delete-first"}, + }, + "first known older (v1alpha1) with multiple versions (unknown, v1alpha1)": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "multiple3.kuberc"), + expectedDefaults: []string{"v1alpha1-apply-first", "v1alpha1-delete-first"}, + }, + "first v1alpha1 with multiple versions (unknown, v1alpha1, v1beta1)": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "multiple4.kuberc"), + expectedDefaults: []string{"v1alpha1-apply-first", "v1alpha1-delete-first"}, + }, + "single unknown version": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "unknown.kuberc"), + expectedError: "no valid preferences found", + }, + "multiple unknown version": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "unknown.kuberc"), + expectedError: "no valid preferences found", + }, + "non-existent file": { + kuberc: filepath.Join("..", "..", "testdata", "kuberc", "non-existent"), + expectedError: "no such file or directory", + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + actual, err := decodePreference(tc.kuberc) + if len(tc.expectedError) != 0 { + require.ErrorContains(t, err, tc.expectedError, "wrong expected error") + return + } + require.NoError(t, err, "unexpected error") + require.NotNil(t, actual, "missing preferences when decoding") + defaults := []string{} + for _, o := range actual.Defaults { + defaults = append(defaults, o.Command) + } + require.ElementsMatch(t, defaults, tc.expectedDefaults, "defaults mismatch") + aliases := []string{} + for _, o := range actual.Aliases { + aliases = append(aliases, o.Name) + } + require.ElementsMatch(t, aliases, tc.expectedAliases, "aliases mismatch") + }) + } +} + +func TestDecodeEmptyPreference(t *testing.T) { + actual, err := decodePreference(filepath.Join("..", "..", "testdata", "kuberc", "empty.kuberc")) + require.NoError(t, err, "unexpected error") + require.Nil(t, actual, "unexpected preferences") +} diff --git a/testdata/kuberc/allversions.kuberc b/testdata/kuberc/allversions.kuberc new file mode 100644 index 000000000..eaeadf4aa --- /dev/null +++ b/testdata/kuberc/allversions.kuberc @@ -0,0 +1,34 @@ +--- +apiVersion: kubectl.config.k8s.io/v1beta1 +kind: Preference +aliases: + - name: getn + command: get + prependArgs: + - namespace + - name: runx + command: run + appendArgs: + - -- + - custom-arg +defaults: + - command: v1beta1-apply + options: + - name: server-side + default: "true" + - command: v1beta1-delete + options: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/empty.kuberc b/testdata/kuberc/empty.kuberc new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/kuberc/multiple1.kuberc b/testdata/kuberc/multiple1.kuberc new file mode 100644 index 000000000..de3e0c12a --- /dev/null +++ b/testdata/kuberc/multiple1.kuberc @@ -0,0 +1,36 @@ +--- +apiVersion: kubectl.config.k8s.io/v1unknown1 +kind: Preference +overrides: + - command: v1unknown1-apply + flags: + - name: server-side + default: "true" + - command: v1unknown1-delete + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1beta1 +kind: Preference +defaults: + - command: v1beta1-apply + options: + - name: server-side + default: "true" + - command: v1beta1-delete + options: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/multiple2.kuberc b/testdata/kuberc/multiple2.kuberc new file mode 100644 index 000000000..14cc0e731 --- /dev/null +++ b/testdata/kuberc/multiple2.kuberc @@ -0,0 +1,42 @@ +--- +apiVersion: kubectl.config.k8s.io/v1unknown1 +kind: Preference +overrides: + - command: v1unknown1-apply + flags: + - name: server-side + default: "true" + - command: v1unknown1-delete + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1beta1 +kind: Preference +defaults: + - command: v1beta1-apply-first + options: + - name: server-side + default: "true" + - command: v1beta1-delete-first +--- +apiVersion: kubectl.config.k8s.io/v1beta1 +kind: Preference +defaults: + - command: v1beta1-apply-second + options: + - name: server-side + default: "true" + - command: v1beta1-delete-second +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/multiple3.kuberc b/testdata/kuberc/multiple3.kuberc new file mode 100644 index 000000000..f00777565 --- /dev/null +++ b/testdata/kuberc/multiple3.kuberc @@ -0,0 +1,36 @@ +--- +apiVersion: kubectl.config.k8s.io/v1unknown1 +kind: Preference +overrides: + - command: v1unknown1-apply + flags: + - name: server-side + default: "true" + - command: v1unknown1-delete + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply-first + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete-first + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply-second + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete-second + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/multiple4.kuberc b/testdata/kuberc/multiple4.kuberc new file mode 100644 index 000000000..ac709d2cb --- /dev/null +++ b/testdata/kuberc/multiple4.kuberc @@ -0,0 +1,45 @@ +--- +apiVersion: kubectl.config.k8s.io/v1unknown1 +kind: Preference +overrides: + - command: v1unknown1-apply + flags: + - name: server-side + default: "true" + - command: v1unknown1-delete + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply-first + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete-first + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply-second + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete-second + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1beta1 +kind: Preference +defaults: + - command: v1beta1-apply-first + options: + - name: server-side + default: "true" + - command: v1beta1-delete-first diff --git a/testdata/kuberc/unknown.kuberc b/testdata/kuberc/unknown.kuberc new file mode 100644 index 000000000..4b432f961 --- /dev/null +++ b/testdata/kuberc/unknown.kuberc @@ -0,0 +1,11 @@ +apiVersion: kubectl.config.k8s.io/v1unknown1 +kind: Preference +overrides: + - command: v1unknown1-apply + flags: + - name: server-side + default: "true" + - command: v1unknown1-delete + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/unknown2.kuberc b/testdata/kuberc/unknown2.kuberc new file mode 100644 index 000000000..b2ead7561 --- /dev/null +++ b/testdata/kuberc/unknown2.kuberc @@ -0,0 +1,24 @@ +--- +apiVersion: kubectl.config.k8s.io/v1unknown1 +kind: Preference +overrides: + - command: v1unknown1-apply + flags: + - name: server-side + default: "true" + - command: v1unknown1-delete + flags: + - name: interactive + default: "true" +--- +apiVersion: kubectl.config.k8s.io/v1unknown2 +kind: Preference +overrides: + - command: v1unknown2-apply + flags: + - name: server-side + default: "true" + - command: v1unknown2-delete + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/v1alpha1.kuberc b/testdata/kuberc/v1alpha1.kuberc new file mode 100644 index 000000000..7d133b6a0 --- /dev/null +++ b/testdata/kuberc/v1alpha1.kuberc @@ -0,0 +1,11 @@ +apiVersion: kubectl.config.k8s.io/v1alpha1 +kind: Preference +overrides: + - command: v1alpha1-apply + flags: + - name: server-side + default: "true" + - command: v1alpha1-delete + flags: + - name: interactive + default: "true" diff --git a/testdata/kuberc/v1beta1.kuberc b/testdata/kuberc/v1beta1.kuberc new file mode 100644 index 000000000..b0a1c418c --- /dev/null +++ b/testdata/kuberc/v1beta1.kuberc @@ -0,0 +1,11 @@ +apiVersion: kubectl.config.k8s.io/v1beta1 +kind: Preference +defaults: + - command: v1beta1-apply + options: + - name: server-side + default: "true" + - command: v1beta1-delete + options: + - name: interactive + default: "true"