Skip to content

Commit

Permalink
feat: run all matched rules
Browse files Browse the repository at this point in the history
  • Loading branch information
wass3r committed Aug 10, 2021
1 parent eb455f2 commit 90ef19a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 56 deletions.
41 changes: 16 additions & 25 deletions core/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ func Matcher(inputMsgs <-chan models.Message, outputMsgs chan<- models.Message,
func matcherLoop(message models.Message, outputMsgs chan<- models.Message, rules map[string]models.Rule, hitRule chan<- models.Rule, bot *models.Bot) {
match := false

RuleSearch:
// Look through rules to see if we can find a match
for _, rule := range rules {
// Only check active rules.
Expand All @@ -38,17 +37,9 @@ RuleSearch:
// Determine what service we are processing the rule for
switch message.Service {
case models.MsgServiceChat, models.MsgServiceCLI:
foundMatch, stopSearch := handleChatServiceRule(outputMsgs, message, hitRule, rule, processedInput, hit, bot)
match = foundMatch
if stopSearch {
break RuleSearch
}
match = handleChatServiceRule(outputMsgs, message, hitRule, rule, processedInput, hit, bot)
case models.MsgServiceScheduler:
foundMatch, stopSearch := handleSchedulerServiceRule(outputMsgs, message, hitRule, rule, bot)
match = foundMatch
if stopSearch {
break RuleSearch
}
match = handleSchedulerServiceRule(outputMsgs, message, hitRule, rule, bot)
}
}
}
Expand All @@ -71,8 +62,8 @@ func getProccessedInputAndHitValue(messageInput, ruleRespondValue, ruleHearValue

// handleChatServiceRule handles the processing logic for a rule that came from either the chat application or CLI remote
// nolint:gocyclo // mark for refactor
func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Message, hitRule chan<- models.Rule, rule models.Rule, processedInput string, hit bool, bot *models.Bot) (bool, bool) {
match, stopSearch := false, false
func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Message, hitRule chan<- models.Rule, rule models.Rule, processedInput string, hit bool, bot *models.Bot) bool {
match := false
if rule.Respond != "" || rule.Hear != "" {
// You can only use 'respond' OR 'hear'
if rule.Respond != "" && rule.Hear != "" {
Expand All @@ -85,7 +76,7 @@ func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Mess

if hit && message.ThreadTimestamp != "" && rule.IgnoreThreads {
bot.Log.Debug().Msg("response suppressed due to 'ignore_threads' being set")
return true, true
return true
}

// check if limit_to_rooms is set on the rule
Expand All @@ -110,7 +101,7 @@ func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Mess
// suppress the response
if !isInLimitToRooms {
bot.Log.Debug().Msgf("rule '%s' was matched but skipped due to message not coming from a room defined in 'limit_to_rooms'", rule.Name)
return true, false
return true
}
}

Expand All @@ -119,13 +110,13 @@ func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Mess

// if it's a 'respond' rule, make sure the bot was mentioned
if hit && rule.Respond != "" && !message.BotMentioned && message.Type != models.MsgTypeDirect {
return match, stopSearch
return match
}

if hit {
bot.Log.Info().Msgf("found rule match '%s' for input '%s'", rule.Name, message.Input)
// Don't go through more rules if rule is matched
match, stopSearch = true, true
match = true
// Publish metric to prometheus - metricname will be combination of bot name and rule name
Prommetric(bot.Name+"-"+rule.Name, bot)
// Capture untouched user input
Expand All @@ -138,26 +129,26 @@ func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Mess
outputMsgs <- message
hitRule <- models.Rule{}
// prevent actions from being run; exit early
return match, stopSearch
return match
}
msg := deepcopy.Copy(message).(models.Message)
go doRuleActions(msg, outputMsgs, rule, hitRule, bot)
return match, stopSearch
return match
}
}
return match, stopSearch
return match
}

