Added 'No resources found' message to describe and top pod commands

Kubernetes-commit: e70a630dac6c0158a5f9bb571223ed5759096dc1
This commit is contained in:
Brian Pursley 2020-01-24 10:42:08 -05:00 committed by Kubernetes Publisher
parent 2a89737620
commit 445baa99d2
4 changed files with 171 additions and 0 deletions

View File

@ -203,6 +203,15 @@ func (o *DescribeOptions) Run() error {
}
}
if len(infos) == 0 && len(allErrs) == 0 {
// if we wrote no output, and had no errors, be sure we output something.
if o.AllNamespaces {
fmt.Fprintln(o.ErrOut, "No resources found")
} else {
fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
}
}
return utilerrors.NewAggregate(allErrs)
}

View File

@ -245,6 +245,59 @@ func TestDescribeHelpMessage(t *testing.T) {
}
}
func TestDescribeNoResourcesFound(t *testing.T) {
testNS := "testns"
testCases := []struct {
name string
flags map[string]string
namespace string
expectedOutput string
expectedErr string
}{
{
name: "all namespaces",
flags: map[string]string{"all-namespaces": "true"},
expectedOutput: "",
expectedErr: "No resources found\n",
},
{
name: "all in namespace",
namespace: testNS,
expectedOutput: "",
expectedErr: "No resources found in " + testNS + " namespace.\n",
},
}
cmdtesting.InitTestErrorHandler(t)
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
pods, _, _ := cmdtesting.EmptyTestData()
tf := cmdtesting.NewTestFactory().WithNamespace(testNS)
defer tf.Cleanup()
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
Resp: &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
}
streams, _, buf, errbuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdDescribe("kubectl", tf, streams)
for name, value := range testCase.flags {
_ = cmd.Flags().Set(name, value)
}
cmd.Run(cmd, []string{"pods"})
if e, a := testCase.expectedOutput, buf.String(); e != a {
t.Errorf("Unexpected output:\nExpected:\n%v\nActual:\n%v", e, a)
}
if e, a := testCase.expectedErr, errbuf.String(); e != a {
t.Errorf("Unexpected error:\nExpected:\n%v\nActual:\n%v", e, a)
}
})
}
}
type testDescriber struct {
Name, Namespace string
Settings describe.DescriberSettings

View File

@ -197,6 +197,13 @@ func (o TopPodOptions) RunTopPod() error {
if e != nil {
return e
}
// if we had no errors, be sure we output something.
if o.AllNamespaces {
fmt.Fprintln(o.ErrOut, "No resources found")
} else {
fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
}
}
if err != nil {
return err

View File

@ -449,6 +449,108 @@ func TestTopPodWithMetricsServer(t *testing.T) {
}
}
func TestTopPodNoResourcesFound(t *testing.T) {
testNS := "testns"
testCases := []struct {
name string
options *TopPodOptions
namespace string
expectedOutput string
expectedErr string
expectedPath string
}{
{
name: "all namespaces",
options: &TopPodOptions{AllNamespaces: true},
expectedOutput: "",
expectedErr: "No resources found\n",
expectedPath: topMetricsAPIPathPrefix + "/pods",
},
{
name: "all in namespace",
namespace: testNS,
expectedOutput: "",
expectedErr: "No resources found in " + testNS + " namespace.\n",
expectedPath: topMetricsAPIPathPrefix + "/namespaces/" + testNS + "/pods",
},
}
cmdtesting.InitTestErrorHandler(t)
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
fakemetricsClientset := &metricsfake.Clientset{}
fakemetricsClientset.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) {
res := &metricsv1beta1api.PodMetricsList{
ListMeta: metav1.ListMeta{
ResourceVersion: "2",
},
Items: nil, // No metrics found
}
return true, res, nil
})
tf := cmdtesting.NewTestFactory().WithNamespace(testNS)
defer tf.Cleanup()
ns := scheme.Codecs.WithoutConversion()
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p := req.URL.Path; {
case p == "/api":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
case p == "/apis":
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
case p == "/api/v1/namespaces/" + testNS + "/pods":
// Top Pod calls this endpoint to check if there are pods whenever it gets no metrics,
// so we need to return no pods for this test scenario
body, _ := marshallBody(metricsv1alpha1api.PodMetricsList{
ListMeta: metav1.ListMeta{
ResourceVersion: "2",
},
Items: nil, // No pods found
})
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
default:
t.Fatalf("%s: unexpected request: %#v\nGot URL: %#v",
testCase.name, req, req.URL)
return nil, nil
}
}),
}
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
streams, _, buf, errbuf := genericclioptions.NewTestIOStreams()
cmd := NewCmdTopPod(tf, nil, streams)
var cmdOptions *TopPodOptions
if testCase.options != nil {
cmdOptions = testCase.options
} else {
cmdOptions = &TopPodOptions{}
}
cmdOptions.IOStreams = streams
if err := cmdOptions.Complete(tf, cmd, nil); err != nil {
t.Fatal(err)
}
cmdOptions.MetricsClient = fakemetricsClientset
if err := cmdOptions.Validate(); err != nil {
t.Fatal(err)
}
if err := cmdOptions.RunTopPod(); err != nil {
t.Fatal(err)
}
if e, a := testCase.expectedOutput, buf.String(); e != a {
t.Errorf("Unexpected output:\nExpected:\n%v\nActual:\n%v", e, a)
}
if e, a := testCase.expectedErr, errbuf.String(); e != a {
t.Errorf("Unexpected error:\nExpected:\n%v\nActual:\n%v", e, a)
}
})
}
}
type fakeDiscovery struct{}
// ServerGroups returns the supported groups, with information like supported versions and the