the browser-facing portion of osu!
at master 13 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace Tests\Controllers\InterOp; 7 8use App\Models\Group; 9use App\Models\User; 10use App\Models\UserGroupEvent; 11use Tests\TestCase; 12 13class UserGroupsControllerTest extends TestCase 14{ 15 public function testUserGroupAdd() 16 { 17 $user = User::factory()->create(); 18 $group = app('groups')->byIdentifier('gmt'); 19 $userAddEventCount = $this->eventCount(UserGroupEvent::USER_ADD, $user, $group); 20 $url = route('interop.user-group.update', [ 21 'group' => $group->getKey(), 22 'timestamp' => time(), 23 'user' => $user->getKey(), 24 ]); 25 26 $this 27 ->withInterOpHeader($url) 28 ->put($url) 29 ->assertStatus(204); 30 31 $user->refresh(); 32 33 $this->assertTrue($user->isGroup($group)); 34 $this->assertSame( 35 $this->eventCount(UserGroupEvent::USER_ADD, $user, $group), 36 $userAddEventCount + 1, 37 ); 38 } 39 40 public function testUserGroupAddWhenAlreadyMember() 41 { 42 $user = User::factory()->withGroup('gmt')->create(); 43 $group = app('groups')->byIdentifier('gmt'); 44 $userAddEventCount = $this->eventCount(UserGroupEvent::USER_ADD, $user, $group); 45 $url = route('interop.user-group.update', [ 46 'group' => $group->getKey(), 47 'timestamp' => time(), 48 'user' => $user->getKey(), 49 ]); 50 51 $this 52 ->withInterOpHeader($url) 53 ->put($url) 54 ->assertStatus(204); 55 56 $user->refresh(); 57 58 $this->assertTrue($user->isGroup($group)); 59 $this->assertSame( 60 $this->eventCount(UserGroupEvent::USER_ADD, $user, $group), 61 $userAddEventCount, 62 ); 63 } 64 65 public function testUserGroupAddWhenHasSamePlaymodes() 66 { 67 $playmodes = ['osu']; 68 $user = User::factory()->withGroup('nat', $playmodes)->create(); 69 $group = app('groups')->byIdentifier('nat'); 70 $userAddPlaymodesEventCount = $this->eventCount(UserGroupEvent::USER_ADD_PLAYMODES, $user, $group); 71 $url = route('interop.user-group.update', [ 72 'group' => $group->getKey(), 73 'playmodes' => $playmodes, 74 'timestamp' => time(), 75 'user' => $user->getKey(), 76 ]); 77 78 $this 79 ->withInterOpHeader($url) 80 ->put($url) 81 ->assertStatus(204); 82 83 $this->assertSame( 84 $this->eventCount(UserGroupEvent::USER_ADD_PLAYMODES, $user, $group), 85 $userAddPlaymodesEventCount, 86 ); 87 } 88 89 public function testUserGroupChangePlaymodes() 90 { 91 $playmodes = ['fruits', 'mania']; 92 $user = User::factory()->withGroup('nat', ['osu', 'taiko'])->create(); 93 $group = app('groups')->byIdentifier('nat'); 94 $userAddEventCount = $this->eventCount(UserGroupEvent::USER_ADD, $user, $group); 95 $userAddPlaymodesEventCount = $this->eventCount(UserGroupEvent::USER_ADD_PLAYMODES, $user, $group); 96 $userRemovePlaymodesEventCount = $this->eventCount(UserGroupEvent::USER_REMOVE_PLAYMODES, $user, $group); 97 $url = route('interop.user-group.update', [ 98 'group' => $group->getKey(), 99 'playmodes' => $playmodes, 100 'timestamp' => time(), 101 'user' => $user->getKey(), 102 ]); 103 104 $this 105 ->withInterOpHeader($url) 106 ->put($url) 107 ->assertStatus(204); 108 109 $user->refresh(); 110 111 $actualPlaymodes = $user->findUserGroup($group, true)->playmodes; 112 113 $this->assertCount(count($playmodes), $actualPlaymodes); 114 $this->assertArraySubset($playmodes, $actualPlaymodes); 115 $this->assertSame( 116 $this->eventCount(UserGroupEvent::USER_ADD, $user, $group), 117 $userAddEventCount, 118 ); 119 $this->assertSame( 120 $this->eventCount(UserGroupEvent::USER_ADD_PLAYMODES, $user, $group), 121 $userAddPlaymodesEventCount + 1, 122 ); 123 $this->assertSame( 124 $this->eventCount(UserGroupEvent::USER_REMOVE_PLAYMODES, $user, $group), 125 $userRemovePlaymodesEventCount + 1, 126 ); 127 } 128 129 public function testUserGroupRemove() 130 { 131 $user = User::factory()->withGroup('gmt')->create(); 132 $group = app('groups')->byIdentifier('gmt'); 133 $userRemoveEventCount = $this->eventCount(UserGroupEvent::USER_REMOVE, $user, $group); 134 $url = route('interop.user-group.destroy', [ 135 'group' => $group->getKey(), 136 'timestamp' => time(), 137 'user' => $user->getKey(), 138 ]); 139 140 $this 141 ->withInterOpHeader($url) 142 ->delete($url) 143 ->assertStatus(204); 144 145 $user->refresh(); 146 147 $this->assertNotSame($user->group_id, $group->getKey()); 148 $this->assertFalse($user->isGroup($group)); 149 $this->assertSame( 150 $this->eventCount(UserGroupEvent::USER_REMOVE, $user, $group), 151 $userRemoveEventCount + 1, 152 ); 153 } 154 155 public function testUserGroupRemoveWhenNotMember() 156 { 157 $user = User::factory()->create(); 158 $group = app('groups')->byIdentifier('gmt'); 159 $userRemoveEventCount = $this->eventCount(UserGroupEvent::USER_REMOVE, $user, $group); 160 $url = route('interop.user-group.destroy', [ 161 'group' => $group->getKey(), 162 'timestamp' => time(), 163 'user' => $user->getKey(), 164 ]); 165 166 $this 167 ->withInterOpHeader($url) 168 ->delete($url) 169 ->assertStatus(204); 170 171 $user->refresh(); 172 173 $this->assertFalse($user->isGroup($group)); 174 $this->assertSame( 175 $this->eventCount(UserGroupEvent::USER_REMOVE, $user, $group), 176 $userRemoveEventCount, 177 ); 178 } 179 180 public function testUserGroupSetDefault() 181 { 182 $user = User::factory()->withGroup('gmt')->create(['group_id' => app('groups')->byIdentifier('default')]); 183 $group = app('groups')->byIdentifier('gmt'); 184 $userAddEventCount = $this->eventCount(UserGroupEvent::USER_ADD, $user, $group); 185 $userSetDefaultEventCount = $this->eventCount(UserGroupEvent::USER_SET_DEFAULT, $user, $group); 186 $url = route('interop.user-group.set-default', [ 187 'group' => $group->getKey(), 188 'timestamp' => time(), 189 'user' => $user->getKey(), 190 ]); 191 192 $this 193 ->withInterOpHeader($url) 194 ->post($url) 195 ->assertStatus(204); 196 197 $user->refresh(); 198 199 $this->assertSame($user->group_id, $group->getKey()); 200 $this->assertTrue($user->isGroup($group)); 201 $this->assertSame( 202 $this->eventCount(UserGroupEvent::USER_ADD, $user, $group), 203 $userAddEventCount, 204 ); 205 $this->assertSame( 206 $this->eventCount(UserGroupEvent::USER_SET_DEFAULT, $user, $group), 207 $userSetDefaultEventCount + 1, 208 ); 209 } 210 211 public function testUserGroupSetDefaultLeavesPlaymodesUnchanged() 212 { 213 $playmodes = ['osu']; 214 $user = User::factory()->withGroup('nat', $playmodes)->create(['group_id' => app('groups')->byIdentifier('default')->getKey()]); 215 $group = app('groups')->byIdentifier('nat'); 216 $url = route('interop.user-group.set-default', [ 217 'group' => $group->getKey(), 218 'timestamp' => time(), 219 'user' => $user->getKey(), 220 ]); 221 222 $this 223 ->withInterOpHeader($url) 224 ->post($url) 225 ->assertStatus(204); 226 227 $user->refresh(); 228 229 $actualPlaymodes = $user->findUserGroup($group, true)->playmodes; 230 231 $this->assertCount(count($playmodes), $actualPlaymodes); 232 $this->assertArraySubset($playmodes, $actualPlaymodes); 233 } 234 235 public function testUserGroupSetDefaultWhenAlreadyDefault() 236 { 237 $user = User::factory()->withGroup('gmt')->create(); 238 $group = app('groups')->byIdentifier('gmt'); 239 $userSetDefaultEventCount = $this->eventCount(UserGroupEvent::USER_SET_DEFAULT, $user, $group); 240 $url = route('interop.user-group.set-default', [ 241 'group' => $group->getKey(), 242 'timestamp' => time(), 243 'user' => $user->getKey(), 244 ]); 245 246 $this 247 ->withInterOpHeader($url) 248 ->post($url) 249 ->assertStatus(204); 250 251 $this->assertSame( 252 $this->eventCount(UserGroupEvent::USER_SET_DEFAULT, $user, $group), 253 $userSetDefaultEventCount, 254 ); 255 } 256 257 public function testUserGroupSetDefaultWhenNotMember() 258 { 259 $user = User::factory()->create(); 260 $group = app('groups')->byIdentifier('gmt'); 261 $userAddEventCount = $this->eventCount(UserGroupEvent::USER_ADD, $user, $group); 262 $userSetDefaultEventCount = $this->eventCount(UserGroupEvent::USER_SET_DEFAULT, $user, $group); 263 $url = route('interop.user-group.set-default', [ 264 'group' => $group->getKey(), 265 'timestamp' => time(), 266 'user' => $user->getKey(), 267 ]); 268 269 $this 270 ->withInterOpHeader($url) 271 ->post($url) 272 ->assertStatus(204); 273 274 $user->refresh(); 275 276 $this->assertSame($user->group_id, $group->getKey()); 277 $this->assertTrue($user->isGroup($group)); 278 $this->assertSame( 279 $this->eventCount(UserGroupEvent::USER_ADD, $user, $group), 280 $userAddEventCount + 1, 281 ); 282 $this->assertSame( 283 $this->eventCount(UserGroupEvent::USER_SET_DEFAULT, $user, $group), 284 $userSetDefaultEventCount + 1, 285 ); 286 } 287 288 public function testInvalidPlaymodes() 289 { 290 $user = User::factory()->create(); 291 $group = app('groups')->byIdentifier('nat'); 292 $group->update(['has_playmodes' => true]); 293 $url = route('interop.user-group.update', [ 294 'group' => $group->getKey(), 295 'playmodes' => ['osu', 'invalid_playmode'], 296 'timestamp' => time(), 297 'user' => $user->getKey(), 298 ]); 299 300 $this 301 ->withInterOpHeader($url) 302 ->put($url) 303 ->assertStatus(422); 304 } 305 306 public function testPlaymodesWithoutGroupPlaymodesSet() 307 { 308 $user = User::factory()->create(); 309 $group = app('groups')->byIdentifier('gmt'); 310 $url = route('interop.user-group.update', [ 311 'group' => $group->getKey(), 312 'playmodes' => ['osu'], 313 'timestamp' => time(), 314 'user' => $user->getKey(), 315 ]); 316 317 $this 318 ->withInterOpHeader($url) 319 ->put($url) 320 ->assertStatus(422); 321 } 322 323 /** 324 * @dataProvider userGroupRoutesDataProvider 325 */ 326 public function testWithActor(string $type, string $method, string $route): void 327 { 328 $user = User::factory()->create(); 329 $group = app('groups')->byIdentifier('gmt'); 330 $actor = User::factory()->create(); 331 $url = route($route, [ 332 'actor_id' => $actor->getKey(), 333 'group' => $group->getKey(), 334 'timestamp' => time(), 335 'user' => $user->getKey(), 336 ]); 337 338 if ($type === UserGroupEvent::USER_REMOVE) { 339 $user->addToGroup($group); 340 } 341 342 $this->expectCountChange( 343 fn () => $this->eventCount($type, $user, $group, $actor), 344 1, 345 ); 346 347 $this 348 ->withInterOpHeader($url) 349 ->$method($url) 350 ->assertStatus(204); 351 } 352 353 /** 354 * @dataProvider userGroupRoutesDataProvider 355 */ 356 public function testWithInvalidActor(string $type, string $method, string $route): void 357 { 358 $user = User::factory()->create(); 359 $group = app('groups')->byIdentifier('gmt'); 360 $url = route($route, [ 361 'actor_id' => $user->getKey() + 1, 362 'group' => $group->getKey(), 363 'timestamp' => time(), 364 'user' => $user->getKey(), 365 ]); 366 367 $this 368 ->withInterOpHeader($url) 369 ->$method($url) 370 ->assertStatus(404); 371 } 372 373 public static function userGroupRoutesDataProvider(): array 374 { 375 return [ 376 'add' => 377 [UserGroupEvent::USER_ADD, 'put', 'interop.user-group.update'], 378 'remove' => 379 [UserGroupEvent::USER_REMOVE, 'delete', 'interop.user-group.destroy'], 380 'set default' => 381 [UserGroupEvent::USER_SET_DEFAULT, 'post', 'interop.user-group.set-default'], 382 ]; 383 } 384 385 private function eventCount(string $type, User $user, Group $group, ?User $actor = null): int 386 { 387 return UserGroupEvent 388 ::where([ 389 'actor_id' => $actor?->getKey(), 390 'group_id' => $group->getKey(), 391 'type' => $type, 392 'user_id' => $user->getKey(), 393 ]) 394 ->count(); 395 } 396}