// handleSchedulerServiceRule handles the processing logic for a rule that came from the Scheduler remote
func handleSchedulerServiceRule(outputMsgs chan<- models.Message, message models.Message, hitRule chan<- models.Rule, rule models.Rule, bot *models.Bot) (bool, bool) {
match, stopSearch := false, false
func handleSchedulerServiceRule(outputMsgs chan<- models.Message, message models.Message, hitRule chan<- models.Rule, rule models.Rule, bot *models.Bot) bool {
match := false
if rule.Schedule != "" && rule.Name == message.Attributes["from_schedule"] {
match, stopSearch = true, true // Don't go through more rules if rule is matched
match = true // Don't go through more rules if rule is matched
msg := deepcopy.Copy(message).(models.Message)
go doRuleActions(msg, outputMsgs, rule, hitRule, bot)
return match, stopSearch
return match
}
return match, stopSearch
return match
}

// handleNoMatch - handles logic for unmatched rule
Expand Down
51 changes: 20 additions & 31 deletions core/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -774,23 +774,22 @@ func Test_handleChatServiceRule(t *testing.T) {
name string
args args
want bool
want1 bool
expectMsg string
expectedVars map[string]string
}{
{"basic", args{}, false, false, "", map[string]string{}},
{"respond + hear", args{rule: models.Rule{Respond: "hi", Hear: "/hi/"}, hit: false, bot: testBot, message: testMessage}, false, false, "", map[string]string{}},
{"hear + rule args", args{rule: ruleHearWithArgs, hit: false, bot: testBot, message: testMessage}, false, false, "", map[string]string{}},
{"respond rule - hit false", args{rule: rule, hit: false}, false, false, "", map[string]string{}},
{"respond rule - hit true - valid", args{rule: rule, hit: true, bot: testBot, message: testMessage, processedInput: "arg1 arg2"}, true, true, "hmm, the 'format_output' field in your configuration is empty", map[string]string{"arg1": "arg1", "arg2": "arg2"}},
{"respond rule - hit true - bot not mentioned", args{rule: rule, hit: true, bot: testBot, message: testMessageBotNotMentioned, processedInput: "arg1 arg2"}, false, false, "", map[string]string{}},
{"respond rule - hit true - valid - not enough args", args{rule: rule, hit: true, bot: testBot, message: testMessageNotEnoughArgs, processedInput: "arg1"}, true, true, "you might be missing an argument or two - this is what i'm looking for\n```foo <arg1> <arg2>```", map[string]string{}},
{"respond rule - hit true - valid optional arg", args{rule: ruleOpt, hit: true, bot: testBot, message: testMessageOptionalArgs, processedInput: "arg1"}, true, true, "", map[string]string{"arg1": "arg1"}},
{"respond rule - hit true - valid vargs", args{rule: ruleVarg, hit: true, bot: testBot, message: testMessageVargs, processedInput: "arg1 arg2 arg3 arg4"}, true, true, "", map[string]string{"arg1": "arg1", "argv": "arg2 arg3 arg4"}},
{"respond rule - hit true - invalid", args{rule: rule, hit: true, bot: testBot, message: testMessage}, true, true, "you might be missing an argument or two - this is what i'm looking for\n```foo <arg1> <arg2>```", map[string]string{}},
{"hear rule - ignore thread", args{rule: ruleIgnoreThread, hit: true, bot: testBot, message: testMessageIgnoreThread}, true, true, "", map[string]string{}},
{"respond rule - limit_to_rooms set", args{rule: ruleLimitToRooms, hit: true, bot: testBot, message: testMessageLimitToRooms}, true, true, "", map[string]string{}},
{"respond rule - skip due to limit_to_rooms", args{rule: ruleSkipDueToLimitToRooms, hit: true, bot: testBot, message: testMessageSkipDueToLimitToRooms}, true, false, "", map[string]string{}},
{"basic", args{}, false, "", map[string]string{}},
{"respond + hear", args{rule: models.Rule{Respond: "hi", Hear: "/hi/"}, hit: false, bot: testBot, message: testMessage}, false, "", map[string]string{}},
{"hear + rule args", args{rule: ruleHearWithArgs, hit: false, bot: testBot, message: testMessage}, false, "", map[string]string{}},
{"respond rule - hit false", args{rule: rule, hit: false}, false, "", map[string]string{}},
{"respond rule - hit true - valid", args{rule: rule, hit: true, bot: testBot, message: testMessage, processedInput: "arg1 arg2"}, true, "hmm, the 'format_output' field in your configuration is empty", map[string]string{"arg1": "arg1", "arg2": "arg2"}},
{"respond rule - hit true - bot not mentioned", args{rule: rule, hit: true, bot: testBot, message: testMessageBotNotMentioned, processedInput: "arg1 arg2"}, false, "", map[string]string{}},
{"respond rule - hit true - valid - not enough args", args{rule: rule, hit: true, bot: testBot, message: testMessageNotEnoughArgs, processedInput: "arg1"}, true, "you might be missing an argument or two - this is what i'm looking for\n```foo <arg1> <arg2>```", map[string]string{}},
{"respond rule - hit true - valid optional arg", args{rule: ruleOpt, hit: true, bot: testBot, message: testMessageOptionalArgs, processedInput: "arg1"}, true, "", map[string]string{"arg1": "arg1"}},
{"respond rule - hit true - valid vargs", args{rule: ruleVarg, hit: true, bot: testBot, message: testMessageVargs, processedInput: "arg1 arg2 arg3 arg4"}, true, "", map[string]string{"arg1": "arg1", "argv": "arg2 arg3 arg4"}},
{"respond rule - hit true - invalid", args{rule: rule, hit: true, bot: testBot, message: testMessage}, true, "you might be missing an argument or two - this is what i'm looking for\n```foo <arg1> <arg2>```", map[string]string{}},
{"hear rule - ignore thread", args{rule: ruleIgnoreThread, hit: true, bot: testBot, message: testMessageIgnoreThread}, true, "", map[string]string{}},
{"respond rule - limit_to_rooms set", args{rule: ruleLimitToRooms, hit: true, bot: testBot, message: testMessageLimitToRooms}, true, "", map[string]string{}},
{"respond rule - skip due to limit_to_rooms", args{rule: ruleSkipDueToLimitToRooms, hit: true, bot: testBot, message: testMessageSkipDueToLimitToRooms}, true, "", map[string]string{}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -799,7 +798,7 @@ func Test_handleChatServiceRule(t *testing.T) {
tt.args.hitRule = testHitRule
tt.args.outputMsgs = testOutput

got, got1 := handleChatServiceRule(tt.args.outputMsgs, tt.args.message, tt.args.hitRule, tt.args.rule, tt.args.processedInput, tt.args.hit, tt.args.bot)
got := handleChatServiceRule(tt.args.outputMsgs, tt.args.message, tt.args.hitRule, tt.args.rule, tt.args.processedInput, tt.args.hit, tt.args.bot)

select {
case output := <-testOutput:
Expand All @@ -809,16 +808,10 @@ func Test_handleChatServiceRule(t *testing.T) {
if got != tt.want {
t.Errorf("handleChatServiceRule() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("handleChatServiceRule() got1 = %v, want %v", got1, tt.want1)
}
default:
if got != tt.want {
t.Errorf("handleChatServiceRule() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("handleChatServiceRule() got1 = %v, want %v", got1, tt.want1)
}
for argk, argv := range tt.expectedVars {
if tt.args.message.Vars[argk] != argv {
t.Errorf("handleChatServiceRules() did not extract argument %v. got = %v, want %v", argk, tt.args.message.Vars[argk], argv)
Expand Down Expand Up @@ -856,23 +849,19 @@ func Test_handleSchedulerServiceRule(t *testing.T) {
}

tests := []struct {
name string
args args
want bool
want1 bool
name string
args args
want bool
}{
{"Basic", args{}, false, false},
{"Valid Schedule", args{message: testMessageValid, rule: testRuleValid, bot: testBot}, true, true},
{"Basic", args{}, false},
{"Valid Schedule", args{message: testMessageValid, rule: testRuleValid, bot: testBot}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := handleSchedulerServiceRule(tt.args.outputMsgs, tt.args.message, tt.args.hitRule, tt.args.rule, tt.args.bot)
got := handleSchedulerServiceRule(tt.args.outputMsgs, tt.args.message, tt.args.hitRule, tt.args.rule, tt.args.bot)
if got != tt.want {
t.Errorf("handleSchedulerServiceRule() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("handleSchedulerServiceRule() got1 = %v, want %v", got1, tt.want1)
}
})
}
}
Expand Down

0 comments on commit 90ef19a

Please sign in to comment.