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;
7
8use App\Jobs\Notifications\BeatmapsetDisqualify;
9use App\Jobs\Notifications\BeatmapsetResetNominations;
10use App\Models\BeatmapDiscussion;
11use App\Models\Beatmapset;
12use App\Models\BeatmapsetEvent;
13use App\Models\BeatmapsetNomination;
14use App\Models\User;
15use Queue;
16
17class BeatmapsetEventNominationResetTest extends TestCase
18{
19 private Beatmapset $beatmapset;
20
21 /** @var User[] */
22 private array $nominators;
23
24 private User $sender;
25
26 #region event logging tests
27 public function testBeatmapsetEventsWhenDisqualified()
28 {
29 $this->createBeatmapsetWithNominators('qualified');
30
31 $disqualifyCount = BeatmapsetEvent::disqualifications()->count();
32 $nominationResetReceivedCount = BeatmapsetEvent::nominationResetReceiveds()->count();
33
34 $this->postProblem()->assertStatus(200);
35
36 Queue::assertPushed(BeatmapsetDisqualify::class);
37 Queue::assertNotPushed(BeatmapsetResetNominations::class);
38
39 $this->assertSame($disqualifyCount + 1, BeatmapsetEvent::disqualifications()->count());
40 $this->assertSame($nominationResetReceivedCount + count($this->nominators), BeatmapsetEvent::nominationResetReceiveds()->count());
41 $this->assertEqualsCanonicalizing(array_pluck($this->nominators, 'user_id'), BeatmapsetEvent::nominationResetReceiveds()->pluck('user_id')->all());
42 }
43
44 public function testBeatmapsetEventsWhenNotDisqualified()
45 {
46 $this->createBeatmapsetWithNominators('pending');
47
48 $disqualifyCount = BeatmapsetEvent::disqualifications()->count();
49 $nominationResetReceivedCount = BeatmapsetEvent::nominationResetReceiveds()->count();
50
51 $this->postProblem()->assertStatus(200);
52
53 Queue::assertNotPushed(BeatmapsetDisqualify::class);
54 Queue::assertPushed(BeatmapsetResetNominations::class);
55
56 $this->assertSame($disqualifyCount, BeatmapsetEvent::disqualifications()->count());
57 $this->assertSame($nominationResetReceivedCount + count($this->nominators), BeatmapsetEvent::nominationResetReceiveds()->count());
58 $this->assertEqualsCanonicalizing(array_pluck($this->nominators, 'user_id'), BeatmapsetEvent::nominationResetReceiveds()->pluck('user_id')->all());
59 }
60 #endregion
61
62 // FIXME: disqualification tests could probably do with some reorganization.
63 public function testInterOpDisqualify()
64 {
65 $this->createBeatmapsetWithNominators('qualified');
66 $banchoBotUser = User::factory()->create([
67 'user_id' => $GLOBALS['cfg']['osu']['legacy']['bancho_bot_user_id'],
68 ]);
69
70 $disqualifyCount = BeatmapsetEvent::disqualifications()->count();
71 $nominationResetReceivedCount = BeatmapsetEvent::nominationResetReceiveds()->count();
72
73 $url = route('interop.beatmapsets.disqualify', [
74 'beatmapset' => $this->beatmapset->getKey(),
75 'timestamp' => time(),
76 ]);
77
78 $response = $this
79 ->withInterOpHeader($url)
80 ->post($url, ['message' => 'hello'])
81 ->assertStatus(200);
82
83 Queue::assertPushed(BeatmapsetDisqualify::class);
84 Queue::assertNotPushed(BeatmapsetResetNominations::class);
85
86 $this->beatmapset->refresh();
87
88 $discussionId = json_decode($response->getContent(), true)['beatmapset_discussion_id'] ?? null;
89
90 $this->assertNotEmpty($discussionId);
91
92 $discussion = BeatmapDiscussion::find($discussionId);
93 $this->assertTrue($banchoBotUser->is($discussion->user));
94 $this->assertSame('hello', $discussion->startingPost->message);
95
96 $this->assertSame($this->beatmapset->status(), 'pending');
97 $this->assertSame($disqualifyCount + 1, BeatmapsetEvent::disqualifications()->count());
98 $this->assertSame($nominationResetReceivedCount + count($this->nominators), BeatmapsetEvent::nominationResetReceiveds()->count());
99 $this->assertEqualsCanonicalizing(array_pluck($this->nominators, 'user_id'), BeatmapsetEvent::nominationResetReceiveds()->pluck('user_id')->all());
100 }
101
102 protected function setUp(): void
103 {
104 parent::setUp();
105
106 config_set('osu.beatmapset.required_nominations', 2);
107
108 Queue::fake();
109
110 $this->sender = User::factory()->withGroup('bng')->create();
111 }
112
113 private function createBeatmapsetWithNominators($state)
114 {
115 $this->beatmapset = Beatmapset::factory()->owner()->$state()->withDiscussion()->create();
116
117 $modes = $this->beatmapset->beatmaps->map->mode->all();
118 $nominatorCount = $GLOBALS['cfg']['osu']['beatmapset']['required_nominations'];
119
120 $this->nominators = [];
121
122 for ($i = 0; $i < $nominatorCount; $i++) {
123 $this->nominators[] = $nominator = User::factory()->withGroup('bng', $modes)->create();
124 BeatmapsetNomination::factory()->create([
125 'beatmapset_id' => $this->beatmapset,
126 'user_id' => $nominator,
127 ]);
128 }
129 }
130
131 private function postProblem()
132 {
133 return $this
134 ->actingAsVerified($this->sender)
135 ->post(route('beatmapsets.discussions.posts.store'), [
136 'beatmapset_id' => $this->beatmapset->beatmapset_id,
137 'beatmap_discussion' => [
138 'message_type' => 'problem',
139 ],
140 'beatmap_discussion_post' => [
141 'message' => 'Hello',
142 ],
143 ]);
144 }
145}