Skip to content

Commit b2ff378

Browse files
committed
Import activation time from contest YAML
Also add tests to check if the (de)activation time is correctly set via API.
1 parent 9dcd13b commit b2ff378

File tree

3 files changed

+131
-12
lines changed

3 files changed

+131
-12
lines changed

webapp/src/Service/ImportExportService.php

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,10 @@ public function importContestData($data, ?string &$message = null, string &$cid
135135
return false;
136136
}
137137

138+
$activateTimeFields = ['activate-time', 'activation-time', 'activate_time', 'activation_time'];
139+
$deactivateTimeFields = preg_filter('/^/', 'de', $activateTimeFields);
138140
$startTimeFields = ['start_time', 'start-time'];
139-
$requiredFields = [$startTimeFields, 'name', ['id', 'short-name'], 'duration'];
141+
$requiredFields = [$startTimeFields, 'formal_name', ['id', 'name', 'short-name', 'short_name'], 'duration'];
140142
$missingFields = [];
141143
foreach ($requiredFields as $field) {
142144
if (is_array($field)) {
@@ -168,13 +170,25 @@ public function importContestData($data, ?string &$message = null, string &$cid
168170
return false;
169171
}
170172

171-
$activateTime = new DateTime();
172-
if ($activateTime > $startTime) {
173-
$activateTime = $startTime;
173+
// Activate time is special, it can return non empty message for parsing error or null if no field was provided
174+
$activateTime = $this->convertImportedTime($activateTimeFields, $data, $message);
175+
if ($message) {
176+
return false;
177+
} elseif (!$activateTime) {
178+
$activateTime = new DateTime();
179+
if ($activateTime > $startTime) {
180+
$activateTime = $startTime;
181+
}
174182
}
183+
184+
$deactivateTime = $this->convertImportedTime($deactivateTimeFields, $data, $message);
185+
if ($message) {
186+
return false;
187+
}
188+
175189
$contest = new Contest();
176190
$contest
177-
->setName($data['name'])
191+
->setName($data['formal_name'])
178192
->setShortname(preg_replace(
179193
$invalid_regex,
180194
'_',
@@ -185,6 +199,9 @@ public function importContestData($data, ?string &$message = null, string &$cid
185199
->setStarttimeString(date_format($startTime, 'Y-m-d H:i:s e'))
186200
->setActivatetimeString(date_format($activateTime, 'Y-m-d H:i:s e'))
187201
->setEndtimeString(sprintf('+%s', $data['duration']));
202+
if ($deactivateTime) {
203+
$contest->setDeactivatetimeString(date_format($deactivateTime, 'Y-m-d H:i:s e'));
204+
}
188205

189206
// Get all visible categories. For now, we assume these are the ones getting awards
190207
$visibleCategories = $this->em->getRepository(TeamCategory::class)->findBy(['visible' => true]);

webapp/tests/Unit/Controller/API/ContestControllerAdminTest.php

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ public function testAddYaml(): void
3232
{
3333
$yaml = <<<EOF
3434
duration: 2:00:00
35-
name: NWERC 2020 Practice Session
36-
penalty-time: 20
37-
scoreboard-freeze-length: 30:00
38-
short-name: practice
39-
start-time: 2021-03-27 09:00:00+00:00
35+
formal_name: NWERC 2020 Practice Session
36+
penalty_time: 20
37+
scoreboard_freeze_duration: 30:00
38+
id: practice
39+
start_time: 2021-03-27 09:00:00+00:00
4040
problems:
4141
- color: '#FE9DAF'
4242
letter: A
@@ -80,6 +80,8 @@ public function testAddYaml(): void
8080
$expected = $this->parseSortYaml($expectedYaml);
8181
$actual = $this->parseSortYaml($exportContestYaml);
8282
self::assertSame($expected, $actual);
83+
self::assertSame($this->getContest($cid)->getActivatetime(), $this->getContest($cid)->getStarttime());
84+
self::assertNull($this->getContest($cid)->getDeactivatetime());
8385
}
8486

8587
public function testAddJson(): void
@@ -238,4 +240,104 @@ public function provideChangeTimes(): Generator
238240
yield [['id' => 1, 'scoreboard_thaw_time' => '+15 seconds'], 204, null, [], false, true];
239241
yield [['id' => 1, 'scoreboard_thaw_time' => '-15 seconds'], 200, 'Demo contest', [], true, true];
240242
}
243+
244+
/**
245+
* @dataProvider provideNewContest
246+
*/
247+
public function testActivationTimeContestYaml(
248+
string $activationTime, string $startTime, ?string $deactivationTime,
249+
bool $setActivation, bool $setDeactivation
250+
): void {
251+
$yaml = <<<EOF
252+
duration: 2:00:00
253+
formal_name: New Contest to check Activation
254+
penalty-time: 20
255+
scoreboard_freeze_duration: 30:00
256+
name: activation
257+
id: activation
258+
start_time: {$startTime}
259+
problems:
260+
- color: '#FE9DAF'
261+
letter: A
262+
rgb: '#FE9DAF'
263+
id: anothereruption
264+
EOF;
265+
266+
if ($setActivation) {
267+
$yaml = "activation_time: ".$activationTime."\n".$yaml;
268+
}
269+
if ($setDeactivation) {
270+
$yaml = "deactivation_time: ".$deactivationTime."\n".$yaml;
271+
}
272+
$url = $this->helperGetEndpointURL($this->apiEndpoint);
273+
$tempYamlFile = tempnam(sys_get_temp_dir(), "/contest-yaml-");
274+
file_put_contents($tempYamlFile, $yaml);
275+
$yamlFile = new UploadedFile($tempYamlFile, 'contest.yaml');
276+
$cid = $this->verifyApiJsonResponse('POST', $url, 200, $this->apiUser, [], ['yaml' => $yamlFile]);
277+
self::assertIsString($cid);
278+
unlink($tempYamlFile);
279+
280+
$now = Utils::now();
281+
$nowTime = Utils::printtime($now, 'Y-m-d H:i:s');
282+
$activation = Utils::toEpochFloat($activationTime);
283+
$start = Utils::toEpochFloat($startTime);
284+
285+
self::assertIsString($cid);
286+
self::assertSame('New Contest to check Activation', $this->getContest($cid)->getName());
287+
self::assertSame($start, $this->getContest($cid)->getStarttime());
288+
289+
if ($setActivation) {
290+
self::assertSame($activationTime, Utils::printtime($this->getContest($cid)->getActivatetime(), 'Y-m-d H:i:s'));
291+
self::assertSame($activation, $this->getContest($cid)->getActivatetime());
292+
} else {
293+
// Contest uploaded starts in the past
294+
if (Utils::printtime(Utils::now(), 'Y-m-d H:i:s')>=$startTime) {
295+
self::assertSame($this->getContest($cid)->getActivatetime(), $this->getContest($cid)->getStarttime());
296+
} else {
297+
self::assertTrue($this->getContest($cid)->getActivatetime() <= $now);
298+
}
299+
}
300+
if ($deactivationTime) {
301+
self::assertSame($deactivationTime, Utils::printtime($this->getContest($cid)->getDeactivatetime(), 'Y-m-d H:i:s'));
302+
} else {
303+
self::assertNull($this->getContest($cid)->getDeactivatetime());
304+
}
305+
}
306+
307+
public function provideNewContest(): Generator
308+
{
309+
// Test Activation in past, present & future
310+
yield [Utils::printtime(Utils::now()-14*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), null, True, False];
311+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), null, True, False];
312+
yield [Utils::printtime(Utils::now()-1, 'Y-m-d H:i:s'), Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), null, True, False];
313+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), null, True, False];
314+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+1, 'Y-m-d H:i:s'), null, True, False];
315+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), null, True, False];
316+
yield [Utils::printtime(Utils::now()+1, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), null, True, False];
317+
yield [Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+14*24*60*60, 'Y-m-d H:i:s'), null, True, False];
318+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), null, True, False];
319+
// Test Deactivation in past, present & future
320+
yield [Utils::printtime(Utils::now()-14*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-14*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), False, True];
321+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-1, 'Y-m-d H:i:s'), False, True];
322+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), False, True];
323+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+1, 'Y-m-d H:i:s'), False, True];
324+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), False, True];
325+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), False, True];
326+
yield [Utils::printtime(Utils::now()+1, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+1, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), False, True];
327+
yield [Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+14*24*60*60, 'Y-m-d H:i:s'), False, True];
328+
// Only activate during the contest
329+
foreach ([True, False] as $explicitSet) {
330+
yield [Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()-(7*24-2)*60*60, 'Y-m-d H:i:s'), $explicitSet, True];
331+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+2*60*60, 'Y-m-d H:i:s'), $explicitSet, True];
332+
yield [Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+7*24*60*60, 'Y-m-d H:i:s'), Utils::printtime(Utils::now()+(7*24+2)*60*60, 'Y-m-d H:i:s'), $explicitSet, True];
333+
}
334+
// Pick hardcoded times
335+
yield ["2000-01-01 10:10:10", "2000-01-01 10:10:10", "2002-01-01 10:10:10", False, True];
336+
yield ["2000-01-01 10:10:10", "2001-01-01 10:10:10", null, True, False];
337+
yield ["2077-01-01 10:10:10", "2099-01-01 10:10:10", null, True, False];
338+
yield ["2077-01-01 10:10:10", "2099-01-01 10:10:10", "2100-01-01 10:10:10", True, True];
339+
yield ["2000-01-01 10:10:10", "2000-01-01 10:10:10", null, False, False];
340+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), "2099-01-01 10:10:10", null, False, False];
341+
yield [Utils::printtime(Utils::now(), 'Y-m-d H:i:s'), "2077-01-01 10:10:10", "2099-01-01 10:10:10", False, True];
342+
}
241343
}

webapp/tests/Unit/Service/ImportExportServiceTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function provideImportContestDataErrors(): Generator
4646
'duration' => '5:00:00',
4747
'start-time' => 'Invalid start time here',
4848
],
49-
'Can not parse start time'
49+
'Can not parse start-time'
5050
];
5151
yield [
5252
[
@@ -55,7 +55,7 @@ public function provideImportContestDataErrors(): Generator
5555
'duration' => '5:00:00',
5656
'start_time' => 'Invalid start time here',
5757
],
58-
'Can not parse start time'
58+
'Can not parse start_time'
5959
];
6060
yield [
6161
[

0 commit comments

Comments
 (0)