Alerting: Add api client to integration tests (#50970)

This commit is contained in:
Yuriy Tseretyan 2022-06-21 11:39:22 -04:00 committed by GitHub
parent 53714282cd
commit 53d03aec78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 289 additions and 392 deletions

View File

@ -38,7 +38,7 @@ func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) {
Login: "grafana",
Password: "password",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// create another organisation
orgID := createOrg(t, s, "another org", userID)
// ensure that the orgID is 3 (the disabled org)
@ -150,8 +150,7 @@ func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) {
// Now, let's set an alert that should fire as quickly as possible.
{
// Create the namespace we'll save our alerts to
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
interval, err := model.ParseDuration("10s")
require.NoError(t, err)

View File

@ -421,6 +421,8 @@ func TestAlertAndGroupsQuery(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// invalid credentials request to get the alerts should fail
{
alertsURL := fmt.Sprintf("http://grafana:invalid@%s/api/alertmanager/grafana/api/v2/alerts", grafanaListedAddr)
@ -476,9 +478,8 @@ func TestAlertAndGroupsQuery(t *testing.T) {
// Now, let's test the endpoint with some alerts.
{
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
apiClient.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
}
// Create an alert that will fire as quickly as possible
@ -511,20 +512,9 @@ func TestAlertAndGroupsQuery(t *testing.T) {
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
status, _ := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
}
// Eventually, we'll get an alert with its state being active.
@ -586,39 +576,40 @@ func TestRulerAccess(t *testing.T) {
Login: "admin",
})
client := newAlertingApiClient(grafanaListedAddr, "editor", "editor")
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "editor", "editor")
client.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "editor", "editor")
require.NoError(t, err)
// Now, let's test the access policies.
testCases := []struct {
desc string
url string
client apiClient
expStatus int
expectedMessage string
}{
{
desc: "un-authenticated request should fail",
url: "http://%s/api/ruler/grafana/api/v1/rules/default",
client: newAlertingApiClient(grafanaListedAddr, "", ""),
expStatus: http.StatusUnauthorized,
expectedMessage: `Unauthorized`,
},
{
desc: "viewer request should fail",
url: "http://viewer:viewer@%s/api/ruler/grafana/api/v1/rules/default",
client: newAlertingApiClient(grafanaListedAddr, "viewer", "viewer"),
expStatus: http.StatusForbidden,
expectedMessage: `You'll need additional permissions to perform this action. Permissions needed: any of alert.rules:write, alert.rules:create, alert.rules:delete`,
},
{
desc: "editor request should succeed",
url: "http://editor:editor@%s/api/ruler/grafana/api/v1/rules/default",
client: newAlertingApiClient(grafanaListedAddr, "editor", "editor"),
expStatus: http.StatusAccepted,
expectedMessage: `rule group updated successfully`,
},
{
desc: "admin request should succeed",
url: "http://admin:admin@%s/api/ruler/grafana/api/v1/rules/default",
client: newAlertingApiClient(grafanaListedAddr, "admin", "admin"),
expStatus: http.StatusAccepted,
expectedMessage: `rule group updated successfully`,
},
@ -661,25 +652,10 @@ func TestRulerAccess(t *testing.T) {
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf(tc.url, grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, tc.expStatus, resp.StatusCode)
status, body := tc.client.PostRulesGroup(t, "default", &rules)
assert.Equal(t, tc.expStatus, status)
res := &Response{}
err = json.Unmarshal(b, &res)
err = json.Unmarshal([]byte(body), &res)
require.NoError(t, err)
require.Equal(t, tc.expectedMessage, res.Message)
})
@ -710,13 +686,14 @@ func TestDeleteFolderWithRules(t *testing.T) {
Login: "editor",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "editor", "editor")
// Create the namespace we'll save our alerts to.
namespaceUID := "default"
err := createFolder(t, namespaceUID, grafanaListedAddr, "editor", "editor")
apiClient.CreateFolder(t, namespaceUID, namespaceUID)
reloadCachedPermissions(t, grafanaListedAddr, "editor", "editor")
require.NoError(t, err)
createRule(t, grafanaListedAddr, "default", "editor", "editor")
createRule(t, apiClient, "default")
// First, let's have an editor create a rule within the folder/namespace.
{
@ -865,9 +842,10 @@ func TestAlertRuleCRUD(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
interval, err := model.ParseDuration("1m")
@ -1093,30 +1071,15 @@ func TestAlertRuleCRUD(t *testing.T) {
tc.rule,
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err := enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
res := &Response{}
err = json.Unmarshal(b, &res)
err = json.Unmarshal([]byte(body), &res)
require.NoError(t, err)
assert.Equal(t, res.Message, tc.expectedMessage)
assert.NotEmpty(t, res.TraceID)
assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
assert.Equal(t, http.StatusBadRequest, status)
})
}
}
@ -1179,24 +1142,9 @@ func TestAlertRuleCRUD(t *testing.T) {
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err := enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
}
// With the rules created, let's make sure that rule definition is stored correctly.
@ -1359,14 +1307,17 @@ func TestAlertRuleCRUD(t *testing.T) {
},
Interval: interval,
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusNotFound, status)
var res map[string]interface{}
assert.NoError(t, json.Unmarshal([]byte(body), &res))
require.Equal(t, "failed to update rule group: failed to update rule with UID unknown because could not find alert rule", res["message"])
// let's make sure that rule definitions are not affected by the failed POST request.
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
resp, err := http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
@ -1375,23 +1326,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
var res map[string]interface{}
assert.NoError(t, json.Unmarshal(b, &res))
require.Equal(t, "failed to update rule group: failed to update rule with UID unknown because could not find alert rule", res["message"])
// let's make sure that rule definitions are not affected by the failed POST request.
u = fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err = ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
body, m := rulesNamespaceWithoutVariableValues(t, b)
@ -1480,14 +1414,16 @@ func TestAlertRuleCRUD(t *testing.T) {
},
Interval: interval,
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusBadRequest, status)
var res map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(body), &res))
require.Equal(t, fmt.Sprintf("rule [1] has UID %s that is already assigned to another rule at index 0", ruleUID), res["message"])
// let's make sure that rule definitions are not affected by the failed POST request.
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
resp, err := http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
@ -1496,23 +1432,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
var res map[string]interface{}
require.NoError(t, json.Unmarshal(b, &res))
require.Equal(t, fmt.Sprintf("rule [1] has UID %s that is already assigned to another rule at index 0", ruleUID), res["message"])
// let's make sure that rule definitions are not affected by the failed POST request.
u = fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err = ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
body, m := rulesNamespaceWithoutVariableValues(t, b)
@ -1569,14 +1488,14 @@ func TestAlertRuleCRUD(t *testing.T) {
},
Interval: interval,
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
// let's make sure that rule definitions are updated correctly.
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
resp, err := http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
@ -1585,21 +1504,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
// let's make sure that rule definitions are updated correctly.
u = fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err = ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
body, m := rulesNamespaceWithoutVariableValues(t, b)
@ -1701,14 +1605,14 @@ func TestAlertRuleCRUD(t *testing.T) {
},
Interval: interval,
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
// let's make sure that rule definitions are updated correctly.
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
resp, err := http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
@ -1717,21 +1621,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
// let's make sure that rule definitions are updated correctly.
u = fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err = ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
body, m := rulesNamespaceWithoutVariableValues(t, b)
@ -1801,14 +1690,14 @@ func TestAlertRuleCRUD(t *testing.T) {
},
Interval: interval,
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"no changes detected in the rule group"}`, body)
// let's make sure that rule definitions are updated correctly.
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
resp, err := http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
@ -1817,21 +1706,6 @@ func TestAlertRuleCRUD(t *testing.T) {
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
require.JSONEq(t, `{"message":"no changes detected in the rule group"}`, string(b))
// let's make sure that rule definitions are updated correctly.
u = fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err = ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
body, m := rulesNamespaceWithoutVariableValues(t, b)
@ -2009,17 +1883,16 @@ func TestQuota(t *testing.T) {
Password: "password",
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
interval, err := model.ParseDuration("1m")
require.NoError(t, err)
// Create rule under folder1
createRule(t, grafanaListedAddr, "default", "grafana", "password")
createRule(t, apiClient, "default")
// get the generated rule UID
var ruleUID string
@ -2100,24 +1973,10 @@ func TestQuota(t *testing.T) {
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusForbidden, resp.StatusCode)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusForbidden, status)
var res map[string]interface{}
require.NoError(t, json.Unmarshal(b, &res))
require.NoError(t, json.Unmarshal([]byte(body), &res))
require.Equal(t, "quota has been exceeded", res["message"])
})
@ -2150,14 +2009,15 @@ func TestQuota(t *testing.T) {
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
// let's make sure that rule definitions are updated correctly.
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
resp, err := http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
@ -2165,20 +2025,6 @@ func TestQuota(t *testing.T) {
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusAccepted, resp.StatusCode)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
// let's make sure that rule definitions are updated correctly.
u = fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(u)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err = ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
@ -2254,10 +2100,9 @@ func TestEval(t *testing.T) {
Password: "password",
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
// test eval conditions
testCases := []struct {
@ -2675,24 +2520,6 @@ func TestEval(t *testing.T) {
}
}
// createFolder creates a folder for storing our alerts under. Grafana uses folders as a replacement for alert namespaces to match its permission model.
// We use the dashboard command using IsFolder = true to tell it's a folder, it takes the dashboard as the name of the folder.
func createFolder(t *testing.T, folderUID, grafanaListedAddr, login, password string) error {
t.Helper()
payload := fmt.Sprintf(`{"uid": "%s","title": "%s"}`, folderUID, folderUID)
u := fmt.Sprintf("http://%s:%s@%s/api/folders", login, password, grafanaListedAddr)
r := strings.NewReader(payload)
// nolint:gosec
resp, err := http.Post(u, "application/json", r)
t.Cleanup(func() {
require.NoError(t, resp.Body.Close())
})
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
return err
}
// rulesNamespaceWithoutVariableValues takes a apimodels.NamespaceConfigResponse JSON-based input and makes the dynamic fields static e.g. uid, dates, etc.
// it returns a map of the modified rule UIDs with the namespace,rule_group as a key
func rulesNamespaceWithoutVariableValues(t *testing.T, b []byte) (string, map[string][]string) {

View File

@ -744,6 +744,8 @@ func TestNotificationChannels(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
{
// There are no notification channel config initially - so it returns the default configuration.
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr)
@ -755,8 +757,7 @@ func TestNotificationChannels(t *testing.T) {
{
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
// Post the alertmanager config.

View File

@ -41,9 +41,10 @@ func TestPrometheusRules(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// Create the namespace we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
interval, err := model.ParseDuration("10s")
@ -335,10 +336,10 @@ func TestPrometheusRulesFilterByDashboard(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// Create the namespace we'll save our alerts to.
dashboardUID := "default"
err := createFolder(t, dashboardUID, grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, dashboardUID, dashboardUID)
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
interval, err := model.ParseDuration("10s")
@ -630,24 +631,24 @@ func TestPrometheusRulesPermissions(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
// access control permissions store
permissionsStore := acdb.ProvideService(store)
// Create the namespace we'll save our alerts to.
err := createFolder(t, "folder1", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "folder1", "folder1")
// Create the namespace we'll save our alerts to.
err = createFolder(t, "folder2", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "folder2", "folder2")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
// Create rule under folder1
createRule(t, grafanaListedAddr, "folder1", "grafana", "password")
createRule(t, apiClient, "folder1")
// Create rule under folder2
createRule(t, grafanaListedAddr, "folder2", "grafana", "password")
createRule(t, apiClient, "folder2")
// Now, let's see how this looks like.
{

View File

@ -1,7 +1,6 @@
package alerting
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
@ -39,21 +38,20 @@ func TestAlertRulePermissions(t *testing.T) {
Login: "grafana",
})
// Create the namespace we'll save our alerts to.
err := createFolder(t, "folder1", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
err = createFolder(t, "folder2", grafanaListedAddr, "grafana", "password")
// Create the namespace we'll save our alerts to.
require.NoError(t, err)
apiClient.CreateFolder(t, "folder1", "folder1")
// Create the namespace we'll save our alerts to.
apiClient.CreateFolder(t, "folder2", "folder2")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
// Create rule under folder1
createRule(t, grafanaListedAddr, "folder1", "grafana", "password")
createRule(t, apiClient, "folder1")
// Create rule under folder2
createRule(t, grafanaListedAddr, "folder2", "grafana", "password")
createRule(t, apiClient, "folder2")
// With the rules created, let's make sure that rule definitions are stored.
{
@ -270,7 +268,7 @@ func TestAlertRulePermissions(t *testing.T) {
}
}
func createRule(t *testing.T, grafanaListedAddr string, folder string, user, password string) {
func createRule(t *testing.T, client apiClient, folder string) {
t.Helper()
interval, err := model.ParseDuration("1m")
@ -307,24 +305,9 @@ func createRule(t *testing.T, grafanaListedAddr string, folder string, user, pas
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://%s:%s@%s/api/ruler/grafana/api/v1/rules/%s", user, password, grafanaListedAddr, folder)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusAccepted, resp.StatusCode)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
status, body := client.PostRulesGroup(t, folder, &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
}
func TestAlertRuleConflictingTitle(t *testing.T) {
@ -347,70 +330,32 @@ func TestAlertRuleConflictingTitle(t *testing.T) {
Login: "admin",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "admin", "admin")
// Create the namespace we'll save our alerts to.
err := createFolder(t, "folder1", grafanaListedAddr, "admin", "admin")
require.NoError(t, err)
apiClient.CreateFolder(t, "folder1", "folder1")
// Create the namespace we'll save our alerts to.
err = createFolder(t, "folder2", grafanaListedAddr, "admin", "admin")
require.NoError(t, err)
apiClient.CreateFolder(t, "folder2", "folder2")
rules := newTestingRuleConfig(t)
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://admin:admin@%s/api/ruler/grafana/api/v1/rules/folder1", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusAccepted, resp.StatusCode)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
status, body := apiClient.PostRulesGroup(t, "folder1", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
// fetch the created rules, so we can get the uid's and trigger
// and update by reusing the uid's
resp, err = http.Get(u + "/" + rules.Name)
require.NoError(t, err)
var createdRuleGroup apimodels.GettableRuleGroupConfig
data, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
err = json.Unmarshal(data, &createdRuleGroup)
require.NoError(t, err)
createdRuleGroup := apiClient.GetRulesGroup(t, "folder1", rules.Name).GettableRuleGroupConfig
require.Len(t, createdRuleGroup.Rules, 2)
t.Run("trying to create alert with same title under same folder should fail", func(t *testing.T) {
rules := newTestingRuleConfig(t)
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://admin:admin@%s/api/ruler/grafana/api/v1/rules/folder1", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
status, body := apiClient.PostRulesGroup(t, "folder1", &rules)
assert.Equal(t, http.StatusInternalServerError, status)
var res map[string]interface{}
require.NoError(t, json.Unmarshal(b, &res))
require.NoError(t, json.Unmarshal([]byte(body), &res))
require.Equal(t, "failed to update rule group: failed to add rules: a conflicting alert rule is found: rule title under the same organisation and folder should be unique", res["message"])
})
@ -419,49 +364,20 @@ func TestAlertRuleConflictingTitle(t *testing.T) {
rules.Rules[0].GrafanaManagedAlert.UID = createdRuleGroup.Rules[0].GrafanaManagedAlert.UID
rules.Rules[1].GrafanaManagedAlert.UID = createdRuleGroup.Rules[1].GrafanaManagedAlert.UID
rules.Rules[1].GrafanaManagedAlert.Title = "AlwaysFiring"
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://admin:admin@%s/api/ruler/grafana/api/v1/rules/folder1", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
status, body := apiClient.PostRulesGroup(t, "folder1", &rules)
assert.Equal(t, http.StatusInternalServerError, status)
var res map[string]interface{}
require.NoError(t, json.Unmarshal(b, &res))
require.NoError(t, json.Unmarshal([]byte(body), &res))
require.Equal(t, "failed to update rule group: failed to update rules: a conflicting alert rule is found: rule title under the same organisation and folder should be unique", res["message"])
})
t.Run("trying to create alert with same title under another folder should succeed", func(t *testing.T) {
rules := newTestingRuleConfig(t)
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err = enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://admin:admin@%s/api/ruler/grafana/api/v1/rules/folder2", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusAccepted, resp.StatusCode)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
status, body := apiClient.PostRulesGroup(t, "folder2", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
})
}
@ -481,10 +397,12 @@ func TestRulerRulesFilterByDashboard(t *testing.T) {
Login: "grafana",
})
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
dashboardUID := "default"
// Create the namespace under default organisation (orgID = 1) where we'll save our alerts to.
err := createFolder(t, "default", grafanaListedAddr, "grafana", "password")
require.NoError(t, err)
apiClient.CreateFolder(t, "default", "default")
reloadCachedPermissions(t, grafanaListedAddr, "grafana", "password")
interval, err := model.ParseDuration("10s")
@ -547,24 +465,9 @@ func TestRulerRulesFilterByDashboard(t *testing.T) {
},
},
}
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err := enc.Encode(&rules)
require.NoError(t, err)
u := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, resp.StatusCode, 202)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, string(b))
status, body := apiClient.PostRulesGroup(t, "default", &rules)
assert.Equal(t, http.StatusAccepted, status)
require.JSONEq(t, `{"message":"rule group updated successfully"}`, body)
}
expectedAllJSON := fmt.Sprintf(`

