1 package cmd
2
3 import (
4 "context"
5 "net/http"
6 "net/http/httptest"
7 "testing"
8 "time"
9
10 sp "github.com/linkerd/linkerd2/controller/gen/apis/serviceprofile/v1alpha2"
11 "github.com/linkerd/linkerd2/pkg/k8s"
12 "github.com/linkerd/linkerd2/pkg/profiles"
13 "github.com/linkerd/linkerd2/pkg/protohttp"
14 metricsPb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
15 tapPb "github.com/linkerd/linkerd2/viz/tap/gen/tap"
16 "github.com/linkerd/linkerd2/viz/tap/pkg"
17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18 )
19
20 func TestTapToServiceProfile(t *testing.T) {
21 name := "service-name"
22 namespace := "service-namespace"
23 clusterDomain := "service-cluster.local"
24 tapDuration := 5 * time.Second
25 routeLimit := 20
26
27 params := pkg.TapRequestParams{
28 Resource: "deploy/" + name,
29 Namespace: namespace,
30 }
31
32 tapReq, err := pkg.BuildTapByResourceRequest(params)
33 if err != nil {
34 t.Fatalf("Unexpected error: %v", err)
35 }
36
37 event1 := pkg.CreateTapEvent(
38 &tapPb.TapEvent_Http{
39 Event: &tapPb.TapEvent_Http_RequestInit_{
40
41 RequestInit: &tapPb.TapEvent_Http_RequestInit{
42 Id: &tapPb.TapEvent_Http_StreamId{
43 Base: 1,
44 },
45 Authority: "",
46 Path: "/emojivoto.v1.VotingService/VoteFire",
47 Method: &metricsPb.HttpMethod{
48 Type: &metricsPb.HttpMethod_Registered_{
49 Registered: metricsPb.HttpMethod_POST,
50 },
51 },
52 },
53 },
54 },
55 map[string]string{},
56 tapPb.TapEvent_INBOUND,
57 )
58
59 event2 := pkg.CreateTapEvent(
60 &tapPb.TapEvent_Http{
61 Event: &tapPb.TapEvent_Http_RequestInit_{
62
63 RequestInit: &tapPb.TapEvent_Http_RequestInit{
64 Id: &tapPb.TapEvent_Http_StreamId{
65 Base: 2,
66 },
67 Authority: "",
68 Path: "/my/path/hi",
69 Method: &metricsPb.HttpMethod{
70 Type: &metricsPb.HttpMethod_Registered_{
71 Registered: metricsPb.HttpMethod_GET,
72 },
73 },
74 },
75 },
76 },
77 map[string]string{},
78 tapPb.TapEvent_INBOUND,
79 )
80
81 kubeAPI, err := k8s.NewFakeAPI()
82 if err != nil {
83 t.Fatalf("Unexpected error: %v", err)
84 }
85 ts := httptest.NewServer(http.HandlerFunc(
86 func(w http.ResponseWriter, r *http.Request) {
87 for _, event := range []*tapPb.TapEvent{event1, event2} {
88 event := event
89 err = protohttp.WriteProtoToHTTPResponse(w, event)
90 if err != nil {
91 t.Fatalf("Unexpected error: %v", err)
92 }
93 }
94 }),
95 )
96 defer ts.Close()
97 kubeAPI.Config.Host = ts.URL
98
99 expectedServiceProfile := sp.ServiceProfile{
100 TypeMeta: profiles.ServiceProfileMeta,
101 ObjectMeta: metav1.ObjectMeta{
102 Name: name + "." + namespace + ".svc." + clusterDomain,
103 Namespace: namespace,
104 },
105 Spec: sp.ServiceProfileSpec{
106 Routes: []*sp.RouteSpec{
107 {
108 Name: "GET /my/path/hi",
109 Condition: &sp.RequestMatch{
110 PathRegex: `/my/path/hi`,
111 Method: "GET",
112 },
113 },
114 {
115 Name: "POST /emojivoto.v1.VotingService/VoteFire",
116 Condition: &sp.RequestMatch{
117 PathRegex: `/emojivoto\.v1\.VotingService/VoteFire`,
118 Method: "POST",
119 },
120 },
121 },
122 },
123 }
124
125 actualServiceProfile, err := tapToServiceProfile(context.Background(), kubeAPI, tapReq, namespace, name, clusterDomain, tapDuration, routeLimit)
126 if err != nil {
127 t.Fatalf("Failed to create ServiceProfile: %v", err)
128 }
129
130 err = profiles.ServiceProfileYamlEquals(actualServiceProfile, expectedServiceProfile)
131 if err != nil {
132 t.Fatalf("ServiceProfiles are not equal: %v", err)
133 }
134 }
135
View as plain text