Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update Dynatrace provider to query metrics over a range #1658

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ type DynatraceData struct {
func (d *KeptnDynatraceProvider) EvaluateQuery(ctx context.Context, metric metricsapi.KeptnMetric, provider metricsapi.KeptnMetricsProvider) (string, []byte, error) {
baseURL := d.normalizeAPIURL(provider.Spec.TargetServer)
query := url.QueryEscape(metric.Spec.Query)
qURL := baseURL + "v2/metrics/query?metricSelector=" + query
var qURL string
if metric.Spec.Range != nil {
qURL = baseURL + "v2/metrics/query?metricSelector=" + query + "&from=now-" + metric.Spec.Range.Interval
} else {
qURL = baseURL + "v2/metrics/query?metricSelector=" + query
}

d.Log.Info("Running query: " + qURL)
ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func TestEvaluateQuery_CorrectHTTP(t *testing.T) {
require.Equal(t, 1, len(r.Header["Authorization"]))
}))
defer svr.Close()
kdp, obj := setupTest()
kdp, objects := setupTest()
p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
SecretKeyRef: v1.SecretKeySelector{
Expand All @@ -164,11 +164,12 @@ func TestEvaluateQuery_CorrectHTTP(t *testing.T) {
TargetServer: svr.URL,
},
}
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.True(t, errors.IsNotFound(e))
require.Equal(t, []byte(nil), raw)
require.Equal(t, "", r)

for _, obj := range objects {
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.True(t, errors.IsNotFound(e))
require.Equal(t, []byte(nil), raw)
require.Equal(t, "", r)
}
}

func TestEvaluateQuery_APIError(t *testing.T) {
Expand All @@ -188,7 +189,7 @@ func TestEvaluateQuery_APIError(t *testing.T) {
secretKey: []byte(secretValue),
},
}
kdp, obj := setupTest(apiToken)
kdp, objects := setupTest(apiToken)
p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
SecretKeyRef: v1.SecretKeySelector{
Expand All @@ -200,12 +201,14 @@ func TestEvaluateQuery_APIError(t *testing.T) {
TargetServer: svr.URL,
},
}
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.Equal(t, "", r)
t.Log(string(raw))
require.Equal(t, errorResponse, raw) //we still return the raw answer to help user debug
require.NotNil(t, e)
require.Contains(t, e.Error(), "Token is missing required scope.")
for _, obj := range objects {
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.Equal(t, "", r)
t.Log(string(raw))
require.Equal(t, errorResponse, raw) //we still return the raw answer to help user debug
require.NotNil(t, e)
require.Contains(t, e.Error(), "Token is missing required scope.")
}
}

func TestEvaluateQuery_WrongPayloadHandling(t *testing.T) {
Expand All @@ -225,7 +228,7 @@ func TestEvaluateQuery_WrongPayloadHandling(t *testing.T) {
},
}

kdp, obj := setupTest(apiToken)
kdp, objects := setupTest(apiToken)
p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
SecretKeyRef: v1.SecretKeySelector{
Expand All @@ -237,11 +240,13 @@ func TestEvaluateQuery_WrongPayloadHandling(t *testing.T) {
TargetServer: svr.URL,
},
}
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.Equal(t, "", r)
t.Log(string(raw), e)
require.Equal(t, []byte("garbage"), raw) //we still return the raw answer to help user debug
require.NotNil(t, e)
for _, obj := range objects {
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.Equal(t, "", r)
t.Log(string(raw), e)
require.Equal(t, []byte("garbage"), raw) //we still return the raw answer to help user debug
require.NotNil(t, e)
}
}

func TestEvaluateQuery_MissingSecret(t *testing.T) {
Expand All @@ -250,16 +255,18 @@ func TestEvaluateQuery_MissingSecret(t *testing.T) {
require.Nil(t, err)
}))
defer svr.Close()
kdp, obj := setupTest()
kdp, objects := setupTest()

p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
TargetServer: svr.URL,
},
}
_, _, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.NotNil(t, e)
require.ErrorIs(t, e, ErrSecretKeyRefNotDefined)
for _, obj := range objects {
_, _, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.NotNil(t, e)
require.ErrorIs(t, e, ErrSecretKeyRefNotDefined)
}
}

