1 package endpoints
2
3 import (
4 "context"
5 "fmt"
6 "os"
7 "regexp"
8 "strings"
9 "testing"
10 "time"
11
12 "github.com/linkerd/linkerd2/testutil"
13 )
14
15 var TestHelper *testutil.TestHelper
16
17 type testCase struct {
18 name string
19 authority string
20 expectedRE string
21 ns string
22 }
23
24 func TestMain(m *testing.M) {
25 TestHelper = testutil.NewTestHelper()
26
27 TestHelper.WaitUntilDeployReady(testutil.LinkerdDeployReplicasEdge)
28 os.Exit(m.Run())
29 }
30
31 func TestGoodEndpoints(t *testing.T) {
32 ctx := context.Background()
33 controlNs := TestHelper.GetLinkerdNamespace()
34
35 TestHelper.WithDataPlaneNamespace(ctx, "endpoints-test", map[string]string{}, t, func(t *testing.T, ns string) {
36 out, err := TestHelper.Kubectl("", "apply", "-f", "testdata/nginx.yaml", "-n", ns)
37 if err != nil {
38 testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v output:\n%s", err, out)
39 }
40
41 err = TestHelper.CheckPods(ctx, ns, "nginx", 1)
42 if err != nil {
43
44 if rce, ok := err.(*testutil.RestartCountError); ok {
45 testutil.AnnotatedWarn(t, "CheckPods timed-out", rce)
46 } else {
47 testutil.AnnotatedError(t, "CheckPods timed-out", err)
48 }
49 }
50
51 endpointCases := createTestCaseTable(controlNs, ns)
52 for _, endpointCase := range endpointCases {
53 testName := fmt.Sprintf("expect endpoints created for %s", endpointCase.name)
54
55 t.Run(testName, func(t *testing.T) {
56 err = testutil.RetryFor(5*time.Second, func() error {
57 out, err = TestHelper.LinkerdRun("diagnostics", "endpoints", endpointCase.authority, "-ojson")
58 if err != nil {
59 return fmt.Errorf("failed to get endpoints for %s: %w", endpointCase.authority, err)
60 }
61
62 re := regexp.MustCompile(endpointCase.expectedRE)
63 if !re.MatchString(out) {
64 return fmt.Errorf("endpoint data does not match pattern\nexpected output:\n%s\nactual:\n%s", endpointCase.expectedRE, out)
65 }
66
67 matches := re.FindStringSubmatch(out)
68 if matches == nil || len(matches) < 2 {
69 return fmt.Errorf("invalid endpoint data\nexpected: \n%s\nactual: \n%s", endpointCase.expectedRE, out)
70 }
71
72 namespaceMatch := matches[1]
73 if namespaceMatch != endpointCase.ns {
74 return fmt.Errorf("endpoint namespace does not match\nexpected: %s, actual: %s", endpointCase.ns, namespaceMatch)
75 }
76
77 return nil
78 })
79 if err != nil {
80 testutil.AnnotatedErrorf(t, "unexpected error", "unexpected error: %v", err)
81 }
82 })
83 }
84
85 })
86 }
87
88
89 func TestBadEndpoints(t *testing.T) {
90 _, stderr, err := TestHelper.PipeToLinkerdRun("", "diagnostics", "endpoints", "foo")
91 if err == nil {
92 testutil.AnnotatedFatalf(t, "was expecting an error", "was expecting an error: %v", err)
93 }
94 stderrOut := strings.Split(stderr, "\n")
95 if len(stderrOut) == 0 {
96 testutil.AnnotatedFatalf(t, "unexpected output", "unexpected output: %s", stderr)
97 }
98 if stderrOut[0] != "Destination API error: Invalid authority: foo" {
99 testutil.AnnotatedErrorf(t, "unexpected error string", "unexpected error string: %s", stderrOut[0])
100 }
101 }
102
103 func createTestCaseTable(controlNs, endpointNs string) []testCase {
104 return []testCase{
105 {
106 name: "linkerd-dst",
107 authority: fmt.Sprintf("linkerd-dst.%s.svc.cluster.local:8086", controlNs),
108 expectedRE: `\[
109 \{
110 "namespace": "(\S*)",
111 "ip": "[a-f0-9.:]+",
112 "port": 8086,
113 "pod": "linkerd-destination\-[a-f0-9]+\-[a-z0-9]+",
114 "service": "linkerd-dst\.\S*",
115 "weight": \d+,
116 "http2": \{(?s).*\},
117 "labels": \{(?s).*\}
118 \}
119 \]`,
120 ns: controlNs,
121 },
122 {
123 name: "linkerd-identity",
124 authority: fmt.Sprintf("linkerd-identity.%s.svc.cluster.local:8080", controlNs),
125 expectedRE: `\[
126 \{
127 "namespace": "(\S*)",
128 "ip": "[a-f0-9.:]+",
129 "port": 8080,
130 "pod": "linkerd-identity\-[a-f0-9]+\-[a-z0-9]+",
131 "service": "linkerd-identity\.\S*",
132 "weight": \d+,
133 "http2": \{(?s).*\},
134 "labels": \{(?s).*\}
135 \}
136 \]`,
137 ns: controlNs,
138 },
139 {
140 name: "linkerd-proxy-injector",
141 authority: fmt.Sprintf("linkerd-proxy-injector.%s.svc.cluster.local:443", controlNs),
142 expectedRE: `\[
143 \{
144 "namespace": "(\S*)",
145 "ip": "[a-f0-9.:]+",
146 "port": 8443,
147 "pod": "linkerd-proxy-injector-[a-f0-9]+\-[a-z0-9]+",
148 "service": "linkerd-proxy-injector\.\S*",
149 "weight": \d+,
150 "http2": \{(?s).*\},
151 "labels": \{(?s).*\}
152 \}
153 \]`,
154 ns: controlNs,
155 },
156 {
157 name: "nginx",
158 authority: fmt.Sprintf("nginx.%s.svc.cluster.local:8080", endpointNs),
159 expectedRE: `\[
160 \{
161 "namespace": "(\S*)",
162 "ip": "[a-f0-9.:]+",
163 "port": 8080,
164 "pod": "nginx-[a-f0-9]+\-[a-z0-9]+",
165 "service": "nginx\.\S*",
166 "weight": \d+,
167 "http2": \{(?s).*\},
168 "labels": \{(?s).*\}
169 \}
170 \]`,
171 ns: endpointNs,
172 },
173 }
174 }
175
View as plain text