diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..3253e2c --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,16 @@ +name: "CodeQL" + +on: [pull_request] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 00096f3..ff12c67 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,9 +20,13 @@ jobs: - name: Validate composer.json and composer.lock run: composer validate --strict + + - name: Install dependencies + run: composer install --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist - - name: Compose install - run: composer install --ignore-platform-reqs + - name: Start container + # For local testing, also run this before retrying tests: docker rm --force $(docker ps -aq) + run: docker compose up -d && sleep 15 - name: Run tests - run: composer test \ No newline at end of file + run: docker compose exec tests vendor/bin/phpunit --configuration phpunit.xml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5e8a951..e913320 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,16 +9,22 @@ COPY composer.lock /usr/local/src/ COPY composer.json /usr/local/src/ RUN composer install --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist - + +RUN docker-php-ext-install sockets + FROM php:8.0-cli-alpine as final +ENV DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} +ENV DOCKER_API_VERSION=1.43 + LABEL maintainer="team@appwrite.io" RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN \ apk update \ - && apk add --no-cache make automake autoconf gcc g++ git brotli-dev \ + && apk add --no-cache make automake autoconf gcc g++ git brotli-dev docker-cli \ + && docker-php-ext-install sockets \ && docker-php-ext-install opcache WORKDIR /usr/src/code diff --git a/composer.lock b/composer.lock index 64b086d..e0890e8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,33 +4,31 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9df3ba5cdbb0b79eaf17b4bcb407c05b", + "content-hash": "48c2bbcd6ef1dc35e86875383889ffa9", "packages": [ { "name": "utopia-php/cli", - "version": "1.0.0-RC1", + "version": "0.16.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cli.git", - "reference": "7664161dcdb9b76a3ece0ae2f36a9aca1e548e80" + "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cli/zipball/7664161dcdb9b76a3ece0ae2f36a9aca1e548e80", - "reference": "7664161dcdb9b76a3ece0ae2f36a9aca1e548e80", + "url": "https://api.github.com/repos/utopia-php/cli/zipball/5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", + "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", "shasum": "" }, "require": { "php": ">=7.4", - "utopia-php/di": "0.1.*", - "utopia-php/framework": "1.0.*" + "utopia-php/framework": "0.*.*" }, "require-dev": { "laravel/pint": "1.2.*", - "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.3", "squizlabs/php_codesniffer": "^3.6", - "swoole/ide-helper": "4.8.8" + "vimeo/psalm": "4.0.1" }, "type": "library", "autoload": { @@ -53,79 +51,29 @@ ], "support": { "issues": "https://github.com/utopia-php/cli/issues", - "source": "https://github.com/utopia-php/cli/tree/1.0.0-RC1" - }, - "time": "2024-08-09T17:35:04+00:00" - }, - { - "name": "utopia-php/di", - "version": "0.1.0", - "source": { - "type": "git", - "url": "https://github.com/utopia-php/di.git", - "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/utopia-php/di/zipball/22490c95f7ac3898ed1c33f1b1b5dd577305ee31", - "reference": "22490c95f7ac3898ed1c33f1b1b5dd577305ee31", - "shasum": "" - }, - "require": { - "php": ">=8.2" - }, - "require-dev": { - "laravel/pint": "^1.2", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5.25", - "swoole/ide-helper": "4.8.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Utopia\\": "src/", - "Tests\\E2E\\": "tests/e2e" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A simple and lite library for managing dependency injections", - "keywords": [ - "framework", - "http", - "php", - "upf" - ], - "support": { - "issues": "https://github.com/utopia-php/di/issues", - "source": "https://github.com/utopia-php/di/tree/0.1.0" + "source": "https://github.com/utopia-php/cli/tree/0.16.0" }, - "time": "2024-08-08T14:35:19+00:00" + "time": "2023-08-05T13:13:08+00:00" }, { "name": "utopia-php/framework", - "version": "1.0.0-RC2", + "version": "0.34.3", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "d1e9674dbf33bed03fa53854ec1f2c6e074cf4d7" + "reference": "e3bbca07c1df4e908ea9d3ce4f59367a7696b66b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/d1e9674dbf33bed03fa53854ec1f2c6e074cf4d7", - "reference": "d1e9674dbf33bed03fa53854ec1f2c6e074cf4d7", + "url": "https://api.github.com/repos/utopia-php/http/zipball/e3bbca07c1df4e908ea9d3ce4f59367a7696b66b", + "reference": "e3bbca07c1df4e908ea9d3ce4f59367a7696b66b", "shasum": "" }, "require": { "ext-swoole": "*", - "php": ">=8.0", - "utopia-php/servers": "0.1.* " + "php": ">=8.0" }, "require-dev": { - "ext-xdebug": "*", "laravel/pint": "^1.2", "phpbench/phpbench": "^1.2", "phpstan/phpstan": "^1.10", @@ -135,7 +83,8 @@ "type": "library", "autoload": { "psr-4": { - "Utopia\\": "src/" + "Utopia\\": "src/", + "Tests\\E2E\\": "tests/e2e" } }, "notification-url": "https://packagist.org/downloads/", @@ -151,62 +100,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/1.0.0-RC2" + "source": "https://github.com/utopia-php/http/tree/0.34.3" }, - "time": "2024-08-08T14:46:41+00:00" - }, - { - "name": "utopia-php/servers", - "version": "0.1.0", - "source": { - "type": "git", - "url": "https://github.com/utopia-php/servers.git", - "reference": "7d9e4f364fb1ab1889fb89ca96eb9946467cb09c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/utopia-php/servers/zipball/7d9e4f364fb1ab1889fb89ca96eb9946467cb09c", - "reference": "7d9e4f364fb1ab1889fb89ca96eb9946467cb09c", - "shasum": "" - }, - "require": { - "php": ">=8.0", - "utopia-php/di": "0.1.*" - }, - "require-dev": { - "laravel/pint": "^0.2.3", - "phpstan/phpstan": "^1.8", - "phpunit/phpunit": "^9.5.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Utopia\\Servers\\": "src/Servers" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Team Appwrite", - "email": "team@appwrite.io" - } - ], - "description": "A base library for building Utopia style servers.", - "keywords": [ - "framework", - "php", - "servers", - "upf", - "utopia" - ], - "support": { - "issues": "https://github.com/utopia-php/servers/issues", - "source": "https://github.com/utopia-php/servers/tree/0.1.0" - }, - "time": "2024-08-08T14:31:39+00:00" + "time": "2024-07-02T15:08:46+00:00" } ], "packages-dev": [ @@ -584,16 +480,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.10", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f" + "reference": "384af967d35b2162f69526c7276acadce534d0e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/640410b32995914bde3eed26fa89552f9c2c082f", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/384af967d35b2162f69526c7276acadce534d0e1", + "reference": "384af967d35b2162f69526c7276acadce534d0e1", "shasum": "" }, "require": { @@ -638,39 +534,39 @@ "type": "github" } ], - "time": "2024-08-08T09:02:50+00:00" + "time": "2024-08-27T09:18:05+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.31", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -679,7 +575,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -708,7 +604,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -716,7 +612,7 @@ "type": "github" } ], - "time": "2024-03-02T06:37:42+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2077,7 +1973,7 @@ } ], "aliases": [], - "minimum-stability": "RC", + "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, diff --git a/docker-compose.yml b/docker-compose.yml index d7c2211..9123116 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,9 @@ services: context: . networks: - orchestration - volumes: + environment: + HOST_DIR: "$PWD" # Nessessary to mount test resources to child containers + volumes: - ./:/usr/src/code - /var/run/docker.sock:/var/run/docker.sock diff --git a/src/Orchestration/Adapter.php b/src/Orchestration/Adapter.php index 0fefb74..9f62aba 100644 --- a/src/Orchestration/Adapter.php +++ b/src/Orchestration/Adapter.php @@ -60,6 +60,11 @@ abstract public function networkConnect(string $container, string $network): boo */ abstract public function networkDisconnect(string $container, string $network, bool $force = false): bool; + /** + * Check if a network exists + */ + abstract public function networkExists(string $name): bool; + /** * List Networks * diff --git a/src/Orchestration/Adapter/DockerAPI.php b/src/Orchestration/Adapter/DockerAPI.php index 2b6d785..44eb4e5 100644 --- a/src/Orchestration/Adapter/DockerAPI.php +++ b/src/Orchestration/Adapter/DockerAPI.php @@ -130,34 +130,50 @@ protected function streamCall(string $url, int $timeout = -1): array $stdout = ''; $stderr = ''; - $callback = function (mixed $ch, string $str) use (&$stdout, &$stderr): int { + $isHeader = true; + $currentHeader = null; + $currentData = ''; + + $callback = function (mixed $ch, string $str) use (&$stdout, &$stderr, &$isHeader, &$currentHeader, &$currentData): int { if (empty($str)) { return 0; } - $rawStream = unpack('C*', $str); - $stream = $rawStream[1]; // 1-based index, not 0-based - - // Ascii encoding support - if ($stream === \ord('1')) { - $stream = 1; - } elseif ($stream === \ord('2')) { - $stream = 2; - } - - switch ($stream) { // only 1 or 2, as set while creating exec - case 1: - $packed = pack('C*', ...\array_slice($rawStream, 8)); - $stdout .= $packed; - break; - case 2: - $packed = pack('C*', ...\array_slice($rawStream, 8)); - $stderr .= $packed; - break; + $originalSize = \strlen($str); + + while (\strlen($str) > 0) { + if ($isHeader) { + $header = \unpack('Ctype/Cfill1/Cfill2/Cfill3/Nsize', $str); + $str = \substr($str, 8, null); + $isHeader = false; + $currentHeader = $header; + } else { + $size = $currentHeader['size']; + $type = $currentHeader['type']; + + if (\strlen($str) >= $size) { + $currentData .= \substr($str, 0, $size); + $str = \substr($str, $size, null); + $isHeader = true; + $currentHeader = null; + + if ($type === 1) { + $stdout .= $currentData; + } else { + $stderr .= $currentData; + } + $currentData = ''; + } else { + $currentHeader['size'] -= \strlen($str); + $currentData .= $str; + $str = ''; + } + } } - return strlen($str); // must return full frame from callback + return $originalSize; // must return full frame from callback }; + \curl_setopt($ch, CURLOPT_WRITEFUNCTION, $callback); \curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); @@ -265,6 +281,16 @@ public function networkDisconnect(string $container, string $network, bool $forc return $result['code'] === 200; } + /** + * Check if a network exists + */ + public function networkExists(string $name): bool + { + $result = $this->call('http://localhost/networks/'.$name, 'GET'); + + return $result['code'] === 200; + } + /** * Get usage stats of containers * diff --git a/src/Orchestration/Adapter/DockerCLI.php b/src/Orchestration/Adapter/DockerCLI.php index f4e9019..e23f0b3 100644 --- a/src/Orchestration/Adapter/DockerCLI.php +++ b/src/Orchestration/Adapter/DockerCLI.php @@ -76,6 +76,18 @@ public function networkDisconnect(string $container, string $network, bool $forc return $result === 0; } + /** + * Check if a network exists + */ + public function networkExists(string $name): bool + { + $output = ''; + + $result = Console::execute('docker network inspect '.$name.' --format "{{.Name}}"', '', $output); + + return $result === 0 && trim($output) === $name; + } + /** * Get usage stats of containers * diff --git a/src/Orchestration/Orchestration.php b/src/Orchestration/Orchestration.php index 5ae5922..6e366b7 100644 --- a/src/Orchestration/Orchestration.php +++ b/src/Orchestration/Orchestration.php @@ -125,6 +125,14 @@ public function networkDisconnect(string $container, string $network, bool $forc return $this->adapter->networkDisconnect($container, $network, $force); } + /** + * Check if a network exists + */ + public function networkExists(string $name): bool + { + return $this->adapter->networkExists($name); + } + /** * Pull Image */ diff --git a/tests/Orchestration/Base.php b/tests/Orchestration/Base.php index b6be5f7..5cf7082 100644 --- a/tests/Orchestration/Base.php +++ b/tests/Orchestration/Base.php @@ -17,9 +17,18 @@ abstract protected static function getAdapterName(): string; */ public static $containerID; - public function setUp(): void {} + public function setUp(): void + { + \exec('rm -rf /usr/src/code/tests/Orchestration/Resources/screens'); // cleanup + + \exec('sh -c "cd /usr/src/code/tests/Orchestration/Resources && tar -zcf ./php.tar.gz php"'); + \exec('sh -c "cd /usr/src/code/tests/Orchestration/Resources && tar -zcf ./timeout.tar.gz timeout"'); + } - public function tearDown(): void {} + public function tearDown(): void + { + \exec('rm -rf /usr/src/code/tests/Orchestration/Resources/screens'); // cleanup + } public function testPullImage(): void { @@ -58,10 +67,10 @@ public function testCreateContainer(): void '', '/usr/local/src/', [ - __DIR__.'/Resources:/test:rw', + \getenv('HOST_DIR').'/tests/Orchestration/Resources:/test:rw', ], [], - __DIR__.'/Resources' + \getenv('HOST_DIR').'/tests/Orchestration/Resources' ); $this->assertNotEmpty($response); @@ -78,22 +87,22 @@ public function testCreateContainer(): void '', '/usr/local/src/', [ - __DIR__.'/Resources:/test:rw', + \getenv('HOST_DIR').'/tests/Orchestration/Resources:/test:rw', ], [], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', restart: DockerAPI::RESTART_ALWAYS ); $this->assertNotEmpty($response); - sleep(7); + sleep(10); // Docker restart can take quite long to restart. This is safety to prevent flaky tests $output = []; \exec('docker logs '.$response, $output); $output = \implode("\n", $output); $occurances = \substr_count($output, 'Custom start'); - $this->assertGreaterThanOrEqual(5, $occurances); + $this->assertGreaterThanOrEqual(2, $occurances); // 2 logs mean it restarted at least once $response = static::getOrchestration()->remove('TestContainerWithRestart', true); $this->assertEquals(true, $response); @@ -110,10 +119,10 @@ public function testCreateContainer(): void '', '/usr/local/src/', [ - __DIR__.'/Resources:/test:rw', + \getenv('HOST_DIR').'/tests/Orchestration/Resources:/test:rw', ], [], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', restart: DockerAPI::RESTART_NO ); @@ -147,7 +156,7 @@ public function testCreateContainer(): void '/usr/local/src/', [], [], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', ); /** @@ -167,7 +176,7 @@ public function testCreateContainer(): void '/usr/local/src/', [], [], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', ); } @@ -220,7 +229,7 @@ public function testNetworkConnect(): void [ 'teasdsa' => '', ], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', [ 'test2' => 'Hello World!', ], @@ -268,37 +277,64 @@ public function testExecContainer(): void */ $output = ''; - $this->expectException(\Exception::class); - - static::getOrchestration()->execute( - '60clotVWpufbEpy33zJLcoYHrUTqWaD1FV0FZWsw', // Non-Existent Container - [ - 'php', - 'index.php', - ], - $output - ); + $threwException = false; + try { + static::getOrchestration()->execute( + '60clotVWpufbEpy33zJLcoYHrUTqWaD1FV0FZWsw', // Non-Existent Container + [ + 'php', + 'index.php', + ], + $output + ); + } catch (\Exception $err) { + $threwException = true; + } + $this->assertTrue($threwException); /** * Test for Failure */ $output = ''; - $this->expectException(\Exception::class); + $threwException = false; + try { + static::getOrchestration()->execute( + 'TestContainer', + [ + 'php', + 'doesnotexist.php', // Non-Existent File + ], + $output, + [ + 'test' => 'testEnviromentVariable', + ], + 1 + ); + } catch (\Exception $err) { + $threwException = true; + } + $this->assertTrue($threwException); + + /** + * Test for Success + */ + $output = ''; static::getOrchestration()->execute( 'TestContainer', [ 'php', - 'doesnotexist.php', // Non-Existent File + 'index.php', ], $output, [ 'test' => 'testEnviromentVariable', ], - 1 ); + $this->assertEquals('Hello World! testEnviromentVariable', $output); + /** * Test for Success */ @@ -307,16 +343,20 @@ public function testExecContainer(): void static::getOrchestration()->execute( 'TestContainer', [ - 'php', - 'index.php', - ], - $output, - [ - 'test' => 'testEnviromentVariable', + 'sh', + 'logs.sh', ], + $output ); - $this->assertEquals('Hello World! testEnviromentVariable', $output); + $length = 0; + $length += 1024 * 1024 * 5; // 5MB + $length += 5; // "start" + $length += 3; // "end" + + $this->assertEquals($length, \strlen($output)); + $this->assertStringStartsWith('START', $output); + $this->assertStringEndsWith('END', $output); } /** @@ -358,7 +398,7 @@ public function testTimeoutContainer(): void [ 'teasdsa' => '', ], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', [ 'test2' => 'Hello World!', ] @@ -372,19 +412,22 @@ public function testTimeoutContainer(): void * Test for Failure */ $output = ''; - - $this->expectException(\Exception::class); - - $response = static::getOrchestration()->execute( - 'TestContainerTimeout', - [ - 'php', - 'index.php', - ], - $output, - [], - 1 - ); + $threwException = false; + try { + $response = static::getOrchestration()->execute( + 'TestContainerTimeout', + [ + 'php', + 'index.php', + ], + $output, + [], + 1 + ); + } catch (\Exception $err) { + $threwException = true; + } + $this->assertTrue($threwException); /** * Test for Success @@ -414,7 +457,7 @@ public function testTimeoutContainer(): void [ 'sh', '-c', - 'echo Hello World!', + 'echo -n Hello World!', // -n prevents from adding linebreak afterwards ], $output, [], @@ -454,7 +497,7 @@ public function testListFilters(): void } /** - * @depends testCreateContainer + * @depends testExecContainer */ public function testRemoveContainer(): void { @@ -530,7 +573,7 @@ public function testRunRemove(): void [ 'teasdsa' => '', ], - __DIR__.'/Resources', + \getenv('HOST_DIR').'/tests/Orchestration/Resources', [ 'test2' => 'Hello World!', ], @@ -557,7 +600,8 @@ public function testUsageStats(): void * Test for Success */ $stats = static::getOrchestration()->getStats(); - $this->assertCount(0, $stats, 'Container(s) still running: '.\json_encode($stats, JSON_PRETTY_PRINT)); + // 1 expected due to container running tests + $this->assertCount(1, $stats, 'Container(s) still running: '.\json_encode($stats, JSON_PRETTY_PRINT)); // This allows CPU-heavy load check static::getOrchestration()->setCpus(1); @@ -571,7 +615,7 @@ public function testUsageStats(): void 'apk update && apk add screen && tail -f /dev/null', ], workdir: '/usr/local/src/', - mountFolder: __DIR__.'/Resources', + mountFolder: \getenv('HOST_DIR').'/tests/Orchestration/Resources', labels: ['utopia-container-type' => 'stats'] ); @@ -586,7 +630,7 @@ public function testUsageStats(): void 'apk update && apk add screen && tail -f /dev/null', ], workdir: '/usr/local/src/', - mountFolder: __DIR__.'/Resources', + mountFolder: \getenv('HOST_DIR').'/tests/Orchestration/Resources', ); $this->assertNotEmpty($containerId2); @@ -603,7 +647,7 @@ public function testUsageStats(): void // Fetch stats, should include high CPU usage $stats = static::getOrchestration()->getStats(); - $this->assertCount(2, $stats); + $this->assertCount(2 + 1, $stats); // +1 due to container running tests $this->assertNotEmpty($stats[0]->getContainerId()); $this->assertEquals(64, \strlen($stats[0]->getContainerId())); @@ -672,4 +716,24 @@ public function testUsageStats(): void $stats = static::getOrchestration()->getStats('IDontExist'); } + + public function testNetworkExists(): void + { + $networkName = 'test_network_'.uniqid(); + + // Test non-existent network + $this->assertFalse(static::getOrchestration()->networkExists($networkName)); + + // Create network and test it exists + $response = static::getOrchestration()->createNetwork($networkName); + $this->assertTrue($response); + $this->assertTrue(static::getOrchestration()->networkExists($networkName)); + + // Remove network + $response = static::getOrchestration()->removeNetwork($networkName); + $this->assertTrue($response); + + // Test removed network + $this->assertFalse(static::getOrchestration()->networkExists($networkName)); + } } diff --git a/tests/Orchestration/Resources/.gitignore b/tests/Orchestration/Resources/.gitignore new file mode 100644 index 0000000..c32b546 --- /dev/null +++ b/tests/Orchestration/Resources/.gitignore @@ -0,0 +1 @@ +*.tar.gz \ No newline at end of file diff --git a/tests/Orchestration/Resources/php.tar.gz b/tests/Orchestration/Resources/php.tar.gz deleted file mode 100644 index a2fccbb..0000000 Binary files a/tests/Orchestration/Resources/php.tar.gz and /dev/null differ diff --git a/tests/Orchestration/Resources/php/logs.sh b/tests/Orchestration/Resources/php/logs.sh new file mode 100644 index 0000000..f8d0e2b --- /dev/null +++ b/tests/Orchestration/Resources/php/logs.sh @@ -0,0 +1,16 @@ +set -e + +CHARS_128="11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +CHARS_1KB="$CHARS_128$CHARS_128$CHARS_128$CHARS_128$CHARS_128$CHARS_128$CHARS_128$CHARS_128" +CHARS_16KB="$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB$CHARS_1KB" +CHARS_128KB="$CHARS_16KB$CHARS_16KB$CHARS_16KB$CHARS_16KB$CHARS_16KB$CHARS_16KB$CHARS_16KB$CHARS_16KB" +CHARS_1MB="$CHARS_128KB$CHARS_128KB$CHARS_128KB$CHARS_128KB$CHARS_128KB$CHARS_128KB$CHARS_128KB$CHARS_128KB" + +# 5 * CHARS_1MB +echo -n "START" +echo -n "$CHARS_1MB" +echo -n "$CHARS_1MB" +echo -n "$CHARS_1MB" +echo -n "$CHARS_1MB" +echo -n "$CHARS_1MB" +echo -n "END" \ No newline at end of file diff --git a/tests/Orchestration/Resources/timeout.tar.gz b/tests/Orchestration/Resources/timeout.tar.gz deleted file mode 100644 index d1c7c03..0000000 Binary files a/tests/Orchestration/Resources/timeout.tar.gz and /dev/null differ