func TestEvaluateQuery_SecretNotFound(t *testing.T) {
Expand All @@ -268,7 +275,7 @@ func TestEvaluateQuery_SecretNotFound(t *testing.T) {
require.Nil(t, err)
}))
defer svr.Close()
kdp, obj := setupTest()
kdp, objects := setupTest()

p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
Expand All @@ -281,9 +288,11 @@ func TestEvaluateQuery_SecretNotFound(t *testing.T) {
TargetServer: svr.URL,
},
}
_, _, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.NotNil(t, e)
require.True(t, errors.IsNotFound(e))
for _, obj := range objects {
_, _, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.NotNil(t, e)
require.True(t, errors.IsNotFound(e))
}
}

func TestEvaluateQuery_RefNotExistingKey(t *testing.T) {
Expand All @@ -302,7 +311,7 @@ func TestEvaluateQuery_RefNotExistingKey(t *testing.T) {
secretKey: []byte(secretValue),
},
}
kdp, obj := setupTest(apiToken)
kdp, objects := setupTest(apiToken)

missingKey := "key_not_found"
p := metricsapi.KeptnMetricsProvider{
Expand All @@ -316,10 +325,11 @@ func TestEvaluateQuery_RefNotExistingKey(t *testing.T) {
TargetServer: svr.URL,
},
}

_, _, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.NotNil(t, e)
require.True(t, strings.Contains(e.Error(), "invalid key "+missingKey))
for _, obj := range objects {
_, _, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.NotNil(t, e)
require.True(t, strings.Contains(e.Error(), "invalid key "+missingKey))
}
}

func TestEvaluateQuery_HappyPath(t *testing.T) {
thisthat marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -338,7 +348,46 @@ func TestEvaluateQuery_HappyPath(t *testing.T) {
secretKey: []byte(secretValue),
},
}
kdp, obj := setupTest(apiToken)
kdp, objects := setupTest(apiToken)

p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
SecretKeyRef: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: secretName,
},
Key: secretKey,
},
TargetServer: svr.URL,
},
}
for _, obj := range objects {
r, raw, e := kdp.EvaluateQuery(context.TODO(), obj, p)
require.Nil(t, e)
require.Equal(t, []byte(dtpayload), raw)
require.Equal(t, fmt.Sprintf("%f", 50.0), r)
}
}

func TestEvaluateQuery_HappyPathForTimerange(t *testing.T) {
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(dtpayload))
p := r.URL.Query().Get("from")
require.NotNil(t, p)
require.Nil(t, err)
}))
defer svr.Close()
secretName, secretKey, secretValue := "secretName", "secretKey", "secretValue"
apiToken := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: "",
},
Data: map[string][]byte{
secretKey: []byte(secretValue),
},
}
kdp, obj := setupTestForTimerange(apiToken)

p := metricsapi.KeptnMetricsProvider{
Spec: metricsapi.KeptnMetricsProviderSpec{
Expand All @@ -357,7 +406,32 @@ func TestEvaluateQuery_HappyPath(t *testing.T) {
require.Equal(t, fmt.Sprintf("%f", 50.0), r)
}

func setupTest(objs ...client.Object) (KeptnDynatraceProvider, metricsapi.KeptnMetric) {
func setupTest(objs ...client.Object) (KeptnDynatraceProvider, []metricsapi.KeptnMetric) {

fakeClient := fake.NewClient(objs...)

kdp := KeptnDynatraceProvider{
HttpClient: http.Client{},
Log: ctrl.Log.WithName("testytest"),
K8sClient: fakeClient,
}
objects := []metricsapi.KeptnMetric{
{
Spec: metricsapi.KeptnMetricSpec{
Query: "my-query",
},
},
{
Spec: metricsapi.KeptnMetricSpec{
Query: "my-query",
Range: &metricsapi.RangeSpec{Interval: "5m"},
},
},
}
return kdp, objects
}

func setupTestForTimerange(objs ...client.Object) (KeptnDynatraceProvider, metricsapi.KeptnMetric) {

fakeClient := fake.NewClient(objs...)

Expand All @@ -369,6 +443,7 @@ func setupTest(objs ...client.Object) (KeptnDynatraceProvider, metricsapi.KeptnM
obj := metricsapi.KeptnMetric{
Spec: metricsapi.KeptnMetricSpec{
Query: "my-query",
Range: &metricsapi.RangeSpec{Interval: "5m"},
},
}
return kdp, obj
Expand Down
Loading