mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Adding e2e test to ensure kubectl get output is using custom columns when desired.
This uses etcd test data to load resources and then ensures that kubectl get output contains a different set of columns than default. This assumes that all future API resources will either have appropriate kubectl get output or add an exception here. Co-authored-by: Luis Sanchez <sanchezl@redhat.com>
This commit is contained in:
parent
ad6f30c535
commit
8ae5632859
@ -19,15 +19,19 @@ go_library(
|
||||
"//staging/src/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/rand:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/kubectl/pkg/polymorphichelpers:go_default_library",
|
||||
"//test/e2e/common:go_default_library",
|
||||
@ -39,6 +43,7 @@ go_library(
|
||||
"//test/e2e/framework/service:go_default_library",
|
||||
"//test/e2e/framework/testfiles:go_default_library",
|
||||
"//test/e2e/scheduling:go_default_library",
|
||||
"//test/integration/etcd:go_default_library",
|
||||
"//test/utils:go_default_library",
|
||||
"//test/utils/crd:go_default_library",
|
||||
"//test/utils/image:go_default_library",
|
||||
|
@ -46,15 +46,19 @@ import (
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/client-go/dynamic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubectl/pkg/polymorphichelpers"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
@ -67,6 +71,7 @@ import (
|
||||
e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
|
||||
"k8s.io/kubernetes/test/e2e/framework/testfiles"
|
||||
"k8s.io/kubernetes/test/e2e/scheduling"
|
||||
"k8s.io/kubernetes/test/integration/etcd"
|
||||
testutils "k8s.io/kubernetes/test/utils"
|
||||
"k8s.io/kubernetes/test/utils/crd"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
@ -410,6 +415,82 @@ var _ = SIGDescribe("Kubectl client", func() {
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.Describe("kubectl get output", func() {
|
||||
ginkgo.It("should contain custom columns for each resource", func() {
|
||||
randString := rand.String(10)
|
||||
|
||||
ignoredResources := map[string]bool{
|
||||
// ignored for intentionally using standard fields.
|
||||
// This assumption is based on a lack of TableColumnDefinition
|
||||
// in pkg/printers/internalversion/printers.go
|
||||
"ClusterRole": true,
|
||||
"LimitRange": true,
|
||||
"PodPreset": true,
|
||||
|
||||
// ignored temporarily while waiting for bug fix.
|
||||
"ComponentStatus": true,
|
||||
"ClusterRoleBinding": true,
|
||||
"ResourceQuota": true,
|
||||
|
||||
// ignored because no test data exists.
|
||||
// Do not add anything to this list, instead add fixtures in
|
||||
// the test/integration/etcd package.
|
||||
"BackendConfig": true,
|
||||
"NodeMetrics": true,
|
||||
"PodMetrics": true,
|
||||
"ScalingPolicy": true,
|
||||
"VolumeSnapshotClass": true,
|
||||
"VolumeSnapshotContent": true,
|
||||
"VolumeSnapshot": true,
|
||||
|
||||
// A CRD created by other e2e tests without any test data.
|
||||
"Noxu": true,
|
||||
}
|
||||
|
||||
apiGroups, err := c.Discovery().ServerPreferredResources()
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
testableResources := etcd.GetEtcdStorageDataForNamespace(f.Namespace.Name)
|
||||
|
||||
for _, group := range apiGroups {
|
||||
for _, resource := range group.APIResources {
|
||||
if !verbsContain(resource.Verbs, "get") || ignoredResources[resource.Kind] || strings.HasPrefix(resource.Name, "e2e-test") {
|
||||
continue
|
||||
}
|
||||
|
||||
// compute gvr
|
||||
gv, err := schema.ParseGroupVersion(group.GroupVersion)
|
||||
framework.ExpectNoError(err)
|
||||
gvr := gv.WithResource(resource.Name)
|
||||
|
||||
// assert test data exists
|
||||
testData := testableResources[gvr]
|
||||
gomega.ExpectWithOffset(1, testData).ToNot(gomega.BeZero(), "No test data available for %s", gvr)
|
||||
|
||||
// create test resource
|
||||
mapping := &meta.RESTMapping{
|
||||
Resource: gvr,
|
||||
GroupVersionKind: gv.WithKind(resource.Kind),
|
||||
}
|
||||
|
||||
if resource.Namespaced {
|
||||
mapping.Scope = meta.RESTScopeNamespace
|
||||
} else {
|
||||
mapping.Scope = meta.RESTScopeRoot
|
||||
}
|
||||
|
||||
client, obj, err := etcd.JSONToUnstructured(testData.Stub, f.Namespace.Name, mapping, f.DynamicClient)
|
||||
framework.ExpectNoError(err)
|
||||
if resource.Kind != "APIService" && resource.Kind != "CustomResourceDefinition" {
|
||||
obj.SetName(obj.GetName() + randString)
|
||||
}
|
||||
|
||||
createObjValidateOutputAndCleanup(client, obj, resource)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.Describe("Simple pod", func() {
|
||||
var podYaml string
|
||||
ginkgo.BeforeEach(func() {
|
||||
@ -2482,3 +2563,43 @@ waitLoop:
|
||||
// Reaching here means that one of more checks failed multiple times. Assuming its not a race condition, something is broken.
|
||||
framework.Failf("Timed out after %v seconds waiting for %s pods to reach valid state", framework.PodStartTimeout.Seconds(), testname)
|
||||
}
|
||||
|
||||
// verbsContain returns true if the provided list of verbs contain the provided
|
||||
// verb string.
|
||||
func verbsContain(verbs metav1.Verbs, str string) bool {
|
||||
for _, v := range verbs {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// deleteObj deletes an Object with the provided client and name.
|
||||
func deleteObj(client dynamic.ResourceInterface, name string) {
|
||||
err := client.Delete(name, &metav1.DeleteOptions{})
|
||||
framework.ExpectNoError(err)
|
||||
}
|
||||
|
||||
// createObjValidateOutputAndCleanup creates an object using the provided client
|
||||
// and then verifies that the kubectl get output provides custom columns. Once
|
||||
// the test has completed, it deletes the object.
|
||||
func createObjValidateOutputAndCleanup(client dynamic.ResourceInterface, obj *unstructured.Unstructured, resource metav1.APIResource) {
|
||||
_, err := client.Create(obj, metav1.CreateOptions{})
|
||||
framework.ExpectNoError(err)
|
||||
defer deleteObj(client, obj.GetName())
|
||||
|
||||
// get test resource
|
||||
output := framework.RunKubectlOrDie("get", resource.Name, "--all-namespaces")
|
||||
if output == "" {
|
||||
framework.Failf("No stdout from kubectl get for %s (likely need to define test resources)", resource.Name)
|
||||
}
|
||||
|
||||
splitOutput := strings.SplitN(output, "\n", 2)
|
||||
fields := strings.Fields(splitOutput[0])
|
||||
if resource.Namespaced {
|
||||
framework.ExpectNotEqual(fields, []string{"NAMESPACE", "NAME", "CREATED", "AT"}, fmt.Sprintf("expected non-default fields for namespaced resource: %s", resource.Name))
|
||||
} else {
|
||||
framework.ExpectNotEqual(fields, []string{"NAME", "AGE"}, fmt.Sprintf("expected non-default fields for resource: %s", resource.Name))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user