actions_test.go
Rama master · réplica de lectura del repositorio original.
package main
import (
"errors"
"fmt"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/Luzifer/go_helpers/fieldcollection"
"github.com/stretchr/testify/require"
"gopkg.in/irc.v4"
"github.com/Luzifer/twitch-bot/v3/plugins"
)
type testExecutionActor struct {
exec func(*irc.Message) (bool, error)
name string
}
func (a testExecutionActor) Execute(_ *irc.Client, m *irc.Message, _ *plugins.Rule, _ *fieldcollection.FieldCollection, _ *fieldcollection.FieldCollection) (bool, error) {
return a.exec(m)
}
func (testExecutionActor) IsAsync() bool { return false }
func (a testExecutionActor) Name() string { return a.name }
func (testExecutionActor) Validate(plugins.TemplateValidatorFunc, *fieldcollection.FieldCollection) error {
return nil
}
func registerTestExecutionActor(t *testing.T, exec func(*irc.Message) (bool, error)) string {
t.Helper()
name := fmt.Sprintf("test-execution-%s-%d", t.Name(), time.Now().UnixNano())
registerAction(name, func() plugins.Actor { return testExecutionActor{name: name, exec: exec} })
return name
}
func testExecutionRule(actionName, uuid string) *plugins.Rule {
return &plugins.Rule{
UUID: uuid,
Actions: []*plugins.RuleAction{
{Type: actionName, Attributes: fieldcollection.NewFieldCollection()},
},
}
}
func TestHandleMessageRuleExecutionAppliesRuleCooldownOnce(t *testing.T) {
var executed atomic.Int32
actionName := registerTestExecutionActor(t, func(*irc.Message) (bool, error) {
executed.Add(1)
time.Sleep(50 * time.Millisecond)
return false, nil
})
rule := testExecutionRule(actionName, "rule-cooldown-once")
rule.Cooldown = func(d time.Duration) *time.Duration { return &d }(time.Minute)
msg := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :!test")
var wg sync.WaitGroup
wg.Add(2)
for range 2 {
go func() {
defer wg.Done()
handleMessageRuleExecution(nil, msg, rule, nil)
}()
}
wg.Wait()
require.Equal(t, int32(1), executed.Load())
inCooldown, err := timerService.InCooldown(plugins.TimerTypeCooldown, "", rule.MatcherID())
require.NoError(t, err)
require.True(t, inCooldown)
}
func TestHandleMessageRuleExecutionAppliesChannelCooldownOncePerChannel(t *testing.T) {
var executed atomic.Int32
actionName := registerTestExecutionActor(t, func(*irc.Message) (bool, error) {
executed.Add(1)
time.Sleep(50 * time.Millisecond)
return false, nil
})
rule := testExecutionRule(actionName, "channel-cooldown-once")
rule.ChannelCooldown = func(d time.Duration) *time.Duration { return &d }(time.Minute)
msg := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :!test")
var wg sync.WaitGroup
wg.Add(2)
for range 2 {
go func() {
defer wg.Done()
handleMessageRuleExecution(nil, msg, rule, nil)
}()
}
wg.Wait()
require.Equal(t, int32(1), executed.Load())
inCooldown, err := timerService.InCooldown(plugins.TimerTypeCooldown, "#mychannel", rule.MatcherID())
require.NoError(t, err)
require.True(t, inCooldown)
}
func TestHandleMessageRuleExecutionAllowsChannelCooldownAcrossChannels(t *testing.T) {
var executed atomic.Int32
actionName := registerTestExecutionActor(t, func(*irc.Message) (bool, error) {
executed.Add(1)
time.Sleep(50 * time.Millisecond)
return false, nil
})
rule := testExecutionRule(actionName, "channel-cooldown-different-channels")
rule.ChannelCooldown = func(d time.Duration) *time.Duration { return &d }(time.Minute)
msgA := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :!test")
msgB := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #otherchannel :!test")
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
handleMessageRuleExecution(nil, msgA, rule, nil)
}()
go func() {
defer wg.Done()
handleMessageRuleExecution(nil, msgB, rule, nil)
}()
wg.Wait()
require.Equal(t, int32(2), executed.Load())
}
func TestHandleMessageRuleExecutionSkipsCooldownWhenPrevented(t *testing.T) {
actionName := registerTestExecutionActor(t, func(*irc.Message) (bool, error) {
return true, nil
})
rule := testExecutionRule(actionName, "prevent-cooldown")
rule.Cooldown = func(d time.Duration) *time.Duration { return &d }(time.Minute)
msg := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :!test")
handleMessageRuleExecution(nil, msg, rule, nil)
inCooldown, err := timerService.InCooldown(plugins.TimerTypeCooldown, "", rule.MatcherID())
require.NoError(t, err)
require.False(t, inCooldown)
}
func TestHandleMessageRuleExecutionSkipsCooldownOnActionError(t *testing.T) {
actionName := registerTestExecutionActor(t, func(*irc.Message) (bool, error) {
return false, errors.New("boom")
})
rule := testExecutionRule(actionName, "error-no-cooldown")
rule.Cooldown = func(d time.Duration) *time.Duration { return &d }(time.Minute)
msg := irc.MustParseMessage(":amy!amy@foo.example.com PRIVMSG #mychannel :!test")
handleMessageRuleExecution(nil, msg, rule, nil)
inCooldown, err := timerService.InCooldown(plugins.TimerTypeCooldown, "", rule.MatcherID())
require.NoError(t, err)
require.False(t, inCooldown)
}