ci: add retries to endpoints integration test (#7569)

Endpoints test can be flakey when endpoints do not come up fast enough.
This change adds a retry per endpoint. Fixes #7540.

* Add retry per-authority

* Bump timeout to 5 seconds

* Delete golden files

* Change template to regex capture in fixtures

Signed-off-by: Matei David <matei@buoyant.io>
This commit is contained in:
Matei David 2022-01-10 14:50:31 +00:00 committed by GitHub
parent f8c07ff1e6
commit 8ec18ae91c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 102 additions and 93 deletions

View File

@ -1,20 +1,26 @@
package endpoints
import (
"bytes"
"context"
"fmt"
"os"
"regexp"
"strings"
"testing"
"text/template"
"time"
"github.com/linkerd/linkerd2/testutil"
)
var TestHelper *testutil.TestHelper
type testCase struct {
name string
authority string
expectedRE string
ns string
}
func TestMain(m *testing.M) {
TestHelper = testutil.NewTestHelper()
os.Exit(m.Run())
@ -23,19 +29,9 @@ func TestMain(m *testing.M) {
func TestGoodEndpoints(t *testing.T) {
ctx := context.Background()
controlNs := TestHelper.GetLinkerdNamespace()
testDataPath := "testdata"
cmd := []string{
"diagnostics",
"endpoints",
fmt.Sprintf("linkerd-dst.%s.svc.cluster.local:8086", controlNs),
fmt.Sprintf("linkerd-identity.%s.svc.cluster.local:8080", controlNs),
fmt.Sprintf("linkerd-proxy-injector.%s.svc.cluster.local:443", controlNs),
fmt.Sprintf("nginx.%s.svc.cluster.local:8080", "linkerd-endpoints-test"),
"-ojson",
}
TestHelper.WithDataPlaneNamespace(ctx, "endpoints-test", map[string]string{}, t, func(t *testing.T, ns string) {
out, err := TestHelper.Kubectl("", "apply", "-f", fmt.Sprintf("%s/%s", testDataPath, "nginx.yaml"), "-n", ns)
out, err := TestHelper.Kubectl("", "apply", "-f", "testdata/nginx.yaml", "-n", ns)
if err != nil {
testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v output:\n%s", err, out)
}
@ -49,28 +45,40 @@ func TestGoodEndpoints(t *testing.T) {
}
}
out, err = TestHelper.LinkerdRun(cmd...)
if err != nil {
testutil.AnnotatedFatal(t, "unexpected error", err)
endpointCases := createTestCaseTable(controlNs, ns)
for _, endpointCase := range endpointCases {
testName := fmt.Sprintf("expect endpoints created for %s", endpointCase.name)
t.Run(testName, func(t *testing.T) {
err = TestHelper.RetryFor(5*time.Second, func() error {
out, err = TestHelper.LinkerdRun("diagnostics", "endpoints", endpointCase.authority, "-ojson")
if err != nil {
return fmt.Errorf("failed to get endpoints for %s: %s", endpointCase.authority, err)
}
re := regexp.MustCompile(endpointCase.expectedRE)
if !re.MatchString(out) {
return fmt.Errorf("endpoint data does not match pattern\nexpected output:\n%s\nactual:\n%s", endpointCase.expectedRE, out)
}
matches := re.FindStringSubmatch(out)
if matches == nil || len(matches) < 2 {
return fmt.Errorf("invalid endpoint data\nexpected: \n%s\nactual: \n%s", endpointCase.expectedRE, out)
}
namespaceMatch := matches[1]
if namespaceMatch != endpointCase.ns {
return fmt.Errorf("endpoint namespace does not match\nexpected: %s, actual: %s", endpointCase.ns, namespaceMatch)
}
return nil
})
if err != nil {
testutil.AnnotatedErrorf(t, "unexpected error", "unexpected error: %v", err)
}
})
}
tpl := template.Must(template.ParseFiles(testDataPath + "/linkerd_endpoints.golden"))
vars := struct {
Ns string
EndpointNs string
}{
controlNs,
ns,
}
var b bytes.Buffer
if err := tpl.Execute(&b, vars); err != nil {
testutil.AnnotatedFatalf(t, "failed to parse linkerd_endpoints.golden template", "failed to parse linkerd_endpoints.golden template: %s", err)
}
r := regexp.MustCompile(b.String())
if !r.MatchString(out) {
testutil.AnnotatedErrorf(t, "unexpected output", "expected output:\n%s\nactual:\n%s", b.String(), out)
}
})
}
@ -88,3 +96,64 @@ func TestBadEndpoints(t *testing.T) {
testutil.AnnotatedErrorf(t, "unexpected error string", "unexpected error string: %s", stderrOut[0])
}
}
func createTestCaseTable(controlNs, endpointNs string) []testCase {
return []testCase{
{
name: "linkerd-dst",
authority: fmt.Sprintf("linkerd-dst.%s.svc.cluster.local:8086", controlNs),
expectedRE: `\[
\{
"namespace": "(\S*)",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8086,
"pod": "linkerd\-destination\-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-dst\.\S*"
\}
\]`,
ns: controlNs,
},
{
name: "linkerd-identity",
authority: fmt.Sprintf("linkerd-identity.%s.svc.cluster.local:8080", controlNs),
expectedRE: `\[
\{
"namespace": "(\S*)",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8080,
"pod": "linkerd\-identity\-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-identity\.\S*"
\}
\]`,
ns: controlNs,
},
{
name: "linkerd-proxy-injector",
authority: fmt.Sprintf("linkerd-proxy-injector.%s.svc.cluster.local:443", controlNs),
expectedRE: `\[
\{
"namespace": "(\S*)",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8443,
"pod": "linkerd\-proxy\-injector-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-proxy\-injector\.\S*"
\}
\]`,
ns: controlNs,
},
{
name: "nginx",
authority: fmt.Sprintf("nginx.%s.svc.cluster.local:8080", endpointNs),
expectedRE: `\[
\{
"namespace": "(\S*)",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8080,
"pod": "nginx\-[a-f0-9]+\-[a-z0-9]+",
"service": "nginx\.\S*"
\}
\]`,
ns: endpointNs,
},
}
}

View File

@ -1,30 +0,0 @@
\[
\{
"namespace": "external\-prometheus",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 9090,
"pod": "prometheus\-[a-f0-9]+\-[a-z0-9]+",
"service": "prometheus.external\-prometheus"
\},
\{
"namespace": "{{.Ns}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8086,
"pod": "linkerd\-destination\-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-dst\.{{.Ns}}"
\},
\{
"namespace": "{{.Ns}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8080,
"pod": "linkerd\-identity\-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-identity\.{{.Ns}}"
\},
\{
"namespace": "{{.Ns}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8443,
"pod": "linkerd\-proxy\-injector-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-proxy\-injector\.{{.Ns}}"
\}
\]

View File

@ -1,30 +0,0 @@
\[
\{
"namespace": "{{.Ns}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8086,
"pod": "linkerd\-destination\-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-dst\.{{.Ns}}"
\},
\{
"namespace": "{{.Ns}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8080,
"pod": "linkerd\-identity\-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-identity\.{{.Ns}}"
\},
\{
"namespace": "{{.Ns}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8443,
"pod": "linkerd\-proxy\-injector-[a-f0-9]+\-[a-z0-9]+",
"service": "linkerd\-proxy\-injector\.{{.Ns}}"
\},
\{
"namespace": "{{.EndpointNs}}",
"ip": "\d+\.\d+\.\d+\.\d+",
"port": 8080,
"pod": "nginx\-[a-f0-9]+\-[a-z0-9]+",
"service": "nginx\.{{.EndpointNs}}"
\}
\]