linkerd2/test/integration/smimetrics/smi-metrics_test.go

167 lines
4.3 KiB
Go

package smimetrics
import (
"context"
"encoding/json"
"fmt"
"os"
"testing"
"time"
"github.com/linkerd/linkerd2/testutil"
"github.com/servicemeshinterface/smi-sdk-go/pkg/apis/metrics/v1alpha1"
)
var TestHelper *testutil.TestHelper
type testCase struct {
name string
kind string
// edges > 0 denotes that its a edges query, otherwise a resource query
edges int
}
func TestMain(m *testing.M) {
TestHelper = testutil.NewTestHelper()
os.Exit(testutil.Run(m, TestHelper))
}
func TestSMIMetrics(t *testing.T) {
ctx := context.Background()
if os.Getenv("RUN_ARM_TEST") != "" {
t.Skip("Skipped. SMI-metrics image does not support ARM yet")
}
// Install smi-metrics using Helm chart
testNamespace := TestHelper.GetTestNamespace("smi-metrics-test")
err := TestHelper.CreateDataPlaneNamespaceIfNotExists(ctx, testNamespace, nil)
if err != nil {
testutil.AnnotatedFatalf(t, "failed to create %s namespace: %s", testNamespace, err)
}
// Currently, SMI-Metrics Helm chart is saved locally and can be updated to a newer version
// by downloading from https://github.com/servicemeshinterface/smi-metrics/releases and
// moving the package here, along with a version bump below
args := []string{
"install",
"smi-metrics",
"smi-metrics-0.2.1.tgz",
"--set",
"adapter=linkerd",
"--namespace",
testNamespace,
}
if stdout, stderr, err := TestHelper.HelmRun(args...); err != nil {
testutil.AnnotatedFatalf(t, "'helm install' command failed\n%s\n%s\n%v", stdout, stderr, err)
}
if err := TestHelper.CheckPods(ctx, testNamespace, "smi-metrics", 1); err != nil {
if rce, ok := err.(*testutil.RestartCountError); ok {
testutil.AnnotatedWarn(t, "CheckPods timed-out", rce)
} else {
testutil.AnnotatedError(t, "CheckPods timed-out", err)
}
}
if err := TestHelper.CheckDeployment(ctx, testNamespace, "smi-metrics", 1); err != nil {
testutil.AnnotatedErrorf(t, "CheckDeployment timed-out", "error validating deployment [%s]:\n%s", "terminus", err)
}
testCases := []testCase{
{
name: "linkerd-controller",
kind: "deployments",
},
{
name: "linkerd-destination",
kind: "deployments",
},
{
name: "linkerd-prometheus",
kind: "deployments",
},
{
name: "linkerd-destination",
kind: "deployments",
edges: 2,
},
{
name: "linkerd-identity",
kind: "deployments",
edges: 1,
},
}
timeout := 50 * time.Second
// check resource queries
for _, tc := range testCases {
tc := tc // pin
err = TestHelper.RetryFor(timeout, func() error {
queryURL := fmt.Sprintf("/apis/metrics.smi-spec.io/v1alpha1/namespaces/%s/%s/%s", TestHelper.GetLinkerdNamespace(), tc.kind, tc.name)
if tc.edges > 0 {
queryURL += "/edges"
}
queryArgs := []string{
"get",
"--raw",
queryURL,
}
out, err := TestHelper.Kubectl("", queryArgs...)
if err != nil {
return fmt.Errorf("failed to query smi-metrics URL %s: %s\n%s", queryURL, err, out)
}
if tc.edges > 0 {
// edges query
var metrics v1alpha1.TrafficMetricsList
err = json.Unmarshal([]byte(out), &metrics)
if err != nil {
return fmt.Errorf("failed to unmarshal output for query %s into TrafficMetricsList type: %s", queryURL, err)
}
if err = checkTrafficMetricsList(metrics, tc.name, tc.edges); err != nil {
return err
}
} else {
// resource query
var metrics v1alpha1.TrafficMetrics
err = json.Unmarshal([]byte(out), &metrics)
if err != nil {
return fmt.Errorf("failed to unmarshal output for query %s into TrafficMetrics type: %s", queryURL, err)
}
if err = checkTrafficMetrics(metrics, tc.name); err != nil {
return err
}
}
return nil
})
if err != nil {
testutil.AnnotatedError(t, fmt.Sprintf("timed-out checking smi-metrics output (%s)", timeout), err)
}
}
}
func checkTrafficMetrics(metrics v1alpha1.TrafficMetrics, name string) error {
if metrics.Name == name {
return nil
}
return fmt.Errorf("excpected %s, but got %s", name, metrics.Name)
}
func checkTrafficMetricsList(metrics v1alpha1.TrafficMetricsList, name string, numberOfEdges int) error {
if metrics.Resource.Name == name && len(metrics.Items) == numberOfEdges {
return nil
}
return fmt.Errorf("excpected %s with %d edges, but got %s with %d edges", name, numberOfEdges, metrics.Resource.Name, len(metrics.Items))
}