-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Keep track of potential first to solves so we can update them when we…
… get 'delayed' results. Fixes #2281.
- Loading branch information
Nicky Gerritsen
committed
Mar 13, 2024
1 parent
440cfa2
commit 9f4dcc0
Showing
5 changed files
with
272 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DoctrineMigrations; | ||
|
||
use Doctrine\DBAL\Schema\Schema; | ||
use Doctrine\Migrations\AbstractMigration; | ||
|
||
/** | ||
* Auto-generated Migration: Please modify to your needs! | ||
*/ | ||
final class Version20231229094359 extends AbstractMigration | ||
{ | ||
public function getDescription(): string | ||
{ | ||
return 'Add potential first to solve to scorecache.'; | ||
} | ||
|
||
public function up(Schema $schema): void | ||
{ | ||
// this up() migration is auto-generated, please modify it to your needs | ||
$this->addSql('ALTER TABLE scorecache ADD is_potential_first_to_solve TINYINT(1) DEFAULT 0 NOT NULL COMMENT \'Is this potentially the first solution to this problem?\' AFTER is_first_to_solve'); | ||
} | ||
|
||
public function down(Schema $schema): void | ||
{ | ||
// this down() migration is auto-generated, please modify it to your needs | ||
$this->addSql('ALTER TABLE scorecache DROP is_potential_first_to_solve'); | ||
} | ||
|
||
public function isTransactional(): bool | ||
{ | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace App\DataFixtures\Test; | ||
|
||
use App\Entity\Team; | ||
use App\Entity\TeamAffiliation; | ||
use App\Entity\TeamCategory; | ||
use Doctrine\Persistence\ObjectManager; | ||
|
||
class SampleTeamsFixture extends AbstractTestDataFixture | ||
{ | ||
final public const FIRST_TEAM_REFERENCE = 'team1'; | ||
final public const SECOND_TEAM_REFERENCE = 'team2'; | ||
|
||
public function load(ObjectManager $manager): void | ||
{ | ||
$affiliation = $manager->getRepository(TeamAffiliation::class)->findOneBy(['externalid' => 'utrecht']); | ||
$category = $manager->getRepository(TeamCategory::class)->findOneBy(['externalid' => 'participants']); | ||
|
||
$team1 = new Team(); | ||
$team1 | ||
->setExternalid('team1') | ||
->setIcpcid('team1') | ||
->setLabel('team1') | ||
->setName('Team 1') | ||
->setAffiliation($affiliation) | ||
->setCategory($category); | ||
|
||
$team2 = new Team(); | ||
$team2 | ||
->setExternalid('team2') | ||
->setIcpcid('team2') | ||
->setLabel('team2') | ||
->setName('Team 2') | ||
->setAffiliation($affiliation) | ||
->setCategory($category); | ||
|
||
$manager->persist($team1); | ||
$manager->persist($team2); | ||
$manager->flush(); | ||
|
||
$this->addReference(self::FIRST_TEAM_REFERENCE, $team1); | ||
$this->addReference(self::SECOND_TEAM_REFERENCE, $team2); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace App\Tests\Unit\Service; | ||
|
||
use App\DataFixtures\Test\SampleTeamsFixture; | ||
use App\Entity\Contest; | ||
use App\Entity\ContestProblem; | ||
use App\Entity\Judging; | ||
use App\Entity\Language; | ||
use App\Entity\ScoreCache; | ||
use App\Entity\Submission; | ||
use App\Entity\Team; | ||
use App\Service\ScoreboardService; | ||
use App\Tests\Unit\BaseTestCase; | ||
use App\Utils\Utils; | ||
use Doctrine\ORM\EntityManagerInterface; | ||
|
||
class ScoreboardServiceTest extends BaseTestCase | ||
{ | ||
/** | ||
* Test that a delayed submission result still results in a correct first to solve | ||
*/ | ||
public function testFirstToSolveDelayed(): void | ||
{ | ||
$em = static::getContainer()->get(EntityManagerInterface::class); | ||
$this->loadFixture(SampleTeamsFixture::class); | ||
$team1 = $this->fixtureExecutor->getReferenceRepository()->getReference(SampleTeamsFixture::FIRST_TEAM_REFERENCE); | ||
$team2 = $this->fixtureExecutor->getReferenceRepository()->getReference(SampleTeamsFixture::SECOND_TEAM_REFERENCE); | ||
$contest = $em->getRepository(Contest::class)->findOneBy(['shortname' => 'demo']); | ||
$contestProblem = $contest->getProblems()->first(); | ||
$problem = $contestProblem->getProblem(); | ||
|
||
$scoreboardService = static::getContainer()->get(ScoreboardService::class); | ||
|
||
// Create a submission for both team 1 and team 2. | ||
// The submission for team 1 will be pending, while the submission | ||
// for team 2 will be correct. | ||
$submission1 = $this->createSubmission($em, $team1, $contestProblem, $contest, null); | ||
$submission2 = $this->createSubmission($em, $team2, $contestProblem, $contest, 'correct'); | ||
$em->flush(); | ||
|
||
$scoreboardService->calculateScoreRow($contest, $team1, $problem); | ||
$scoreboardService->calculateScoreRow($contest, $team2, $problem); | ||
|
||
/** @var ScoreCache $scoreCacheTeam1 */ | ||
$scoreCacheTeam1 = $em->getRepository(ScoreCache::class)->findOneBy([ | ||
'contest' => $contest, | ||
'team' => $team1, | ||
'problem' => $problem, | ||
]); | ||
/** @var ScoreCache $scoreCacheTeam2 */ | ||
$scoreCacheTeam2 = $em->getRepository(ScoreCache::class)->findOneBy([ | ||
'contest' => $contest, | ||
'team' => $team2, | ||
'problem' => $problem, | ||
]); | ||
|
||
static::assertFalse($scoreCacheTeam1->getIsFirstToSolve()); | ||
static::assertFalse($scoreCacheTeam2->getIsFirstToSolve()); | ||
|
||
// Now update the submission for team 1 to be wrong | ||
$submission1->getJudgings()->first()->setResult('wrong'); | ||
$em->flush(); | ||
|
||
$scoreboardService->calculateScoreRow($contest, $team1, $problem); | ||
|
||
// We need to clear the entity manager to make sure we get the updated score caches. | ||
$em->clear(); | ||
|
||
/** @var ScoreCache $scoreCacheTeam1 */ | ||
$scoreCacheTeam1 = $em->getRepository(ScoreCache::class)->findOneBy([ | ||
'contest' => $contest, | ||
'team' => $team1, | ||
'problem' => $problem, | ||
]); | ||
/** @var ScoreCache $scoreCacheTeam2 */ | ||
$scoreCacheTeam2 = $em->getRepository(ScoreCache::class)->findOneBy([ | ||
'contest' => $contest, | ||
'team' => $team2, | ||
'problem' => $problem, | ||
]); | ||
|
||
static::assertFalse($scoreCacheTeam1->getIsFirstToSolve()); | ||
static::assertTrue($scoreCacheTeam2->getIsFirstToSolve()); | ||
} | ||
|
||
protected function createSubmission( | ||
EntityManagerInterface $em, | ||
Team $team, | ||
ContestProblem $problem, | ||
Contest $contest, | ||
?string $result | ||
): Submission { | ||
$submission = new Submission(); | ||
$submission | ||
->setTeam($team) | ||
->setProblem($problem->getProblem()) | ||
->setContest($contest) | ||
->setContestProblem($problem) | ||
->setLanguage($em->getRepository(Language::class)->findOneBy(['name' => 'C++'])) | ||
->setValid(true) | ||
->setSubmittime(Utils::now()) | ||
->addJudging( | ||
$judging = (new Judging()) | ||
->setValid(true) | ||
->setStarttime(Utils::now()) | ||
->setEndtime(Utils::now()) | ||
->setSubmission($submission) | ||
->setResult($result) | ||
); | ||
|
||
$em->persist($submission); | ||
$em->persist($judging); | ||
|
||
return $submission; | ||
} | ||
} |