1647213fac
As outlined in https://github.com/matrix-org/gomatrixserverlib/pull/368 The main change Dendrite side is that `RoomVersion` no longer has any methods on it. Instead, you need to bounce via `gmsl.GetRoomVersion`. It's very interesting to see where exactly Dendrite cares about this. For some places it's creating events (fine) but others are way more specific. Those areas will need to migrate to GMSL at some point.
198 lines
9.4 KiB
Go
198 lines
9.4 KiB
Go
package pushrules
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/matrix-org/gomatrixserverlib"
|
|
)
|
|
|
|
func TestRuleSetEvaluatorMatchEvent(t *testing.T) {
|
|
ev := mustEventFromJSON(t, `{}`)
|
|
defaultEnabled := &Rule{
|
|
RuleID: ".default.enabled",
|
|
Default: true,
|
|
Enabled: true,
|
|
}
|
|
userEnabled := &Rule{
|
|
RuleID: ".user.enabled",
|
|
Default: false,
|
|
Enabled: true,
|
|
}
|
|
userEnabled2 := &Rule{
|
|
RuleID: ".user.enabled.2",
|
|
Default: false,
|
|
Enabled: true,
|
|
}
|
|
defaultRuleset := DefaultGlobalRuleSet("test", "test")
|
|
tsts := []struct {
|
|
Name string
|
|
RuleSet RuleSet
|
|
Want *Rule
|
|
Event *gomatrixserverlib.Event
|
|
}{
|
|
{"empty", RuleSet{}, nil, ev},
|
|
{"defaultCanWin", RuleSet{Override: []*Rule{defaultEnabled}}, defaultEnabled, ev},
|
|
{"userWins", RuleSet{Override: []*Rule{defaultEnabled, userEnabled}}, userEnabled, ev},
|
|
{"defaultOverrideWins", RuleSet{Override: []*Rule{defaultEnabled}, Underride: []*Rule{userEnabled}}, defaultEnabled, ev},
|
|
{"overrideContent", RuleSet{Override: []*Rule{userEnabled}, Content: []*Rule{userEnabled2}}, userEnabled, ev},
|
|
{"overrideRoom", RuleSet{Override: []*Rule{userEnabled}, Room: []*Rule{userEnabled2}}, userEnabled, ev},
|
|
{"overrideSender", RuleSet{Override: []*Rule{userEnabled}, Sender: []*Rule{userEnabled2}}, userEnabled, ev},
|
|
{"overrideUnderride", RuleSet{Override: []*Rule{userEnabled}, Underride: []*Rule{userEnabled2}}, userEnabled, ev},
|
|
{"reactions don't notify", *defaultRuleset, &mRuleReactionDefinition, mustEventFromJSON(t, `{"type":"m.reaction"}`)},
|
|
{"receipts don't notify", *defaultRuleset, nil, mustEventFromJSON(t, `{"type":"m.receipt"}`)},
|
|
}
|
|
for _, tst := range tsts {
|
|
t.Run(tst.Name, func(t *testing.T) {
|
|
rse := NewRuleSetEvaluator(fakeEvaluationContext{3}, &tst.RuleSet)
|
|
got, err := rse.MatchEvent(tst.Event)
|
|
if err != nil {
|
|
t.Fatalf("MatchEvent failed: %v", err)
|
|
}
|
|
if diff := cmp.Diff(tst.Want, got); diff != "" {
|
|
t.Errorf("MatchEvent rule: +got -want:\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRuleMatches(t *testing.T) {
|
|
emptyRule := Rule{Enabled: true}
|
|
tsts := []struct {
|
|
Name string
|
|
Kind Kind
|
|
Rule Rule
|
|
EventJSON string
|
|
Want bool
|
|
}{
|
|
{"emptyOverride", OverrideKind, emptyRule, `{}`, true},
|
|
{"emptyContent", ContentKind, emptyRule, `{}`, false},
|
|
{"emptyRoom", RoomKind, emptyRule, `{}`, true},
|
|
{"emptySender", SenderKind, emptyRule, `{}`, true},
|
|
{"emptyUnderride", UnderrideKind, emptyRule, `{}`, true},
|
|
|
|
{"disabled", OverrideKind, Rule{}, `{}`, false},
|
|
|
|
{"overrideConditionMatch", OverrideKind, Rule{Enabled: true}, `{}`, true},
|
|
{"overrideConditionNoMatch", OverrideKind, Rule{Enabled: true, Conditions: []*Condition{{}}}, `{}`, false},
|
|
|
|
{"underrideConditionMatch", UnderrideKind, Rule{Enabled: true}, `{}`, true},
|
|
{"underrideConditionNoMatch", UnderrideKind, Rule{Enabled: true, Conditions: []*Condition{{}}}, `{}`, false},
|
|
|
|
{"contentMatch", ContentKind, Rule{Enabled: true, Pattern: pointer("b")}, `{"content":{"body":"abc"}}`, true},
|
|
{"contentNoMatch", ContentKind, Rule{Enabled: true, Pattern: pointer("d")}, `{"content":{"body":"abc"}}`, false},
|
|
|
|
{"roomMatch", RoomKind, Rule{Enabled: true, RuleID: "!room@example.com"}, `{"room_id":"!room@example.com"}`, true},
|
|
{"roomNoMatch", RoomKind, Rule{Enabled: true, RuleID: "!room@example.com"}, `{"room_id":"!otherroom@example.com"}`, false},
|
|
|
|
{"senderMatch", SenderKind, Rule{Enabled: true, RuleID: "@user@example.com"}, `{"sender":"@user@example.com"}`, true},
|
|
{"senderNoMatch", SenderKind, Rule{Enabled: true, RuleID: "@user@example.com"}, `{"sender":"@otheruser@example.com"}`, false},
|
|
}
|
|
for _, tst := range tsts {
|
|
t.Run(tst.Name, func(t *testing.T) {
|
|
got, err := ruleMatches(&tst.Rule, tst.Kind, mustEventFromJSON(t, tst.EventJSON), nil)
|
|
if err != nil {
|
|
t.Fatalf("ruleMatches failed: %v", err)
|
|
}
|
|
if got != tst.Want {
|
|
t.Errorf("ruleMatches: got %v, want %v", got, tst.Want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConditionMatches(t *testing.T) {
|
|
tsts := []struct {
|
|
Name string
|
|
Cond Condition
|
|
EventJSON string
|
|
WantMatch bool
|
|
WantErr bool
|
|
}{
|
|
{Name: "empty", Cond: Condition{}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
{Name: "empty", Cond: Condition{Kind: "unknownstring"}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
|
|
// Neither of these should match because `content` is not a full string match,
|
|
// and `content.body` is not a string value.
|
|
{Name: "eventMatch", Cond: Condition{Kind: EventMatchCondition, Key: "content", Pattern: pointer("")}, EventJSON: `{"content":{}}`, WantMatch: false, WantErr: false},
|
|
{Name: "eventBodyMatch", Cond: Condition{Kind: EventMatchCondition, Key: "content.body", Is: "3", Pattern: pointer("")}, EventJSON: `{"content":{"body": "3"}}`, WantMatch: false, WantErr: false},
|
|
{Name: "eventBodyMatch matches", Cond: Condition{Kind: EventMatchCondition, Key: "content.body", Pattern: pointer("world")}, EventJSON: `{"content":{"body": "hello world!"}}`, WantMatch: true, WantErr: false},
|
|
{Name: "EventMatch missing pattern", Cond: Condition{Kind: EventMatchCondition, Key: "content.body"}, EventJSON: `{"content":{"body": "hello world!"}}`, WantMatch: false, WantErr: true},
|
|
|
|
{Name: "displayNameNoMatch", Cond: Condition{Kind: ContainsDisplayNameCondition}, EventJSON: `{"content":{"body":"something without displayname"}}`, WantMatch: false, WantErr: false},
|
|
{Name: "displayNameMatch", Cond: Condition{Kind: ContainsDisplayNameCondition}, EventJSON: `{"content":{"body":"hello Dear User, how are you?"}}`, WantMatch: true, WantErr: false},
|
|
|
|
{Name: "roomMemberCountLessNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<2"}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
{Name: "roomMemberCountLessMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<3"}, EventJSON: `{}`, WantMatch: true, WantErr: false},
|
|
{Name: "roomMemberCountLessEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<=1"}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
{Name: "roomMemberCountLessEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<=2"}, EventJSON: `{}`, WantMatch: true, WantErr: false},
|
|
{Name: "roomMemberCountEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "==1"}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
{Name: "roomMemberCountEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "==2"}, EventJSON: `{}`, WantMatch: true, WantErr: false},
|
|
{Name: "roomMemberCountGreaterEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">=3"}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
{Name: "roomMemberCountGreaterEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">=2"}, EventJSON: `{}`, WantMatch: true, WantErr: false},
|
|
{Name: "roomMemberCountGreaterNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">2"}, EventJSON: `{}`, WantMatch: false, WantErr: false},
|
|
{Name: "roomMemberCountGreaterMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">1"}, EventJSON: `{}`, WantMatch: true, WantErr: false},
|
|
|
|
{Name: "senderNotificationPermissionMatch", Cond: Condition{Kind: SenderNotificationPermissionCondition, Key: "powerlevel"}, EventJSON: `{"sender":"@poweruser:example.com"}`, WantMatch: true, WantErr: false},
|
|
{Name: "senderNotificationPermissionNoMatch", Cond: Condition{Kind: SenderNotificationPermissionCondition, Key: "powerlevel"}, EventJSON: `{"sender":"@nobody:example.com"}`, WantMatch: false, WantErr: false},
|
|
}
|
|
for _, tst := range tsts {
|
|
t.Run(tst.Name, func(t *testing.T) {
|
|
got, err := conditionMatches(&tst.Cond, mustEventFromJSON(t, tst.EventJSON), &fakeEvaluationContext{2})
|
|
if err != nil && !tst.WantErr {
|
|
t.Fatalf("conditionMatches failed: %v", err)
|
|
}
|
|
if got != tst.WantMatch {
|
|
t.Errorf("conditionMatches: got %v, want %v on %s", got, tst.WantMatch, tst.Name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type fakeEvaluationContext struct{ memberCount int }
|
|
|
|
func (fakeEvaluationContext) UserDisplayName() string { return "Dear User" }
|
|
func (f fakeEvaluationContext) RoomMemberCount() (int, error) { return f.memberCount, nil }
|
|
func (fakeEvaluationContext) HasPowerLevel(userID, levelKey string) (bool, error) {
|
|
return userID == "@poweruser:example.com" && levelKey == "powerlevel", nil
|
|
}
|
|
|
|
func TestPatternMatches(t *testing.T) {
|
|
tsts := []struct {
|
|
Name string
|
|
Key string
|
|
Pattern string
|
|
EventJSON string
|
|
Want bool
|
|
}{
|
|
{"empty", "", "", `{}`, false},
|
|
|
|
{"patternEmpty", "content", "", `{"content":{}}`, false},
|
|
|
|
{"literal", "content.creator", "acreator", `{"content":{"creator":"acreator"}}`, true},
|
|
{"substring", "content.creator", "reat", `{"content":{"creator":"acreator"}}`, true},
|
|
{"singlePattern", "content.creator", "acr?ator", `{"content":{"creator":"acreator"}}`, true},
|
|
{"multiPattern", "content.creator", "a*ea*r", `{"content":{"creator":"acreator"}}`, true},
|
|
{"patternNoSubstring", "content.creator", "r*t", `{"content":{"creator":"acreator"}}`, false},
|
|
}
|
|
for _, tst := range tsts {
|
|
t.Run(tst.Name, func(t *testing.T) {
|
|
got, err := patternMatches(tst.Key, tst.Pattern, mustEventFromJSON(t, tst.EventJSON))
|
|
if err != nil {
|
|
t.Fatalf("patternMatches failed: %v", err)
|
|
}
|
|
if got != tst.Want {
|
|
t.Errorf("patternMatches: got %v, want %v on %s", got, tst.Want, tst.Name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func mustEventFromJSON(t *testing.T, json string) *gomatrixserverlib.Event {
|
|
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV7).NewEventFromTrustedJSON([]byte(json), false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return ev
|
|
}
|