mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #82333 from tlereste/fix_sort_by_cpu_memory
Fix kubectl top sort-by cpu and sort-by memory options
This commit is contained in:
commit
a3a9c78d01
@ -21,6 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -283,6 +284,147 @@ func TestTopNodeWithLabelSelectorMetrics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTopNodeWithSortByCpuMetrics(t *testing.T) {
|
||||||
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
|
metrics, nodes := testNodeV1beta1MetricsData()
|
||||||
|
expectedMetrics := metricsv1beta1api.NodeMetricsList{
|
||||||
|
ListMeta: metrics.ListMeta,
|
||||||
|
Items: metrics.Items[:],
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMetricsPath := fmt.Sprintf("%s/%s/nodes", baseMetricsAddress, metricsAPIVersion)
|
||||||
|
expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
|
||||||
|
expectedNodes := []string{"node2", "node3", "node1"}
|
||||||
|
|
||||||
|
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||||
|
defer tf.Cleanup()
|
||||||
|
|
||||||
|
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||||
|
ns := scheme.Codecs
|
||||||
|
|
||||||
|
tf.Client = &fake.RESTClient{
|
||||||
|
NegotiatedSerializer: ns,
|
||||||
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/api":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
|
||||||
|
case p == "/apis":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbody)))}, nil
|
||||||
|
case p == expectedMetricsPath && m == "GET":
|
||||||
|
body, err := marshallBody(expectedMetrics)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
|
||||||
|
case p == expectedNodePath && m == "GET":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, nodes)}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\nGot URL: %#v\nExpected path: %#v", req, req.URL, expectedMetricsPath)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
|
||||||
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
|
|
||||||
|
cmd := NewCmdTopNode(tf, nil, streams)
|
||||||
|
cmd.Flags().Set("sort-by", "cpu")
|
||||||
|
|
||||||
|
cmd.Run(cmd, []string{})
|
||||||
|
|
||||||
|
// Check the presence of node names in the output.
|
||||||
|
result := buf.String()
|
||||||
|
|
||||||
|
for _, m := range expectedMetrics.Items {
|
||||||
|
if !strings.Contains(result, m.Name) {
|
||||||
|
t.Errorf("missing metrics for %s: \n%s", m.Name, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultNodes := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultNodes[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(resultNodes, expectedNodes) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", expectedNodes, resultNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTopNodeWithSortByMemoryMetrics(t *testing.T) {
|
||||||
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
|
metrics, nodes := testNodeV1beta1MetricsData()
|
||||||
|
expectedMetrics := metricsv1beta1api.NodeMetricsList{
|
||||||
|
ListMeta: metrics.ListMeta,
|
||||||
|
Items: metrics.Items[:],
|
||||||
|
}
|
||||||
|
expectedMetricsPath := fmt.Sprintf("%s/%s/nodes", baseMetricsAddress, metricsAPIVersion)
|
||||||
|
expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
|
||||||
|
expectedNodes := []string{"node2", "node3", "node1"}
|
||||||
|
|
||||||
|
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||||
|
defer tf.Cleanup()
|
||||||
|
|
||||||
|
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||||
|
ns := scheme.Codecs
|
||||||
|
|
||||||
|
tf.Client = &fake.RESTClient{
|
||||||
|
NegotiatedSerializer: ns,
|
||||||
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/api":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
|
||||||
|
case p == "/apis":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbody)))}, nil
|
||||||
|
case p == expectedMetricsPath && m == "GET":
|
||||||
|
body, err := marshallBody(expectedMetrics)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
|
||||||
|
case p == expectedNodePath && m == "GET":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, nodes)}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\nGot URL: %#v\nExpected path: %#v", req, req.URL, expectedMetricsPath)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
|
||||||
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
|
|
||||||
|
cmd := NewCmdTopNode(tf, nil, streams)
|
||||||
|
cmd.Flags().Set("sort-by", "memory")
|
||||||
|
|
||||||
|
cmd.Run(cmd, []string{})
|
||||||
|
|
||||||
|
// Check the presence of node names in the output.
|
||||||
|
result := buf.String()
|
||||||
|
|
||||||
|
for _, m := range expectedMetrics.Items {
|
||||||
|
if !strings.Contains(result, m.Name) {
|
||||||
|
t.Errorf("missing metrics for %s: \n%s", m.Name, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultNodes := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultNodes[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(resultNodes, expectedNodes) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", expectedNodes, resultNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestTopNodeAllMetricsFromMetricsServer(t *testing.T) {
|
func TestTopNodeAllMetricsFromMetricsServer(t *testing.T) {
|
||||||
cmdtesting.InitTestErrorHandler(t)
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
expectedMetrics, nodes := testNodeV1beta1MetricsData()
|
expectedMetrics, nodes := testNodeV1beta1MetricsData()
|
||||||
@ -494,3 +636,175 @@ func TestTopNodeWithLabelSelectorMetricsFromMetricsServer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTopNodeWithSortByCpuMetricsFromMetricsServer(t *testing.T) {
|
||||||
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
|
metrics, nodes := testNodeV1beta1MetricsData()
|
||||||
|
expectedMetrics := &metricsv1beta1api.NodeMetricsList{
|
||||||
|
ListMeta: metrics.ListMeta,
|
||||||
|
Items: metrics.Items[:],
|
||||||
|
}
|
||||||
|
expectedNodes := v1.NodeList{
|
||||||
|
ListMeta: nodes.ListMeta,
|
||||||
|
Items: nodes.Items[:],
|
||||||
|
}
|
||||||
|
expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
|
||||||
|
expectedNodesNames := []string{"node2", "node3", "node1"}
|
||||||
|
|
||||||
|
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||||
|
defer tf.Cleanup()
|
||||||
|
|
||||||
|
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||||
|
ns := scheme.Codecs
|
||||||
|
|
||||||
|
tf.Client = &fake.RESTClient{
|
||||||
|
NegotiatedSerializer: ns,
|
||||||
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/api":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
|
||||||
|
case p == "/apis":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
|
||||||
|
case p == expectedNodePath && m == "GET":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &expectedNodes)}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\nGot URL: %#v\n", req, req.URL)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
fakemetricsClientset := &metricsfake.Clientset{}
|
||||||
|
fakemetricsClientset.AddReactor("list", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||||
|
return true, expectedMetrics, nil
|
||||||
|
})
|
||||||
|
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
|
||||||
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
|
|
||||||
|
cmd := NewCmdTopNode(tf, nil, streams)
|
||||||
|
cmd.Flags().Set("sort-by", "cpu")
|
||||||
|
|
||||||
|
// TODO in the long run, we want to test most of our commands like this. Wire the options struct with specific mocks
|
||||||
|
// TODO then check the particular Run functionality and harvest results from fake clients
|
||||||
|
cmdOptions := &TopNodeOptions{
|
||||||
|
IOStreams: streams,
|
||||||
|
SortBy: "cpu",
|
||||||
|
}
|
||||||
|
if err := cmdOptions.Complete(tf, cmd, []string{}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cmdOptions.MetricsClient = fakemetricsClientset
|
||||||
|
if err := cmdOptions.Validate(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := cmdOptions.RunTopNode(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the presence of node names in the output.
|
||||||
|
result := buf.String()
|
||||||
|
|
||||||
|
for _, m := range expectedMetrics.Items {
|
||||||
|
if !strings.Contains(result, m.Name) {
|
||||||
|
t.Errorf("missing metrics for %s: \n%s", m.Name, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultNodes := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultNodes[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(resultNodes, expectedNodesNames) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", expectedNodesNames, resultNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTopNodeWithSortByMemoryMetricsFromMetricsServer(t *testing.T) {
|
||||||
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
|
metrics, nodes := testNodeV1beta1MetricsData()
|
||||||
|
expectedMetrics := &metricsv1beta1api.NodeMetricsList{
|
||||||
|
ListMeta: metrics.ListMeta,
|
||||||
|
Items: metrics.Items[:],
|
||||||
|
}
|
||||||
|
expectedNodes := v1.NodeList{
|
||||||
|
ListMeta: nodes.ListMeta,
|
||||||
|
Items: nodes.Items[:],
|
||||||
|
}
|
||||||
|
expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
|
||||||
|
expectedNodesNames := []string{"node2", "node3", "node1"}
|
||||||
|
|
||||||
|
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||||
|
defer tf.Cleanup()
|
||||||
|
|
||||||
|
codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
|
||||||
|
ns := scheme.Codecs
|
||||||
|
|
||||||
|
tf.Client = &fake.RESTClient{
|
||||||
|
NegotiatedSerializer: ns,
|
||||||
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
switch p, m := req.URL.Path, req.Method; {
|
||||||
|
case p == "/api":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
|
||||||
|
case p == "/apis":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
|
||||||
|
case p == expectedNodePath && m == "GET":
|
||||||
|
return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &expectedNodes)}, nil
|
||||||
|
default:
|
||||||
|
t.Fatalf("unexpected request: %#v\nGot URL: %#v\n", req, req.URL)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
fakemetricsClientset := &metricsfake.Clientset{}
|
||||||
|
fakemetricsClientset.AddReactor("list", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
|
||||||
|
return true, expectedMetrics, nil
|
||||||
|
})
|
||||||
|
tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
|
||||||
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
|
|
||||||
|
cmd := NewCmdTopNode(tf, nil, streams)
|
||||||
|
cmd.Flags().Set("sort-by", "memory")
|
||||||
|
|
||||||
|
// TODO in the long run, we want to test most of our commands like this. Wire the options struct with specific mocks
|
||||||
|
// TODO then check the particular Run functionality and harvest results from fake clients
|
||||||
|
cmdOptions := &TopNodeOptions{
|
||||||
|
IOStreams: streams,
|
||||||
|
SortBy: "memory",
|
||||||
|
}
|
||||||
|
if err := cmdOptions.Complete(tf, cmd, []string{}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cmdOptions.MetricsClient = fakemetricsClientset
|
||||||
|
if err := cmdOptions.Validate(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := cmdOptions.RunTopNode(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the presence of node names in the output.
|
||||||
|
result := buf.String()
|
||||||
|
|
||||||
|
for _, m := range expectedMetrics.Items {
|
||||||
|
if !strings.Contains(result, m.Name) {
|
||||||
|
t.Errorf("missing metrics for %s: \n%s", m.Name, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultNodes := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultNodes[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(resultNodes, expectedNodesNames) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", expectedNodesNames, resultNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -96,6 +97,7 @@ func TestTopPod(t *testing.T) {
|
|||||||
args []string
|
args []string
|
||||||
expectedPath string
|
expectedPath string
|
||||||
expectedQuery string
|
expectedQuery string
|
||||||
|
expectedPods []string
|
||||||
namespaces []string
|
namespaces []string
|
||||||
containers bool
|
containers bool
|
||||||
listsNamespaces bool
|
listsNamespaces bool
|
||||||
@ -141,6 +143,20 @@ func TestTopPod(t *testing.T) {
|
|||||||
namespaces: []string{testNS},
|
namespaces: []string{testNS},
|
||||||
containers: true,
|
containers: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "pod with label sort by cpu",
|
||||||
|
flags: map[string]string{"sort-by": "cpu"},
|
||||||
|
expectedPath: topPathPrefix + "/namespaces/" + testNS + "/pods",
|
||||||
|
expectedPods: []string{"pod2", "pod3", "pod1"},
|
||||||
|
namespaces: []string{testNS, testNS, testNS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pod with label sort by memory",
|
||||||
|
flags: map[string]string{"sort-by": "memory"},
|
||||||
|
expectedPath: topPathPrefix + "/namespaces/" + testNS + "/pods",
|
||||||
|
expectedPods: []string{"pod2", "pod3", "pod1"},
|
||||||
|
namespaces: []string{testNS, testNS, testNS},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cmdtesting.InitTestErrorHandler(t)
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
@ -210,6 +226,7 @@ func TestTopPod(t *testing.T) {
|
|||||||
|
|
||||||
// Check the presence of pod names&namespaces/container names in the output.
|
// Check the presence of pod names&namespaces/container names in the output.
|
||||||
result := buf.String()
|
result := buf.String()
|
||||||
|
|
||||||
if testCase.containers {
|
if testCase.containers {
|
||||||
for _, containerName := range expectedContainerNames {
|
for _, containerName := range expectedContainerNames {
|
||||||
if !strings.Contains(result, containerName) {
|
if !strings.Contains(result, containerName) {
|
||||||
@ -233,6 +250,19 @@ func TestTopPod(t *testing.T) {
|
|||||||
if cmdutil.GetFlagBool(cmd, "no-headers") && strings.Contains(result, "MEMORY") {
|
if cmdutil.GetFlagBool(cmd, "no-headers") && strings.Contains(result, "MEMORY") {
|
||||||
t.Errorf("%s: unexpected headers with no-headers option set: \n%s", testCase.name, result)
|
t.Errorf("%s: unexpected headers with no-headers option set: \n%s", testCase.name, result)
|
||||||
}
|
}
|
||||||
|
if cmdutil.GetFlagString(cmd, "sort-by") == "cpu" || cmdutil.GetFlagString(cmd, "sort-by") == "memory" {
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultPods := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultPods[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(testCase.expectedPods, resultPods) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", testCase.expectedPods, resultPods)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,6 +276,7 @@ func TestTopPodWithMetricsServer(t *testing.T) {
|
|||||||
args []string
|
args []string
|
||||||
expectedPath string
|
expectedPath string
|
||||||
expectedQuery string
|
expectedQuery string
|
||||||
|
expectedPods []string
|
||||||
namespaces []string
|
namespaces []string
|
||||||
containers bool
|
containers bool
|
||||||
listsNamespaces bool
|
listsNamespaces bool
|
||||||
@ -283,6 +314,20 @@ func TestTopPodWithMetricsServer(t *testing.T) {
|
|||||||
namespaces: []string{testNS},
|
namespaces: []string{testNS},
|
||||||
containers: true,
|
containers: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "pod with label sort by cpu",
|
||||||
|
options: &TopPodOptions{SortBy: "cpu"},
|
||||||
|
expectedPath: topPathPrefix + "/namespaces/" + testNS + "/pods",
|
||||||
|
expectedPods: []string{"pod2", "pod3", "pod1"},
|
||||||
|
namespaces: []string{testNS, testNS, testNS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pod with label sort by memory",
|
||||||
|
options: &TopPodOptions{SortBy: "memory"},
|
||||||
|
expectedPath: topPathPrefix + "/namespaces/" + testNS + "/pods",
|
||||||
|
expectedPods: []string{"pod2", "pod3", "pod1"},
|
||||||
|
namespaces: []string{testNS, testNS, testNS},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cmdtesting.InitTestErrorHandler(t)
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
@ -387,6 +432,19 @@ func TestTopPodWithMetricsServer(t *testing.T) {
|
|||||||
t.Errorf("unexpected metrics for %s: \n%s", name, result)
|
t.Errorf("unexpected metrics for %s: \n%s", name, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cmdutil.GetFlagString(cmd, "sort-by") == "cpu" || cmdutil.GetFlagString(cmd, "sort-by") == "memory" {
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultPods := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultPods[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(testCase.expectedPods, resultPods) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", testCase.expectedPods, resultPods)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,6 +513,7 @@ func TestTopPodCustomDefaults(t *testing.T) {
|
|||||||
args []string
|
args []string
|
||||||
expectedPath string
|
expectedPath string
|
||||||
expectedQuery string
|
expectedQuery string
|
||||||
|
expectedPods []string
|
||||||
namespaces []string
|
namespaces []string
|
||||||
containers bool
|
containers bool
|
||||||
listsNamespaces bool
|
listsNamespaces bool
|
||||||
@ -492,6 +551,20 @@ func TestTopPodCustomDefaults(t *testing.T) {
|
|||||||
namespaces: []string{testNS},
|
namespaces: []string{testNS},
|
||||||
containers: true,
|
containers: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "pod with label sort by cpu",
|
||||||
|
flags: map[string]string{"sort-by": "cpu"},
|
||||||
|
expectedPath: customTopPathPrefix + "/namespaces/" + testNS + "/pods",
|
||||||
|
expectedPods: []string{"pod2", "pod3", "pod1"},
|
||||||
|
namespaces: []string{testNS, testNS, testNS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pod with label sort by memory",
|
||||||
|
flags: map[string]string{"sort-by": "memory"},
|
||||||
|
expectedPath: customTopPathPrefix + "/namespaces/" + testNS + "/pods",
|
||||||
|
expectedPods: []string{"pod2", "pod3", "pod1"},
|
||||||
|
namespaces: []string{testNS, testNS, testNS},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cmdtesting.InitTestErrorHandler(t)
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
@ -590,6 +663,19 @@ func TestTopPodCustomDefaults(t *testing.T) {
|
|||||||
t.Errorf("%s: unexpected metrics for %s: \n%s", testCase.name, name, result)
|
t.Errorf("%s: unexpected metrics for %s: \n%s", testCase.name, name, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cmdutil.GetFlagString(cmd, "sort-by") == "cpu" || cmdutil.GetFlagString(cmd, "sort-by") == "memory" {
|
||||||
|
resultLines := strings.Split(result, "\n")
|
||||||
|
resultPods := make([]string, len(resultLines)-2) // don't process first (header) and last (empty) line
|
||||||
|
|
||||||
|
for i, line := range resultLines[1 : len(resultLines)-1] { // don't process first (header) and last (empty) line
|
||||||
|
lineFirstColumn := strings.Split(line, " ")[0]
|
||||||
|
resultPods[i] = lineFirstColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(testCase.expectedPods, resultPods) {
|
||||||
|
t.Errorf("kinds not matching:\n\texpectedKinds: %v\n\tgotKinds: %v\n", testCase.expectedPods, resultPods)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,15 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
|
|||||||
v1.ResourceStorage: *resource.NewQuantity(7*(1024*1024), resource.DecimalSI),
|
v1.ResourceStorage: *resource.NewQuantity(7*(1024*1024), resource.DecimalSI),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "node3", ResourceVersion: "11"},
|
||||||
|
Window: metav1.Duration{Duration: time.Minute},
|
||||||
|
Usage: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: *resource.NewMilliQuantity(3, resource.DecimalSI),
|
||||||
|
v1.ResourceMemory: *resource.NewQuantity(4*(1024*1024), resource.DecimalSI),
|
||||||
|
v1.ResourceStorage: *resource.NewQuantity(5*(1024*1024), resource.DecimalSI),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
nodes := &v1.NodeList{
|
nodes := &v1.NodeList{
|
||||||
@ -168,6 +177,16 @@ func testNodeV1beta1MetricsData() (*metricsv1beta1api.NodeMetricsList, *v1.NodeL
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "node3", ResourceVersion: "11"},
|
||||||
|
Status: v1.NodeStatus{
|
||||||
|
Allocatable: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: *resource.NewMilliQuantity(30, resource.DecimalSI),
|
||||||
|
v1.ResourceMemory: *resource.NewQuantity(40*(1024*1024), resource.DecimalSI),
|
||||||
|
v1.ResourceStorage: *resource.NewQuantity(50*(1024*1024), resource.DecimalSI),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return metrics, nodes
|
return metrics, nodes
|
||||||
|
@ -64,6 +64,7 @@ func (n *NodeMetricsSorter) Len() int {
|
|||||||
|
|
||||||
func (n *NodeMetricsSorter) Swap(i, j int) {
|
func (n *NodeMetricsSorter) Swap(i, j int) {
|
||||||
n.metrics[i], n.metrics[j] = n.metrics[j], n.metrics[i]
|
n.metrics[i], n.metrics[j] = n.metrics[j], n.metrics[i]
|
||||||
|
n.usages[i], n.usages[j] = n.usages[j], n.usages[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeMetricsSorter) Less(i, j int) bool {
|
func (n *NodeMetricsSorter) Less(i, j int) bool {
|
||||||
@ -71,7 +72,7 @@ func (n *NodeMetricsSorter) Less(i, j int) bool {
|
|||||||
case "cpu":
|
case "cpu":
|
||||||
qi := n.usages[i][v1.ResourceCPU]
|
qi := n.usages[i][v1.ResourceCPU]
|
||||||
qj := n.usages[j][v1.ResourceCPU]
|
qj := n.usages[j][v1.ResourceCPU]
|
||||||
return qi.Value() > qj.Value()
|
return qi.MilliValue() > qj.MilliValue()
|
||||||
case "memory":
|
case "memory":
|
||||||
qi := n.usages[i][v1.ResourceMemory]
|
qi := n.usages[i][v1.ResourceMemory]
|
||||||
qj := n.usages[j][v1.ResourceMemory]
|
qj := n.usages[j][v1.ResourceMemory]
|
||||||
@ -109,6 +110,7 @@ func (p *PodMetricsSorter) Len() int {
|
|||||||
|
|
||||||
func (p *PodMetricsSorter) Swap(i, j int) {
|
func (p *PodMetricsSorter) Swap(i, j int) {
|
||||||
p.metrics[i], p.metrics[j] = p.metrics[j], p.metrics[i]
|
p.metrics[i], p.metrics[j] = p.metrics[j], p.metrics[i]
|
||||||
|
p.podMetrics[i], p.podMetrics[j] = p.podMetrics[j], p.podMetrics[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PodMetricsSorter) Less(i, j int) bool {
|
func (p *PodMetricsSorter) Less(i, j int) bool {
|
||||||
@ -116,7 +118,7 @@ func (p *PodMetricsSorter) Less(i, j int) bool {
|
|||||||
case "cpu":
|
case "cpu":
|
||||||
qi := p.podMetrics[i][v1.ResourceCPU]
|
qi := p.podMetrics[i][v1.ResourceCPU]
|
||||||
qj := p.podMetrics[j][v1.ResourceCPU]
|
qj := p.podMetrics[j][v1.ResourceCPU]
|
||||||
return qi.Value() > qj.Value()
|
return qi.MilliValue() > qj.MilliValue()
|
||||||
case "memory":
|
case "memory":
|
||||||
qi := p.podMetrics[i][v1.ResourceMemory]
|
qi := p.podMetrics[i][v1.ResourceMemory]
|
||||||
qj := p.podMetrics[j][v1.ResourceMemory]
|
qj := p.podMetrics[j][v1.ResourceMemory]
|
||||||
|
Loading…
Reference in New Issue
Block a user