View File

@ -2,12 +2,22 @@ package alerting
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"testing"
"time"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/util"
)
const defaultAlertmanagerConfigJSON = `
@ -74,3 +84,159 @@ func getBody(t *testing.T, body io.ReadCloser) string {
require.NoError(t, err)
return string(b)
}
func AlertRuleGen() func() apimodels.PostableExtendedRuleNode {
return func() apimodels.PostableExtendedRuleNode {
return apimodels.PostableExtendedRuleNode{
ApiRuleNode: &apimodels.ApiRuleNode{
For: model.Duration(10 * time.Second),
Labels: map[string]string{"label1": "val1"},
Annotations: map[string]string{"annotation1": "val1"},
},
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: fmt.Sprintf("rule-%s", util.GenerateShortUID()),
Condition: "A",
Data: []ngmodels.AlertQuery{
{
RefID: "A",
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(time.Duration(5) * time.Hour),
To: ngmodels.Duration(time.Duration(3) * time.Hour),
},
DatasourceUID: "-100",
Model: json.RawMessage(`{
"type": "math",
"expression": "2 + 3 > 1"
}`),
},
},
},
}
}
}
func GenerateAlertRuleGroup(rulesCount int, gen func() apimodels.PostableExtendedRuleNode) apimodels.PostableRuleGroupConfig {
rules := make([]apimodels.PostableExtendedRuleNode, 0, rulesCount)
for i := 0; i < rulesCount; i++ {
rules = append(rules, gen())
}
return apimodels.PostableRuleGroupConfig{
Name: "arulegroup-" + util.GenerateShortUID(),
Interval: model.Duration(10 * time.Second),
Rules: rules,
}
}
func ConvertGettableRuleGroupToPostable(gettable apimodels.GettableRuleGroupConfig) apimodels.PostableRuleGroupConfig {
rules := make([]apimodels.PostableExtendedRuleNode, 0, len(gettable.Rules))
for _, rule := range gettable.Rules {
rules = append(rules, ConvertGettableRuleToPostable(rule))
}
return apimodels.PostableRuleGroupConfig{
Name: gettable.Name,
Interval: gettable.Interval,
Rules: rules,
}
}
func ConvertGettableRuleToPostable(gettable apimodels.GettableExtendedRuleNode) apimodels.PostableExtendedRuleNode {
return apimodels.PostableExtendedRuleNode{
ApiRuleNode: gettable.ApiRuleNode,
GrafanaManagedAlert: ConvertGettableGrafanaRuleToPostable(gettable.GrafanaManagedAlert),
}
}
func ConvertGettableGrafanaRuleToPostable(gettable *apimodels.GettableGrafanaRule) *apimodels.PostableGrafanaRule {
if gettable == nil {
return nil
}
return &apimodels.PostableGrafanaRule{
Title: gettable.Title,
Condition: gettable.Condition,
Data: gettable.Data,
UID: gettable.UID,
NoDataState: gettable.NoDataState,
ExecErrState: gettable.ExecErrState,
}
}
type apiClient struct {
url string
}
func newAlertingApiClient(host, user, pass string) apiClient {
if len(user) == 0 && len(pass) == 0 {
return apiClient{url: fmt.Sprintf("http://%s", host)}
}
return apiClient{url: fmt.Sprintf("http://%s:%s@%s", user, pass, host)}
}
// CreateFolder creates a folder for storing our alerts under.
func (a apiClient) CreateFolder(t *testing.T, uID string, title string) {
t.Helper()
payload := fmt.Sprintf(`{"uid": "%s","title": "%s"}`, uID, title)
u := fmt.Sprintf("%s/api/folders", a.url)
r := strings.NewReader(payload)
// nolint:gosec
resp, err := http.Post(u, "application/json", r)
defer func() {
require.NoError(t, resp.Body.Close())
}()
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func (a apiClient) PostRulesGroup(t *testing.T, folder string, group *apimodels.PostableRuleGroupConfig) (int, string) {
t.Helper()
buf := bytes.Buffer{}
enc := json.NewEncoder(&buf)
err := enc.Encode(group)
require.NoError(t, err)
u := fmt.Sprintf("%s/api/ruler/grafana/api/v1/rules/%s", a.url, folder)
// nolint:gosec
resp, err := http.Post(u, "application/json", &buf)
require.NoError(t, err)
defer func() {
_ = resp.Body.Close()
}()
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
return resp.StatusCode, string(b)
}
func (a apiClient) GetRulesGroup(t *testing.T, folder string, group string) apimodels.RuleGroupConfigResponse {
t.Helper()
u := fmt.Sprintf("%s/api/ruler/grafana/api/v1/rules/%s/%s", a.url, folder, group)
// nolint:gosec
resp, err := http.Get(u)
require.NoError(t, err)
defer func() {
_ = resp.Body.Close()
}()
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, http.StatusAccepted, resp.StatusCode)
result := apimodels.RuleGroupConfigResponse{}
require.NoError(t, json.Unmarshal(b, &result))
return result
}
func (a apiClient) GetAllRulesGroupInFolder(t *testing.T, folder string) apimodels.NamespaceConfigResponse {
t.Helper()
u := fmt.Sprintf("%s/api/ruler/grafana/api/v1/rules/%s", a.url, folder)
// nolint:gosec
resp, err := http.Get(u)
require.NoError(t, err)
defer func() {
_ = resp.Body.Close()
}()
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, http.StatusAccepted, resp.StatusCode)
result := apimodels.NamespaceConfigResponse{}
require.NoError(t, json.Unmarshal(b, &result))
return result
}