Skip to content

Commit

Permalink
Try fix timeserver
Browse files Browse the repository at this point in the history
  • Loading branch information
AydinHassan committed Sep 4, 2024
1 parent 2906141 commit 9269bc6
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 61 deletions.
8 changes: 4 additions & 4 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

139 changes: 90 additions & 49 deletions src/Exercise/TimeServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
use PhpSchool\PhpWorkshop\Exercise\ExerciseType;
use PhpSchool\PhpWorkshop\Exercise\Scenario\CliScenario;
use PhpSchool\PhpWorkshop\ExerciseDispatcher;
use PhpSchool\PhpWorkshop\Output\OutputInterface;
use PhpSchool\PhpWorkshop\Result\ComparisonFailure;
use PhpSchool\PhpWorkshop\Result\Failure;
Expand All @@ -31,71 +30,101 @@ public function getDescription(): string

public function defineListeners(EventDispatcher $eventDispatcher): void
{
$appendArgsListener = function (CliExecuteEvent $event) {
$event->appendArg('127.0.0.1');
$event->appendArg($this->getRandomPort());
};
$referencePort = $this->getRandomPort();
$studentPort = $this->getRandomPort();

$eventDispatcher->listen(
'cli.verify.reference-execute.pre',
function (CliExecuteEvent $event) use ($referencePort) {
$event->appendArg('0.0.0.0');
$event->appendArg((string) $referencePort);
$event->getScenario()->exposePort($referencePort);
}
);
$eventDispatcher->listen(
['cli.verify.student-execute.pre', 'cli.run.student-execute.pre'],
function (CliExecuteEvent $event) use ($studentPort) {
$event->appendArg('0.0.0.0');
$event->appendArg((string) $studentPort);
$event->getScenario()->exposePort($studentPort);
}
);

$eventDispatcher->listen('cli.verify.reference-execute.pre', $appendArgsListener);
$eventDispatcher->listen('cli.verify.student-execute.pre', $appendArgsListener);
$eventDispatcher->listen('cli.run.student-execute.pre', $appendArgsListener);
$eventDispatcher->listen(
'cli.verify.reference.executing',
function (CliExecuteEvent $event) use ($referencePort) {
//wait for server to boot
sleep(1);

$eventDispatcher->listen('cli.verify.reference.executing', function (CliExecuteEvent $event) {
$args = $event->getArgs()->getArrayCopy();
$socket = $this->createSocket();
@socket_connect($socket, '0.0.0.0', $referencePort);
@socket_read($socket, 2048, PHP_NORMAL_READ);

//wait for server to boot
usleep(100000);
socket_close($socket);

$socket = $this->createSocket();
socket_connect($socket, $args[0], (int) $args[1]);
socket_read($socket, 2048, PHP_NORMAL_READ);
//wait for shutdown
usleep(100000);
}
);

//wait for shutdown
usleep(100000);
});
$eventDispatcher->insertVerifier(
'cli.verify.student.executing',
function (CliExecuteEvent $event) use ($studentPort) {
//wait for server to boot
sleep(1);

$eventDispatcher->insertVerifier('cli.verify.student.executing', function (CliExecuteEvent $event) {
$args = $event->getArgs()->getArrayCopy();
$socket = $this->createSocket();

//wait for server to boot
usleep(100000);
$result = @socket_connect($socket, '0.0.0.0', $studentPort);

$socket = $this->createSocket();
$connectResult = @socket_connect($socket, $args[0], (int) $args[1]);

if (!$connectResult) {
return Failure::fromNameAndReason($this->getName(), sprintf(
"Client returns an error (number %d): Connection refused while trying to join tcp://127.0.0.1:%d.",
socket_last_error($socket),
$args[1]
));
}
if (!$result) {
$error = "Client returns an error (number %d): Connection refused ";
$error .= "while trying to join tcp://0.0.0.0:%d.";

$out = (string) socket_read($socket, 2048, PHP_NORMAL_READ);
return Failure::fromNameAndReason($this->getName(), sprintf(
$error,
socket_last_error($socket),
$studentPort
));
}

//wait for shutdown
usleep(100000);
$out = (string) socket_read($socket, 2048, PHP_NORMAL_READ);

socket_close($socket);

$date = new \DateTime();
//wait for shutdown
usleep(100000);

//match the current date but any seconds
//since we can't mock time in PHP easily
if (!preg_match(sprintf('/^%s:([0-5][0-9]|60)\n$/', $date->format('Y-m-d H:i')), $out)) {
return ComparisonFailure::fromNameAndValues($this->getName(), $date->format("Y-m-d H:i:s\n"), $out);
$date = new \DateTime();

//match the current date but any seconds
//since we can't mock time in PHP easily
if (!preg_match(sprintf('/^%s:([0-5][0-9]|60)\n$/', $date->format('Y-m-d H:i')), $out)) {
return ComparisonFailure::fromNameAndValues($this->getName(), $date->format("Y-m-d H:i:s\n"), $out);
}
return new Success($this->getName());
}
return new Success($this->getName());
});
);

$eventDispatcher->listen('cli.run.student.executing', function (CliExecuteEvent $event) {
$eventDispatcher->listen('cli.run.student.executing', function (CliExecuteEvent $event) use ($studentPort) {
/** @var OutputInterface $output */
$output = $event->getParameter('output');
$args = $event->getArgs()->getArrayCopy();

//wait for server to boot
usleep(100000);
sleep(1);

$socket = $this->createSocket();
socket_connect($socket, $args[0], (int) $args[1]);
try {
$connectResult = @socket_connect($socket, '0.0.0.0', $studentPort);
} catch (\ErrorException $e) {
$output->write('Cannot connect');
return;
}

if (false === $connectResult) {
$output->write('Cannot connect');
return;
}
$out = (string) socket_read($socket, 2048, PHP_NORMAL_READ);

//wait for shutdown
Expand All @@ -105,9 +134,18 @@ public function defineListeners(EventDispatcher $eventDispatcher): void
});
}

private function getRandomPort(): string
private function getRandomPort(): int
{
return (string) mt_rand(1025, 65535);
$sock = socket_create_listen(0);

if ($sock === false) {
throw new RuntimeException('Cannot create socket');
}

socket_getsockname($sock, $addr, $port);
socket_close($sock);

return $port;
}

public function getType(): ExerciseType
Expand All @@ -117,7 +155,8 @@ public function getType(): ExerciseType

public function defineTestScenario(): CliScenario
{
return (new CliScenario())->withExecution();
return (new CliScenario())
->withExecution();
}

private function createSocket(): Socket
Expand All @@ -128,6 +167,8 @@ private function createSocket(): Socket
throw new RuntimeException('Cannot create socket');
}

socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 5, "usec" => 0]);

return $socket;
}
}
10 changes: 2 additions & 8 deletions test/Exercise/TimeServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,8 @@ public function testFailureWhenCannotConnect(): void

$this->assertVerifyWasNotSuccessful();

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$reason = '/^Client returns an error \(number \d+\): No connection could be made because';
$reason .= ' the target machine actively refused it\.\r\n';
$reason .= ' while trying to join tcp:\/\/127\.0\.0\.1:\d+\.$/';
} else {
$reason = '/^Client returns an error \(number \d+\): Connection refused';
$reason .= ' while trying to join tcp:\/\/127\.0\.0\.1:\d+\.$/';
}
$reason = '/^Client returns an error \(number \d+\): Connection refused';
$reason .= ' while trying to join tcp:\/\/0\.0\.0\.0:\d+\.$/';

$this->assertResultsHasFailureAndMatches(Failure::class, function (Failure $failure) use ($reason) {
$this->assertMatchesRegularExpression($reason, $failure->getReason());
Expand Down

0 comments on commit 9269bc6

Please sign in to comment.