@@ -20,19 +20,20 @@ public class CommandProcessorTest
2020 private readonly ILogger < CommandProcessor > _nullLogger = new NullLogger < CommandProcessor > ( ) ;
2121 private readonly Mock < ICommandLogger > _commandLoggerMock = new ( ) ;
2222 private readonly ImmutableList < string > _noArgs = ImmutableList < string > . Empty ;
23- private readonly User _mockUser = new User (
23+ private static User MockUser ( ) => new (
2424 id : Guid . NewGuid ( ) . ToString ( ) ,
2525 name : "MockUser" , twitchDisplayName : "☺MockUser" , simpleName : "mockuser" , color : null ,
2626 firstActiveAt : Instant . FromUnixTimeSeconds ( 0 ) , lastActiveAt : Instant . FromUnixTimeSeconds ( 0 ) ,
2727 lastMessageAt : null , pokeyen : 0 , tokens : 0 ) ;
28+ private readonly User _mockUser = MockUser ( ) ;
2829
29- private Message MockMessage ( string text = "" )
30- => new Message ( _mockUser , text , MessageSource . Chat , string . Empty ) ;
30+ private Message MockMessage ( string text = "" ) => new ( _mockUser , text , MessageSource . Chat , string . Empty ) ;
3131
3232 [ Test ]
3333 public async Task TestUnknownCommand ( )
3434 {
35- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
35+ var commandProcessor = new CommandProcessor (
36+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
3637
3738 CommandResult ? result = await commandProcessor . Process ( "unknown" , _noArgs , MockMessage ( ) ) ;
3839
@@ -44,7 +45,8 @@ public async Task TestUnknownCommand()
4445 public async Task TestLogSlowCommand ( )
4546 {
4647 var loggerMock = new Mock < ILogger < CommandProcessor > > ( ) ;
47- var commandProcessor = new CommandProcessor ( loggerMock . Object , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
48+ var commandProcessor = new CommandProcessor (
49+ loggerMock . Object , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
4850 commandProcessor . InstallCommand ( new Command ( "slow" , async _ =>
4951 {
5052 await Task . Delay ( TimeSpan . FromMilliseconds ( 1050 ) ) ;
@@ -62,7 +64,8 @@ public async Task TestLogSlowCommand()
6264 public async Task TestCommandThrowsError ( )
6365 {
6466 var loggerMock = new Mock < ILogger < CommandProcessor > > ( ) ;
65- var commandProcessor = new CommandProcessor ( loggerMock . Object , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
67+ var commandProcessor = new CommandProcessor (
68+ loggerMock . Object , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
6669 commandProcessor . InstallCommand ( new Command ( "broken" ,
6770 _ => throw new InvalidOperationException ( "this command is busted!" ) ) ) ;
6871
@@ -78,7 +81,8 @@ public async Task TestCommandThrowsError()
7881 [ Test ]
7982 public async Task TestCaseInsensitive ( )
8083 {
81- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
84+ var commandProcessor = new CommandProcessor (
85+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
8286 commandProcessor . InstallCommand ( new Command ( "MiXeD" , CommandUtils . StaticResponse ( "Hi!" ) ) ) ;
8387
8488 foreach ( string command in ImmutableList . Create ( "MiXeD" , "mixed" , "MIXED" ) )
@@ -91,7 +95,8 @@ public async Task TestCaseInsensitive()
9195 [ Test ]
9296 public async Task TestAliases ( )
9397 {
94- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
98+ var commandProcessor = new CommandProcessor (
99+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
95100 commandProcessor . InstallCommand ( new Command (
96101 "main" , CommandUtils . StaticResponse ( "Hi!" ) ) { Aliases = new [ ] { "alias1" , "alias2" } } ) ;
97102
@@ -105,7 +110,8 @@ public async Task TestAliases()
105110 [ Test ]
106111 public void InstallConflictName ( )
107112 {
108- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
113+ var commandProcessor = new CommandProcessor (
114+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
109115
110116 commandProcessor . InstallCommand ( new Command ( "a" , CommandUtils . StaticResponse ( "Hi!" ) ) ) ;
111117 ArgumentException ex = Assert . Throws < ArgumentException > ( ( ) => commandProcessor
@@ -116,7 +122,8 @@ public void InstallConflictName()
116122 [ Test ]
117123 public void InstallConflictAlias ( )
118124 {
119- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
125+ var commandProcessor = new CommandProcessor (
126+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
120127
121128 commandProcessor . InstallCommand ( new Command (
122129 "a" , CommandUtils . StaticResponse ( "Hi!" ) ) { Aliases = new [ ] { "x" } } ) ;
@@ -128,7 +135,8 @@ public void InstallConflictAlias()
128135 [ Test ]
129136 public void InstallConflictNameVsAlias ( )
130137 {
131- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
138+ var commandProcessor = new CommandProcessor (
139+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
132140
133141 commandProcessor . InstallCommand ( new Command (
134142 "a" , CommandUtils . StaticResponse ( "Hi!" ) ) { Aliases = new [ ] { "b" } } ) ;
@@ -140,7 +148,8 @@ public void InstallConflictNameVsAlias()
140148 [ Test ]
141149 public async Task TestPermissions ( )
142150 {
143- var commandProcessor = new CommandProcessor ( _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) ) ;
151+ var commandProcessor = new CommandProcessor (
152+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , Mock . Of < IClock > ( ) ) ;
144153 commandProcessor . InstallCommand (
145154 new Command ( "opsonly" , CommandUtils . StaticResponse ( "you are an operator" ) ) . WithCondition (
146155 canExecute : ctx => IsOperator ( ctx . Message . User ) ,
@@ -161,5 +170,49 @@ bool IsOperator(User user) =>
161170 "opsonly" , _noArgs , new Message ( op , "" , MessageSource . Chat , "" ) ) ;
162171 Assert . That ( opResult ? . Response , Is . EqualTo ( "you are an operator" ) ) ;
163172 }
173+
174+ [ Test ]
175+ public async Task MaxCommandsPerUser ( )
176+ {
177+ Mock < IClock > clockMock = new ( ) ;
178+ var commandProcessor = new CommandProcessor (
179+ _nullLogger , _commandLoggerMock . Object , new ArgsParser ( ) , clockMock . Object ,
180+ maxLoadFactor : 6 , maxLoadFactorTimeframe : Duration . FromSeconds ( 10 ) ,
181+ additionalLoadFactorAtHighThreshold : 6 ) ;
182+
183+ commandProcessor . InstallCommand ( new Command ( "foo" ,
184+ _ => Task . FromResult ( new CommandResult { Response = "yes!" } ) ) ) ;
185+
186+ clockMock . Setup ( clock => clock . GetCurrentInstant ( ) ) . Returns ( Instant . FromUnixTimeSeconds ( 0 ) ) ;
187+ CommandResult ? resultOk1 = await commandProcessor . Process (
188+ "foo" , ImmutableList . Create ( "" ) , new Message ( _mockUser , "" , MessageSource . Chat , "" ) ) ;
189+
190+ // has +1 additional load factor because the load factor is already at 1/6, which * 6 additional load is 1
191+ // result is a total load of 3
192+ clockMock . Setup ( clock => clock . GetCurrentInstant ( ) ) . Returns ( Instant . FromUnixTimeSeconds ( 5 ) ) ;
193+ CommandResult ? resultOk2 = await commandProcessor . Process (
194+ "foo" , ImmutableList . Create ( "" ) , new Message ( _mockUser , "" , MessageSource . Chat , "" ) ) ;
195+
196+ // at 50% load already. this gets rejected and adds an additional +3 load (50% of additional 6 load)
197+ // result is a total load of 7
198+ clockMock . Setup ( clock => clock . GetCurrentInstant ( ) ) . Returns ( Instant . FromUnixTimeSeconds ( 10 ) ) ;
199+ CommandResult ? resultNo = await commandProcessor . Process (
200+ "foo" , ImmutableList . Create ( "" ) , new Message ( _mockUser , "" , MessageSource . Chat , "" ) ) ;
201+
202+ // make sure this is per-user
203+ CommandResult ? resultOkOtherUser = await commandProcessor . Process (
204+ "foo" , ImmutableList . Create ( "" ) , new Message ( MockUser ( ) , "" , MessageSource . Chat , "" ) ) ;
205+
206+ // letting everything so far expire lets the user use commands again
207+ clockMock . Setup ( clock => clock . GetCurrentInstant ( ) ) . Returns ( Instant . FromUnixTimeSeconds ( 21 ) ) ;
208+ CommandResult ? resultOk3 = await commandProcessor . Process (
209+ "foo" , ImmutableList . Create ( "" ) , new Message ( _mockUser , "" , MessageSource . Chat , "" ) ) ;
210+
211+ Assert . That ( resultOk1 ? . Response , Is . EqualTo ( "yes!" ) ) ;
212+ Assert . That ( resultOk2 ? . Response , Is . EqualTo ( "yes!" ) ) ;
213+ Assert . That ( resultNo ? . Response , Is . Null ) ;
214+ Assert . That ( resultOkOtherUser ? . Response , Is . EqualTo ( "yes!" ) ) ;
215+ Assert . That ( resultOk3 ? . Response , Is . EqualTo ( "yes!" ) ) ;
216+ }
164217 }
165218}
0 commit comments