Passed
Push — master ( 0838e7...46b6ee )
by Caen
04:34 queued 14s
created

IntegrationTestCase::projectPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Hyde\RealtimeCompiler\Tests\Integration;
4
5
use InvalidArgumentException;
6
use PHPUnit\Framework\TestCase;
7
use RuntimeException;
8
use ZipArchive;
9
10
abstract class IntegrationTestCase extends TestCase
11
{
12
    /** @var resource */
13
    protected static $server;
14
15
    public static function setUpBeforeClass(): void
16
    {
17
        $monorepo = realpath(__DIR__.'/../../../../');
18
19
        if ($monorepo && realpath(getcwd()) === $monorepo && file_exists($monorepo.'/hyde')) {
20
            throw new InvalidArgumentException('This test suite is not intended to be run from the monorepo.');
21
        }
22
23
        if (! self::hasTestRunnerSetUp()) {
24
            self::setUpTestRunner();
25
        }
26
27
        // Check that post 8080 is available
28
        $process = @fsockopen('localhost', 8080, $errno, $errstr, 1);
29
30
        if ($process) {
0 ignored issues
show
introduced by
$process is of type false|resource, thus it always evaluated to false.
Loading history...
31
            // Try to find the PID of the process using the port
32
            if (PHP_OS_FAMILY === 'Windows') {
33
                $raw = shell_exec('netstat -aon | findstr :8080');
34
                // Get the PID of the process (last column of the first line)
35
                preg_match('/\s+(\d+)$/', explode("\n", $raw)[0], $matches);
36
                $pid = trim($matches[1]);
37
            } else {
38
                $pid = shell_exec('lsof -t -i:8080');
39
            }
40
41
            fclose($process);
42
            $throwInsteadOfKill = false;
43
            if ($throwInsteadOfKill) {
44
                throw new RuntimeException(sprintf('Port 8080 is already in use. (PID %s)', $pid));
45
            } else {
46
                // Kill the process using the port
47
                shell_exec(PHP_OS_FAMILY === 'Windows' ? "taskkill /F /PID $pid" : "kill -9 $pid");
48
            }
49
        }
50
51
        // Start the server in a background process, keeping the task ID for later
52
        $null = PHP_OS_FAMILY === 'Windows' ? 'NUL' : '/dev/null';
53
        self::$server = proc_open("php hyde serve > $null", [], $pipes, realpath(__DIR__.'/../runner'));
54
55
        // Wait for the server to start
56
        while (@fsockopen('localhost', 8080, $errno, $errstr, 1) === false) {
57
            if (proc_get_status(self::$server)['running'] === false) {
58
                break;
59
            }
60
        }
61
62
        // Assert that the server was started successfully
63
        if (! self::$server) {
64
            throw new RuntimeException('Failed to start the test server.');
65
        }
66
    }
67
68
    public function __destruct()
69
    {
70
        // Ensure the server is stopped, regardless of any errors
71
        if (self::$server) {
72
            proc_terminate(self::$server);
73
        }
74
    }
75
76
    protected static function hasTestRunnerSetUp(): bool
77
    {
78
        return file_exists(__DIR__.'/../runner');
79
    }
80
81
    public static function setUpTestRunner(): void
82
    {
83
        echo "\33[33mSetting up test runner...\33[0m This may take a while.\n";
84
85
        $archive = 'https://github.com/hydephp/hyde/archive/refs/heads/master.zip';
86
        $target = __DIR__.'/../runner';
87
88
        $raw = file_get_contents($archive);
89
90
        if ($raw === false) {
91
            throw new RuntimeException('Failed to download test runner.');
92
        }
93
94
        $zipPath = tempnam(sys_get_temp_dir(), 'hyde-master');
95
96
        if ($zipPath === false) {
97
            throw new RuntimeException('Failed to create temporary file.');
98
        }
99
100
        file_put_contents($zipPath, $raw);
101
102
        $zip = new ZipArchive();
103
104
        if ($zip->open($zipPath) !== true) {
105
            throw new RuntimeException('Failed to open zip archive.');
106
        }
107
108
        // Get the name of the root directory in the zip file
109
        $rootDir = $zip->getNameIndex(0);
110
111
        // Extract to a temporary directory
112
        $tempExtractPath = $target.'_temp';
113
        $zip->extractTo($tempExtractPath);
114
115
        $zip->close();
116
117
        // Move the contents of the extracted directory to the target directory
118
        rename($tempExtractPath.'/'.$rootDir, $target);
119
120
        // Remove the temporary extraction directory
121
        rmdir($tempExtractPath);
122
123
        unlink($zipPath);
124
125
        $runner = realpath($target);
126
127
        // Junction the package source of hyde/realtime-compiler to the test runner
128
        $branch = trim(shell_exec('git rev-parse --abbrev-ref HEAD') ?: 'master');
129
        shell_exec("cd $runner && composer config repositories.realtime-compiler path ../../");
130
        shell_exec("cd $runner && composer require --dev hyde/realtime-compiler:dev-$branch --no-progress > setup.log 2>&1");
131
    }
132
133
    public function projectPath(string $path = ''): string
134
    {
135
        return realpath(__DIR__.'/../runner').($path ? '/'.$path : '');
136
    }
137
138
    public function get(string $uri): TestResponse
139
    {
140
        return TestResponse::get($this, $uri);
141
    }
142
}
143