...

Source file src/github.com/linkerd/linkerd2/viz/metrics-api/util/api_utils_test.go

Documentation: github.com/linkerd/linkerd2/viz/metrics-api/util

     1  package util
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/go-test/deep"
     7  	"github.com/linkerd/linkerd2/pkg/k8s"
     8  	pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
     9  	corev1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  )
    12  
    13  func TestBuildStatSummaryRequest(t *testing.T) {
    14  	t.Run("Maps Kubernetes friendly names to canonical names", func(t *testing.T) {
    15  		expectations := map[string]string{
    16  			"deployments": k8s.Deployment,
    17  			"deployment":  k8s.Deployment,
    18  			"deploy":      k8s.Deployment,
    19  			"pods":        k8s.Pod,
    20  			"pod":         k8s.Pod,
    21  			"po":          k8s.Pod,
    22  		}
    23  
    24  		for friendly, canonical := range expectations {
    25  			statSummaryRequest, err := BuildStatSummaryRequest(
    26  				StatsSummaryRequestParams{
    27  					StatsBaseRequestParams: StatsBaseRequestParams{
    28  						ResourceType: friendly,
    29  					},
    30  				},
    31  			)
    32  			if err != nil {
    33  				t.Fatalf("Unexpected error from BuildStatSummaryRequest [%s => %s]: %s", friendly, canonical, err)
    34  			}
    35  			if statSummaryRequest.Selector.Resource.Type != canonical {
    36  				t.Fatalf("Unexpected resource type from BuildStatSummaryRequest [%s => %s]: %s", friendly, canonical, statSummaryRequest.Selector.Resource.Type)
    37  			}
    38  		}
    39  	})
    40  
    41  	t.Run("Parses valid time windows", func(t *testing.T) {
    42  		expectations := []string{
    43  			"1m",
    44  			"60s",
    45  			"1m",
    46  		}
    47  
    48  		for _, timeWindow := range expectations {
    49  			statSummaryRequest, err := BuildStatSummaryRequest(
    50  				StatsSummaryRequestParams{
    51  					StatsBaseRequestParams: StatsBaseRequestParams{
    52  						TimeWindow:   timeWindow,
    53  						ResourceType: k8s.Deployment,
    54  					},
    55  				},
    56  			)
    57  			if err != nil {
    58  				t.Fatalf("Unexpected error from BuildStatSummaryRequest [%s => %s]", timeWindow, err)
    59  			}
    60  			if statSummaryRequest.TimeWindow != timeWindow {
    61  				t.Fatalf("Unexpected TimeWindow from BuildStatSummaryRequest [%s => %s]", timeWindow, statSummaryRequest.TimeWindow)
    62  			}
    63  		}
    64  	})
    65  
    66  	t.Run("Rejects invalid time windows", func(t *testing.T) {
    67  		expectations := map[string]string{
    68  			"1": "time: missing unit in duration \"1\"",
    69  			"s": "time: invalid duration \"s\"",
    70  		}
    71  
    72  		for timeWindow, msg := range expectations {
    73  			_, err := BuildStatSummaryRequest(
    74  				StatsSummaryRequestParams{
    75  					StatsBaseRequestParams: StatsBaseRequestParams{
    76  						TimeWindow: timeWindow,
    77  					},
    78  				},
    79  			)
    80  			if err == nil {
    81  				t.Fatalf("BuildStatSummaryRequest(%s) unexpectedly succeeded, should have returned %s", timeWindow, msg)
    82  			}
    83  			if err.Error() != msg {
    84  				t.Fatalf("BuildStatSummaryRequest(%s) should have returned: %s but got unexpected message: %s", timeWindow, msg, err)
    85  			}
    86  		}
    87  	})
    88  
    89  	t.Run("Rejects invalid Kubernetes resource types", func(t *testing.T) {
    90  		expectations := map[string]string{
    91  			"foo": "cannot find Kubernetes canonical name from friendly name [foo]",
    92  			"":    "cannot find Kubernetes canonical name from friendly name []",
    93  		}
    94  
    95  		for input, msg := range expectations {
    96  			_, err := BuildStatSummaryRequest(
    97  				StatsSummaryRequestParams{
    98  					StatsBaseRequestParams: StatsBaseRequestParams{
    99  						ResourceType: input,
   100  					},
   101  				},
   102  			)
   103  			if err == nil {
   104  				t.Fatalf("BuildStatSummaryRequest(%s) unexpectedly succeeded, should have returned %s", input, msg)
   105  			}
   106  			if err.Error() != msg {
   107  				t.Fatalf("BuildStatSummaryRequest(%s) should have returned: %s but got unexpected message: %s", input, msg, err)
   108  			}
   109  		}
   110  	})
   111  }
   112  
   113  func TestBuildTopRoutesRequest(t *testing.T) {
   114  	t.Run("Parses valid time windows", func(t *testing.T) {
   115  		expectations := []string{
   116  			"1m",
   117  			"60s",
   118  			"1m",
   119  		}
   120  
   121  		for _, timeWindow := range expectations {
   122  			topRoutesRequest, err := BuildTopRoutesRequest(
   123  				TopRoutesRequestParams{
   124  					StatsBaseRequestParams: StatsBaseRequestParams{
   125  						TimeWindow:   timeWindow,
   126  						ResourceType: k8s.Deployment,
   127  					},
   128  				},
   129  			)
   130  			if err != nil {
   131  				t.Fatalf("Unexpected error from BuildTopRoutesRequest [%s => %s]", timeWindow, err)
   132  			}
   133  			if topRoutesRequest.TimeWindow != timeWindow {
   134  				t.Fatalf("Unexpected TimeWindow from BuildTopRoutesRequest [%s => %s]", timeWindow, topRoutesRequest.TimeWindow)
   135  			}
   136  		}
   137  	})
   138  
   139  	t.Run("Rejects invalid time windows", func(t *testing.T) {
   140  		expectations := map[string]string{
   141  			"1": "time: missing unit in duration \"1\"",
   142  			"s": "time: invalid duration \"s\"",
   143  		}
   144  
   145  		for timeWindow, msg := range expectations {
   146  			_, err := BuildTopRoutesRequest(
   147  				TopRoutesRequestParams{
   148  					StatsBaseRequestParams: StatsBaseRequestParams{
   149  						TimeWindow:   timeWindow,
   150  						ResourceType: k8s.Deployment,
   151  					},
   152  				},
   153  			)
   154  			if err == nil {
   155  				t.Fatalf("BuildTopRoutesRequest(%s) unexpectedly succeeded, should have returned %s", timeWindow, msg)
   156  			}
   157  			if err.Error() != msg {
   158  				t.Fatalf("BuildTopRoutesRequest(%s) should have returned: %s but got unexpected message: %s", timeWindow, msg, err)
   159  			}
   160  		}
   161  	})
   162  }
   163  
   164  func TestK8sPodToPublicPod(t *testing.T) {
   165  	type podExp struct {
   166  		k8sPod    corev1.Pod
   167  		ownerKind string
   168  		ownerName string
   169  		publicPod *pb.Pod
   170  	}
   171  
   172  	t.Run("Returns expected pods", func(t *testing.T) {
   173  		expectations := []podExp{
   174  			{
   175  				k8sPod: corev1.Pod{},
   176  				publicPod: &pb.Pod{
   177  					Name: "/",
   178  				},
   179  			},
   180  			{
   181  				k8sPod: corev1.Pod{
   182  					ObjectMeta: metav1.ObjectMeta{
   183  						Namespace:       "ns",
   184  						Name:            "name",
   185  						ResourceVersion: "resource-version",
   186  						Labels: map[string]string{
   187  							k8s.ControllerComponentLabel: "controller-component",
   188  							k8s.ControllerNSLabel:        "controller-ns",
   189  						},
   190  					},
   191  					Spec: corev1.PodSpec{
   192  						Containers: []corev1.Container{
   193  							{
   194  								Name:  k8s.ProxyContainerName,
   195  								Image: "linkerd-proxy:test-version",
   196  							},
   197  						},
   198  					},
   199  					Status: corev1.PodStatus{
   200  						PodIP: "pod-ip",
   201  						Phase: "status",
   202  						ContainerStatuses: []corev1.ContainerStatus{
   203  							{
   204  								Name:  k8s.ProxyContainerName,
   205  								Ready: true,
   206  							},
   207  						},
   208  					},
   209  				},
   210  				ownerKind: k8s.Deployment,
   211  				ownerName: "owner-name",
   212  				publicPod: &pb.Pod{
   213  					Name:                "ns/name",
   214  					Owner:               &pb.Pod_Deployment{Deployment: "ns/owner-name"},
   215  					ResourceVersion:     "resource-version",
   216  					ControlPlane:        true,
   217  					ControllerNamespace: "controller-ns",
   218  					Status:              "status",
   219  					ProxyReady:          true,
   220  					ProxyVersion:        "test-version",
   221  					PodIP:               "pod-ip",
   222  				},
   223  			},
   224  			{
   225  				k8sPod: corev1.Pod{
   226  					Status: corev1.PodStatus{
   227  						Phase:  "Failed",
   228  						Reason: "Evicted",
   229  						ContainerStatuses: []corev1.ContainerStatus{
   230  							{
   231  								Name:  k8s.ProxyContainerName,
   232  								Ready: true,
   233  							},
   234  						},
   235  					},
   236  				},
   237  				ownerName: "owner-name",
   238  				publicPod: &pb.Pod{
   239  					Name:       "/",
   240  					Status:     "Evicted",
   241  					ProxyReady: true,
   242  				},
   243  			},
   244  		}
   245  
   246  		for _, exp := range expectations {
   247  			res := K8sPodToPublicPod(exp.k8sPod, exp.ownerKind, exp.ownerName)
   248  			if diff := deep.Equal(exp.publicPod, res); diff != nil {
   249  				t.Errorf("%v", diff)
   250  			}
   251  		}
   252  	})
   253  }
   254  

View as plain text