Completed
Push — master ( 3338f6...2ff2f4 )
by Aydin
02:03
created

TimeServer::check()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 42
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 42
rs 8.439
cc 5
eloc 22
nc 7
nop 1
1
<?php
2
3
namespace PhpSchool\LearnYouPhp\Exercise;
4
5
use Hoa\Core\Exception\Exception;
6
use PhpSchool\LearnYouPhp\TcpSocketFactory;
7
use PhpSchool\PhpWorkshop\Exercise\ExerciseInterface;
8
use PhpSchool\PhpWorkshop\ExerciseCheck\SelfCheck;
9
use PhpSchool\PhpWorkshop\Result\Failure;
10
use PhpSchool\PhpWorkshop\Result\ResultInterface;
11
use PhpSchool\PhpWorkshop\Result\StdOutFailure;
12
use PhpSchool\PhpWorkshop\Result\Success;
13
use Psr\Http\Message\RequestInterface;
14
use Symfony\Component\Process\Process;
15
use Symfony\Component\Process\ProcessBuilder;
16
use Zend\Diactoros\Request;
17
18
/**
19
 * Class TimeServer
20
 * @package PhpSchool\LearnYouPhp\Exercise
21
 * @author Aydin Hassan <[email protected]>
22
 */
23
class TimeServer implements ExerciseInterface, SelfCheck
24
{
25
26
    /**
27
     * @var TcpSocketFactory
28
     */
29
    private $socketFactory;
30
31
    /**
32
     * TimeServer constructor.
33
     * @param TcpSocketFactory $socketFactory
34
     */
35
    public function __construct(TcpSocketFactory $socketFactory)
36
    {
37
        $this->socketFactory = $socketFactory;
38
    }
39
    
40
    /**
41
     * @return string
42
     */
43
    public function getName()
44
    {
45
        return 'Time Server';
46
    }
47
48
    /**
49
     * @return string
50
     */
51
    public function getDescription()
52
    {
53
        return 'Build a Time Server!';
54
    }
55
56
    /**
57
     * @return string
58
     */
59
    public function getSolution()
60
    {
61
        return __DIR__ . '/../../res/solutions/time-server/solution.php';
62
    }
63
64
    /**
65
     * @return string
66
     */
67
    public function getProblem()
68
    {
69
        return __DIR__ . '/../../res/problems/time-server/problem.md';
70
    }
71
72
    /**
73
     * @return null
74
     */
75
    public function tearDown()
76
    {
77
    }
78
79
    /**
80
     * @param string $fileName
81
     * @return ResultInterface
82
     */
83
    public function check($fileName)
84
    {
85
        $address    = '127.0.0.1';
86
        $port       = $this->getRandomPort();
87
88
        $cmd        = sprintf('%s %s %s', PHP_BINARY, $fileName, implode(' ', [$address, $port]));
89
        $process    = new Process($cmd, dirname($fileName));
90
        $process->start();
91
        
92
        //wait for server to boot
93
        usleep(100000);
94
        
95
        $client = $this->socketFactory->createClient($address, $port);
96
        
97
        try {
98
            $client->connect();
99
        } catch (Exception $e) {
100
            return Failure::fromNameAndReason($this->getName(), $e->getMessage());
101
        }
102
      
103
        $out = $client->readAll();
104
        
105
        //wait for shutdown
106
        usleep(100000);
107
        
108
        if ($process->isRunning()) {
109
            $process->stop();
110
        }
111
        
112
        if ($process->isSuccessful()) {
113
            $date = new \DateTime;
114
            
115
            //match the current date but any seconds
116
            //since we can't mock time in PHP easily
117
            if (!preg_match(sprintf('/^%s:([0-5][0-9]|60)\n$/', $date->format('Y-m-d H:i')), $out)) {
118
                return new StdOutFailure($this->getName(), $date->format("Y-m-d H:i:s\n"), $out);
119
            }
120
            return new Success($this->getName());
121
        }
122
123
        return new Failure($this->getName(), $process->getErrorOutput());
124
    }
125
126
    /**
127
     * @return int
128
     */
129
    private function getRandomPort()
130
    {
131
        return mt_rand(1025, 65535);
132
    }
133
}
134