diff --git a/internal/client/client.go b/internal/client/client.go index cd5a5b80..eaabca5b 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -188,6 +188,78 @@ func (c *CSAPI) SetRoomAccountData(t *testing.T, roomID string, eventType string return c.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}, WithJSONBody(t, content)) } +// GetAllPushRules fetches all configured push rules for a user from the homeserver. +// Push rules are returned as a parsed gjson result +// +// Example of printing the IDs of all underride rules of the current user: +// +// allPushRules := c.GetAllPushRules(t) +// globalUnderridePushRules := allPushRules.Get("global").Get("underride").Array() +// +// for index, rule := range globalUnderridePushRules { +// fmt.Printf("This rule's ID is: %s\n", rule.Get("rule_id").Str) +// } +// +// Push rules are returned in the same order received from the homeserver. +func (c *CSAPI) GetAllPushRules(t *testing.T) gjson.Result { + t.Helper() + + // We have to supply an empty string to the end of this path in order to generate a trailing slash. + // See https://github.com/matrix-org/matrix-spec/issues/457 + res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushrules", ""}) + pushRulesBytes := ParseJSON(t, res) + return gjson.ParseBytes(pushRulesBytes) +} + +// GetPushRule queries the contents of a client's push rule by scope, kind and rule ID. +// A parsed gjson result is returned. Fails the test if the query to server returns a non-2xx status code. +// +// Example of checking that a global underride rule contains the expected actions: +// +// containsDisplayNameRule := c.GetPushRule(t, "global", "underride", ".m.rule.contains_display_name") +// must.MatchGJSON( +// t, +// containsDisplayNameRule, +// match.JSONKeyEqual("actions", []interface{}{ +// "notify", +// map[string]interface{}{"set_tweak": "sound", "value": "default"}, +// map[string]interface{}{"set_tweak": "highlight"}, +// }), +// ) +func (c *CSAPI) GetPushRule(t *testing.T, scope string, kind string, ruleID string) gjson.Result { + t.Helper() + + res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}) + pushRuleBytes := ParseJSON(t, res) + return gjson.ParseBytes(pushRuleBytes) +} + +// SetPushRule creates a new push rule on the user, or modifies an existing one. +// If `before` or `after` parameters are not set to an empty string, their values +// will be set as the `before` and `after` query parameters respectively on the +// "set push rules" client endpoint: +// https://spec.matrix.org/v1.5/client-server-api/#put_matrixclientv3pushrulesscopekindruleid +// +// Example of setting a push rule with ID 'com.example.rule2' that must come after 'com.example.rule1': +// +// c.SetPushRule(t, "global", "underride", "com.example.rule2", map[string]interface{}{ +// "actions": []string{"dont_notify"}, +// }, nil, "com.example.rule1") +func (c *CSAPI) SetPushRule(t *testing.T, scope string, kind string, ruleID string, body map[string]interface{}, before string, after string) *http.Response { + t.Helper() + + // If the `before` or `after` arguments have been provided, construct same-named query parameters + queryParams := url.Values{} + if before != "" { + queryParams.Add("before", before) + } + if after != "" { + queryParams.Add("after", after) + } + + return c.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}, WithJSONBody(t, body), WithQueries(queryParams)) +} + // SendEventSynced sends `e` into the room and waits for its event ID to come down /sync. // Returns the event ID of the sent event. func (c *CSAPI) SendEventSynced(t *testing.T, roomID string, e b.Event) string { diff --git a/tests/csapi/account_change_password_pushers_test.go b/tests/csapi/account_change_password_pushers_test.go index ab660ea5..3291fc88 100644 --- a/tests/csapi/account_change_password_pushers_test.go +++ b/tests/csapi/account_change_password_pushers_test.go @@ -59,7 +59,7 @@ func TestChangePasswordPushers(t *testing.T) { }) // sytest: Pushers created with a the same access token are not deleted on password change - t.Run("Pushers created with a the same access token are not deleted on password change", func(t *testing.T) { + t.Run("Pushers created with the same access token are not deleted on password change", func(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "data": map[string]interface{}{ "url": "https://dummy.url/_matrix/push/v1/notify", diff --git a/tests/csapi/push_test.go b/tests/csapi/push_test.go index efcb6bcc..12237e76 100644 --- a/tests/csapi/push_test.go +++ b/tests/csapi/push_test.go @@ -20,26 +20,16 @@ func TestPushRuleCacheHealth(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "sender", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ + // Set a global push rule + alice.SetPushRule(t, "global", "sender", alice.UserID, map[string]interface{}{ "actions": []string{"dont_notify"}, - })) + }, "", "") - // the extra "" is to make sure the submitted URL ends with a trailing slash - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushrules", ""}) + // Fetch the rule once and check its contents + must.MatchGJSON(t, alice.GetAllPushRules(t), match.JSONKeyEqual("global.sender.0.actions.0", "dont_notify")) - must.MatchResponse(t, res, match.HTTPResponse{ - JSON: []match.JSON{ - match.JSONKeyEqual("global.sender.0.actions.0", "dont_notify"), - }, - }) - - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushrules", ""}) - - must.MatchResponse(t, res, match.HTTPResponse{ - JSON: []match.JSON{ - match.JSONKeyEqual("global.sender.0.actions.0", "dont_notify"), - }, - }) + // Fetch the rule and check its contents again. It should not have changed. + must.MatchGJSON(t, alice.GetAllPushRules(t), match.JSONKeyEqual("global.sender.0.actions.0", "dont_notify")) } func TestPushSync(t *testing.T) {