2021-08-19 13:33:56 +00:00
|
|
|
package plugins
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/sirupsen/logrus"
|
2024-01-01 16:52:18 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2023-09-11 17:51:38 +00:00
|
|
|
"gopkg.in/irc.v4"
|
2021-11-25 22:48:16 +00:00
|
|
|
|
2022-11-02 21:38:14 +00:00
|
|
|
"github.com/Luzifer/twitch-bot/v3/pkg/twitch"
|
2021-04-03 12:11:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
testLogger = logrus.NewEntry(logrus.StandardLogger())
|
|
|
|
testBadgeLevel0 = func(i int) *int { return &i }(0)
|
2021-05-24 23:23:23 +00:00
|
|
|
testPtrBool = func(b bool) *bool { return &b }
|
2021-04-03 12:11:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestAllowExecuteBadgeBlacklist(t *testing.T) {
|
2021-08-19 13:33:56 +00:00
|
|
|
r := &Rule{DisableOn: []string{twitch.BadgeBroadcaster}}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if r.allowExecuteBadgeBlacklist(testLogger, nil, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Error("Execution allowed on blacklisted badge")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteBadgeBlacklist(testLogger, nil, nil, twitch.BadgeCollection{twitch.BadgeModerator: testBadgeLevel0}, nil) {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Error("Execution denied without blacklisted badge")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAllowExecuteBadgeWhitelist(t *testing.T) {
|
2021-08-19 13:33:56 +00:00
|
|
|
r := &Rule{EnableOn: []string{twitch.BadgeBroadcaster}}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if r.allowExecuteBadgeWhitelist(testLogger, nil, nil, twitch.BadgeCollection{twitch.BadgeModerator: testBadgeLevel0}, nil) {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Error("Execution allowed without whitelisted badge")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteBadgeWhitelist(testLogger, nil, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Error("Execution denied with whitelisted badge")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAllowExecuteChannelWhitelist(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{MatchChannels: []string{"#mychannel", "otherchannel"}}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
for m, exp := range map[string]bool{
|
|
|
|
":amy!amy@foo.example.com PRIVMSG #mychannel :Testing": true,
|
|
|
|
":amy!amy@foo.example.com PRIVMSG #otherchannel :Testing": true,
|
|
|
|
":amy!amy@foo.example.com PRIVMSG #randomchannel :Testing": false,
|
|
|
|
":amy!amy@foo.example.com JOIN #mychannel": true,
|
|
|
|
":tmi.twitch.tv CLEARCHAT #mychannel": true,
|
|
|
|
":tmi.twitch.tv CLEARCHAT #mychannel :ronni": true,
|
|
|
|
":tmi.twitch.tv CLEARCHAT #dallas": false,
|
|
|
|
"@msg-id=slow_off :tmi.twitch.tv NOTICE #mychannel :This room is no longer in slow mode.": true,
|
|
|
|
} {
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteChannelWhitelist(testLogger, irc.MustParseMessage(m), nil, twitch.BadgeCollection{}, nil); res != exp {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Errorf("Message %q yield unxpected result: exp=%v res=%v", m, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-24 23:23:23 +00:00
|
|
|
func TestAllowExecuteDisable(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
for exp, r := range map[bool]*Rule{
|
2021-05-24 23:23:23 +00:00
|
|
|
true: {Disable: testPtrBool(false)},
|
|
|
|
false: {Disable: testPtrBool(true)},
|
|
|
|
} {
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteDisable(testLogger, nil, nil, twitch.BadgeCollection{}, nil); res != exp {
|
2021-05-24 23:23:23 +00:00
|
|
|
t.Errorf("Disable status %v yield unexpected result: exp=%v res=%v", *r.Disable, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-03 12:11:47 +00:00
|
|
|
func TestAllowExecuteDisableOnOffline(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{DisableOnOffline: testPtrBool(true)}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
// Fake cache entries to prevent calling the real Twitch API
|
2021-12-31 12:42:37 +00:00
|
|
|
r.twitchClient = twitch.New("", "", "", "")
|
2021-08-19 13:33:56 +00:00
|
|
|
r.twitchClient.APICache().Set([]string{"hasLiveStream", "channel1"}, time.Minute, true)
|
|
|
|
r.twitchClient.APICache().Set([]string{"hasLiveStream", "channel2"}, time.Minute, false)
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
for ch, exp := range map[string]bool{
|
|
|
|
"channel1": true,
|
|
|
|
"channel2": false,
|
|
|
|
} {
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteDisableOnOffline(testLogger, irc.MustParseMessage(fmt.Sprintf("PRIVMSG #%s :test", ch)), nil, twitch.BadgeCollection{}, nil); res != exp {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Errorf("Channel %q yield an unexpected result: exp=%v res=%v", ch, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 20:20:19 +00:00
|
|
|
func TestAllowExecuteChannelCooldown(t *testing.T) {
|
2021-08-19 13:33:56 +00:00
|
|
|
r := &Rule{ChannelCooldown: func(i time.Duration) *time.Duration { return &i }(time.Minute), SkipCooldownFor: []string{twitch.BadgeBroadcaster}}
|
2021-06-07 20:20:19 +00:00
|
|
|
c1 := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :Testing")
|
|
|
|
c2 := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #otherchannel :Testing")
|
|
|
|
|
2021-08-19 13:33:56 +00:00
|
|
|
r.timerStore = newTestTimerStore()
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteChannelCooldown(testLogger, c1, nil, twitch.BadgeCollection{}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Initial call was not allowed")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add cooldown
|
2024-01-01 16:52:18 +00:00
|
|
|
require.NoError(t, r.timerStore.AddCooldown(TimerTypeCooldown, c1.Params[0], r.MatcherID(), time.Now().Add(*r.ChannelCooldown)))
|
2021-06-07 20:20:19 +00:00
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if r.allowExecuteChannelCooldown(testLogger, c1, nil, twitch.BadgeCollection{}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call after cooldown added was allowed")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteChannelCooldown(testLogger, c1, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call in cooldown with skip badge was not allowed")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteChannelCooldown(testLogger, c2, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call in cooldown with different channel was not allowed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-03 12:11:47 +00:00
|
|
|
func TestAllowExecuteDisableOnPermit(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{DisableOnPermit: testPtrBool(true)}
|
2021-08-19 13:33:56 +00:00
|
|
|
r.timerStore = newTestTimerStore()
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
m := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :Testing")
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteDisableOnPermit(testLogger, m, nil, twitch.BadgeCollection{}, nil) {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Error("Execution was not allowed without permit")
|
|
|
|
}
|
|
|
|
|
2024-01-01 16:52:18 +00:00
|
|
|
require.NoError(t, r.timerStore.AddPermit(m.Params[0], m.User))
|
2021-09-02 21:26:39 +00:00
|
|
|
if r.allowExecuteDisableOnPermit(testLogger, m, nil, twitch.BadgeCollection{}, nil) {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Error("Execution was allowed with permit")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-24 23:23:23 +00:00
|
|
|
func TestAllowExecuteDisableOnTemplate(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{DisableOnTemplate: func(s string) *string { return &s }(`{{ ne .username "amy" }}`)}
|
2021-05-24 23:23:23 +00:00
|
|
|
|
|
|
|
for msg, exp := range map[string]bool{
|
2021-08-19 13:33:56 +00:00
|
|
|
"false": true,
|
|
|
|
"true": false,
|
2021-05-24 23:23:23 +00:00
|
|
|
} {
|
2021-08-19 13:33:56 +00:00
|
|
|
// We don't test the message formatter here but only the disable functionality
|
|
|
|
// so we fake the result of the evaluation
|
2021-11-11 13:59:08 +00:00
|
|
|
r.msgFormatter = func(tplString string, m *irc.Message, r *Rule, fields *FieldCollection) (string, error) {
|
2021-08-19 13:33:56 +00:00
|
|
|
return msg, nil
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteDisableOnTemplate(testLogger, irc.MustParseMessage(msg), nil, twitch.BadgeCollection{}, nil); exp != res {
|
2021-05-24 23:23:23 +00:00
|
|
|
t.Errorf("Message %q yield unexpected result: exp=%v res=%v", msg, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-03 12:11:47 +00:00
|
|
|
func TestAllowExecuteEventWhitelist(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{MatchEvent: func(s string) *string { return &s }("test")}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
for evt, exp := range map[string]bool{
|
|
|
|
"foobar": false,
|
|
|
|
"test": true,
|
|
|
|
} {
|
2023-04-07 23:10:49 +00:00
|
|
|
if res := r.allowExecuteEventMatch(testLogger, nil, &evt, twitch.BadgeCollection{}, nil); exp != res {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Errorf("Event %q yield unexpected result: exp=%v res=%v", evt, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAllowExecuteMessageMatcherBlacklist(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{DisableOnMatchMessages: []string{`^!disable`}}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
for msg, exp := range map[string]bool{
|
|
|
|
"PRIVMSG #test :Random message": true,
|
|
|
|
"PRIVMSG #test :!disable this one": false,
|
|
|
|
} {
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteMessageMatcherBlacklist(testLogger, irc.MustParseMessage(msg), nil, twitch.BadgeCollection{}, nil); exp != res {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Errorf("Message %q yield unexpected result: exp=%v res=%v", msg, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAllowExecuteMessageMatcherWhitelist(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{MatchMessage: func(s string) *string { return &s }(`^!test`)}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
for msg, exp := range map[string]bool{
|
|
|
|
"PRIVMSG #test :Random message": false,
|
|
|
|
"PRIVMSG #test :!test this one": true,
|
|
|
|
} {
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteMessageMatcherWhitelist(testLogger, irc.MustParseMessage(msg), nil, twitch.BadgeCollection{}, nil); exp != res {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Errorf("Message %q yield unexpected result: exp=%v res=%v", msg, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 20:20:19 +00:00
|
|
|
func TestAllowExecuteRuleCooldown(t *testing.T) {
|
2021-08-19 13:33:56 +00:00
|
|
|
r := &Rule{Cooldown: func(i time.Duration) *time.Duration { return &i }(time.Minute), SkipCooldownFor: []string{twitch.BadgeBroadcaster}}
|
|
|
|
r.timerStore = newTestTimerStore()
|
2021-06-07 20:20:19 +00:00
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteRuleCooldown(testLogger, nil, nil, twitch.BadgeCollection{}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Initial call was not allowed")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add cooldown
|
2024-01-01 16:52:18 +00:00
|
|
|
require.NoError(t, r.timerStore.AddCooldown(TimerTypeCooldown, "", r.MatcherID(), time.Now().Add(*r.Cooldown)))
|
2021-06-07 20:20:19 +00:00
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if r.allowExecuteRuleCooldown(testLogger, nil, nil, twitch.BadgeCollection{}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call after cooldown added was allowed")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteRuleCooldown(testLogger, nil, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call in cooldown with skip badge was not allowed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAllowExecuteUserCooldown(t *testing.T) {
|
2021-08-19 13:33:56 +00:00
|
|
|
r := &Rule{UserCooldown: func(i time.Duration) *time.Duration { return &i }(time.Minute), SkipCooldownFor: []string{twitch.BadgeBroadcaster}}
|
2021-06-07 20:20:19 +00:00
|
|
|
c1 := irc.MustParseMessage(":ben!ben@foo.example.com PRIVMSG #mychannel :Testing")
|
|
|
|
c2 := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :Testing")
|
|
|
|
|
2021-08-19 13:33:56 +00:00
|
|
|
r.timerStore = newTestTimerStore()
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteUserCooldown(testLogger, c1, nil, twitch.BadgeCollection{}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Initial call was not allowed")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add cooldown
|
2024-01-01 16:52:18 +00:00
|
|
|
require.NoError(t, r.timerStore.AddCooldown(TimerTypeCooldown, c1.User, r.MatcherID(), time.Now().Add(*r.UserCooldown)))
|
2021-06-07 20:20:19 +00:00
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if r.allowExecuteUserCooldown(testLogger, c1, nil, twitch.BadgeCollection{}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call after cooldown added was allowed")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteUserCooldown(testLogger, c1, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call in cooldown with skip badge was not allowed")
|
|
|
|
}
|
|
|
|
|
2021-09-02 21:26:39 +00:00
|
|
|
if !r.allowExecuteUserCooldown(testLogger, c2, nil, twitch.BadgeCollection{twitch.BadgeBroadcaster: testBadgeLevel0}, nil) {
|
2021-06-07 20:20:19 +00:00
|
|
|
t.Error("Call in cooldown with different user was not allowed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-03 12:11:47 +00:00
|
|
|
func TestAllowExecuteUserWhitelist(t *testing.T) {
|
2021-06-11 11:52:42 +00:00
|
|
|
r := &Rule{MatchUsers: []string{"amy"}}
|
2021-04-03 12:11:47 +00:00
|
|
|
|
|
|
|
for msg, exp := range map[string]bool{
|
|
|
|
":amy!amy@foo.example.com PRIVMSG #mychannel :Testing": true,
|
|
|
|
":bob!bob@foo.example.com PRIVMSG #mychannel :Testing": false,
|
|
|
|
} {
|
2021-09-02 21:26:39 +00:00
|
|
|
if res := r.allowExecuteUserWhitelist(testLogger, irc.MustParseMessage(msg), nil, twitch.BadgeCollection{}, nil); exp != res {
|
2021-04-03 12:11:47 +00:00
|
|
|
t.Errorf("Message %q yield unexpected result: exp=%v res=%v", msg, exp, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|